diff options
Diffstat (limited to 'lib/Sema/Sema.cpp')
-rw-r--r-- | lib/Sema/Sema.cpp | 177 |
1 files changed, 163 insertions, 14 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 30a9cd7..7f79f0c 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/APFloat.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/ExternalSemaSource.h" @@ -29,6 +30,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -90,13 +92,13 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, PackContext(0), MSStructPragmaOn(false), VisContext(0), ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0), IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0), - NSNumberDecl(0), NSArrayDecl(0), ArrayWithObjectsMethod(0), + NSNumberDecl(0), + NSStringDecl(0), StringWithUTF8StringMethod(0), + NSArrayDecl(0), ArrayWithObjectsMethod(0), NSDictionaryDecl(0), DictionaryWithObjectsMethod(0), GlobalNewDeleteDeclared(false), - ObjCShouldCallSuperDealloc(false), - ObjCShouldCallSuperFinalize(false), TUKind(TUKind), - NumSFINAEErrors(0), InFunctionDeclarator(0), SuppressAccessChecking(false), + NumSFINAEErrors(0), InFunctionDeclarator(0), AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(0), TyposCorrected(0), @@ -176,6 +178,10 @@ void Sema::Initialize() { if (IdResolver.begin(Protocol) == IdResolver.end()) PushOnScopeChains(Context.getObjCProtocolDecl(), TUScope); } + + DeclarationName BuiltinVaList = &Context.Idents.get("__builtin_va_list"); + if (IdResolver.begin(BuiltinVaList) == IdResolver.end()) + PushOnScopeChains(Context.getBuiltinVaListDecl(), TUScope); } Sema::~Sema() { @@ -199,7 +205,6 @@ Sema::~Sema() { ExternalSema->ForgetSema(); } - /// makeUnavailableInSystemHeader - There is an error in the current /// context. If we're still in a system header, and we can plausibly /// make the relevant declaration unavailable instead of erroring, do @@ -420,10 +425,88 @@ void Sema::LoadExternalWeakUndeclaredIdentifiers() { } } + +typedef llvm::DenseMap<const CXXRecordDecl*, bool> RecordCompleteMap; + +/// \brief Returns true, if all methods and nested classes of the given +/// CXXRecordDecl are defined in this translation unit. +/// +/// Should only be called from ActOnEndOfTranslationUnit so that all +/// definitions are actually read. +static bool MethodsAndNestedClassesComplete(const CXXRecordDecl *RD, + RecordCompleteMap &MNCComplete) { + RecordCompleteMap::iterator Cache = MNCComplete.find(RD); + if (Cache != MNCComplete.end()) + return Cache->second; + if (!RD->isCompleteDefinition()) + return false; + bool Complete = true; + for (DeclContext::decl_iterator I = RD->decls_begin(), + E = RD->decls_end(); + I != E && Complete; ++I) { + if (const CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(*I)) + Complete = M->isDefined() || (M->isPure() && !isa<CXXDestructorDecl>(M)); + else if (const FunctionTemplateDecl *F = dyn_cast<FunctionTemplateDecl>(*I)) + Complete = F->getTemplatedDecl()->isDefined(); + else if (const CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(*I)) { + if (R->isInjectedClassName()) + continue; + if (R->hasDefinition()) + Complete = MethodsAndNestedClassesComplete(R->getDefinition(), + MNCComplete); + else + Complete = false; + } + } + MNCComplete[RD] = Complete; + return Complete; +} + +/// \brief Returns true, if the given CXXRecordDecl is fully defined in this +/// translation unit, i.e. all methods are defined or pure virtual and all +/// friends, friend functions and nested classes are fully defined in this +/// translation unit. +/// +/// Should only be called from ActOnEndOfTranslationUnit so that all +/// definitions are actually read. +static bool IsRecordFullyDefined(const CXXRecordDecl *RD, + RecordCompleteMap &RecordsComplete, + RecordCompleteMap &MNCComplete) { + RecordCompleteMap::iterator Cache = RecordsComplete.find(RD); + if (Cache != RecordsComplete.end()) + return Cache->second; + bool Complete = MethodsAndNestedClassesComplete(RD, MNCComplete); + for (CXXRecordDecl::friend_iterator I = RD->friend_begin(), + E = RD->friend_end(); + I != E && Complete; ++I) { + // Check if friend classes and methods are complete. + if (TypeSourceInfo *TSI = (*I)->getFriendType()) { + // Friend classes are available as the TypeSourceInfo of the FriendDecl. + if (CXXRecordDecl *FriendD = TSI->getType()->getAsCXXRecordDecl()) + Complete = MethodsAndNestedClassesComplete(FriendD, MNCComplete); + else + Complete = false; + } else { + // Friend functions are available through the NamedDecl of FriendDecl. + if (const FunctionDecl *FD = + dyn_cast<FunctionDecl>((*I)->getFriendDecl())) + Complete = FD->isDefined(); + else + // This is a template friend, give up. + Complete = false; + } + } + RecordsComplete[RD] = Complete; + return Complete; +} + /// 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() { + assert(DelayedDiagnostics.getCurrentPool() == NULL + && "reached end of translation unit with a pool attached?"); + // Only complete translation units define vtables and perform implicit // instantiations. if (TUKind == TU_Complete) { @@ -597,9 +680,17 @@ void Sema::ActOnEndOfTranslationUnit() { if (isa<CXXMethodDecl>(DiagD)) Diag(DiagD->getLocation(), diag::warn_unneeded_member_function) << DiagD->getDeclName(); - else - Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) - << /*function*/0 << DiagD->getDeclName(); + else { + if (FD->getStorageClassAsWritten() == SC_Static && + !FD->isInlineSpecified() && + !SourceMgr.isFromMainFile( + SourceMgr.getExpansionLoc(FD->getLocation()))) + Diag(DiagD->getLocation(), diag::warn_unneeded_static_internal_decl) + << DiagD->getDeclName(); + else + Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) + << /*function*/0 << DiagD->getDeclName(); + } } else { Diag(DiagD->getLocation(), isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function @@ -623,6 +714,23 @@ void Sema::ActOnEndOfTranslationUnit() { checkUndefinedInternals(*this); } + if (Diags.getDiagnosticLevel(diag::warn_unused_private_field, + SourceLocation()) + != DiagnosticsEngine::Ignored) { + RecordCompleteMap RecordsComplete; + RecordCompleteMap MNCComplete; + for (NamedDeclSetType::iterator I = UnusedPrivateFields.begin(), + E = UnusedPrivateFields.end(); I != E; ++I) { + const NamedDecl *D = *I; + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()); + if (RD && !RD->isUnion() && + IsRecordFullyDefined(RD, RecordsComplete, MNCComplete)) { + Diag(D->getLocation(), diag::warn_unused_private_field) + << D->getDeclName(); + } + } + } + // Check we've noticed that we're no longer parsing the initializer for every // variable. If we miss cases, then at best we have a performance issue and // at worst a rejects-valid bug. @@ -693,6 +801,15 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { // Count this failure so that we know that template argument deduction // has failed. ++NumSFINAEErrors; + + // Make a copy of this suppressed diagnostic and store it with the + // template-deduction information. + if (*Info && !(*Info)->hasSFINAEDiagnostic()) { + Diagnostic DiagInfo(&Diags); + (*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(), + PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); + } + Diags.setLastDiagnosticIgnored(); Diags.Clear(); return; @@ -709,6 +826,15 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { // Suppress this diagnostic. ++NumSFINAEErrors; + + // Make a copy of this suppressed diagnostic and store it with the + // template-deduction information. + if (*Info && !(*Info)->hasSFINAEDiagnostic()) { + Diagnostic DiagInfo(&Diags); + (*Info)->addSFINAEDiagnostic(DiagInfo.getLocation(), + PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); + } + Diags.setLastDiagnosticIgnored(); Diags.Clear(); @@ -725,13 +851,13 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { case DiagnosticIDs::SFINAE_Suppress: // Make a copy of this suppressed diagnostic and store it with the // template-deduction information; - Diagnostic DiagInfo(&Diags); - - if (*Info) + if (*Info) { + Diagnostic DiagInfo(&Diags); (*Info)->addSuppressedDiagnostic(DiagInfo.getLocation(), - PartialDiagnostic(DiagInfo,Context.getDiagAllocator())); - - // Suppress this diagnostic. + PartialDiagnostic(DiagInfo, Context.getDiagAllocator())); + } + + // Suppress this diagnostic. Diags.setLastDiagnosticIgnored(); Diags.Clear(); return; @@ -894,6 +1020,29 @@ LambdaScopeInfo *Sema::getCurLambda() { return dyn_cast<LambdaScopeInfo>(FunctionScopes.back()); } +void Sema::ActOnComment(SourceRange Comment) { + RawComment RC(SourceMgr, Comment); + if (RC.isAlmostTrailingComment()) { + SourceRange MagicMarkerRange(Comment.getBegin(), + Comment.getBegin().getLocWithOffset(3)); + StringRef MagicMarkerText; + switch (RC.getKind()) { + case RawComment::RCK_OrdinaryBCPL: + MagicMarkerText = "///<"; + break; + case RawComment::RCK_OrdinaryC: + MagicMarkerText = "/**<"; + break; + default: + llvm_unreachable("if this is an almost Doxygen comment, " + "it should be ordinary"); + } + Diag(Comment.getBegin(), diag::warn_not_a_doxygen_trailing_member_comment) << + FixItHint::CreateReplacement(MagicMarkerRange, MagicMarkerText); + } + Context.addComment(RC); +} + // Pin this vtable to this file. ExternalSemaSource::~ExternalSemaSource() {} |