John McCall cebee16bc0 When performing template-substitution into a type, don't just replace the
TemplateTypeParmType with the substituted type directly;  instead, replace it
with a SubstTemplateTypeParmType which will note that the type was originally
written as a template type parameter.  This makes it reasonable to preserve
source information even through template substitution.

Also define the new SubstTemplateTypeParmType class, obviously.

For consistency with current behavior, we stringize these types as if they
were the underlying type.  I'm not sure this is the right thing to do.
At any rate, I paled at adding yet another clause to the don't-desugar 'if'
statement, so I extracted a function to do it.  The new function also does
The Right Thing more often, I think:  e.g. if we have a chain of typedefs
leading to a vector type, we will now desugar all but the last one.

llvm-svn: 84412
2009-10-18 09:09:24 +00:00

514 lines
19 KiB
C++

//===--- Sema.cpp - AST Builder and Semantic Analysis Implementation ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the actions class which performs semantic analysis and
// builds an AST out of a parse stream.
//
//===----------------------------------------------------------------------===//
#include "Sema.h"
#include "llvm/ADT/DenseMap.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
using namespace clang;
/// Determines whether we should have an a.k.a. clause when
/// pretty-printing a type. There are two main criteria:
///
/// 1) Some types provide very minimal sugar that doesn't impede the
/// user's understanding --- for example, elaborated type
/// specifiers. If this is all the sugar we see, we don't want an
/// a.k.a. clause.
/// 2) Some types are technically sugared but are much more familiar
/// when seen in their sugared form --- for example, va_list,
/// vector types, and the magic Objective C types. We don't
/// want to desugar these, even if we do produce an a.k.a. clause.
static bool ShouldAKA(ASTContext &Context, QualType QT,
QualType& DesugaredQT) {
bool AKA = false;
QualifierCollector Qc;
while (true) {
const Type *Ty = Qc.strip(QT);
// Don't aka just because we saw an elaborated type...
if (isa<ElaboratedType>(Ty)) {
QT = cast<ElaboratedType>(Ty)->desugar();
continue;
}
// ...or a qualified name type...
if (isa<QualifiedNameType>(Ty)) {
QT = cast<QualifiedNameType>(Ty)->desugar();
continue;
}
// ...or a substituted template type parameter.
if (isa<SubstTemplateTypeParmType>(Ty)) {
QT = cast<SubstTemplateTypeParmType>(Ty)->desugar();
continue;
}
// Don't desugar template specializations.
if (isa<TemplateSpecializationType>(Ty))
break;
// Don't desugar magic Objective-C types.
if (QualType(Ty,0) == Context.getObjCIdType() ||
QualType(Ty,0) == Context.getObjCClassType() ||
QualType(Ty,0) == Context.getObjCSelType() ||
QualType(Ty,0) == Context.getObjCProtoType())
break;
// Don't desugar va_list.
if (QualType(Ty,0) == Context.getBuiltinVaListType())
break;
// Otherwise, do a single-step desugar.
QualType Underlying;
bool IsSugar = false;
switch (Ty->getTypeClass()) {
#define ABSTRACT_TYPE(Class, Base)
#define TYPE(Class, Base) \
case Type::Class: { \
const Class##Type *CTy = cast<Class##Type>(Ty); \
if (CTy->isSugared()) { \
IsSugar = true; \
Underlying = CTy->desugar(); \
} \
break; \
}
#include "clang/AST/TypeNodes.def"
}
// If it wasn't sugared, we're done.
if (!IsSugar)
break;
// If the desugared type is a vector type, we don't want to expand
// it, it will turn into an attribute mess. People want their "vec4".
if (isa<VectorType>(Underlying))
break;
// Otherwise, we're tearing through something opaque; note that
// we'll eventually need an a.k.a. clause and keep going.
AKA = true;
QT = Underlying;
continue;
}
// If we ever tore through opaque sugar
if (AKA) {
DesugaredQT = Qc.apply(QT);
return true;
}
return false;
}
/// \brief Convert the given type to a string suitable for printing as part of
/// a diagnostic.
///
/// \param Context the context in which the type was allocated
/// \param Ty the type to print
static std::string ConvertTypeToDiagnosticString(ASTContext &Context,
QualType Ty) {
// FIXME: Playing with std::string is really slow.
std::string S = Ty.getAsString(Context.PrintingPolicy);
// Consider producing an a.k.a. clause if removing all the direct
// sugar gives us something "significantly different".
QualType DesugaredTy;
if (ShouldAKA(Context, Ty, DesugaredTy)) {
S = "'"+S+"' (aka '";
S += DesugaredTy.getAsString(Context.PrintingPolicy);
S += "')";
return S;
}
S = "'" + S + "'";
return S;
}
/// ConvertQualTypeToStringFn - This function is used to pretty print the
/// specified QualType as a string in diagnostics.
static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val,
const char *Modifier, unsigned ModLen,
const char *Argument, unsigned ArgLen,
llvm::SmallVectorImpl<char> &Output,
void *Cookie) {
ASTContext &Context = *static_cast<ASTContext*>(Cookie);
std::string S;
bool NeedQuotes = true;
if (Kind == Diagnostic::ak_qualtype) {
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for QualType argument");
QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val)));
S = ConvertTypeToDiagnosticString(Context, Ty);
NeedQuotes = false;
} else if (Kind == Diagnostic::ak_declarationname) {
DeclarationName N = DeclarationName::getFromOpaqueInteger(Val);
S = N.getAsString();
if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0)
S = '+' + S;
else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) && ArgLen==0)
S = '-' + S;
else
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for DeclarationName argument");
} else if (Kind == Diagnostic::ak_nameddecl) {
bool Qualified;
if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0)
Qualified = true;
else {
assert(ModLen == 0 && ArgLen == 0 &&
"Invalid modifier for NamedDecl* argument");
Qualified = false;
}
reinterpret_cast<NamedDecl*>(Val)->getNameForDiagnostic(S,
Context.PrintingPolicy,
Qualified);
} else if (Kind == Diagnostic::ak_nestednamespec) {
llvm::raw_string_ostream OS(S);
reinterpret_cast<NestedNameSpecifier*> (Val)->print(OS,
Context.PrintingPolicy);
NeedQuotes = false;
} else {
assert(Kind == Diagnostic::ak_declcontext);
DeclContext *DC = reinterpret_cast<DeclContext *> (Val);
NeedQuotes = false;
if (!DC) {
assert(false && "Should never have a null declaration context");
S = "unknown context";
} else if (DC->isTranslationUnit()) {
// FIXME: Get these strings from some localized place
if (Context.getLangOptions().CPlusPlus)
S = "the global namespace";
else
S = "the global scope";
} else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) {
S = ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type));
NeedQuotes = false;
} else {
// FIXME: Get these strings from some localized place
NamedDecl *ND = cast<NamedDecl>(DC);
if (isa<NamespaceDecl>(ND))
S += "namespace ";
else if (isa<ObjCMethodDecl>(ND))
S += "method ";
else if (isa<FunctionDecl>(ND))
S += "function ";
S += "'";
ND->getNameForDiagnostic(S, Context.PrintingPolicy, true);
S += "'";
NeedQuotes = false;
}
}
if (NeedQuotes)
Output.push_back('\'');
Output.append(S.begin(), S.end());
if (NeedQuotes)
Output.push_back('\'');
}
static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *Name) {
if (C.getLangOptions().CPlusPlus)
return CXXRecordDecl::Create(C, TagDecl::TK_struct,
C.getTranslationUnitDecl(),
SourceLocation(), &C.Idents.get(Name));
return RecordDecl::Create(C, TagDecl::TK_struct,
C.getTranslationUnitDecl(),
SourceLocation(), &C.Idents.get(Name));
}
void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) {
TUScope = S;
PushDeclContext(S, Context.getTranslationUnitDecl());
if (PP.getTargetInfo().getPointerWidth(0) >= 64) {
// Install [u]int128_t for 64-bit targets.
PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
SourceLocation(),
&Context.Idents.get("__int128_t"),
Context.Int128Ty), TUScope);
PushOnScopeChains(TypedefDecl::Create(Context, CurContext,
SourceLocation(),
&Context.Idents.get("__uint128_t"),
Context.UnsignedInt128Ty), TUScope);
}
if (!PP.getLangOptions().ObjC1) return;
// Built-in ObjC types may already be set by PCHReader (hence isNull checks).
if (Context.getObjCSelType().isNull()) {
// Synthesize "typedef struct objc_selector *SEL;"
RecordDecl *SelTag = CreateStructDecl(Context, "objc_selector");
PushOnScopeChains(SelTag, TUScope);
QualType SelT = Context.getPointerType(Context.getTagDeclType(SelTag));
TypedefDecl *SelTypedef = TypedefDecl::Create(Context, CurContext,
SourceLocation(),
&Context.Idents.get("SEL"),
SelT);
PushOnScopeChains(SelTypedef, TUScope);
Context.setObjCSelType(Context.getTypeDeclType(SelTypedef));
}
// Synthesize "@class Protocol;
if (Context.getObjCProtoType().isNull()) {
ObjCInterfaceDecl *ProtocolDecl =
ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(),
&Context.Idents.get("Protocol"),
SourceLocation(), true);
Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl));
PushOnScopeChains(ProtocolDecl, TUScope);
}
// Create the built-in typedef for 'id'.
if (Context.getObjCIdType().isNull()) {
TypedefDecl *IdTypedef =
TypedefDecl::Create(
Context, CurContext, SourceLocation(), &Context.Idents.get("id"),
Context.getObjCObjectPointerType(Context.ObjCBuiltinIdTy)
);
PushOnScopeChains(IdTypedef, TUScope);
Context.setObjCIdType(Context.getTypeDeclType(IdTypedef));
Context.ObjCIdRedefinitionType = Context.getObjCIdType();
}
// Create the built-in typedef for 'Class'.
if (Context.getObjCClassType().isNull()) {
TypedefDecl *ClassTypedef =
TypedefDecl::Create(
Context, CurContext, SourceLocation(), &Context.Idents.get("Class"),
Context.getObjCObjectPointerType(Context.ObjCBuiltinClassTy)
);
PushOnScopeChains(ClassTypedef, TUScope);
Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef));
Context.ObjCClassRedefinitionType = Context.getObjCClassType();
}
}
Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
bool CompleteTranslationUnit)
: LangOpts(pp.getLangOptions()), PP(pp), Context(ctxt), Consumer(consumer),
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
ExternalSource(0), CodeCompleter(0), CurContext(0),
PreDeclaratorDC(0), CurBlock(0), PackContext(0),
IdResolver(pp.getLangOptions()), StdNamespace(0), StdBadAlloc(0),
GlobalNewDeleteDeclared(false), ExprEvalContext(PotentiallyEvaluated),
CompleteTranslationUnit(CompleteTranslationUnit),
NumSFINAEErrors(0), CurrentInstantiationScope(0) {
TUScope = 0;
if (getLangOptions().CPlusPlus)
FieldCollector.reset(new CXXFieldCollector());
// Tell diagnostics how to render things from the AST library.
PP.getDiagnostics().SetArgToStringFn(ConvertArgToStringFn, &Context);
}
/// ImpCastExprToType - If Expr is not of type 'Type', insert an implicit cast.
/// If there is already an implicit cast, merge into the existing one.
/// If isLvalue, the result of the cast is an lvalue.
void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty,
CastExpr::CastKind Kind, bool isLvalue) {
QualType ExprTy = Context.getCanonicalType(Expr->getType());
QualType TypeTy = Context.getCanonicalType(Ty);
if (ExprTy == TypeTy)
return;
if (Expr->getType().getTypePtr()->isPointerType() &&
Ty.getTypePtr()->isPointerType()) {
QualType ExprBaseType =
cast<PointerType>(ExprTy.getUnqualifiedType())->getPointeeType();
QualType BaseType =
cast<PointerType>(TypeTy.getUnqualifiedType())->getPointeeType();
if (ExprBaseType.getAddressSpace() != BaseType.getAddressSpace()) {
Diag(Expr->getExprLoc(), diag::err_implicit_pointer_address_space_cast)
<< Expr->getSourceRange();
}
}
if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) {
if (ImpCast->getCastKind() == Kind) {
ImpCast->setType(Ty);
ImpCast->setLvalueCast(isLvalue);
return;
}
}
Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, isLvalue);
}
void Sema::DeleteExpr(ExprTy *E) {
if (E) static_cast<Expr*>(E)->Destroy(Context);
}
void Sema::DeleteStmt(StmtTy *S) {
if (S) static_cast<Stmt*>(S)->Destroy(Context);
}
/// ActOnEndOfTranslationUnit - This is called at the very end of the
/// translation unit when EOF is reached and all but the top-level scope is
/// popped.
void Sema::ActOnEndOfTranslationUnit() {
// C++: Perform implicit template instantiations.
//
// FIXME: When we perform these implicit instantiations, we do not carefully
// keep track of the point of instantiation (C++ [temp.point]). This means
// that name lookup that occurs within the template instantiation will
// always happen at the end of the translation unit, so it will find
// some names that should not be found. Although this is common behavior
// for C++ compilers, it is technically wrong. In the future, we either need
// to be able to filter the results of name lookup or we need to perform
// template instantiations earlier.
PerformPendingImplicitInstantiations();
// Check for #pragma weak identifiers that were never declared
// FIXME: This will cause diagnostics to be emitted in a non-determinstic
// order! Iterating over a densemap like this is bad.
for (llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator
I = WeakUndeclaredIdentifiers.begin(),
E = WeakUndeclaredIdentifiers.end(); I != E; ++I) {
if (I->second.getUsed()) continue;
Diag(I->second.getLocation(), diag::warn_weak_identifier_undeclared)
<< I->first;
}
if (!CompleteTranslationUnit)
return;
// C99 6.9.2p2:
// A declaration of an identifier for an object that has file
// scope without an initializer, and without a storage-class
// specifier or with the storage-class specifier static,
// constitutes a tentative definition. If a translation unit
// contains one or more tentative definitions for an identifier,
// and the translation unit contains no external definition for
// that identifier, then the behavior is exactly as if the
// translation unit contains a file scope declaration of that
// identifier, with the composite type as of the end of the
// translation unit, with an initializer equal to 0.
for (unsigned i = 0, e = TentativeDefinitionList.size(); i != e; ++i) {
VarDecl *VD = TentativeDefinitions.lookup(TentativeDefinitionList[i]);
// If the tentative definition was completed, it will be in the list, but
// not the map.
if (VD == 0 || VD->isInvalidDecl() || !VD->isTentativeDefinition(Context))
continue;
if (const IncompleteArrayType *ArrayT
= Context.getAsIncompleteArrayType(VD->getType())) {
if (RequireCompleteType(VD->getLocation(),
ArrayT->getElementType(),
diag::err_tentative_def_incomplete_type_arr)) {
VD->setInvalidDecl();
continue;
}
// Set the length of the array to 1 (C99 6.9.2p5).
Diag(VD->getLocation(), diag::warn_tentative_incomplete_array);
llvm::APInt One(Context.getTypeSize(Context.getSizeType()), true);
QualType T = Context.getConstantArrayType(ArrayT->getElementType(),
One, ArrayType::Normal, 0);
VD->setType(T);
} else if (RequireCompleteType(VD->getLocation(), VD->getType(),
diag::err_tentative_def_incomplete_type))
VD->setInvalidDecl();
// Notify the consumer that we've completed a tentative definition.
if (!VD->isInvalidDecl())
Consumer.CompleteTentativeDefinition(VD);
}
}
//===----------------------------------------------------------------------===//
// Helper functions.
//===----------------------------------------------------------------------===//
DeclContext *Sema::getFunctionLevelDeclContext() {
DeclContext *DC = PreDeclaratorDC ? PreDeclaratorDC : CurContext;
while (isa<BlockDecl>(DC))
DC = DC->getParent();
return DC;
}
/// getCurFunctionDecl - If inside of a function body, this returns a pointer
/// to the function decl for the function being parsed. If we're currently
/// in a 'block', this returns the containing context.
FunctionDecl *Sema::getCurFunctionDecl() {
DeclContext *DC = getFunctionLevelDeclContext();
return dyn_cast<FunctionDecl>(DC);
}
ObjCMethodDecl *Sema::getCurMethodDecl() {
DeclContext *DC = getFunctionLevelDeclContext();
return dyn_cast<ObjCMethodDecl>(DC);
}
NamedDecl *Sema::getCurFunctionOrMethodDecl() {
DeclContext *DC = getFunctionLevelDeclContext();
if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC))
return cast<NamedDecl>(DC);
return 0;
}
Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() {
if (!this->Emit())
return;
// If this is not a note, and we're in a template instantiation
// that is different from the last template instantiation where
// we emitted an error, print a template instantiation
// backtrace.
if (!SemaRef.Diags.isBuiltinNote(DiagID) &&
!SemaRef.ActiveTemplateInstantiations.empty() &&
SemaRef.ActiveTemplateInstantiations.back()
!= SemaRef.LastTemplateInstantiationErrorContext) {
SemaRef.PrintInstantiationStack();
SemaRef.LastTemplateInstantiationErrorContext
= SemaRef.ActiveTemplateInstantiations.back();
}
}
Sema::SemaDiagnosticBuilder
Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) {
SemaDiagnosticBuilder Builder(Diag(Loc, PD.getDiagID()));
PD.Emit(Builder);
return Builder;
}
void Sema::ActOnComment(SourceRange Comment) {
Context.Comments.push_back(Comment);
}