diff options
Diffstat (limited to 'lib/Sema/Sema.cpp')
-rw-r--r-- | lib/Sema/Sema.cpp | 329 |
1 files changed, 210 insertions, 119 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index d1e8e21..ba05a07 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -13,15 +13,65 @@ //===----------------------------------------------------------------------===// #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; -/// ConvertQualTypeToStringFn - This function is used to pretty print the +/// \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); + + // If this is a sugared type (like a typedef, typeof, etc), then unwrap one + // level of the sugar so that the type is more obvious to the user. + QualType DesugaredTy = Ty.getDesugaredType(); + + if (Ty != DesugaredTy && + // 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". + !isa<VectorType>(DesugaredTy) && + + // Don't aka just because we saw an elaborated type... + (!isa<ElaboratedType>(Ty) || + cast<ElaboratedType>(Ty)->desugar() != DesugaredTy) && + + // ...or a qualified name type... + (!isa<QualifiedNameType>(Ty) || + cast<QualifiedNameType>(Ty)->desugar() != DesugaredTy) && + + // ...or a non-dependent template specialization. + (!isa<TemplateSpecializationType>(Ty) || Ty->isDependentType()) && + + // Don't desugar magic Objective-C types. + Ty.getUnqualifiedType() != Context.getObjCIdType() && + Ty.getUnqualifiedType() != Context.getObjCClassType() && + Ty.getUnqualifiedType() != Context.getObjCSelType() && + Ty.getUnqualifiedType() != Context.getObjCProtoType() && + + // Not va_list. + Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) { + 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, @@ -29,48 +79,21 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, 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))); - - // FIXME: Playing with std::string is really slow. - S = Ty.getAsString(Context.PrintingPolicy); - - // If this is a sugared type (like a typedef, typeof, etc), then unwrap one - // level of the sugar so that the type is more obvious to the user. - QualType DesugaredTy = Ty->getDesugaredType(true); - DesugaredTy.setCVRQualifiers(DesugaredTy.getCVRQualifiers() | - Ty.getCVRQualifiers()); - - if (Ty != DesugaredTy && - // 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". - !isa<VectorType>(DesugaredTy) && - - // Don't desugar magic Objective-C types. - Ty.getUnqualifiedType() != Context.getObjCIdType() && - Ty.getUnqualifiedType() != Context.getObjCSelType() && - Ty.getUnqualifiedType() != Context.getObjCProtoType() && - Ty.getUnqualifiedType() != Context.getObjCClassType() && - - // Not va_list. - Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) { - S = "'"+S+"' (aka '"; - S += DesugaredTy.getAsString(Context.PrintingPolicy); - S += "')"; - Output.append(S.begin(), S.end()); - return; - } - + 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) @@ -78,30 +101,73 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, else assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for DeclarationName argument"); - } else { - assert(Kind == Diagnostic::ak_nameddecl); + } else if (Kind == Diagnostic::ak_nameddecl) { + bool Qualified; if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) - S = reinterpret_cast<NamedDecl*>(Val)->getQualifiedNameAsString(); - else { + Qualified = true; + else { assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for NamedDecl* argument"); - S = reinterpret_cast<NamedDecl*>(Val)->getNameAsString(); + 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.push_back('\''); Output.append(S.begin(), S.end()); - Output.push_back('\''); + + 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, + return CXXRecordDecl::Create(C, TagDecl::TK_struct, C.getTranslationUnitDecl(), SourceLocation(), &C.Idents.get(Name)); - return RecordDecl::Create(C, TagDecl::TK_struct, + return RecordDecl::Create(C, TagDecl::TK_struct, C.getTranslationUnitDecl(), SourceLocation(), &C.Idents.get(Name)); } @@ -109,7 +175,7 @@ static inline RecordDecl *CreateStructDecl(ASTContext &C, const char *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, @@ -121,16 +187,16 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { &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(), @@ -140,74 +206,72 @@ void Sema::ActOnTranslationUnitScope(SourceLocation Loc, Scope *S) { Context.setObjCSelType(Context.getTypeDeclType(SelTypedef)); } - if (Context.getObjCClassType().isNull()) { - RecordDecl *ClassTag = CreateStructDecl(Context, "objc_class"); - QualType ClassT = Context.getPointerType(Context.getTagDeclType(ClassTag)); - TypedefDecl *ClassTypedef = - TypedefDecl::Create(Context, CurContext, SourceLocation(), - &Context.Idents.get("Class"), ClassT); - PushOnScopeChains(ClassTag, TUScope); - PushOnScopeChains(ClassTypedef, TUScope); - Context.setObjCClassType(Context.getTypeDeclType(ClassTypedef)); - } - // Synthesize "@class Protocol; if (Context.getObjCProtoType().isNull()) { ObjCInterfaceDecl *ProtocolDecl = ObjCInterfaceDecl::Create(Context, CurContext, SourceLocation(), - &Context.Idents.get("Protocol"), + &Context.Idents.get("Protocol"), SourceLocation(), true); Context.setObjCProtoType(Context.getObjCInterfaceType(ProtocolDecl)); PushOnScopeChains(ProtocolDecl, TUScope); } - - // Synthesize "typedef struct objc_object { Class isa; } *id;" + // Create the built-in typedef for 'id'. if (Context.getObjCIdType().isNull()) { - RecordDecl *ObjectTag = CreateStructDecl(Context, "objc_object"); - - QualType ObjT = Context.getPointerType(Context.getTagDeclType(ObjectTag)); - PushOnScopeChains(ObjectTag, TUScope); - TypedefDecl *IdTypedef = TypedefDecl::Create(Context, CurContext, - SourceLocation(), - &Context.Idents.get("id"), - ObjT); + 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), CurContext(0), PreDeclaratorDC(0), - CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()), + 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) { - - StdNamespace = 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. +/// 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, bool isLvalue) { +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 = + QualType ExprBaseType = cast<PointerType>(ExprTy.getUnqualifiedType())->getPointeeType(); QualType BaseType = cast<PointerType>(TypeTy.getUnqualifiedType())->getPointeeType(); @@ -216,12 +280,16 @@ void Sema::ImpCastExprToType(Expr *&Expr, QualType Ty, bool isLvalue) { << Expr->getSourceRange(); } } - + if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(Expr)) { - ImpCast->setType(Ty); - ImpCast->setLvalueCast(isLvalue); - } else - Expr = new (Context) ImplicitCastExpr(Ty, Expr, isLvalue); + if (ImpCast->getCastKind() == Kind) { + ImpCast->setType(Ty); + ImpCast->setLvalueCast(isLvalue); + return; + } + } + + Expr = new (Context) ImplicitCastExpr(Ty, Kind, Expr, isLvalue); } void Sema::DeleteExpr(ExprTy *E) { @@ -241,12 +309,24 @@ void Sema::ActOnEndOfTranslationUnit() { // 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 + // 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; @@ -261,32 +341,31 @@ void Sema::ActOnEndOfTranslationUnit() { // 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 (llvm::DenseMap<DeclarationName, VarDecl *>::iterator - D = TentativeDefinitions.begin(), - DEnd = TentativeDefinitions.end(); - D != DEnd; ++D) { - VarDecl *VD = D->second; + for (unsigned i = 0, e = TentativeDefinitionList.size(); i != e; ++i) { + VarDecl *VD = TentativeDefinitions.lookup(TentativeDefinitionList[i]); - if (VD->isInvalidDecl() || !VD->isTentativeDefinition(Context)) + // 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 + if (const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(VD->getType())) { - if (RequireCompleteType(VD->getLocation(), + if (RequireCompleteType(VD->getLocation(), ArrayT->getElementType(), - diag::err_tentative_def_incomplete_type_arr)) + diag::err_tentative_def_incomplete_type_arr)) { VD->setInvalidDecl(); - else { - // 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); + continue; } - } else if (RequireCompleteType(VD->getLocation(), VD->getType(), + + // 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.getConstantArrayWithoutExprType(ArrayT->getElementType(), + One, ArrayType::Normal, 0); + VD->setType(T); + } else if (RequireCompleteType(VD->getLocation(), VD->getType(), diag::err_tentative_def_incomplete_type)) VD->setInvalidDecl(); @@ -302,27 +381,30 @@ void Sema::ActOnEndOfTranslationUnit() { // 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 = CurContext; - while (isa<BlockDecl>(DC)) - DC = DC->getParent(); + DeclContext *DC = getFunctionLevelDeclContext(); return dyn_cast<FunctionDecl>(DC); } ObjCMethodDecl *Sema::getCurMethodDecl() { - DeclContext *DC = CurContext; - while (isa<BlockDecl>(DC)) - DC = DC->getParent(); + DeclContext *DC = getFunctionLevelDeclContext(); return dyn_cast<ObjCMethodDecl>(DC); } NamedDecl *Sema::getCurFunctionOrMethodDecl() { - DeclContext *DC = CurContext; - while (isa<BlockDecl>(DC)) - DC = DC->getParent(); + DeclContext *DC = getFunctionLevelDeclContext(); if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC)) return cast<NamedDecl>(DC); return 0; @@ -331,21 +413,30 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() { 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.ActiveTemplateInstantiations.back() != SemaRef.LastTemplateInstantiationErrorContext) { SemaRef.PrintInstantiationStack(); - SemaRef.LastTemplateInstantiationErrorContext + 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); } + |