diff options
Diffstat (limited to 'lib')
374 files changed, 27784 insertions, 14661 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp index f291dec21fda..b57d9964736f 100644 --- a/lib/ARCMigrate/ARCMT.cpp +++ b/lib/ARCMigrate/ARCMT.cpp @@ -14,7 +14,7 @@ #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Frontend/Utils.h" #include "clang/AST/ASTConsumer.h" -#include "clang/Rewrite/Rewriter.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Basic/DiagnosticCategories.h" #include "clang/Lex/Preprocessor.h" @@ -42,7 +42,7 @@ bool CapturedDiagList::clearDiagnostic(ArrayRef<unsigned> IDs, while (I != List.end() && I->getLevel() == DiagnosticsEngine::Note) ++I; // Clear the diagnostic and any notes following it. - List.erase(eraseS, I); + I = List.erase(eraseS, I); continue; } @@ -147,54 +147,10 @@ public: } // end anonymous namespace -static inline StringRef SimulatorVersionDefineName() { - return "__IPHONE_OS_VERSION_MIN_REQUIRED="; -} - -/// \brief Parse the simulator version define: -/// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9]) -// and return the grouped values as integers, e.g: -// __IPHONE_OS_VERSION_MIN_REQUIRED=40201 -// will return Major=4, Minor=2, Micro=1. -static bool GetVersionFromSimulatorDefine(StringRef define, - unsigned &Major, unsigned &Minor, - unsigned &Micro) { - assert(define.startswith(SimulatorVersionDefineName())); - StringRef name, version; - llvm::tie(name, version) = define.split('='); - if (version.empty()) - return false; - std::string verstr = version.str(); - char *end; - unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10); - if (*end != '\0') - return false; - Major = num / 10000; - num = num % 10000; - Minor = num / 100; - Micro = num % 100; - return true; -} - static bool HasARCRuntime(CompilerInvocation &origCI) { // This duplicates some functionality from Darwin::AddDeploymentTarget // but this function is well defined, so keep it decoupled from the driver // and avoid unrelated complications. - - for (unsigned i = 0, e = origCI.getPreprocessorOpts().Macros.size(); - i != e; ++i) { - StringRef define = origCI.getPreprocessorOpts().Macros[i].first; - bool isUndef = origCI.getPreprocessorOpts().Macros[i].second; - if (isUndef) - continue; - if (!define.startswith(SimulatorVersionDefineName())) - continue; - unsigned Major = 0, Minor = 0, Micro = 0; - if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) && - Major < 10 && Minor < 100 && Micro < 100) - return Major >= 5; - } - llvm::Triple triple(origCI.getTargetOpts().Triple); if (triple.getOS() == llvm::Triple::IOS) @@ -237,18 +193,19 @@ createInvocationForMigration(CompilerInvocation &origCI) { WarnOpts.push_back("error=arc-unsafe-retained-assign"); CInvok->getDiagnosticOpts().Warnings = llvm_move(WarnOpts); - CInvok->getLangOpts()->ObjCRuntimeHasWeak = HasARCRuntime(origCI); + CInvok->getLangOpts()->ObjCARCWeak = HasARCRuntime(origCI); return CInvok.take(); } static void emitPremigrationErrors(const CapturedDiagList &arcDiags, - const DiagnosticOptions &diagOpts, + DiagnosticOptions *diagOpts, Preprocessor &PP) { TextDiagnosticPrinter printer(llvm::errs(), diagOpts); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, &printer, /*ShouldOwnClient=*/false)); + new DiagnosticsEngine(DiagID, diagOpts, &printer, + /*ShouldOwnClient=*/false)); Diags->setSourceManager(&PP.getSourceManager()); printer.BeginSourceFile(PP.getLangOpts(), &PP); @@ -286,7 +243,8 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, assert(DiagClient); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), + DiagClient, /*ShouldOwnClient=*/false)); // Filter of all diagnostics. CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); @@ -314,7 +272,7 @@ bool arcmt::checkForManualIssues(CompilerInvocation &origCI, } if (emitPremigrationARCErrors) - emitPremigrationErrors(capturedDiags, origCI.getDiagnosticOpts(), + emitPremigrationErrors(capturedDiags, &origCI.getDiagnosticOpts(), Unit->getPreprocessor()); if (!plistOut.empty()) { SmallVector<StoredDiagnostic, 8> arcDiags; @@ -395,7 +353,8 @@ static bool applyTransforms(CompilerInvocation &origCI, IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + new DiagnosticsEngine(DiagID, &origCI.getDiagnosticOpts(), + DiagClient, /*ShouldOwnClient=*/false)); if (outputDir.empty()) { origCI.getLangOpts()->ObjCAutoRefCount = true; @@ -434,7 +393,8 @@ bool arcmt::getFileRemappings(std::vector<std::pair<std::string,std::string> > & IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + new DiagnosticsEngine(DiagID, new DiagnosticOptions, + DiagClient, /*ShouldOwnClient=*/false)); FileRemapper remapper; bool err = remapper.initFromDisk(outputDir, *Diags, @@ -458,7 +418,8 @@ bool arcmt::getFileRemappingsFromFileList( llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + new DiagnosticsEngine(DiagID, new DiagnosticOptions, + DiagClient, /*ShouldOwnClient=*/false)); for (ArrayRef<StringRef>::iterator I = remapFiles.begin(), E = remapFiles.end(); I != E; ++I) { @@ -574,7 +535,8 @@ MigrationProcess::MigrationProcess(const CompilerInvocation &CI, if (!outputDir.empty()) { IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), + DiagClient, /*ShouldOwnClient=*/false)); Remapper.initFromDisk(outputDir, *Diags, /*ignoreIfFilesChanges=*/true); } } @@ -593,7 +555,8 @@ bool MigrationProcess::applyTransform(TransformFn trans, assert(DiagClient); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, DiagClient, /*ShouldOwnClient=*/false)); + new DiagnosticsEngine(DiagID, new DiagnosticOptions, + DiagClient, /*ShouldOwnClient=*/false)); // Filter of all diagnostics. CaptureDiagnosticConsumer errRec(*Diags, *DiagClient, capturedDiags); diff --git a/lib/ARCMigrate/CMakeLists.txt b/lib/ARCMigrate/CMakeLists.txt index f602fc8e5f88..731bcb4fc7f9 100644 --- a/lib/ARCMigrate/CMakeLists.txt +++ b/lib/ARCMigrate/CMakeLists.txt @@ -37,5 +37,6 @@ target_link_libraries(clangARCMigrate clangAST clangParse clangFrontend - clangRewrite + clangRewriteCore + clangRewriteFrontend ) diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp index e9b49b3039ba..28ca9a56b20e 100644 --- a/lib/ARCMigrate/FileRemapper.cpp +++ b/lib/ARCMigrate/FileRemapper.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/ARCMigrate/FileRemapper.h" -#include "clang/Frontend/PreprocessorOptions.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/Diagnostic.h" #include "llvm/Support/MemoryBuffer.h" diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h index 935fc9b52535..1966a9823b92 100644 --- a/lib/ARCMigrate/Internals.h +++ b/lib/ARCMigrate/Internals.h @@ -11,8 +11,10 @@ #define LLVM_CLANG_LIB_ARCMIGRATE_INTERNALS_H #include "clang/ARCMigrate/ARCMT.h" +#include "clang/Basic/Diagnostic.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" +#include <list> namespace clang { class Sema; diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp index 0098f973e63d..dfe14e2b5dd7 100644 --- a/lib/ARCMigrate/ObjCMT.cpp +++ b/lib/ARCMigrate/ObjCMT.cpp @@ -18,7 +18,7 @@ #include "clang/Edit/EditedSource.h" #include "clang/Edit/Commit.h" #include "clang/Edit/EditsReceiver.h" -#include "clang/Rewrite/Rewriter.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/FileManager.h" #include "llvm/ADT/SmallString.h" diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index 1175c363163b..805a67d9d188 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -40,7 +40,7 @@ bool MigrationPass::CFBridgingFunctionsDefined() { bool trans::canApplyWeak(ASTContext &Ctx, QualType type, bool AllowOnUnknownClass) { - if (!Ctx.getLangOpts().ObjCRuntimeHasWeak) + if (!Ctx.getLangOpts().ObjCARCWeak) return false; QualType T = type; @@ -59,7 +59,7 @@ bool trans::canApplyWeak(ASTContext &Ctx, QualType type, return false; // id/NSObject is not safe for weak. if (!AllowOnUnknownClass && !Class->hasDefinition()) return false; // forward classes are not verifiable, therefore not safe. - if (Class->isArcWeakrefUnavailable()) + if (Class && Class->isArcWeakrefUnavailable()) return false; } diff --git a/lib/AST/ASTConsumer.cpp b/lib/AST/ASTConsumer.cpp index 1672bc8aed7c..a4e17c03e4e3 100644 --- a/lib/AST/ASTConsumer.cpp +++ b/lib/AST/ASTConsumer.cpp @@ -13,6 +13,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/DeclGroup.h" +#include "clang/AST/Decl.h" using namespace clang; bool ASTConsumer::HandleTopLevelDecl(DeclGroupRef D) { @@ -24,3 +25,7 @@ void ASTConsumer::HandleInterestingDecl(DeclGroupRef D) { } void ASTConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {} + +void ASTConsumer::HandleImplicitImportDecl(ImportDecl *D) { + HandleTopLevelDecl(DeclGroupRef(D)); +} diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c02132329e6d..74c68ae627ce 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -24,6 +24,7 @@ #include "clang/AST/ASTMutationListener.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Mangle.h" +#include "clang/AST/Comment.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -72,6 +73,22 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { return NULL; } + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (VD->isStaticDataMember() && + VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) + return NULL; + } + + if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) { + if (CRD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) + return NULL; + } + + if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) { + if (ED->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) + return NULL; + } + // TODO: handle comments for function parameters properly. if (isa<ParmVarDecl>(D)) return NULL; @@ -196,15 +213,72 @@ RawComment *ASTContext::getRawCommentForDeclNoCache(const Decl *D) const { namespace { /// If we have a 'templated' declaration for a template, adjust 'D' to /// refer to the actual template. +/// If we have an implicit instantiation, adjust 'D' to refer to template. const Decl *adjustDeclToTemplate(const Decl *D) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // Is this function declaration part of a function template? if (const FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) - D = FTD; - } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { - if (const ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) - D = CTD; + return FTD; + + // Nothing to do if function is not an implicit instantiation. + if (FD->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) + return D; + + // Function is an implicit instantiation of a function template? + if (const FunctionTemplateDecl *FTD = FD->getPrimaryTemplate()) + return FTD; + + // Function is instantiated from a member definition of a class template? + if (const FunctionDecl *MemberDecl = + FD->getInstantiatedFromMemberFunction()) + return MemberDecl; + + return D; } - // FIXME: Alias templates? + if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + // Static data member is instantiated from a member definition of a class + // template? + if (VD->isStaticDataMember()) + if (const VarDecl *MemberDecl = VD->getInstantiatedFromStaticDataMember()) + return MemberDecl; + + return D; + } + if (const CXXRecordDecl *CRD = dyn_cast<CXXRecordDecl>(D)) { + // Is this class declaration part of a class template? + if (const ClassTemplateDecl *CTD = CRD->getDescribedClassTemplate()) + return CTD; + + // Class is an implicit instantiation of a class template or partial + // specialization? + if (const ClassTemplateSpecializationDecl *CTSD = + dyn_cast<ClassTemplateSpecializationDecl>(CRD)) { + if (CTSD->getSpecializationKind() != TSK_ImplicitInstantiation) + return D; + llvm::PointerUnion<ClassTemplateDecl *, + ClassTemplatePartialSpecializationDecl *> + PU = CTSD->getSpecializedTemplateOrPartial(); + return PU.is<ClassTemplateDecl*>() ? + static_cast<const Decl*>(PU.get<ClassTemplateDecl *>()) : + static_cast<const Decl*>( + PU.get<ClassTemplatePartialSpecializationDecl *>()); + } + + // Class is instantiated from a member definition of a class template? + if (const MemberSpecializationInfo *Info = + CRD->getMemberSpecializationInfo()) + return Info->getInstantiatedFrom(); + + return D; + } + if (const EnumDecl *ED = dyn_cast<EnumDecl>(D)) { + // Enum is instantiated from a member definition of a class template? + if (const EnumDecl *MemberDecl = ED->getInstantiatedFromMemberEnum()) + return MemberDecl; + + return D; + } + // FIXME: Adjust alias templates? return D; } } // unnamed namespace @@ -282,23 +356,83 @@ const RawComment *ASTContext::getRawCommentForAnyRedecl( return RC; } -comments::FullComment *ASTContext::getCommentForDecl(const Decl *D) const { +static void addRedeclaredMethods(const ObjCMethodDecl *ObjCMethod, + SmallVectorImpl<const NamedDecl *> &Redeclared) { + const DeclContext *DC = ObjCMethod->getDeclContext(); + if (const ObjCImplDecl *IMD = dyn_cast<ObjCImplDecl>(DC)) { + const ObjCInterfaceDecl *ID = IMD->getClassInterface(); + if (!ID) + return; + // Add redeclared method here. + for (const ObjCCategoryDecl *ClsExtDecl = ID->getFirstClassExtension(); + ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) { + if (ObjCMethodDecl *RedeclaredMethod = + ClsExtDecl->getMethod(ObjCMethod->getSelector(), + ObjCMethod->isInstanceMethod())) + Redeclared.push_back(RedeclaredMethod); + } + } +} + +comments::FullComment *ASTContext::cloneFullComment(comments::FullComment *FC, + const Decl *D) const { + comments::DeclInfo *ThisDeclInfo = new (*this) comments::DeclInfo; + ThisDeclInfo->CommentDecl = D; + ThisDeclInfo->IsFilled = false; + ThisDeclInfo->fill(); + ThisDeclInfo->CommentDecl = FC->getDecl(); + comments::FullComment *CFC = + new (*this) comments::FullComment(FC->getBlocks(), + ThisDeclInfo); + return CFC; + +} + +comments::FullComment *ASTContext::getCommentForDecl( + const Decl *D, + const Preprocessor *PP) const { D = adjustDeclToTemplate(D); + const Decl *Canonical = D->getCanonicalDecl(); llvm::DenseMap<const Decl *, comments::FullComment *>::iterator Pos = ParsedComments.find(Canonical); - if (Pos != ParsedComments.end()) + + if (Pos != ParsedComments.end()) { + if (Canonical != D) { + comments::FullComment *FC = Pos->second; + comments::FullComment *CFC = cloneFullComment(FC, D); + return CFC; + } return Pos->second; - + } + const Decl *OriginalDecl; + const RawComment *RC = getRawCommentForAnyRedecl(D, &OriginalDecl); - if (!RC) + if (!RC) { + if (isa<ObjCMethodDecl>(D) || isa<FunctionDecl>(D)) { + SmallVector<const NamedDecl*, 8> Overridden; + if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) + addRedeclaredMethods(OMD, Overridden); + getOverriddenMethods(dyn_cast<NamedDecl>(D), Overridden); + for (unsigned i = 0, e = Overridden.size(); i < e; i++) { + if (comments::FullComment *FC = getCommentForDecl(Overridden[i], PP)) { + comments::FullComment *CFC = cloneFullComment(FC, D); + return CFC; + } + } + } return NULL; - + } + + // If the RawComment was attached to other redeclaration of this Decl, we + // should parse the comment in context of that other Decl. This is important + // because comments can contain references to parameter names which can be + // different across redeclarations. if (D != OriginalDecl) - return getCommentForDecl(OriginalDecl); + return getCommentForDecl(OriginalDecl, PP); - comments::FullComment *FC = RC->parse(*this, D); + comments::FullComment *FC = RC->parse(*this, PP, D); ParsedComments[Canonical] = FC; return FC; } @@ -481,6 +615,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, Int128Decl(0), UInt128Decl(0), BuiltinVaListDecl(0), ObjCIdDecl(0), ObjCSelDecl(0), ObjCClassDecl(0), ObjCProtocolClassDecl(0), + BOOLDecl(0), CFConstantStringTypeDecl(0), ObjCInstanceTypeDecl(0), FILEDecl(0), jmp_bufDecl(0), sigjmp_bufDecl(0), ucontext_tDecl(0), @@ -495,6 +630,7 @@ ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, DeclarationNames(*this), ExternalSource(0), Listener(0), Comments(SM), CommentsLoaded(false), + CommentCommandTraits(BumpAlloc), LastSDM(0, 0), UniqueBlockByRefTypeID(0) { @@ -683,12 +819,12 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { InitBuiltinType(Int128Ty, BuiltinType::Int128); InitBuiltinType(UnsignedInt128Ty, BuiltinType::UInt128); - if (LangOpts.CPlusPlus) { // C++ 3.9.1p5 + if (LangOpts.CPlusPlus && LangOpts.WChar) { // C++ 3.9.1p5 if (TargetInfo::isTypeSigned(Target.getWCharType())) InitBuiltinType(WCharTy, BuiltinType::WChar_S); else // -fshort-wchar makes wchar_t be unsigned. InitBuiltinType(WCharTy, BuiltinType::WChar_U); - } else // C99 + } else // C99 (or C++ using -fno-wchar) WCharTy = getFromTargetType(Target.getWCharType()); WIntTy = getFromTargetType(Target.getWIntType()); @@ -725,6 +861,9 @@ void ASTContext::InitBuiltinTypes(const TargetInfo &Target) { // Placeholder type for unbridged ARC casts. InitBuiltinType(ARCUnbridgedCastTy, BuiltinType::ARCUnbridgedCast); + // Placeholder type for builtin functions. + InitBuiltinType(BuiltinFnTy, BuiltinType::BuiltinFn); + // C99 6.2.5p11. FloatComplexTy = getComplexType(FloatTy); DoubleComplexTy = getComplexType(DoubleTy); @@ -909,7 +1048,7 @@ bool ASTContext::BitfieldFollowsNonBitfield(const FieldDecl *FD, ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos - = OverriddenMethods.find(Method); + = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return 0; @@ -919,7 +1058,7 @@ ASTContext::overridden_methods_begin(const CXXMethodDecl *Method) const { ASTContext::overridden_cxx_method_iterator ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos - = OverriddenMethods.find(Method); + = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return 0; @@ -929,7 +1068,7 @@ ASTContext::overridden_methods_end(const CXXMethodDecl *Method) const { unsigned ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const { llvm::DenseMap<const CXXMethodDecl *, CXXMethodVector>::const_iterator Pos - = OverriddenMethods.find(Method); + = OverriddenMethods.find(Method->getCanonicalDecl()); if (Pos == OverriddenMethods.end()) return 0; @@ -938,9 +1077,30 @@ ASTContext::overridden_methods_size(const CXXMethodDecl *Method) const { void ASTContext::addOverriddenMethod(const CXXMethodDecl *Method, const CXXMethodDecl *Overridden) { + assert(Method->isCanonicalDecl() && Overridden->isCanonicalDecl()); OverriddenMethods[Method].push_back(Overridden); } +void ASTContext::getOverriddenMethods( + const NamedDecl *D, + SmallVectorImpl<const NamedDecl *> &Overridden) const { + assert(D); + + if (const CXXMethodDecl *CXXMethod = dyn_cast<CXXMethodDecl>(D)) { + Overridden.append(CXXMethod->begin_overridden_methods(), + CXXMethod->end_overridden_methods()); + return; + } + + const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(D); + if (!Method) + return; + + SmallVector<const ObjCMethodDecl *, 8> OverDecls; + Method->getOverriddenMethods(OverDecls); + Overridden.append(OverDecls.begin(), OverDecls.end()); +} + void ASTContext::addedLocalImportDecl(ImportDecl *Import) { assert(!Import->NextLocalImport && "Import declaration already in the chain"); assert(!Import->isFromASTFile() && "Non-local import declaration"); @@ -1062,6 +1222,27 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool RefAsPointee) const { return toCharUnitsFromBits(Align); } +// getTypeInfoDataSizeInChars - Return the size of a type, in +// chars. If the type is a record, its data size is returned. This is +// the size of the memcpy that's performed when assigning this type +// using a trivial copy/move assignment operator. +std::pair<CharUnits, CharUnits> +ASTContext::getTypeInfoDataSizeInChars(QualType T) const { + std::pair<CharUnits, CharUnits> sizeAndAlign = getTypeInfoInChars(T); + + // In C++, objects can sometimes be allocated into the tail padding + // of a base-class subobject. We decide whether that's possible + // during class layout, so here we can just trust the layout results. + if (getLangOpts().CPlusPlus) { + if (const RecordType *RT = T->getAs<RecordType>()) { + const ASTRecordLayout &layout = getASTRecordLayout(RT->getDecl()); + sizeAndAlign.first = layout.getDataSize(); + } + } + + return sizeAndAlign; +} + std::pair<CharUnits, CharUnits> ASTContext::getTypeInfoInChars(const Type *T) const { std::pair<uint64_t, unsigned> Info = getTypeInfo(T); @@ -3353,6 +3534,12 @@ QualType ASTContext::getPointerDiffType() const { return getFromTargetType(Target->getPtrDiffType(0)); } +/// \brief Return the unique type for "pid_t" defined in +/// <sys/types.h>. We need this to compute the correct type for vfork(). +QualType ASTContext::getProcessIDType() const { + return getFromTargetType(Target->getProcessIDType()); +} + //===----------------------------------------------------------------------===// // Type Operators //===----------------------------------------------------------------------===// @@ -3581,11 +3768,14 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { return Arg; case TemplateArgument::Declaration: { - if (Decl *D = Arg.getAsDecl()) - return TemplateArgument(D->getCanonicalDecl()); - return TemplateArgument((Decl*)0); + ValueDecl *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl()); + return TemplateArgument(D, Arg.isDeclForReferenceParam()); } + case TemplateArgument::NullPtr: + return TemplateArgument(getCanonicalType(Arg.getNullPtrType()), + /*isNullPtr*/true); + case TemplateArgument::Template: return TemplateArgument(getCanonicalTemplateName(Arg.getAsTemplate())); @@ -4297,7 +4487,13 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { QualType BlockTy = Expr->getType()->getAs<BlockPointerType>()->getPointeeType(); // Encode result type. - getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getResultType(), S); + if (getLangOpts().EncodeExtendedBlockSig) + getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None, + BlockTy->getAs<FunctionType>()->getResultType(), + S, true /*Extended*/); + else + getObjCEncodingForType(BlockTy->getAs<FunctionType>()->getResultType(), + S); // Compute size of all parameters. // Start with computing size of a pointer in number of bytes. // FIXME: There might(should) be a better way of doing this computation! @@ -4332,7 +4528,11 @@ std::string ASTContext::getObjCEncodingForBlock(const BlockExpr *Expr) const { PType = PVDecl->getType(); } else if (PType->isFunctionType()) PType = PVDecl->getType(); - getObjCEncodingForType(PType, S); + if (getLangOpts().EncodeExtendedBlockSig) + getObjCEncodingForMethodParameter(Decl::OBJC_TQ_None, PType, + S, true /*Extended*/); + else + getObjCEncodingForType(PType, S); S += charUnitsToString(ParmOffset); ParmOffset += getObjCEncodingTypeSize(PType); } @@ -5393,6 +5593,65 @@ static TypedefDecl *CreatePNaClABIBuiltinVaListDecl(const ASTContext *Context) { return VaListTypedefDecl; } +static TypedefDecl * +CreateAAPCSABIBuiltinVaListDecl(const ASTContext *Context) { + RecordDecl *VaListDecl; + if (Context->getLangOpts().CPlusPlus) { + // namespace std { struct __va_list { + NamespaceDecl *NS; + NS = NamespaceDecl::Create(const_cast<ASTContext &>(*Context), + Context->getTranslationUnitDecl(), + /*Inline*/false, SourceLocation(), + SourceLocation(), &Context->Idents.get("std"), + /*PrevDecl*/0); + + VaListDecl = CXXRecordDecl::Create(*Context, TTK_Struct, + Context->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Context->Idents.get("__va_list")); + + VaListDecl->setDeclContext(NS); + + } else { + // struct __va_list { + VaListDecl = CreateRecordDecl(*Context, TTK_Struct, + Context->getTranslationUnitDecl(), + &Context->Idents.get("__va_list")); + } + + VaListDecl->startDefinition(); + + // void * __ap; + FieldDecl *Field = FieldDecl::Create(const_cast<ASTContext &>(*Context), + VaListDecl, + SourceLocation(), + SourceLocation(), + &Context->Idents.get("__ap"), + Context->getPointerType(Context->VoidTy), + /*TInfo=*/0, + /*BitWidth=*/0, + /*Mutable=*/false, + ICIS_NoInit); + Field->setAccess(AS_public); + VaListDecl->addDecl(Field); + + // }; + VaListDecl->completeDefinition(); + + // typedef struct __va_list __builtin_va_list; + TypeSourceInfo *TInfo + = Context->getTrivialTypeSourceInfo(Context->getRecordType(VaListDecl)); + + TypedefDecl *VaListTypeDecl + = TypedefDecl::Create(const_cast<ASTContext &>(*Context), + Context->getTranslationUnitDecl(), + SourceLocation(), SourceLocation(), + &Context->Idents.get("__builtin_va_list"), + TInfo); + + return VaListTypeDecl; +} + static TypedefDecl *CreateVaListDecl(const ASTContext *Context, TargetInfo::BuiltinVaListKind Kind) { switch (Kind) { @@ -5406,6 +5665,8 @@ static TypedefDecl *CreateVaListDecl(const ASTContext *Context, return CreateX86_64ABIBuiltinVaListDecl(Context); case TargetInfo::PNaClABIBuiltinVaList: return CreatePNaClABIBuiltinVaListDecl(Context); + case TargetInfo::AAPCSABIBuiltinVaList: + return CreateAAPCSABIBuiltinVaListDecl(Context); } llvm_unreachable("Unhandled __builtin_va_list type kind"); @@ -5702,7 +5963,7 @@ ASTContext::ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, return false; } -/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...> +/// QualifiedIdConformsQualifiedId - compare id<pr,...> with id<pr1,...> /// return true if lhs's protocols conform to rhs's protocol; false /// otherwise. bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { @@ -5711,8 +5972,8 @@ bool ASTContext::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) { return false; } -/// ObjCQualifiedClassTypesAreCompatible - compare Class<p,...> and -/// Class<p1, ...>. +/// ObjCQualifiedClassTypesAreCompatible - compare Class<pr,...> and +/// Class<pr1, ...>. bool ASTContext::ObjCQualifiedClassTypesAreCompatible(QualType lhs, QualType rhs) { const ObjCObjectPointerType *lhsQID = lhs->getAs<ObjCObjectPointerType>(); @@ -6315,10 +6576,13 @@ QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, for (unsigned i = 0; i < proto_nargs; ++i) { QualType argTy = proto->getArgType(i); - // Look at the promotion type of enum types, since that is the type used + // Look at the converted type of enum types, since that is the type used // to pass enum values. - if (const EnumType *Enum = argTy->getAs<EnumType>()) - argTy = Enum->getDecl()->getPromotionType(); + if (const EnumType *Enum = argTy->getAs<EnumType>()) { + argTy = Enum->getDecl()->getIntegerType(); + if (argTy.isNull()) + return QualType(); + } if (argTy->isPromotableIntegerType() || getCanonicalType(argTy).getUnqualifiedType() == FloatTy) @@ -6725,7 +6989,7 @@ unsigned ASTContext::getIntWidth(QualType T) const { return (unsigned)getTypeSize(T); } -QualType ASTContext::getCorrespondingUnsignedType(QualType T) { +QualType ASTContext::getCorrespondingUnsignedType(QualType T) const { assert(T->hasSignedIntegerRepresentation() && "Unexpected type"); // Turn <4 x signed int> -> <4 x unsigned int> @@ -6959,6 +7223,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, return QualType(); } break; + case 'p': + Type = Context.getProcessIDType(); + break; } // If there are modifiers and if we're allowed to parse them, go for it. diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index a605f1a40cb3..0b9c5249448f 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -430,6 +430,15 @@ class TemplateDiff { /// arguments or the type arguments that are templates. TemplateDecl *FromTD, *ToTD; + /// FromQual, ToQual - Qualifiers for template types. + Qualifiers FromQual, ToQual; + + /// FromInt, ToInt - APSInt's for integral arguments. + llvm::APSInt FromInt, ToInt; + + /// IsValidFromInt, IsValidToInt - Whether the APSInt's are valid. + bool IsValidFromInt, IsValidToInt; + /// FromDefault, ToDefault - Whether the argument is a default argument. bool FromDefault, ToDefault; @@ -480,6 +489,21 @@ class TemplateDiff { FlatTree[CurrentNode].ToExpr = ToExpr; } + /// SetNode - Set FromInt and ToInt of the current node. + void SetNode(llvm::APSInt FromInt, llvm::APSInt ToInt, + bool IsValidFromInt, bool IsValidToInt) { + FlatTree[CurrentNode].FromInt = FromInt; + FlatTree[CurrentNode].ToInt = ToInt; + FlatTree[CurrentNode].IsValidFromInt = IsValidFromInt; + FlatTree[CurrentNode].IsValidToInt = IsValidToInt; + } + + /// SetNode - Set FromQual and ToQual of the current node. + void SetNode(Qualifiers FromQual, Qualifiers ToQual) { + FlatTree[CurrentNode].FromQual = FromQual; + FlatTree[CurrentNode].ToQual = ToQual; + } + /// SetSame - Sets the same flag of the current node. void SetSame(bool Same) { FlatTree[CurrentNode].Same = Same; @@ -557,6 +581,12 @@ class TemplateDiff { (FlatTree[ReadNode].FromTD || FlatTree[ReadNode].ToTD); } + /// NodeIsAPSInt - Returns true if the arugments are stored in APSInt's. + bool NodeIsAPSInt() { + return FlatTree[ReadNode].IsValidFromInt || + FlatTree[ReadNode].IsValidToInt; + } + /// GetNode - Gets the FromType and ToType. void GetNode(QualType &FromType, QualType &ToType) { FromType = FlatTree[ReadNode].FromType; @@ -575,6 +605,21 @@ class TemplateDiff { ToTD = FlatTree[ReadNode].ToTD; } + /// GetNode - Gets the FromInt and ToInt. + void GetNode(llvm::APSInt &FromInt, llvm::APSInt &ToInt, + bool &IsValidFromInt, bool &IsValidToInt) { + FromInt = FlatTree[ReadNode].FromInt; + ToInt = FlatTree[ReadNode].ToInt; + IsValidFromInt = FlatTree[ReadNode].IsValidFromInt; + IsValidToInt = FlatTree[ReadNode].IsValidToInt; + } + + /// GetNode - Gets the FromQual and ToQual. + void GetNode(Qualifiers &FromQual, Qualifiers &ToQual) { + FromQual = FlatTree[ReadNode].FromQual; + ToQual = FlatTree[ReadNode].ToQual; + } + /// NodeIsSame - Returns true the arguments are the same. bool NodeIsSame() { return FlatTree[ReadNode].Same; @@ -778,18 +823,21 @@ class TemplateDiff { if (Context.hasSameType(FromType, ToType)) { Tree.SetSame(true); } else { + Qualifiers FromQual = FromType.getQualifiers(), + ToQual = ToType.getQualifiers(); const TemplateSpecializationType *FromArgTST = GetTemplateSpecializationType(Context, FromType); const TemplateSpecializationType *ToArgTST = GetTemplateSpecializationType(Context, ToType); - if (FromArgTST && ToArgTST) { - bool SameTemplate = hasSameTemplate(FromArgTST, ToArgTST); - if (SameTemplate) { - Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(), - ToArgTST->getTemplateName().getAsTemplateDecl()); - DiffTemplate(FromArgTST, ToArgTST); - } + if (FromArgTST && ToArgTST && + hasSameTemplate(FromArgTST, ToArgTST)) { + FromQual -= QualType(FromArgTST, 0).getQualifiers(); + ToQual -= QualType(ToArgTST, 0).getQualifiers(); + Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(), + ToArgTST->getTemplateName().getAsTemplateDecl()); + Tree.SetNode(FromQual, ToQual); + DiffTemplate(FromArgTST, ToArgTST); } } } @@ -799,12 +847,41 @@ class TemplateDiff { if (NonTypeTemplateParmDecl *DefaultNTTPD = dyn_cast<NonTypeTemplateParmDecl>(ParamND)) { Expr *FromExpr, *ToExpr; - GetExpr(FromIter, DefaultNTTPD, FromExpr); - GetExpr(ToIter, DefaultNTTPD, ToExpr); - Tree.SetNode(FromExpr, ToExpr); - Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr)); - Tree.SetDefault(FromIter.isEnd() && FromExpr, - ToIter.isEnd() && ToExpr); + llvm::APSInt FromInt, ToInt; + bool HasFromInt = !FromIter.isEnd() && + FromIter->getKind() == TemplateArgument::Integral; + bool HasToInt = !ToIter.isEnd() && + ToIter->getKind() == TemplateArgument::Integral; + //bool IsValidFromInt = false, IsValidToInt = false; + if (HasFromInt) + FromInt = FromIter->getAsIntegral(); + else + GetExpr(FromIter, DefaultNTTPD, FromExpr); + + if (HasToInt) + ToInt = ToIter->getAsIntegral(); + else + GetExpr(ToIter, DefaultNTTPD, ToExpr); + + if (!HasFromInt && !HasToInt) { + Tree.SetNode(FromExpr, ToExpr); + Tree.SetSame(IsEqualExpr(Context, FromExpr, ToExpr)); + Tree.SetDefault(FromIter.isEnd() && FromExpr, + ToIter.isEnd() && ToExpr); + } else { + if (!HasFromInt && FromExpr) { + FromInt = FromExpr->EvaluateKnownConstInt(Context); + HasFromInt = true; + } + if (!HasToInt && ToExpr) { + ToInt = ToExpr->EvaluateKnownConstInt(Context); + HasToInt = true; + } + Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt); + Tree.SetSame(llvm::APSInt::isSameValue(FromInt, ToInt)); + Tree.SetDefault(FromIter.isEnd() && HasFromInt, + ToIter.isEnd() && HasToInt); + } } // Handle Templates @@ -824,6 +901,26 @@ class TemplateDiff { } } + /// makeTemplateList - Dump every template alias into the vector. + static void makeTemplateList( + SmallVector<const TemplateSpecializationType*, 1> &TemplateList, + const TemplateSpecializationType *TST) { + while (TST) { + TemplateList.push_back(TST); + if (!TST->isTypeAlias()) + return; + TST = TST->getAliasedType()->getAs<TemplateSpecializationType>(); + } + } + + /// hasSameBaseTemplate - Returns true when the base templates are the same, + /// even if the template arguments are not. + static bool hasSameBaseTemplate(const TemplateSpecializationType *FromTST, + const TemplateSpecializationType *ToTST) { + return FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() == + ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier(); + } + /// hasSameTemplate - Returns true if both types are specialized from the /// same template declaration. If they come from different template aliases, /// do a parallel ascension search to determine the highest template alias in @@ -831,49 +928,29 @@ class TemplateDiff { static bool hasSameTemplate(const TemplateSpecializationType *&FromTST, const TemplateSpecializationType *&ToTST) { // Check the top templates if they are the same. - if (FromTST->getTemplateName().getAsTemplateDecl()->getIdentifier() == - ToTST->getTemplateName().getAsTemplateDecl()->getIdentifier()) + if (hasSameBaseTemplate(FromTST, ToTST)) return true; // Create vectors of template aliases. SmallVector<const TemplateSpecializationType*, 1> FromTemplateList, ToTemplateList; - const TemplateSpecializationType *TempToTST = ToTST, *TempFromTST = FromTST; - FromTemplateList.push_back(FromTST); - ToTemplateList.push_back(ToTST); - - // Dump every template alias into the vectors. - while (TempFromTST->isTypeAlias()) { - TempFromTST = - TempFromTST->getAliasedType()->getAs<TemplateSpecializationType>(); - if (!TempFromTST) - break; - FromTemplateList.push_back(TempFromTST); - } - while (TempToTST->isTypeAlias()) { - TempToTST = - TempToTST->getAliasedType()->getAs<TemplateSpecializationType>(); - if (!TempToTST) - break; - ToTemplateList.push_back(TempToTST); - } + makeTemplateList(FromTemplateList, FromTST); + makeTemplateList(ToTemplateList, ToTST); SmallVector<const TemplateSpecializationType*, 1>::reverse_iterator FromIter = FromTemplateList.rbegin(), FromEnd = FromTemplateList.rend(), ToIter = ToTemplateList.rbegin(), ToEnd = ToTemplateList.rend(); // Check if the lowest template types are the same. If not, return. - if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() != - (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier()) + if (!hasSameBaseTemplate(*FromIter, *ToIter)) return false; // Begin searching up the template aliases. The bottom most template // matches so move up until one pair does not match. Use the template // right before that one. for (; FromIter != FromEnd && ToIter != ToEnd; ++FromIter, ++ToIter) { - if ((*FromIter)->getTemplateName().getAsTemplateDecl()->getIdentifier() != - (*ToIter)->getTemplateName().getAsTemplateDecl()->getIdentifier()) + if (!hasSameBaseTemplate(*FromIter, *ToIter)) break; } @@ -923,7 +1000,9 @@ class TemplateDiff { bool isVariadic = DefaultTTPD->isParameterPack(); TemplateArgument TA = DefaultTTPD->getDefaultArgument().getArgument(); - TemplateDecl *DefaultTD = TA.getAsTemplate().getAsTemplateDecl(); + TemplateDecl *DefaultTD = 0; + if (TA.getKind() != TemplateArgument::Null) + DefaultTD = TA.getAsTemplate().getAsTemplateDecl(); if (!Iter.isEnd()) ArgDecl = Iter->getAsTemplate().getAsTemplateDecl(); @@ -1018,6 +1097,15 @@ class TemplateDiff { Tree.ToDefault(), Tree.NodeIsSame()); return; } + + if (Tree.NodeIsAPSInt()) { + llvm::APSInt FromInt, ToInt; + bool IsValidFromInt, IsValidToInt; + Tree.GetNode(FromInt, ToInt, IsValidFromInt, IsValidToInt); + PrintAPSInt(FromInt, ToInt, IsValidFromInt, IsValidToInt, + Tree.FromDefault(), Tree.ToDefault(), Tree.NodeIsSame()); + return; + } llvm_unreachable("Unable to deduce template difference."); } @@ -1027,6 +1115,10 @@ class TemplateDiff { assert(Tree.HasChildren() && "Template difference not found in diff tree."); + Qualifiers FromQual, ToQual; + Tree.GetNode(FromQual, ToQual); + PrintQualifiers(FromQual, ToQual); + OS << FromTD->getNameAsString() << '<'; Tree.MoveToChild(); unsigned NumElideArgs = 0; @@ -1088,6 +1180,17 @@ class TemplateDiff { return; } + if (!FromType.isNull() && !ToType.isNull() && + FromType.getLocalUnqualifiedType() == + ToType.getLocalUnqualifiedType()) { + Qualifiers FromQual = FromType.getLocalQualifiers(), + ToQual = ToType.getLocalQualifiers(), + CommonQual; + PrintQualifiers(FromQual, ToQual); + FromType.getLocalUnqualifiedType().print(OS, Policy); + return; + } + std::string FromTypeStr = FromType.isNull() ? "(no argument)" : FromType.getAsString(); std::string ToTypeStr = ToType.isNull() ? "(no argument)" @@ -1177,6 +1280,34 @@ class TemplateDiff { } } + /// PrintAPSInt - Handles printing of integral arguments, highlighting + /// argument differences. + void PrintAPSInt(llvm::APSInt FromInt, llvm::APSInt ToInt, + bool IsValidFromInt, bool IsValidToInt, bool FromDefault, + bool ToDefault, bool Same) { + assert((IsValidFromInt || IsValidToInt) && + "Only one integral argument may be missing."); + + if (Same) { + OS << FromInt.toString(10); + } else if (!PrintTree) { + OS << (FromDefault ? "(default) " : ""); + Bold(); + OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)"); + Unbold(); + } else { + OS << (FromDefault ? "[(default) " : "["); + Bold(); + OS << (IsValidFromInt ? FromInt.toString(10) : "(no argument)"); + Unbold(); + OS << " != " << (ToDefault ? "(default) " : ""); + Bold(); + OS << (IsValidToInt ? ToInt.toString(10) : "(no argument)"); + Unbold(); + OS << ']'; + } + } + // Prints the appropriate placeholder for elided template arguments. void PrintElideArgs(unsigned NumElideArgs, unsigned Indent) { if (PrintTree) { @@ -1191,6 +1322,68 @@ class TemplateDiff { OS << "[" << NumElideArgs << " * ...]"; } + // Prints and highlights differences in Qualifiers. + void PrintQualifiers(Qualifiers FromQual, Qualifiers ToQual) { + // Both types have no qualifiers + if (FromQual.empty() && ToQual.empty()) + return; + + // Both types have same qualifiers + if (FromQual == ToQual) { + PrintQualifier(FromQual, /*ApplyBold*/false); + return; + } + + // Find common qualifiers and strip them from FromQual and ToQual. + Qualifiers CommonQual = Qualifiers::removeCommonQualifiers(FromQual, + ToQual); + + // The qualifiers are printed before the template name. + // Inline printing: + // The common qualifiers are printed. Then, qualifiers only in this type + // are printed and highlighted. Finally, qualifiers only in the other + // type are printed and highlighted inside parentheses after "missing". + // Tree printing: + // Qualifiers are printed next to each other, inside brackets, and + // separated by "!=". The printing order is: + // common qualifiers, highlighted from qualifiers, "!=", + // common qualifiers, highlighted to qualifiers + if (PrintTree) { + OS << "["; + if (CommonQual.empty() && FromQual.empty()) { + Bold(); + OS << "(no qualifiers) "; + Unbold(); + } else { + PrintQualifier(CommonQual, /*ApplyBold*/false); + PrintQualifier(FromQual, /*ApplyBold*/true); + } + OS << "!= "; + if (CommonQual.empty() && ToQual.empty()) { + Bold(); + OS << "(no qualifiers)"; + Unbold(); + } else { + PrintQualifier(CommonQual, /*ApplyBold*/false, + /*appendSpaceIfNonEmpty*/!ToQual.empty()); + PrintQualifier(ToQual, /*ApplyBold*/true, + /*appendSpaceIfNonEmpty*/false); + } + OS << "] "; + } else { + PrintQualifier(CommonQual, /*ApplyBold*/false); + PrintQualifier(FromQual, /*ApplyBold*/true); + } + } + + void PrintQualifier(Qualifiers Q, bool ApplyBold, + bool AppendSpaceIfNonEmpty = true) { + if (Q.empty()) return; + if (ApplyBold) Bold(); + Q.print(OS, Policy, AppendSpaceIfNonEmpty); + if (ApplyBold) Unbold(); + } + public: TemplateDiff(ASTContext &Context, QualType FromType, QualType ToType, @@ -1210,6 +1403,9 @@ public: /// DiffTemplate - Start the template type diffing. void DiffTemplate() { + Qualifiers FromQual = FromType.getQualifiers(), + ToQual = ToType.getQualifiers(); + const TemplateSpecializationType *FromOrigTST = GetTemplateSpecializationType(Context, FromType); const TemplateSpecializationType *ToOrigTST = @@ -1224,7 +1420,10 @@ public: return; } + FromQual -= QualType(FromOrigTST, 0).getQualifiers(); + ToQual -= QualType(ToOrigTST, 0).getQualifiers(); Tree.SetNode(FromType, ToType); + Tree.SetNode(FromQual, ToQual); // Same base template, but different arguments. Tree.SetNode(FromOrigTST->getTemplateName().getAsTemplateDecl(), diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 3e952acdcb42..0d4f303af2b5 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -228,16 +228,12 @@ namespace { public: DiagnosticBuilder Diag1(SourceLocation Loc, unsigned DiagID) { - if (!Complain) - return DiagnosticBuilder::getEmpty(); - + assert(Complain && "Not allowed to complain"); return C1.getDiagnostics().Report(Loc, DiagID); } DiagnosticBuilder Diag2(SourceLocation Loc, unsigned DiagID) { - if (!Complain) - return DiagnosticBuilder::getEmpty(); - + assert(Complain && "Not allowed to complain"); return C2.getDiagnostics().Report(Loc, DiagID); } }; @@ -288,7 +284,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, case TemplateArgument::Type: return Context.IsStructurallyEquivalent(Arg1.getAsType(), Arg2.getAsType()); - + case TemplateArgument::Integral: if (!Context.IsStructurallyEquivalent(Arg1.getIntegralType(), Arg2.getIntegralType())) @@ -297,10 +293,11 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return llvm::APSInt::isSameValue(Arg1.getAsIntegral(), Arg2.getAsIntegral()); case TemplateArgument::Declaration: - if (!Arg1.getAsDecl() || !Arg2.getAsDecl()) - return !Arg1.getAsDecl() && !Arg2.getAsDecl(); return Context.IsStructurallyEquivalent(Arg1.getAsDecl(), Arg2.getAsDecl()); - + + case TemplateArgument::NullPtr: + return true; // FIXME: Is this correct? + case TemplateArgument::Template: return IsStructurallyEquivalent(Context, Arg1.getAsTemplate(), @@ -822,33 +819,47 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, FieldDecl *Field1, FieldDecl *Field2) { RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext()); - - if (!IsStructurallyEquivalent(Context, + + // For anonymous structs/unions, match up the anonymous struct/union type + // declarations directly, so that we don't go off searching for anonymous + // types + if (Field1->isAnonymousStructOrUnion() && + Field2->isAnonymousStructOrUnion()) { + RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl(); + RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl(); + return IsStructurallyEquivalent(Context, D1, D2); + } + + if (!IsStructurallyEquivalent(Context, Field1->getType(), Field2->getType())) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - Context.Diag2(Field2->getLocation(), diag::note_odr_field) - << Field2->getDeclName() << Field2->getType(); - Context.Diag1(Field1->getLocation(), diag::note_odr_field) - << Field1->getDeclName() << Field1->getType(); + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(Owner2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + } return false; } if (Field1->isBitField() != Field2->isBitField()) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - if (Field1->isBitField()) { - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() - << Field1->getBitWidthValue(Context.C1); - Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) - << Field2->getDeclName(); - } else { - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() - << Field2->getBitWidthValue(Context.C2); - Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field) - << Field1->getDeclName(); + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(Owner2); + if (Field1->isBitField()) { + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() + << Field1->getBitWidthValue(Context.C1); + Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) + << Field2->getDeclName(); + } else { + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() + << Field2->getBitWidthValue(Context.C2); + Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field) + << Field1->getDeclName(); + } } return false; } @@ -859,12 +870,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, unsigned Bits2 = Field2->getBitWidthValue(Context.C2); if (Bits1 != Bits2) { - Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(Owner2); - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() << Bits2; - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() << Bits1; + if (Context.Complain) { + Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(Owner2); + Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) + << Field2->getDeclName() << Field2->getType() << Bits2; + Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) + << Field1->getDeclName() << Field1->getType() << Bits1; + } return false; } } @@ -872,17 +885,65 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, return true; } +/// \brief Find the index of the given anonymous struct/union within its +/// context. +/// +/// \returns Returns the index of this anonymous struct/union in its context, +/// including the next assigned index (if none of them match). Returns an +/// empty option if the context is not a record, i.e.. if the anonymous +/// struct/union is at namespace or block scope. +static llvm::Optional<unsigned> +findAnonymousStructOrUnionIndex(RecordDecl *Anon) { + ASTContext &Context = Anon->getASTContext(); + QualType AnonTy = Context.getRecordType(Anon); + + RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext()); + if (!Owner) + return llvm::Optional<unsigned>(); + + unsigned Index = 0; + for (DeclContext::decl_iterator D = Owner->noload_decls_begin(), + DEnd = Owner->noload_decls_end(); + D != DEnd; ++D) { + FieldDecl *F = dyn_cast<FieldDecl>(*D); + if (!F || !F->isAnonymousStructOrUnion()) + continue; + + if (Context.hasSameType(F->getType(), AnonTy)) + break; + + ++Index; + } + + return Index; +} + /// \brief Determine structural equivalence of two records. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, RecordDecl *D1, RecordDecl *D2) { if (D1->isUnion() != D2->isUnion()) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) - << D1->getDeclName() << (unsigned)D1->getTagKind(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(D1->getLocation(), diag::note_odr_tag_kind_here) + << D1->getDeclName() << (unsigned)D1->getTagKind(); + } return false; } - + + if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) { + // If both anonymous structs/unions are in a record context, make sure + // they occur in the same location in the context records. + if (llvm::Optional<unsigned> Index1 + = findAnonymousStructOrUnionIndex(D1)) { + if (llvm::Optional<unsigned> Index2 + = findAnonymousStructOrUnionIndex(D2)) { + if (*Index1 != *Index2) + return false; + } + } + } + // If both declarations are class template specializations, we know // the ODR applies, so check the template and template arguments. ClassTemplateSpecializationDecl *Spec1 @@ -920,12 +981,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (CXXRecordDecl *D1CXX = dyn_cast<CXXRecordDecl>(D1)) { if (CXXRecordDecl *D2CXX = dyn_cast<CXXRecordDecl>(D2)) { if (D1CXX->getNumBases() != D2CXX->getNumBases()) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) - << D2CXX->getNumBases(); - Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) - << D1CXX->getNumBases(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(D2->getLocation(), diag::note_odr_number_of_bases) + << D2CXX->getNumBases(); + Context.Diag1(D1->getLocation(), diag::note_odr_number_of_bases) + << D1CXX->getNumBases(); + } return false; } @@ -937,38 +1000,44 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, ++Base1, ++Base2) { if (!IsStructurallyEquivalent(Context, Base1->getType(), Base2->getType())) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Base2->getLocStart(), diag::note_odr_base) - << Base2->getType() - << Base2->getSourceRange(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->getType() - << Base1->getSourceRange(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Base2->getLocStart(), diag::note_odr_base) + << Base2->getType() + << Base2->getSourceRange(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->getType() + << Base1->getSourceRange(); + } return false; } // Check virtual vs. non-virtual inheritance mismatch. if (Base1->isVirtual() != Base2->isVirtual()) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Base2->getLocStart(), - diag::note_odr_virtual_base) - << Base2->isVirtual() << Base2->getSourceRange(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->isVirtual() - << Base1->getSourceRange(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Base2->getLocStart(), + diag::note_odr_virtual_base) + << Base2->isVirtual() << Base2->getSourceRange(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->isVirtual() + << Base1->getSourceRange(); + } return false; } } } else if (D1CXX->getNumBases() > 0) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); - Context.Diag1(Base1->getLocStart(), diag::note_odr_base) - << Base1->getType() - << Base1->getSourceRange(); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_base); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + const CXXBaseSpecifier *Base1 = D1CXX->bases_begin(); + Context.Diag1(Base1->getLocStart(), diag::note_odr_base) + << Base1->getType() + << Base1->getSourceRange(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_base); + } return false; } } @@ -981,11 +1050,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, Field1 != Field1End; ++Field1, ++Field2) { if (Field2 == Field2End) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(Field1->getLocation(), diag::note_odr_field) - << Field1->getDeclName() << Field1->getType(); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(Field1->getLocation(), diag::note_odr_field) + << Field1->getDeclName() << Field1->getType(); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_field); + } return false; } @@ -994,11 +1065,13 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } if (Field2 != Field2End) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(Field2->getLocation(), diag::note_odr_field) - << Field2->getDeclName() << Field2->getType(); - Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(Field2->getLocation(), diag::note_odr_field) + << Field2->getDeclName() << Field2->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_missing_field); + } return false; } @@ -1014,12 +1087,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, EC1End = D1->enumerator_end(); EC1 != EC1End; ++EC1, ++EC2) { if (EC2 == EC2End) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) - << EC1->getDeclName() - << EC1->getInitVal().toString(10); - Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() + << EC1->getInitVal().toString(10); + Context.Diag2(D2->getLocation(), diag::note_odr_missing_enumerator); + } return false; } @@ -1027,25 +1102,29 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, llvm::APSInt Val2 = EC2->getInitVal(); if (!llvm::APSInt::isSameValue(Val1, Val2) || !IsStructurallyEquivalent(EC1->getIdentifier(), EC2->getIdentifier())) { + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) + << Context.C2.getTypeDeclType(D2); + Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) + << EC2->getDeclName() + << EC2->getInitVal().toString(10); + Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) + << EC1->getDeclName() + << EC1->getInitVal().toString(10); + } + return false; + } + } + + if (EC2 != EC2End) { + if (Context.Complain) { Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) << Context.C2.getTypeDeclType(D2); Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) << EC2->getDeclName() << EC2->getInitVal().toString(10); - Context.Diag1(EC1->getLocation(), diag::note_odr_enumerator) - << EC1->getDeclName() - << EC1->getInitVal().toString(10); - return false; + Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); } - } - - if (EC2 != EC2End) { - Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent) - << Context.C2.getTypeDeclType(D2); - Context.Diag2(EC2->getLocation(), diag::note_odr_enumerator) - << EC2->getDeclName() - << EC2->getInitVal().toString(10); - Context.Diag1(D1->getLocation(), diag::note_odr_missing_enumerator); return false; } @@ -1056,20 +1135,24 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, TemplateParameterList *Params1, TemplateParameterList *Params2) { if (Params1->size() != Params2->size()) { - Context.Diag2(Params2->getTemplateLoc(), - diag::err_odr_different_num_template_parameters) - << Params1->size() << Params2->size(); - Context.Diag1(Params1->getTemplateLoc(), - diag::note_odr_template_parameter_list); + if (Context.Complain) { + Context.Diag2(Params2->getTemplateLoc(), + diag::err_odr_different_num_template_parameters) + << Params1->size() << Params2->size(); + Context.Diag1(Params1->getTemplateLoc(), + diag::note_odr_template_parameter_list); + } return false; } for (unsigned I = 0, N = Params1->size(); I != N; ++I) { if (Params1->getParam(I)->getKind() != Params2->getParam(I)->getKind()) { - Context.Diag2(Params2->getParam(I)->getLocation(), - diag::err_odr_different_template_parameter_kind); - Context.Diag1(Params1->getParam(I)->getLocation(), - diag::note_odr_template_parameter_here); + if (Context.Complain) { + Context.Diag2(Params2->getParam(I)->getLocation(), + diag::err_odr_different_template_parameter_kind); + Context.Diag1(Params1->getParam(I)->getLocation(), + diag::note_odr_template_parameter_here); + } return false; } @@ -1087,10 +1170,12 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, TemplateTypeParmDecl *D1, TemplateTypeParmDecl *D2) { if (D1->isParameterPack() != D2->isParameterPack()) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } return false; } @@ -1100,24 +1185,25 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, NonTypeTemplateParmDecl *D1, NonTypeTemplateParmDecl *D2) { - // FIXME: Enable once we have variadic templates. -#if 0 if (D1->isParameterPack() != D2->isParameterPack()) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } return false; } -#endif // Check types. if (!Context.IsStructurallyEquivalent(D1->getType(), D2->getType())) { - Context.Diag2(D2->getLocation(), - diag::err_odr_non_type_parameter_type_inconsistent) - << D2->getType() << D1->getType(); - Context.Diag1(D1->getLocation(), diag::note_odr_value_here) - << D1->getType(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), + diag::err_odr_non_type_parameter_type_inconsistent) + << D2->getType() << D1->getType(); + Context.Diag1(D1->getLocation(), diag::note_odr_value_here) + << D1->getType(); + } return false; } @@ -1127,17 +1213,16 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, TemplateTemplateParmDecl *D1, TemplateTemplateParmDecl *D2) { - // FIXME: Enable once we have variadic templates. -#if 0 if (D1->isParameterPack() != D2->isParameterPack()) { - Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) - << D2->isParameterPack(); - Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) - << D1->isParameterPack(); + if (Context.Complain) { + Context.Diag2(D2->getLocation(), diag::err_odr_parameter_pack_non_pack) + << D2->isParameterPack(); + Context.Diag1(D1->getLocation(), diag::note_odr_parameter_pack_non_pack) + << D1->isParameterPack(); + } return false; } -#endif - + // Check template parameter lists. return IsStructurallyEquivalent(Context, D1->getTemplateParameters(), D2->getTemplateParameters()); @@ -1509,11 +1594,26 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { ExceptionTypes.push_back(ExceptionType); } - FunctionProtoType::ExtProtoInfo EPI = T->getExtProtoInfo(); - EPI.Exceptions = ExceptionTypes.data(); - + FunctionProtoType::ExtProtoInfo FromEPI = T->getExtProtoInfo(); + FunctionProtoType::ExtProtoInfo ToEPI; + + ToEPI.ExtInfo = FromEPI.ExtInfo; + ToEPI.Variadic = FromEPI.Variadic; + ToEPI.HasTrailingReturn = FromEPI.HasTrailingReturn; + ToEPI.TypeQuals = FromEPI.TypeQuals; + ToEPI.RefQualifier = FromEPI.RefQualifier; + ToEPI.NumExceptions = ExceptionTypes.size(); + ToEPI.Exceptions = ExceptionTypes.data(); + ToEPI.ConsumedArguments = FromEPI.ConsumedArguments; + ToEPI.ExceptionSpecType = FromEPI.ExceptionSpecType; + ToEPI.NoexceptExpr = Importer.Import(FromEPI.NoexceptExpr); + ToEPI.ExceptionSpecDecl = cast_or_null<FunctionDecl>( + Importer.Import(FromEPI.ExceptionSpecDecl)); + ToEPI.ExceptionSpecTemplate = cast_or_null<FunctionDecl>( + Importer.Import(FromEPI.ExceptionSpecTemplate)); + return Importer.getToContext().getFunctionType(ToResultType, ArgTypes.data(), - ArgTypes.size(), EPI); + ArgTypes.size(), ToEPI); } QualType ASTNodeImporter::VisitParenType(const ParenType *T) { @@ -1961,11 +2061,20 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { return TemplateArgument(From, ToType); } - case TemplateArgument::Declaration: - if (Decl *To = Importer.Import(From.getAsDecl())) - return TemplateArgument(To); + case TemplateArgument::Declaration: { + ValueDecl *FromD = From.getAsDecl(); + if (ValueDecl *To = cast_or_null<ValueDecl>(Importer.Import(FromD))) + return TemplateArgument(To, From.isDeclForReferenceParam()); return TemplateArgument(); - + } + + case TemplateArgument::NullPtr: { + QualType ToType = Importer.Import(From.getNullPtrType()); + if (ToType.isNull()) + return TemplateArgument(); + return TemplateArgument(ToType, /*isNullPtr*/true); + } + case TemplateArgument::Template: { TemplateName ToTemplate = Importer.Import(From.getAsTemplate()); if (ToTemplate.isNull()) @@ -2318,6 +2427,20 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { } if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) { + if (D->isAnonymousStructOrUnion() && + FoundRecord->isAnonymousStructOrUnion()) { + // If both anonymous structs/unions are in a record context, make sure + // they occur in the same location in the context records. + if (llvm::Optional<unsigned> Index1 + = findAnonymousStructOrUnionIndex(D)) { + if (llvm::Optional<unsigned> Index2 + = findAnonymousStructOrUnionIndex(FoundRecord)) { + if (*Index1 != *Index2) + continue; + } + } + } + if (RecordDecl *FoundDef = FoundRecord->getDefinition()) { if ((SearchName && !D->isCompleteDefinition()) || (D->isCompleteDefinition() && @@ -2491,8 +2614,30 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // Import additional name location/type info. ImportDeclarationNameLoc(D->getNameInfo(), NameInfo); + QualType FromTy = D->getType(); + bool usedDifferentExceptionSpec = false; + + if (const FunctionProtoType * + FromFPT = D->getType()->getAs<FunctionProtoType>()) { + FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo(); + // FunctionProtoType::ExtProtoInfo's ExceptionSpecDecl can point to the + // FunctionDecl that we are importing the FunctionProtoType for. + // To avoid an infinite recursion when importing, create the FunctionDecl + // with a simplified function type and update it afterwards. + if (FromEPI.ExceptionSpecDecl || FromEPI.ExceptionSpecTemplate || + FromEPI.NoexceptExpr) { + FunctionProtoType::ExtProtoInfo DefaultEPI; + FromTy = Importer.getFromContext().getFunctionType( + FromFPT->getResultType(), + FromFPT->arg_type_begin(), + FromFPT->arg_type_end() - FromFPT->arg_type_begin(), + DefaultEPI); + usedDifferentExceptionSpec = true; + } + } + // Import the type. - QualType T = Importer.Import(D->getType()); + QualType T = Importer.Import(FromTy); if (T.isNull()) return 0; @@ -2572,6 +2717,14 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } ToFunction->setParams(Parameters); + if (usedDifferentExceptionSpec) { + // Update FunctionProtoType::ExtProtoInfo. + QualType T = Importer.Import(D->getType()); + if (T.isNull()) + return 0; + ToFunction->setType(T); + } + // FIXME: Other bits to merge? // Add this function to the lexical context. @@ -2596,6 +2749,25 @@ Decl *ASTNodeImporter::VisitCXXConversionDecl(CXXConversionDecl *D) { return VisitCXXMethodDecl(D); } +static unsigned getFieldIndex(Decl *F) { + RecordDecl *Owner = dyn_cast<RecordDecl>(F->getDeclContext()); + if (!Owner) + return 0; + + unsigned Index = 1; + for (DeclContext::decl_iterator D = Owner->noload_decls_begin(), + DEnd = Owner->noload_decls_end(); + D != DEnd; ++D) { + if (*D == F) + return Index; + + if (isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D)) + ++Index; + } + + return Index; +} + Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { // Import the major distinguishing characteristics of a variable. DeclContext *DC, *LexicalDC; @@ -2609,6 +2781,10 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { DC->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (FieldDecl *FoundField = dyn_cast<FieldDecl>(FoundDecls[I])) { + // For anonymous fields, match up by index. + if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) + continue; + if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType())) { Importer.Imported(D, FoundField); @@ -2642,6 +2818,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { ToField->setLexicalDeclContext(LexicalDC); if (ToField->hasInClassInitializer()) ToField->setInClassInitializer(D->getInClassInitializer()); + ToField->setImplicit(D->isImplicit()); Importer.Imported(D, ToField); LexicalDC->addDeclInternal(ToField); return ToField; @@ -2661,6 +2838,10 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (IndirectFieldDecl *FoundField = dyn_cast<IndirectFieldDecl>(FoundDecls[I])) { + // For anonymous indirect fields, match up by index. + if (!Name && getFieldIndex(D) != getFieldIndex(FoundField)) + continue; + if (Importer.IsStructurallyEquivalent(D->getType(), FoundField->getType(), Name)) { @@ -3025,7 +3206,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { ResultTy, ResultTInfo, DC, D->isInstanceMethod(), D->isVariadic(), - D->isSynthesized(), + D->isPropertyAccessor(), D->isImplicit(), D->isDefined(), D->getImplementationControl(), @@ -4027,7 +4208,8 @@ Expr *ASTNodeImporter::VisitBinaryOperator(BinaryOperator *E) { return new (Importer.getToContext()) BinaryOperator(LHS, RHS, E->getOpcode(), T, E->getValueKind(), E->getObjectKind(), - Importer.Import(E->getOperatorLoc())); + Importer.Import(E->getOperatorLoc()), + E->isFPContractable()); } Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { @@ -4056,7 +4238,8 @@ Expr *ASTNodeImporter::VisitCompoundAssignOperator(CompoundAssignOperator *E) { T, E->getValueKind(), E->getObjectKind(), CompLHSType, CompResultType, - Importer.Import(E->getOperatorLoc())); + Importer.Import(E->getOperatorLoc()), + E->isFPContractable()); } static bool ImportCastPath(CastExpr *E, CXXCastPath &Path) { @@ -4479,7 +4662,8 @@ FileID ASTImporter::Import(FileID FromID) { llvm::MemoryBuffer *ToBuf = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), FromBuf->getBufferIdentifier()); - ToID = ToSM.createFileIDForMemBuffer(ToBuf); + ToID = ToSM.createFileIDForMemBuffer(ToBuf, + FromSLoc.getFile().getFileCharacteristic()); } diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index bcc96f912e28..d20d77ef7ea5 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -64,7 +64,10 @@ add_dependencies(clangAST ClangAttrClasses ClangAttrList ClangAttrImpl + ClangCommentCommandInfo ClangCommentNodes + ClangCommentHTMLTags + ClangCommentHTMLTagsProperties ClangDeclNodes ClangDiagnosticAST ClangDiagnosticComment diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index cf3913bac008..213b214a4e4c 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/DeclCXX.h" +#include "llvm/ADT/SetVector.h" #include <algorithm> #include <set> @@ -25,13 +26,9 @@ void CXXBasePaths::ComputeDeclsFound() { assert(NumDeclsFound == 0 && !DeclsFound && "Already computed the set of declarations"); - SmallVector<NamedDecl *, 8> Decls; + llvm::SetVector<NamedDecl *, SmallVector<NamedDecl *, 8> > Decls; for (paths_iterator Path = begin(), PathEnd = end(); Path != PathEnd; ++Path) - Decls.push_back(*Path->Decls.first); - - // Eliminate duplicated decls. - llvm::array_pod_sort(Decls.begin(), Decls.end()); - Decls.erase(std::unique(Decls.begin(), Decls.end()), Decls.end()); + Decls.insert(*Path->Decls.first); NumDeclsFound = Decls.size(); DeclsFound = new NamedDecl * [NumDeclsFound]; @@ -258,7 +255,7 @@ bool CXXBasePaths::lookupInBases(ASTContext &Context, } } else if (VisitBase) { CXXRecordDecl *BaseRecord - = cast<CXXRecordDecl>(BaseSpec->getType()->getAs<RecordType>() + = cast<CXXRecordDecl>(BaseSpec->getType()->castAs<RecordType>() ->getDecl()); if (lookupInBases(Context, BaseRecord, BaseMatches, UserData)) { // C++ [class.member.lookup]p2: @@ -365,8 +362,8 @@ bool CXXRecordDecl::FindBaseClass(const CXXBaseSpecifier *Specifier, void *BaseRecord) { assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord && "User data for FindBaseClass is not canonical!"); - return Specifier->getType()->getAs<RecordType>()->getDecl() - ->getCanonicalDecl() == BaseRecord; + return Specifier->getType()->castAs<RecordType>()->getDecl() + ->getCanonicalDecl() == BaseRecord; } bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier, @@ -375,14 +372,15 @@ bool CXXRecordDecl::FindVirtualBaseClass(const CXXBaseSpecifier *Specifier, assert(((Decl *)BaseRecord)->getCanonicalDecl() == BaseRecord && "User data for FindBaseClass is not canonical!"); return Specifier->isVirtual() && - Specifier->getType()->getAs<RecordType>()->getDecl() - ->getCanonicalDecl() == BaseRecord; + Specifier->getType()->castAs<RecordType>()->getDecl() + ->getCanonicalDecl() == BaseRecord; } bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { - RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + RecordDecl *BaseRecord = + Specifier->getType()->castAs<RecordType>()->getDecl(); DeclarationName N = DeclarationName::getFromOpaquePtr(Name); for (Path.Decls = BaseRecord->lookup(N); @@ -398,7 +396,8 @@ bool CXXRecordDecl::FindTagMember(const CXXBaseSpecifier *Specifier, bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { - RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + RecordDecl *BaseRecord = + Specifier->getType()->castAs<RecordType>()->getDecl(); const unsigned IDNS = IDNS_Ordinary | IDNS_Tag | IDNS_Member; DeclarationName N = DeclarationName::getFromOpaquePtr(Name); @@ -416,7 +415,8 @@ bool CXXRecordDecl:: FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *Name) { - RecordDecl *BaseRecord = Specifier->getType()->getAs<RecordType>()->getDecl(); + RecordDecl *BaseRecord = + Specifier->getType()->castAs<RecordType>()->getDecl(); DeclarationName N = DeclarationName::getFromOpaquePtr(Name); for (Path.Decls = BaseRecord->lookup(N); @@ -694,7 +694,7 @@ AddIndirectPrimaryBases(const CXXRecordDecl *RD, ASTContext &Context, "Cannot get indirect primary bases for class with dependent bases."); const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl()); // Only bases with virtual bases participate in computing the // indirect primary virtual base classes. @@ -717,7 +717,7 @@ CXXRecordDecl::getIndirectPrimaryBases(CXXIndirectPrimaryBaseSet& Bases) const { "Cannot get indirect primary bases for class with dependent bases."); const CXXRecordDecl *BaseDecl = - cast<CXXRecordDecl>(I->getType()->getAs<RecordType>()->getDecl()); + cast<CXXRecordDecl>(I->getType()->castAs<RecordType>()->getDecl()); // Only bases with virtual bases participate in computing the // indirect primary virtual base classes. diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index 8a711f0c1f80..361f8ac61c2a 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -7,6 +7,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/ASTContext.h" #include "clang/AST/Comment.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -37,11 +38,12 @@ void Comment::dump() const { // in CommentDumper.cpp, that object file would be removed by linker because // none of its functions are referenced by other object files, despite the // LLVM_ATTRIBUTE_USED. - dump(llvm::errs(), NULL); + dump(llvm::errs(), NULL, NULL); } -void Comment::dump(SourceManager &SM) const { - dump(llvm::errs(), &SM); +void Comment::dump(const ASTContext &Context) const { + dump(llvm::errs(), &Context.getCommentCommandTraits(), + &Context.getSourceManager()); } namespace { @@ -149,13 +151,14 @@ void DeclInfo::fill() { ParamVars = ArrayRef<const ParmVarDecl *>(); TemplateParameters = NULL; - if (!ThisDecl) { + if (!CommentDecl) { // If there is no declaration, the defaults is our only guess. IsFilled = true; return; } - - Decl::Kind K = ThisDecl->getKind(); + CurrentDecl = CommentDecl; + + Decl::Kind K = CommentDecl->getKind(); switch (K) { default: // Defaults are should be good for declarations we don't handle explicitly. @@ -165,7 +168,7 @@ void DeclInfo::fill() { case Decl::CXXConstructor: case Decl::CXXDestructor: case Decl::CXXConversion: { - const FunctionDecl *FD = cast<FunctionDecl>(ThisDecl); + const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl); Kind = FunctionKind; ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(), FD->getNumParams()); @@ -179,14 +182,14 @@ void DeclInfo::fill() { if (K == Decl::CXXMethod || K == Decl::CXXConstructor || K == Decl::CXXDestructor || K == Decl::CXXConversion) { - const CXXMethodDecl *MD = cast<CXXMethodDecl>(ThisDecl); + const CXXMethodDecl *MD = cast<CXXMethodDecl>(CommentDecl); IsInstanceMethod = MD->isInstance(); IsClassMethod = !IsInstanceMethod; } break; } case Decl::ObjCMethod: { - const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(ThisDecl); + const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); Kind = FunctionKind; ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(), MD->param_size()); @@ -197,7 +200,7 @@ void DeclInfo::fill() { break; } case Decl::FunctionTemplate: { - const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(ThisDecl); + const FunctionTemplateDecl *FTD = cast<FunctionTemplateDecl>(CommentDecl); Kind = FunctionKind; TemplateKind = Template; const FunctionDecl *FD = FTD->getTemplatedDecl(); @@ -208,7 +211,7 @@ void DeclInfo::fill() { break; } case Decl::ClassTemplate: { - const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(ThisDecl); + const ClassTemplateDecl *CTD = cast<ClassTemplateDecl>(CommentDecl); Kind = ClassKind; TemplateKind = Template; TemplateParameters = CTD->getTemplateParameters(); @@ -216,7 +219,7 @@ void DeclInfo::fill() { } case Decl::ClassTemplatePartialSpecialization: { const ClassTemplatePartialSpecializationDecl *CTPSD = - cast<ClassTemplatePartialSpecializationDecl>(ThisDecl); + cast<ClassTemplatePartialSpecializationDecl>(CommentDecl); Kind = ClassKind; TemplateKind = TemplatePartialSpecialization; TemplateParameters = CTPSD->getTemplateParameters(); @@ -240,12 +243,55 @@ void DeclInfo::fill() { case Decl::Namespace: Kind = NamespaceKind; break; - case Decl::Typedef: + case Decl::Typedef: { + Kind = TypedefKind; + // If this is a typedef to something we consider a function, extract + // arguments and return type. + const TypedefDecl *TD = cast<TypedefDecl>(CommentDecl); + const TypeSourceInfo *TSI = TD->getTypeSourceInfo(); + if (!TSI) + break; + TypeLoc TL = TSI->getTypeLoc().getUnqualifiedLoc(); + while (true) { + TL = TL.IgnoreParens(); + // Look through qualified types. + if (QualifiedTypeLoc *QualifiedTL = dyn_cast<QualifiedTypeLoc>(&TL)) { + TL = QualifiedTL->getUnqualifiedLoc(); + continue; + } + // Look through pointer types. + if (PointerTypeLoc *PointerTL = dyn_cast<PointerTypeLoc>(&TL)) { + TL = PointerTL->getPointeeLoc().getUnqualifiedLoc(); + continue; + } + if (BlockPointerTypeLoc *BlockPointerTL = + dyn_cast<BlockPointerTypeLoc>(&TL)) { + TL = BlockPointerTL->getPointeeLoc().getUnqualifiedLoc(); + continue; + } + if (MemberPointerTypeLoc *MemberPointerTL = + dyn_cast<MemberPointerTypeLoc>(&TL)) { + TL = MemberPointerTL->getPointeeLoc().getUnqualifiedLoc(); + continue; + } + // Is this a typedef for a function type? + if (FunctionTypeLoc *FTL = dyn_cast<FunctionTypeLoc>(&TL)) { + Kind = FunctionKind; + ArrayRef<ParmVarDecl *> Params = FTL->getParams(); + ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(), + Params.size()); + ResultType = FTL->getResultLoc().getType(); + break; + } + break; + } + break; + } case Decl::TypeAlias: Kind = TypedefKind; break; case Decl::TypeAliasTemplate: { - const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(ThisDecl); + const TypeAliasTemplateDecl *TAT = cast<TypeAliasTemplateDecl>(CommentDecl); Kind = TypedefKind; TemplateKind = Template; TemplateParameters = TAT->getTemplateParameters(); @@ -259,6 +305,25 @@ void DeclInfo::fill() { IsFilled = true; } +StringRef ParamCommandComment::getParamName(const FullComment *FC) const { + assert(isParamIndexValid()); + return FC->getThisDeclInfo()->ParamVars[getParamIndex()]->getName(); +} + +StringRef TParamCommandComment::getParamName(const FullComment *FC) const { + assert(isPositionValid()); + const TemplateParameterList *TPL = FC->getThisDeclInfo()->TemplateParameters; + for (unsigned i = 0, e = getDepth(); i != e; ++i) { + if (i == e-1) + return TPL->getParam(getIndex(i))->getName(); + const NamedDecl *Param = TPL->getParam(getIndex(i)); + if (const TemplateTemplateParmDecl *TTP = + dyn_cast<TemplateTemplateParmDecl>(Param)) + TPL = TTP->getTemplateParameters(); + } + return ""; +} + } // end namespace comments } // end namespace clang diff --git a/lib/AST/CommentBriefParser.cpp b/lib/AST/CommentBriefParser.cpp index 0aebc1e4e3dd..95daa7e3f809 100644 --- a/lib/AST/CommentBriefParser.cpp +++ b/lib/AST/CommentBriefParser.cpp @@ -15,6 +15,11 @@ namespace clang { namespace comments { namespace { +inline bool isWhitespace(char C) { + return C == ' ' || C == '\n' || C == '\r' || + C == '\t' || C == '\f' || C == '\v'; +} + /// Convert all whitespace into spaces, remove leading and trailing spaces, /// compress multiple spaces into one. void cleanupBrief(std::string &S) { @@ -23,8 +28,7 @@ void cleanupBrief(std::string &S) { for (std::string::iterator I = S.begin(), E = S.end(); I != E; ++I) { const char C = *I; - if (C == ' ' || C == '\n' || C == '\r' || - C == '\t' || C == '\v' || C == '\f') { + if (isWhitespace(C)) { if (!PrevWasSpace) { *O++ = ' '; PrevWasSpace = true; @@ -40,6 +44,15 @@ void cleanupBrief(std::string &S) { S.resize(O - S.begin()); } + +bool isWhitespace(StringRef Text) { + for (StringRef::const_iterator I = Text.begin(), E = Text.end(); + I != E; ++I) { + if (!isWhitespace(*I)) + return false; + } + return true; +} } // unnamed namespace BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) : @@ -66,19 +79,23 @@ std::string BriefParser::Parse() { } if (Tok.is(tok::command)) { - StringRef Name = Tok.getCommandName(); - if (Traits.isBriefCommand(Name)) { + const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); + if (Info->IsBriefCommand) { FirstParagraphOrBrief.clear(); InBrief = true; ConsumeToken(); continue; } - if (Traits.isReturnsCommand(Name)) { + if (Info->IsReturnsCommand) { InReturns = true; + InBrief = false; + InFirstParagraph = false; ReturnsParagraph += "Returns "; + ConsumeToken(); + continue; } // Block commands implicitly start a new paragraph. - if (Traits.isBlockCommand(Name)) { + if (Info->IsBlockCommand) { // We found an implicit paragraph end. InFirstParagraph = false; if (InBrief) @@ -93,13 +110,29 @@ std::string BriefParser::Parse() { ReturnsParagraph += ' '; ConsumeToken(); + // If the next token is a whitespace only text, ignore it. Thus we allow + // two paragraphs to be separated by line that has only whitespace in it. + // + // We don't need to add a space to the parsed text because we just added + // a space for the newline. + if (Tok.is(tok::text)) { + if (isWhitespace(Tok.getText())) + ConsumeToken(); + } + if (Tok.is(tok::newline)) { ConsumeToken(); - // We found a paragraph end. - InFirstParagraph = false; - InReturns = false; + // We found a paragraph end. This ends the brief description if + // \\brief command or its equivalent was explicitly used. + // Stop scanning text because an explicit \\brief paragraph is the + // preffered one. if (InBrief) break; + // End first paragraph if we found some non-whitespace text. + if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief)) + InFirstParagraph = false; + // End the \\returns paragraph because we found the paragraph end. + InReturns = false; } continue; } diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp index dc7a0bd17532..e7e40fd1090f 100644 --- a/lib/AST/CommentCommandTraits.cpp +++ b/lib/AST/CommentCommandTraits.cpp @@ -8,125 +8,64 @@ //===----------------------------------------------------------------------===// #include "clang/AST/CommentCommandTraits.h" -#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/STLExtras.h" namespace clang { namespace comments { -// TODO: tablegen +#include "clang/AST/CommentCommandInfo.inc" -bool CommandTraits::isVerbatimBlockCommand(StringRef StartName, - StringRef &EndName) const { - const char *Result = llvm::StringSwitch<const char *>(StartName) - .Case("code", "endcode") - .Case("verbatim", "endverbatim") - .Case("htmlonly", "endhtmlonly") - .Case("latexonly", "endlatexonly") - .Case("xmlonly", "endxmlonly") - .Case("manonly", "endmanonly") - .Case("rtfonly", "endrtfonly") +CommandTraits::CommandTraits(llvm::BumpPtrAllocator &Allocator) : + NextID(llvm::array_lengthof(Commands)), Allocator(Allocator) +{ } - .Case("dot", "enddot") - .Case("msc", "endmsc") - - .Case("f$", "f$") // Inline LaTeX formula - .Case("f[", "f]") // Displayed LaTeX formula - .Case("f{", "f}") // LaTeX environment - - .Default(NULL); - - if (Result) { - EndName = Result; - return true; - } - - for (VerbatimBlockCommandVector::const_iterator - I = VerbatimBlockCommands.begin(), - E = VerbatimBlockCommands.end(); - I != E; ++I) - if (I->StartName == StartName) { - EndName = I->EndName; - return true; - } - - return false; +const CommandInfo *CommandTraits::getCommandInfoOrNULL(StringRef Name) const { + if (const CommandInfo *Info = getBuiltinCommandInfo(Name)) + return Info; + return getRegisteredCommandInfo(Name); } -bool CommandTraits::isVerbatimLineCommand(StringRef Name) const { - bool Result = isDeclarationCommand(Name) || llvm::StringSwitch<bool>(Name) - .Case("defgroup", true) - .Case("ingroup", true) - .Case("addtogroup", true) - .Case("weakgroup", true) - .Case("name", true) - - .Case("section", true) - .Case("subsection", true) - .Case("subsubsection", true) - .Case("paragraph", true) - - .Case("mainpage", true) - .Case("subpage", true) - .Case("ref", true) +const CommandInfo *CommandTraits::getCommandInfo(unsigned CommandID) const { + if (const CommandInfo *Info = getBuiltinCommandInfo(CommandID)) + return Info; + return getRegisteredCommandInfo(CommandID); +} - .Default(false); +const CommandInfo *CommandTraits::registerUnknownCommand(StringRef CommandName) { + char *Name = Allocator.Allocate<char>(CommandName.size() + 1); + memcpy(Name, CommandName.data(), CommandName.size()); + Name[CommandName.size()] = '\0'; - if (Result) - return true; + // Value-initialize (=zero-initialize in this case) a new CommandInfo. + CommandInfo *Info = new (Allocator) CommandInfo(); + Info->Name = Name; + Info->ID = NextID++; + Info->IsUnknownCommand = true; - for (VerbatimLineCommandVector::const_iterator - I = VerbatimLineCommands.begin(), - E = VerbatimLineCommands.end(); - I != E; ++I) - if (I->Name == Name) - return true; + RegisteredCommands.push_back(Info); - return false; + return Info; } -bool CommandTraits::isDeclarationCommand(StringRef Name) const { - return llvm::StringSwitch<bool>(Name) - // Doxygen commands. - .Case("fn", true) - .Case("var", true) - .Case("property", true) - .Case("typedef", true) - - .Case("overload", true) - - // HeaderDoc commands. - .Case("class", true) - .Case("interface", true) - .Case("protocol", true) - .Case("category", true) - .Case("template", true) - .Case("function", true) - .Case("method", true) - .Case("callback", true) - .Case("var", true) - .Case("const", true) - .Case("constant", true) - .Case("property", true) - .Case("struct", true) - .Case("union", true) - .Case("typedef", true) - .Case("enum", true) - - .Default(false); +const CommandInfo *CommandTraits::getBuiltinCommandInfo( + unsigned CommandID) { + if (CommandID < llvm::array_lengthof(Commands)) + return &Commands[CommandID]; + return NULL; } -void CommandTraits::addVerbatimBlockCommand(StringRef StartName, - StringRef EndName) { - VerbatimBlockCommand VBC; - VBC.StartName = StartName; - VBC.EndName = EndName; - VerbatimBlockCommands.push_back(VBC); +const CommandInfo *CommandTraits::getRegisteredCommandInfo( + StringRef Name) const { + for (unsigned i = 0, e = RegisteredCommands.size(); i != e; ++i) { + if (RegisteredCommands[i]->Name == Name) + return RegisteredCommands[i]; + } + return NULL; } -void CommandTraits::addVerbatimLineCommand(StringRef Name) { - VerbatimLineCommand VLC; - VLC.Name = Name; - VerbatimLineCommands.push_back(VLC); +const CommandInfo *CommandTraits::getRegisteredCommandInfo( + unsigned CommandID) const { + return RegisteredCommands[CommandID - llvm::array_lengthof(Commands)]; } } // end namespace comments diff --git a/lib/AST/CommentDumper.cpp b/lib/AST/CommentDumper.cpp index dffc8233a0ca..19d24b2f3a03 100644 --- a/lib/AST/CommentDumper.cpp +++ b/lib/AST/CommentDumper.cpp @@ -16,12 +16,20 @@ namespace comments { namespace { class CommentDumper: public comments::ConstCommentVisitor<CommentDumper> { raw_ostream &OS; - SourceManager *SM; + const CommandTraits *Traits; + const SourceManager *SM; + + /// The \c FullComment parent of the comment being dumped. + const FullComment *FC; + unsigned IndentLevel; public: - CommentDumper(raw_ostream &OS, SourceManager *SM) : - OS(OS), SM(SM), IndentLevel(0) + CommentDumper(raw_ostream &OS, + const CommandTraits *Traits, + const SourceManager *SM, + const FullComment *FC) : + OS(OS), Traits(Traits), SM(SM), FC(FC), IndentLevel(0) { } void dumpIndent() const { @@ -56,6 +64,15 @@ public: void visitVerbatimLineComment(const VerbatimLineComment *C); void visitFullComment(const FullComment *C); + + const char *getCommandName(unsigned CommandID) { + if (Traits) + return Traits->getCommandInfo(CommandID)->Name; + const CommandInfo *Info = CommandTraits::getBuiltinCommandInfo(CommandID); + if (Info) + return Info->Name; + return "<not a builtin command>"; + } }; void CommentDumper::dumpSourceRange(const Comment *C) { @@ -107,7 +124,7 @@ void CommentDumper::visitTextComment(const TextComment *C) { void CommentDumper::visitInlineCommandComment(const InlineCommandComment *C) { dumpComment(C); - OS << " Name=\"" << C->getCommandName() << "\""; + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; switch (C->getRenderKind()) { case InlineCommandComment::RenderNormal: OS << " RenderNormal"; @@ -155,7 +172,7 @@ void CommentDumper::visitParagraphComment(const ParagraphComment *C) { void CommentDumper::visitBlockCommandComment(const BlockCommandComment *C) { dumpComment(C); - OS << " Name=\"" << C->getCommandName() << "\""; + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\""; for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\""; } @@ -170,8 +187,12 @@ void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) { else OS << " implicitly"; - if (C->hasParamName()) - OS << " Param=\"" << C->getParamName() << "\""; + if (C->hasParamName()) { + if (C->isParamIndexValid()) + OS << " Param=\"" << C->getParamName(FC) << "\""; + else + OS << " Param=\"" << C->getParamNameAsWritten() << "\""; + } if (C->isParamIndexValid()) OS << " ParamIndex=" << C->getParamIndex(); @@ -181,7 +202,10 @@ void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) { dumpComment(C); if (C->hasParamName()) { - OS << " Param=\"" << C->getParamName() << "\""; + if (C->isPositionValid()) + OS << " Param=\"" << C->getParamName(FC) << "\""; + else + OS << " Param=\"" << C->getParamNameAsWritten() << "\""; } if (C->isPositionValid()) { @@ -198,7 +222,7 @@ void CommentDumper::visitTParamCommandComment(const TParamCommandComment *C) { void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) { dumpComment(C); - OS << " Name=\"" << C->getCommandName() << "\"" + OS << " Name=\"" << getCommandName(C->getCommandID()) << "\"" " CloseName=\"" << C->getCloseName() << "\""; } @@ -220,8 +244,10 @@ void CommentDumper::visitFullComment(const FullComment *C) { } // unnamed namespace -void Comment::dump(llvm::raw_ostream &OS, SourceManager *SM) const { - CommentDumper D(llvm::errs(), SM); +void Comment::dump(llvm::raw_ostream &OS, const CommandTraits *Traits, + const SourceManager *SM) const { + const FullComment *FC = dyn_cast<FullComment>(this); + CommentDumper D(llvm::errs(), Traits, SM, FC); D.dumpSubtree(this); llvm::errs() << '\n'; } diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index b6516ec126f6..31a09f71d993 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -28,6 +28,9 @@ bool isHTMLHexCharacterReferenceCharacter(char C) { (C >= 'a' && C <= 'f') || (C >= 'A' && C <= 'F'); } + +#include "clang/AST/CommentHTMLTags.inc" + } // unnamed namespace StringRef Lexer::resolveHTMLNamedCharacterReference(StringRef Name) const { @@ -223,6 +226,11 @@ bool isWhitespace(const char *BufferPtr, const char *BufferEnd) { return skipWhitespace(BufferPtr, BufferEnd) == BufferEnd; } +bool isCommandNameStartCharacter(char C) { + return (C >= 'a' && C <= 'z') || + (C >= 'A' && C <= 'Z'); +} + bool isCommandNameCharacter(char C) { return (C >= 'a' && C <= 'z') || (C >= 'A' && C <= 'Z') || @@ -337,7 +345,7 @@ void Lexer::lexCommentText(Token &T) { } // Don't make zero-length commands. - if (!isCommandNameCharacter(*TokenPtr)) { + if (!isCommandNameStartCharacter(*TokenPtr)) { formTextToken(T, TokenPtr); return; } @@ -356,18 +364,23 @@ void Lexer::lexCommentText(Token &T) { } const StringRef CommandName(BufferPtr + 1, Length); - StringRef EndName; - if (Traits.isVerbatimBlockCommand(CommandName, EndName)) { - setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, EndName); + const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName); + if (!Info) { + formTokenWithChars(T, TokenPtr, tok::unknown_command); + T.setUnknownCommandName(CommandName); + return; + } + if (Info->IsVerbatimBlockCommand) { + setupAndLexVerbatimBlock(T, TokenPtr, *BufferPtr, Info); return; } - if (Traits.isVerbatimLineCommand(CommandName)) { - setupAndLexVerbatimLine(T, TokenPtr); + if (Info->IsVerbatimLineCommand) { + setupAndLexVerbatimLine(T, TokenPtr, Info); return; } formTokenWithChars(T, TokenPtr, tok::command); - T.setCommandName(CommandName); + T.setCommandID(Info->getID()); return; } @@ -420,14 +433,15 @@ void Lexer::lexCommentText(Token &T) { void Lexer::setupAndLexVerbatimBlock(Token &T, const char *TextBegin, - char Marker, StringRef EndName) { + char Marker, const CommandInfo *Info) { + assert(Info->IsVerbatimBlockCommand); + VerbatimBlockEndCommandName.clear(); VerbatimBlockEndCommandName.append(Marker == '\\' ? "\\" : "@"); - VerbatimBlockEndCommandName.append(EndName); + VerbatimBlockEndCommandName.append(Info->EndCommandName); - StringRef Name(BufferPtr + 1, TextBegin - (BufferPtr + 1)); formTokenWithChars(T, TextBegin, tok::verbatim_block_begin); - T.setVerbatimBlockName(Name); + T.setVerbatimBlockID(Info->getID()); // If there is a newline following the verbatim opening command, skip the // newline so that we don't create an tok::verbatim_block_line with empty @@ -468,7 +482,7 @@ again: const char *End = BufferPtr + VerbatimBlockEndCommandName.size(); StringRef Name(BufferPtr + 1, End - (BufferPtr + 1)); formTokenWithChars(T, End, tok::verbatim_block_end); - T.setVerbatimBlockName(Name); + T.setVerbatimBlockID(Traits.getCommandInfo(Name)->getID()); State = LS_Normal; return; } else { @@ -498,10 +512,11 @@ void Lexer::lexVerbatimBlockBody(Token &T) { lexVerbatimBlockFirstLine(T); } -void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin) { - const StringRef Name(BufferPtr + 1, TextBegin - BufferPtr - 1); +void Lexer::setupAndLexVerbatimLine(Token &T, const char *TextBegin, + const CommandInfo *Info) { + assert(Info->IsVerbatimLineCommand); formTokenWithChars(T, TextBegin, tok::verbatim_line_name); - T.setVerbatimLineName(Name); + T.setVerbatimLineID(Info->getID()); State = LS_VerbatimLineText; } @@ -585,8 +600,12 @@ void Lexer::setupAndLexHTMLStartTag(Token &T) { assert(BufferPtr[0] == '<' && isHTMLIdentifierStartingCharacter(BufferPtr[1])); const char *TagNameEnd = skipHTMLIdentifier(BufferPtr + 2, CommentEnd); - StringRef Name(BufferPtr + 1, TagNameEnd - (BufferPtr + 1)); + if (!isHTMLTagName(Name)) { + formTextToken(T, TagNameEnd); + return; + } + formTokenWithChars(T, TagNameEnd, tok::html_start_tag); T.setHTMLTagStartName(Name); @@ -665,11 +684,16 @@ void Lexer::setupAndLexHTMLEndTag(Token &T) { const char *TagNameBegin = skipWhitespace(BufferPtr + 2, CommentEnd); const char *TagNameEnd = skipHTMLIdentifier(TagNameBegin, CommentEnd); + StringRef Name(TagNameBegin, TagNameEnd - TagNameBegin); + if (!isHTMLTagName(Name)) { + formTextToken(T, TagNameEnd); + return; + } const char *End = skipWhitespace(TagNameEnd, CommentEnd); formTokenWithChars(T, End, tok::html_end_tag); - T.setHTMLTagEndName(StringRef(TagNameBegin, TagNameEnd - TagNameBegin)); + T.setHTMLTagEndName(Name); if (BufferPtr != CommentEnd && *BufferPtr == '>') State = LS_HTMLEndTag; @@ -683,11 +707,11 @@ void Lexer::lexHTMLEndTag(Token &T) { } Lexer::Lexer(llvm::BumpPtrAllocator &Allocator, const CommandTraits &Traits, - SourceLocation FileLoc, const CommentOptions &CommOpts, + SourceLocation FileLoc, const char *BufferStart, const char *BufferEnd): Allocator(Allocator), Traits(Traits), BufferStart(BufferStart), BufferEnd(BufferEnd), - FileLoc(FileLoc), CommOpts(CommOpts), BufferPtr(BufferStart), + FileLoc(FileLoc), BufferPtr(BufferStart), CommentState(LCS_BeforeComment), State(LS_Normal) { } diff --git a/lib/AST/CommentParser.cpp b/lib/AST/CommentParser.cpp index 43abf6a476a8..d0a84741b6f2 100644 --- a/lib/AST/CommentParser.cpp +++ b/lib/AST/CommentParser.cpp @@ -132,8 +132,8 @@ class TextTokenRetokenizer { Result.setKind(tok::text); Result.setLength(TokLength); #ifndef NDEBUG - Result.TextPtr1 = "<UNSET>"; - Result.TextLen1 = 7; + Result.TextPtr = "<UNSET>"; + Result.IntVal = 7; #endif Result.setText(Text); } @@ -312,26 +312,26 @@ BlockCommandComment *Parser::parseBlockCommand() { BlockCommandComment *BC; bool IsParam = false; bool IsTParam = false; - unsigned NumArgs = 0; - if (Traits.isParamCommand(Tok.getCommandName())) { + const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); + if (Info->IsParamCommand) { IsParam = true; PC = S.actOnParamCommandStart(Tok.getLocation(), Tok.getEndLocation(), - Tok.getCommandName()); - } if (Traits.isTParamCommand(Tok.getCommandName())) { + Tok.getCommandID()); + } if (Info->IsTParamCommand) { IsTParam = true; TPC = S.actOnTParamCommandStart(Tok.getLocation(), Tok.getEndLocation(), - Tok.getCommandName()); + Tok.getCommandID()); } else { - NumArgs = Traits.getBlockCommandNumArgs(Tok.getCommandName()); BC = S.actOnBlockCommandStart(Tok.getLocation(), Tok.getEndLocation(), - Tok.getCommandName()); + Tok.getCommandID()); } consumeToken(); - if (Tok.is(tok::command) && Traits.isBlockCommand(Tok.getCommandName())) { + if (Tok.is(tok::command) && + Traits.getCommandInfo(Tok.getCommandID())->IsBlockCommand) { // Block command ahead. We can't nest block commands, so pretend that this // command has an empty argument. ParagraphComment *Paragraph = S.actOnParagraphComment( @@ -348,7 +348,7 @@ BlockCommandComment *Parser::parseBlockCommand() { } } - if (IsParam || IsTParam || NumArgs > 0) { + if (IsParam || IsTParam || Info->NumArgs > 0) { // In order to parse command arguments we need to retokenize a few // following text tokens. TextTokenRetokenizer Retokenizer(Allocator, *this); @@ -358,7 +358,7 @@ BlockCommandComment *Parser::parseBlockCommand() { else if (IsTParam) parseTParamCommandArgs(TPC, Retokenizer); else - parseBlockCommandArgs(BC, Retokenizer, NumArgs); + parseBlockCommandArgs(BC, Retokenizer, Info->NumArgs); Retokenizer.putBackLeftoverTokens(); } @@ -394,14 +394,14 @@ InlineCommandComment *Parser::parseInlineCommand() { if (ArgTokValid) { IC = S.actOnInlineCommand(CommandTok.getLocation(), CommandTok.getEndLocation(), - CommandTok.getCommandName(), + CommandTok.getCommandID(), ArgTok.getLocation(), ArgTok.getEndLocation(), ArgTok.getText()); } else { IC = S.actOnInlineCommand(CommandTok.getLocation(), CommandTok.getEndLocation(), - CommandTok.getCommandName()); + CommandTok.getCommandID()); } Retokenizer.putBackLeftoverTokens(); @@ -540,23 +540,39 @@ BlockContentComment *Parser::parseParagraphOrBlockCommand() { assert(Content.size() != 0); break; // Block content or EOF ahead, finish this parapgaph. - case tok::command: - if (Traits.isBlockCommand(Tok.getCommandName())) { + case tok::unknown_command: + Content.push_back(S.actOnUnknownCommand(Tok.getLocation(), + Tok.getEndLocation(), + Tok.getUnknownCommandName())); + consumeToken(); + continue; + + case tok::command: { + const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); + if (Info->IsBlockCommand) { if (Content.size() == 0) return parseBlockCommand(); break; // Block command ahead, finish this parapgaph. } - if (Traits.isInlineCommand(Tok.getCommandName())) { - Content.push_back(parseInlineCommand()); + if (Info->IsVerbatimBlockEndCommand) { + Diag(Tok.getLocation(), + diag::warn_verbatim_block_end_without_start) + << Info->Name + << SourceRange(Tok.getLocation(), Tok.getEndLocation()); + consumeToken(); continue; } - - // Not a block command, not an inline command ==> an unknown command. - Content.push_back(S.actOnUnknownCommand(Tok.getLocation(), - Tok.getEndLocation(), - Tok.getCommandName())); - consumeToken(); + if (Info->IsUnknownCommand) { + Content.push_back(S.actOnUnknownCommand(Tok.getLocation(), + Tok.getEndLocation(), + Info->getID())); + consumeToken(); + continue; + } + assert(Info->IsInlineCommand); + Content.push_back(parseInlineCommand()); continue; + } case tok::newline: { consumeToken(); @@ -606,7 +622,7 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() { VerbatimBlockComment *VB = S.actOnVerbatimBlockStart(Tok.getLocation(), - Tok.getVerbatimBlockName()); + Tok.getVerbatimBlockID()); consumeToken(); // Don't create an empty line if verbatim opening command is followed @@ -634,8 +650,9 @@ VerbatimBlockComment *Parser::parseVerbatimBlock() { } if (Tok.is(tok::verbatim_block_end)) { + const CommandInfo *Info = Traits.getCommandInfo(Tok.getVerbatimBlockID()); S.actOnVerbatimBlockFinish(VB, Tok.getLocation(), - Tok.getVerbatimBlockName(), + Info->Name, S.copyArray(llvm::makeArrayRef(Lines))); consumeToken(); } else { @@ -666,7 +683,7 @@ VerbatimLineComment *Parser::parseVerbatimLine() { } VerbatimLineComment *VL = S.actOnVerbatimLine(NameTok.getLocation(), - NameTok.getVerbatimLineName(), + NameTok.getVerbatimLineID(), TextBegin, Text); consumeToken(); @@ -676,6 +693,7 @@ VerbatimLineComment *Parser::parseVerbatimLine() { BlockContentComment *Parser::parseBlockContent() { switch (Tok.getKind()) { case tok::text: + case tok::unknown_command: case tok::command: case tok::html_start_tag: case tok::html_end_tag: diff --git a/lib/AST/CommentSema.cpp b/lib/AST/CommentSema.cpp index c39ee573ef6f..08ecb3a994d7 100644 --- a/lib/AST/CommentSema.cpp +++ b/lib/AST/CommentSema.cpp @@ -13,15 +13,22 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclTemplate.h" #include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/SmallString.h" namespace clang { namespace comments { +namespace { +#include "clang/AST/CommentHTMLTagsProperties.inc" +} // unnamed namespace + Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr, - DiagnosticsEngine &Diags, const CommandTraits &Traits) : + DiagnosticsEngine &Diags, CommandTraits &Traits, + const Preprocessor *PP) : Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits), - ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) { + PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) { } void Sema::setDecl(const Decl *D) { @@ -29,7 +36,7 @@ void Sema::setDecl(const Decl *D) { return; ThisDeclInfo = new (Allocator) DeclInfo; - ThisDeclInfo->ThisDecl = D; + ThisDeclInfo->CommentDecl = D; ThisDeclInfo->IsFilled = false; } @@ -40,8 +47,8 @@ ParagraphComment *Sema::actOnParagraphComment( BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, - StringRef Name) { - return new (Allocator) BlockCommandComment(LocBegin, LocEnd, Name); + unsigned CommandID) { + return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID); } void Sema::actOnBlockCommandArgs(BlockCommandComment *Command, @@ -55,18 +62,19 @@ void Sema::actOnBlockCommandFinish(BlockCommandComment *Command, checkBlockCommandEmptyParagraph(Command); checkBlockCommandDuplicate(Command); checkReturnsCommand(Command); + checkDeprecatedCommand(Command); } ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, - StringRef Name) { + unsigned CommandID) { ParamCommandComment *Command = - new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name); + new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID); if (!isFunctionDecl()) Diag(Command->getLocation(), diag::warn_doc_param_not_attached_to_a_function_decl) - << Command->getCommandNameRange(); + << Command->getCommandNameRange(Traits); return Command; } @@ -142,56 +150,6 @@ void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command, ArgLocEnd), Arg); Command->setArgs(llvm::makeArrayRef(A, 1)); - - if (!isFunctionDecl()) { - // We already warned that this \\param is not attached to a function decl. - return; - } - - ArrayRef<const ParmVarDecl *> ParamVars = getParamVars(); - - // Check that referenced parameter name is in the function decl. - const unsigned ResolvedParamIndex = resolveParmVarReference(Arg, ParamVars); - if (ResolvedParamIndex != ParamCommandComment::InvalidParamIndex) { - Command->setParamIndex(ResolvedParamIndex); - if (ParamVarDocs[ResolvedParamIndex]) { - SourceRange ArgRange(ArgLocBegin, ArgLocEnd); - Diag(ArgLocBegin, diag::warn_doc_param_duplicate) - << Arg << ArgRange; - ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex]; - Diag(PrevCommand->getLocation(), diag::note_doc_param_previous) - << PrevCommand->getParamNameRange(); - } - ParamVarDocs[ResolvedParamIndex] = Command; - return; - } - - SourceRange ArgRange(ArgLocBegin, ArgLocEnd); - Diag(ArgLocBegin, diag::warn_doc_param_not_found) - << Arg << ArgRange; - - // No parameters -- can't suggest a correction. - if (ParamVars.size() == 0) - return; - - unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex; - if (ParamVars.size() == 1) { - // If function has only one parameter then only that parameter - // can be documented. - CorrectedParamIndex = 0; - } else { - // Do typo correction. - CorrectedParamIndex = correctTypoInParmVarReference(Arg, ParamVars); - } - if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) { - const ParmVarDecl *CorrectedPVD = ParamVars[CorrectedParamIndex]; - if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier()) - Diag(ArgLocBegin, diag::note_doc_param_name_suggestion) - << CorrectedII->getName() - << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName()); - } - - return; } void Sema::actOnParamCommandFinish(ParamCommandComment *Command, @@ -202,14 +160,14 @@ void Sema::actOnParamCommandFinish(ParamCommandComment *Command, TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin, SourceLocation LocEnd, - StringRef Name) { + unsigned CommandID) { TParamCommandComment *Command = - new (Allocator) TParamCommandComment(LocBegin, LocEnd, Name); + new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID); if (!isTemplateOrSpecialization()) Diag(Command->getLocation(), diag::warn_doc_tparam_not_attached_to_a_template_decl) - << Command->getCommandNameRange(); + << Command->getCommandNameRange(Traits); return Command; } @@ -285,19 +243,20 @@ void Sema::actOnTParamCommandFinish(TParamCommandComment *Command, InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, SourceLocation CommandLocEnd, - StringRef CommandName) { + unsigned CommandID) { ArrayRef<InlineCommandComment::Argument> Args; + StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; return new (Allocator) InlineCommandComment( CommandLocBegin, CommandLocEnd, - CommandName, + CommandID, getInlineCommandRenderKind(CommandName), Args); } InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, SourceLocation CommandLocEnd, - StringRef CommandName, + unsigned CommandID, SourceLocation ArgLocBegin, SourceLocation ArgLocEnd, StringRef Arg) { @@ -305,21 +264,29 @@ InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, ArgLocEnd), Arg); + StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; return new (Allocator) InlineCommandComment( CommandLocBegin, CommandLocEnd, - CommandName, + CommandID, getInlineCommandRenderKind(CommandName), llvm::makeArrayRef(A, 1)); } InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, SourceLocation LocEnd, - StringRef Name) { + StringRef CommandName) { + unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID(); + return actOnUnknownCommand(LocBegin, LocEnd, CommandID); +} + +InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, + SourceLocation LocEnd, + unsigned CommandID) { ArrayRef<InlineCommandComment::Argument> Args; return new (Allocator) InlineCommandComment( - LocBegin, LocEnd, Name, + LocBegin, LocEnd, CommandID, InlineCommandComment::RenderNormal, Args); } @@ -331,11 +298,12 @@ TextComment *Sema::actOnText(SourceLocation LocBegin, } VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc, - StringRef Name) { + unsigned CommandID) { + StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; return new (Allocator) VerbatimBlockComment( Loc, - Loc.getLocWithOffset(1 + Name.size()), - Name); + Loc.getLocWithOffset(1 + CommandName.size()), + CommandID); } VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc, @@ -353,13 +321,13 @@ void Sema::actOnVerbatimBlockFinish( } VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin, - StringRef Name, + unsigned CommandID, SourceLocation TextBegin, StringRef Text) { return new (Allocator) VerbatimLineComment( LocBegin, TextBegin.getLocWithOffset(Text.size()), - Name, + CommandID, TextBegin, Text); } @@ -445,30 +413,35 @@ HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin, FullComment *Sema::actOnFullComment( ArrayRef<BlockContentComment *> Blocks) { - return new (Allocator) FullComment(Blocks, ThisDeclInfo); + FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo); + resolveParamCommandIndexes(FC); + return FC; } void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) { + if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed) + return; + ParagraphComment *Paragraph = Command->getParagraph(); if (Paragraph->isWhitespace()) { SourceLocation DiagLoc; if (Command->getNumArgs() > 0) DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd(); if (!DiagLoc.isValid()) - DiagLoc = Command->getCommandNameRange().getEnd(); + DiagLoc = Command->getCommandNameRange(Traits).getEnd(); Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph) - << Command->getCommandName() + << Command->getCommandName(Traits) << Command->getSourceRange(); } } void Sema::checkReturnsCommand(const BlockCommandComment *Command) { - if (!Traits.isReturnsCommand(Command->getCommandName())) + if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand) return; if (isFunctionDecl()) { if (ThisDeclInfo->ResultType->isVoidType()) { unsigned DiagKind; - switch (ThisDeclInfo->ThisDecl->getKind()) { + switch (ThisDeclInfo->CommentDecl->getKind()) { default: if (ThisDeclInfo->IsObjCMethod) DiagKind = 3; @@ -484,7 +457,7 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) { } Diag(Command->getLocation(), diag::warn_doc_returns_attached_to_a_void_function) - << Command->getCommandName() + << Command->getCommandName(Traits) << DiagKind << Command->getSourceRange(); } @@ -492,20 +465,20 @@ void Sema::checkReturnsCommand(const BlockCommandComment *Command) { } Diag(Command->getLocation(), diag::warn_doc_returns_not_attached_to_a_function_decl) - << Command->getCommandName() + << Command->getCommandName(Traits) << Command->getSourceRange(); } void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { - StringRef Name = Command->getCommandName(); + const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID()); const BlockCommandComment *PrevCommand = NULL; - if (Traits.isBriefCommand(Name)) { + if (Info->IsBriefCommand) { if (!BriefCommand) { BriefCommand = Command; return; } PrevCommand = BriefCommand; - } else if (Traits.isReturnsCommand(Name)) { + } else if (Info->IsReturnsCommand) { if (!ReturnsCommand) { ReturnsCommand = Command; return; @@ -515,18 +488,153 @@ void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { // We don't want to check this command for duplicates. return; } + StringRef CommandName = Command->getCommandName(Traits); + StringRef PrevCommandName = PrevCommand->getCommandName(Traits); Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate) - << Name + << CommandName << Command->getSourceRange(); - if (Name == PrevCommand->getCommandName()) + if (CommandName == PrevCommandName) Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous) - << PrevCommand->getCommandName() - << Command->getSourceRange(); + << PrevCommandName + << PrevCommand->getSourceRange(); else Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous_alias) - << PrevCommand->getCommandName() - << Name; + << PrevCommandName + << CommandName; +} + +void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) { + if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand) + return; + + const Decl *D = ThisDeclInfo->CommentDecl; + if (!D) + return; + + if (D->hasAttr<DeprecatedAttr>() || + D->hasAttr<AvailabilityAttr>() || + D->hasAttr<UnavailableAttr>()) + return; + + Diag(Command->getLocation(), + diag::warn_doc_deprecated_not_sync) + << Command->getSourceRange(); + + // Try to emit a fixit with a deprecation attribute. + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // Don't emit a Fix-It for non-member function definitions. GCC does not + // accept attributes on them. + const DeclContext *Ctx = FD->getDeclContext(); + if ((!Ctx || !Ctx->isRecord()) && + FD->doesThisDeclarationHaveABody()) + return; + + StringRef AttributeSpelling = "__attribute__((deprecated))"; + if (PP) { + TokenValue Tokens[] = { + tok::kw___attribute, tok::l_paren, tok::l_paren, + PP->getIdentifierInfo("deprecated"), + tok::r_paren, tok::r_paren + }; + StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), + Tokens); + if (!MacroName.empty()) + AttributeSpelling = MacroName; + } + + SmallString<64> TextToInsert(" "); + TextToInsert += AttributeSpelling; + Diag(FD->getLocEnd(), + diag::note_add_deprecation_attr) + << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1), + TextToInsert); + } +} + +void Sema::resolveParamCommandIndexes(const FullComment *FC) { + if (!isFunctionDecl()) { + // We already warned that \\param commands are not attached to a function + // decl. + return; + } + + llvm::SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands; + + // Comment AST nodes that correspond to \c ParamVars for which we have + // found a \\param command or NULL if no documentation was found so far. + llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs; + + ArrayRef<const ParmVarDecl *> ParamVars = getParamVars(); + ParamVarDocs.resize(ParamVars.size(), NULL); + + // First pass over all \\param commands: resolve all parameter names. + for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end(); + I != E; ++I) { + ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I); + if (!PCC || !PCC->hasParamName()) + continue; + StringRef ParamName = PCC->getParamNameAsWritten(); + + // Check that referenced parameter name is in the function decl. + const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName, + ParamVars); + if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) { + UnresolvedParamCommands.push_back(PCC); + continue; + } + PCC->setParamIndex(ResolvedParamIndex); + if (ParamVarDocs[ResolvedParamIndex]) { + SourceRange ArgRange = PCC->getParamNameRange(); + Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate) + << ParamName << ArgRange; + ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex]; + Diag(PrevCommand->getLocation(), diag::note_doc_param_previous) + << PrevCommand->getParamNameRange(); + } + ParamVarDocs[ResolvedParamIndex] = PCC; + } + + // Find parameter declarations that have no corresponding \\param. + llvm::SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls; + for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) { + if (!ParamVarDocs[i]) + OrphanedParamDecls.push_back(ParamVars[i]); + } + + // Second pass over unresolved \\param commands: do typo correction. + // Suggest corrections from a set of parameter declarations that have no + // corresponding \\param. + for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) { + const ParamCommandComment *PCC = UnresolvedParamCommands[i]; + + SourceRange ArgRange = PCC->getParamNameRange(); + StringRef ParamName = PCC->getParamNameAsWritten(); + Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found) + << ParamName << ArgRange; + + // All parameters documented -- can't suggest a correction. + if (OrphanedParamDecls.size() == 0) + continue; + + unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex; + if (OrphanedParamDecls.size() == 1) { + // If one parameter is not documented then that parameter is the only + // possible suggestion. + CorrectedParamIndex = 0; + } else { + // Do typo correction. + CorrectedParamIndex = correctTypoInParmVarReference(ParamName, + OrphanedParamDecls); + } + if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) { + const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex]; + if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier()) + Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion) + << CorrectedII->getName() + << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName()); + } + } } bool Sema::isFunctionDecl() { @@ -553,7 +661,6 @@ ArrayRef<const ParmVarDecl *> Sema::getParamVars() { void Sema::inspectThisDecl() { ThisDeclInfo->fill(); - ParamVarDocs.resize(ThisDeclInfo->ParamVars.size(), NULL); } unsigned Sema::resolveParmVarReference(StringRef Name, @@ -629,7 +736,7 @@ unsigned Sema::correctTypoInParmVarReference( if (Corrector.getBestDecl()) return Corrector.getBestDeclIndex(); else - return ParamCommandComment::InvalidParamIndex;; + return ParamCommandComment::InvalidParamIndex; } namespace { @@ -700,7 +807,7 @@ StringRef Sema::correctTypoInTParamReference( InlineCommandComment::RenderKind Sema::getInlineCommandRenderKind(StringRef Name) const { - assert(Traits.isInlineCommand(Name)); + assert(Traits.getCommandInfo(Name)->IsInlineCommand); return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name) .Case("b", InlineCommandComment::RenderBold) @@ -709,31 +816,6 @@ Sema::getInlineCommandRenderKind(StringRef Name) const { .Default(InlineCommandComment::RenderNormal); } -bool Sema::isHTMLEndTagOptional(StringRef Name) { - return llvm::StringSwitch<bool>(Name) - .Case("p", true) - .Case("li", true) - .Case("dt", true) - .Case("dd", true) - .Case("tr", true) - .Case("th", true) - .Case("td", true) - .Case("thead", true) - .Case("tfoot", true) - .Case("tbody", true) - .Case("colgroup", true) - .Default(false); -} - -bool Sema::isHTMLEndTagForbidden(StringRef Name) { - return llvm::StringSwitch<bool>(Name) - .Case("br", true) - .Case("hr", true) - .Case("img", true) - .Case("col", true) - .Default(false); -} - } // end namespace comments } // end namespace clang diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index d5b0be3ba4b1..7b13755979f1 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -126,12 +126,12 @@ static LinkageInfo getLVForTemplateArgumentList(const TemplateArgument *Args, break; case TemplateArgument::Declaration: - // The decl can validly be null as the representation of nullptr - // arguments, valid only in C++0x. - if (Decl *D = Args[I].getAsDecl()) { - if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) - LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate)); - } + if (NamedDecl *ND = dyn_cast<NamedDecl>(Args[I].getAsDecl())) + LV.mergeWithMin(getLVForDecl(ND, OnlyTemplate)); + break; + + case TemplateArgument::NullPtr: + LV.mergeWithMin(getLVForType(Args[I].getNullPtrType())); break; case TemplateArgument::Template: @@ -193,7 +193,7 @@ static bool useInlineVisibilityHidden(const NamedDecl *D) { // anyway. return TSK != TSK_ExplicitInstantiationDeclaration && TSK != TSK_ExplicitInstantiationDefinition && - FD->hasBody(Def) && Def->isInlined(); + FD->hasBody(Def) && Def->isInlined() && !Def->hasAttr<GNUInlineAttr>(); } static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, @@ -213,12 +213,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (Var->getStorageClass() == SC_Static) return LinkageInfo::internal(); - // - an object or reference that is explicitly declared const - // and neither explicitly declared extern nor previously - // declared to have external linkage; or - // (there is no equivalent in C99) + // - a non-volatile object or reference that is explicitly declared const + // or constexpr and neither explicitly declared extern nor previously + // declared to have external linkage; or (there is no equivalent in C99) if (Context.getLangOpts().CPlusPlus && - Var->getType().isConstant(Context) && + Var->getType().isConstQualified() && + !Var->getType().isVolatileQualified() && Var->getStorageClass() != SC_Extern && Var->getStorageClass() != SC_PrivateExtern) { bool FoundExtern = false; @@ -236,8 +236,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, for (; PrevVar; PrevVar = PrevVar->getPreviousDecl()) if (PrevVar->getStorageClass() == SC_PrivateExtern) break; - if (PrevVar) - return PrevVar->getLinkageAndVisibility(); + if (PrevVar) + return PrevVar->getLinkageAndVisibility(); } } else if (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D)) { // C++ [temp]p4: @@ -341,25 +341,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (Var->getStorageClass() == SC_PrivateExtern) LV.mergeVisibility(HiddenVisibility, true); - if (!Context.getLangOpts().CPlusPlus && - (Var->getStorageClass() == SC_Extern || - Var->getStorageClass() == SC_PrivateExtern)) { - - // C99 6.2.2p4: - // For an identifier declared with the storage-class specifier - // extern in a scope in which a prior declaration of that - // identifier is visible, if the prior declaration specifies - // internal or external linkage, the linkage of the identifier - // at the later declaration is the same as the linkage - // specified at the prior declaration. If no prior declaration - // is visible, or if the prior declaration specifies no - // linkage, then the identifier has external linkage. - if (const VarDecl *PrevVar = Var->getPreviousDecl()) { - LinkageInfo PrevLV = getLVForDecl(PrevVar, OnlyTemplate); - if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); - LV.mergeVisibility(PrevLV); - } - } + // Note that Sema::MergeVarDecl already takes care of implementing + // C99 6.2.2p4 and propagating the visibility attribute, so we don't have + // to do it here. // - a function, unless it has internal linkage; or } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { @@ -841,13 +825,10 @@ static LinkageInfo getLVForDecl(const NamedDecl *D, bool OnlyTemplate) { if (llvm::Optional<Visibility> Vis = Var->getExplicitVisibility()) LV.mergeVisibility(*Vis, true); } - - if (const VarDecl *Prev = Var->getPreviousDecl()) { - LinkageInfo PrevLV = getLVForDecl(Prev, OnlyTemplate); - if (PrevLV.linkage()) LV.setLinkage(PrevLV.linkage()); - LV.mergeVisibility(PrevLV); - } + // Note that Sema::MergeVarDecl already takes care of implementing + // C99 6.2.2p4 and propagating the visibility attribute, so we don't + // have to do it here. return LV; } } @@ -903,7 +884,7 @@ std::string NamedDecl::getQualifiedNameAsString(const PrintingPolicy &P) const { } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) { const FunctionProtoType *FT = 0; if (FD->hasWrittenPrototype()) - FT = dyn_cast<FunctionProtoType>(FD->getType()->getAs<FunctionType>()); + FT = dyn_cast<FunctionProtoType>(FD->getType()->castAs<FunctionType>()); OS << *FD << '('; if (FT) { @@ -1204,8 +1185,11 @@ void VarDecl::setStorageClass(StorageClass SC) { } SourceRange VarDecl::getSourceRange() const { - if (getInit()) - return SourceRange(getOuterLocStart(), getInit()->getLocEnd()); + if (const Expr *Init = getInit()) { + SourceLocation InitEnd = Init->getLocEnd(); + if (InitEnd.isValid()) + return SourceRange(getOuterLocStart(), InitEnd); + } return DeclaratorDecl::getSourceRange(); } @@ -1859,7 +1843,7 @@ unsigned FunctionDecl::getBuiltinID() const { /// based on its FunctionType. This is the length of the ParamInfo array /// after it has been created. unsigned FunctionDecl::getNumParams() const { - const FunctionType *FT = getType()->getAs<FunctionType>(); + const FunctionType *FT = getType()->castAs<FunctionType>(); if (isa<FunctionNoProtoType>(FT)) return 0; return cast<FunctionProtoType>(FT)->getNumArgs(); @@ -2514,7 +2498,7 @@ unsigned FieldDecl::getFieldIndex() const { unsigned Index = 0; const RecordDecl *RD = getParent(); const FieldDecl *LastFD = 0; - bool IsMsStruct = RD->hasAttr<MsStructAttr>(); + bool IsMsStruct = RD->isMsStruct(getASTContext()); for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); I != E; ++I, ++Index) { @@ -2762,6 +2746,17 @@ void RecordDecl::completeDefinition() { TagDecl::completeDefinition(); } +/// isMsStruct - Get whether or not this record uses ms_struct layout. +/// This which can be turned on with an attribute, pragma, or the +/// -mms-bitfields command-line option. +bool RecordDecl::isMsStruct(const ASTContext &C) const { + return hasAttr<MsStructAttr>() || C.getLangOpts().MSBitfields == 1; +} + +static bool isFieldOrIndirectField(Decl::Kind K) { + return FieldDecl::classofKind(K) || IndirectFieldDecl::classofKind(K); +} + void RecordDecl::LoadFieldsFromExternalStorage() const { ExternalASTSource *Source = getASTContext().getExternalSource(); assert(hasExternalLexicalStorage() && Source && "No external storage?"); @@ -2771,7 +2766,8 @@ void RecordDecl::LoadFieldsFromExternalStorage() const { SmallVector<Decl*, 64> Decls; LoadedFieldsFromExternalStorage = true; - switch (Source->FindExternalLexicalDeclsBy<FieldDecl>(this, Decls)) { + switch (Source->FindExternalLexicalDecls(this, isFieldOrIndirectField, + Decls)) { case ELR_Success: break; @@ -2783,7 +2779,7 @@ void RecordDecl::LoadFieldsFromExternalStorage() const { #ifndef NDEBUG // Check that all decls we got were FieldDecls. for (unsigned i=0, e=Decls.size(); i != e; ++i) - assert(isa<FieldDecl>(Decls[i])); + assert(isa<FieldDecl>(Decls[i]) || isa<IndirectFieldDecl>(Decls[i])); #endif if (Decls.empty()) diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index f9ce46def5b9..4400d503f263 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -961,7 +961,7 @@ DeclContext::lookup_result ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, DeclarationName Name, ArrayRef<NamedDecl*> Decls) { - ASTContext &Context = DC->getParentASTContext();; + ASTContext &Context = DC->getParentASTContext(); StoredDeclsMap *Map; if (!(Map = DC->LookupPtr.getPointer())) diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 2f21e4cbd652..82e630acefba 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -90,11 +90,12 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, } CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, - SourceLocation Loc, bool Dependent) { + TypeSourceInfo *Info, SourceLocation Loc, + bool Dependent) { CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc, 0, 0); R->IsBeingDefined = true; - R->DefinitionData = new (C) struct LambdaDefinitionData(R, Dependent); + R->DefinitionData = new (C) struct LambdaDefinitionData(R, Info, Dependent); C.getTypeDeclType(R, /*PrevDecl=*/0); return R; } @@ -239,10 +240,13 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // -- the constructor selected to copy/move each direct base class // subobject is trivial, and // FIXME: C++0x: We need to only consider the selected constructor - // instead of all of them. + // instead of all of them. For now, we treat a move constructor as being + // non-trivial if it calls anything other than a trivial move constructor. if (!BaseClassDecl->hasTrivialCopyConstructor()) data().HasTrivialCopyConstructor = false; - if (!BaseClassDecl->hasTrivialMoveConstructor()) + if (!BaseClassDecl->hasTrivialMoveConstructor() || + !(BaseClassDecl->hasDeclaredMoveConstructor() || + BaseClassDecl->needsImplicitMoveConstructor())) data().HasTrivialMoveConstructor = false; // C++0x [class.copy]p27: @@ -254,7 +258,9 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // of all of them. if (!BaseClassDecl->hasTrivialCopyAssignment()) data().HasTrivialCopyAssignment = false; - if (!BaseClassDecl->hasTrivialMoveAssignment()) + if (!BaseClassDecl->hasTrivialMoveAssignment() || + !(BaseClassDecl->hasDeclaredMoveAssignment() || + BaseClassDecl->needsImplicitMoveAssignment())) data().HasTrivialMoveAssignment = false; // C++11 [class.ctor]p6: @@ -466,7 +472,8 @@ void CXXRecordDecl::addedMember(Decl *D) { if (!D->isImplicit() && !isa<FieldDecl>(D) && !isa<IndirectFieldDecl>(D) && - (!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class)) + (!isa<TagDecl>(D) || cast<TagDecl>(D)->getTagKind() == TTK_Class || + cast<TagDecl>(D)->getTagKind() == TTK_Interface)) data().HasOnlyCMembers = false; // Ignore friends and invalid declarations. @@ -828,7 +835,9 @@ NotASpecialMember:; // FIXME: C++0x: We don't correctly model 'selected' constructors. if (!FieldRec->hasTrivialCopyConstructor()) data().HasTrivialCopyConstructor = false; - if (!FieldRec->hasTrivialMoveConstructor()) + if (!FieldRec->hasTrivialMoveConstructor() || + !(FieldRec->hasDeclaredMoveConstructor() || + FieldRec->needsImplicitMoveConstructor())) data().HasTrivialMoveConstructor = false; // C++0x [class.copy]p27: @@ -840,7 +849,9 @@ NotASpecialMember:; // FIXME: C++0x: We don't correctly model 'selected' operators. if (!FieldRec->hasTrivialCopyAssignment()) data().HasTrivialCopyAssignment = false; - if (!FieldRec->hasTrivialMoveAssignment()) + if (!FieldRec->hasTrivialMoveAssignment() || + !(FieldRec->hasDeclaredMoveAssignment() || + FieldRec->needsImplicitMoveAssignment())) data().HasTrivialMoveAssignment = false; if (!FieldRec->hasTrivialDestructor()) @@ -936,7 +947,8 @@ NotASpecialMember:; } bool CXXRecordDecl::isCLike() const { - if (getTagKind() == TTK_Class || !TemplateOrInstantiation.isNull()) + if (getTagKind() == TTK_Class || getTagKind() == TTK_Interface || + !TemplateOrInstantiation.isNull()) return false; if (!hasDefinition()) return true; diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 4d48ad8e4f5a..65a987836ff8 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Stmt.h" #include "clang/AST/ASTMutationListener.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" using namespace clang; //===----------------------------------------------------------------------===// @@ -93,6 +94,16 @@ ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC, return 0; } +IdentifierInfo * +ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const { + SmallString<128> ivarName; + { + llvm::raw_svector_ostream os(ivarName); + os << '_' << getIdentifier()->getName(); + } + return &Ctx.Idents.get(ivarName.str()); +} + /// FindPropertyDeclaration - Finds declaration of the property given its name /// in 'PropertyId' and returns it. It returns 0, if not found. ObjCPropertyDecl * @@ -179,6 +190,21 @@ ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( return 0; } +void ObjCInterfaceDecl::collectPropertiesToImplement(PropertyMap &PM) const { + for (ObjCContainerDecl::prop_iterator P = prop_begin(), + E = prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = *P; + PM[Prop->getIdentifier()] = Prop; + } + for (ObjCInterfaceDecl::all_protocol_iterator + PI = all_referenced_protocol_begin(), + E = all_referenced_protocol_end(); PI != E; ++PI) + (*PI)->collectPropertiesToImplement(PM); + // Note, the properties declared only in class extensions are still copied + // into the main @interface's property list, and therefore we don't + // explicitly, have to search class extension properties. +} + void ObjCInterfaceDecl::mergeClassExtensionProtocolList( ObjCProtocolDecl *const* ExtList, unsigned ExtNum, ASTContext &C) @@ -414,16 +440,15 @@ ObjCMethodDecl *ObjCMethodDecl::Create(ASTContext &C, DeclContext *contextDecl, bool isInstance, bool isVariadic, - bool isSynthesized, + bool isPropertyAccessor, bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl, bool HasRelatedResultType) { return new (C) ObjCMethodDecl(beginLoc, endLoc, SelInfo, T, ResultTInfo, contextDecl, - isInstance, - isVariadic, isSynthesized, isImplicitlyDeclared, - isDefined, + isInstance, isVariadic, isPropertyAccessor, + isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType); } @@ -434,6 +459,10 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { Selector(), QualType(), 0, 0); } +Stmt *ObjCMethodDecl::getBody() const { + return Body.get(getASTContext().getExternalSource()); +} + void ObjCMethodDecl::setAsRedeclaration(const ObjCMethodDecl *PrevMethod) { assert(PrevMethod); getASTContext().setObjCMethodRedeclaration(PrevMethod, this); @@ -707,6 +736,224 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { llvm_unreachable("unknown method context"); } +static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, + const ObjCMethodDecl *Method, + SmallVectorImpl<const ObjCMethodDecl *> &Methods, + bool MovedToSuper) { + if (!Container) + return; + + // In categories look for overriden methods from protocols. A method from + // category is not "overriden" since it is considered as the "same" method + // (same USR) as the one from the interface. + if (const ObjCCategoryDecl * + Category = dyn_cast<ObjCCategoryDecl>(Container)) { + // Check whether we have a matching method at this category but only if we + // are at the super class level. + if (MovedToSuper) + if (ObjCMethodDecl * + Overridden = Container->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + if (Method != Overridden) { + // We found an override at this category; there is no need to look + // into its protocols. + Methods.push_back(Overridden); + return; + } + + for (ObjCCategoryDecl::protocol_iterator P = Category->protocol_begin(), + PEnd = Category->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); + return; + } + + // Check whether we have a matching method at this level. + if (const ObjCMethodDecl * + Overridden = Container->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + if (Method != Overridden) { + // We found an override at this level; there is no need to look + // into other protocols or categories. + Methods.push_back(Overridden); + return; + } + + if (const ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)){ + for (ObjCProtocolDecl::protocol_iterator P = Protocol->protocol_begin(), + PEnd = Protocol->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); + } + + if (const ObjCInterfaceDecl * + Interface = dyn_cast<ObjCInterfaceDecl>(Container)) { + for (ObjCInterfaceDecl::protocol_iterator P = Interface->protocol_begin(), + PEnd = Interface->protocol_end(); + P != PEnd; ++P) + CollectOverriddenMethodsRecurse(*P, Method, Methods, MovedToSuper); + + for (const ObjCCategoryDecl *Category = Interface->getCategoryList(); + Category; Category = Category->getNextClassCategory()) + CollectOverriddenMethodsRecurse(Category, Method, Methods, + MovedToSuper); + + if (const ObjCInterfaceDecl *Super = Interface->getSuperClass()) + return CollectOverriddenMethodsRecurse(Super, Method, Methods, + /*MovedToSuper=*/true); + } +} + +static inline void CollectOverriddenMethods(const ObjCContainerDecl *Container, + const ObjCMethodDecl *Method, + SmallVectorImpl<const ObjCMethodDecl *> &Methods) { + CollectOverriddenMethodsRecurse(Container, Method, Methods, + /*MovedToSuper=*/false); +} + +static void collectOverriddenMethodsSlow(const ObjCMethodDecl *Method, + SmallVectorImpl<const ObjCMethodDecl *> &overridden) { + assert(Method->isOverriding()); + + if (const ObjCProtocolDecl * + ProtD = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext())) { + CollectOverriddenMethods(ProtD, Method, overridden); + + } else if (const ObjCImplDecl * + IMD = dyn_cast<ObjCImplDecl>(Method->getDeclContext())) { + const ObjCInterfaceDecl *ID = IMD->getClassInterface(); + if (!ID) + return; + // Start searching for overridden methods using the method from the + // interface as starting point. + if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + Method = IFaceMeth; + CollectOverriddenMethods(ID, Method, overridden); + + } else if (const ObjCCategoryDecl * + CatD = dyn_cast<ObjCCategoryDecl>(Method->getDeclContext())) { + const ObjCInterfaceDecl *ID = CatD->getClassInterface(); + if (!ID) + return; + // Start searching for overridden methods using the method from the + // interface as starting point. + if (const ObjCMethodDecl *IFaceMeth = ID->getMethod(Method->getSelector(), + Method->isInstanceMethod())) + Method = IFaceMeth; + CollectOverriddenMethods(ID, Method, overridden); + + } else { + CollectOverriddenMethods( + dyn_cast_or_null<ObjCContainerDecl>(Method->getDeclContext()), + Method, overridden); + } +} + +static void collectOnCategoriesAfterLocation(SourceLocation Loc, + const ObjCInterfaceDecl *Class, + SourceManager &SM, + const ObjCMethodDecl *Method, + SmallVectorImpl<const ObjCMethodDecl *> &Methods) { + if (!Class) + return; + + for (const ObjCCategoryDecl *Category = Class->getCategoryList(); + Category; Category = Category->getNextClassCategory()) + if (SM.isBeforeInTranslationUnit(Loc, Category->getLocation())) + CollectOverriddenMethodsRecurse(Category, Method, Methods, true); + + collectOnCategoriesAfterLocation(Loc, Class->getSuperClass(), SM, + Method, Methods); +} + +/// \brief Faster collection that is enabled when ObjCMethodDecl::isOverriding() +/// returns false. +/// You'd think that in that case there are no overrides but categories can +/// "introduce" new overridden methods that are missed by Sema because the +/// overrides lookup that it does for methods, inside implementations, will +/// stop at the interface level (if there is a method there) and not look +/// further in super classes. +/// Methods in an implementation can overide methods in super class's category +/// but not in current class's category. But, such methods +static void collectOverriddenMethodsFast(SourceManager &SM, + const ObjCMethodDecl *Method, + SmallVectorImpl<const ObjCMethodDecl *> &Methods) { + assert(!Method->isOverriding()); + + const ObjCContainerDecl * + ContD = cast<ObjCContainerDecl>(Method->getDeclContext()); + if (isa<ObjCInterfaceDecl>(ContD) || isa<ObjCProtocolDecl>(ContD)) + return; + const ObjCInterfaceDecl *Class = Method->getClassInterface(); + if (!Class) + return; + + collectOnCategoriesAfterLocation(Class->getLocation(), Class->getSuperClass(), + SM, Method, Methods); +} + +void ObjCMethodDecl::getOverriddenMethods( + SmallVectorImpl<const ObjCMethodDecl *> &Overridden) const { + const ObjCMethodDecl *Method = this; + + if (Method->isRedeclaration()) { + Method = cast<ObjCContainerDecl>(Method->getDeclContext())-> + getMethod(Method->getSelector(), Method->isInstanceMethod()); + } + + if (!Method->isOverriding()) { + collectOverriddenMethodsFast(getASTContext().getSourceManager(), + Method, Overridden); + } else { + collectOverriddenMethodsSlow(Method, Overridden); + assert(!Overridden.empty() && + "ObjCMethodDecl's overriding bit is not as expected"); + } +} + +const ObjCPropertyDecl * +ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { + Selector Sel = getSelector(); + unsigned NumArgs = Sel.getNumArgs(); + if (NumArgs > 1) + return 0; + + if (!isInstanceMethod() || getMethodFamily() != OMF_None) + return 0; + + if (isPropertyAccessor()) { + const ObjCContainerDecl *Container = cast<ObjCContainerDecl>(getParent()); + bool IsGetter = (NumArgs == 0); + + for (ObjCContainerDecl::prop_iterator I = Container->prop_begin(), + E = Container->prop_end(); + I != E; ++I) { + Selector NextSel = IsGetter ? (*I)->getGetterName() + : (*I)->getSetterName(); + if (NextSel == Sel) + return *I; + } + + llvm_unreachable("Marked as a property accessor but no property found!"); + } + + if (!CheckOverrides) + return 0; + + typedef SmallVector<const ObjCMethodDecl *, 8> OverridesTy; + OverridesTy Overrides; + getOverriddenMethods(Overrides); + for (OverridesTy::const_iterator I = Overrides.begin(), E = Overrides.end(); + I != E; ++I) { + if (const ObjCPropertyDecl *Prop = (*I)->findPropertyDecl(false)) + return Prop; + } + + return 0; + +} + //===----------------------------------------------------------------------===// // ObjCInterfaceDecl //===----------------------------------------------------------------------===// @@ -1081,6 +1328,20 @@ void ObjCProtocolDecl::startDefinition() { RD->Data = this->Data; } +void ObjCProtocolDecl::collectPropertiesToImplement(PropertyMap &PM) const { + for (ObjCProtocolDecl::prop_iterator P = prop_begin(), + E = prop_end(); P != E; ++P) { + ObjCPropertyDecl *Prop = *P; + // Insert into PM if not there already. + PM.insert(std::make_pair(Prop->getIdentifier(), Prop)); + } + // Scan through protocol's protocols. + for (ObjCProtocolDecl::protocol_iterator PI = protocol_begin(), + E = protocol_end(); PI != E; ++PI) + (*PI)->collectPropertiesToImplement(PM); +} + + //===----------------------------------------------------------------------===// // ObjCCategoryDecl //===----------------------------------------------------------------------===// diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index 7f47604dece3..386ad66c9917 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -105,6 +105,8 @@ static QualType GetBaseType(QualType T) { break; else if (const PointerType* PTy = BaseType->getAs<PointerType>()) BaseType = PTy->getPointeeType(); + else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>()) + BaseType = BPy->getPointeeType(); else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType)) BaseType = ATy->getElementType(); else if (const FunctionType* FTy = BaseType->getAs<FunctionType>()) @@ -189,6 +191,9 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) { } void DeclPrinter::prettyPrintAttributes(Decl *D) { + if (Policy.SuppressAttributes) + return; + if (D->hasAttrs()) { AttrVec &Attrs = D->getAttrs(); for (AttrVec::const_iterator i=Attrs.begin(), e=Attrs.end(); i!=e; ++i) { @@ -220,6 +225,9 @@ void DeclPrinter::Print(AccessSpecifier AS) { //---------------------------------------------------------------------------- void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { + if (Policy.TerseOutput) + return; + if (Indent) Indentation += Policy.Indentation; @@ -459,7 +467,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (I) Proto += ", "; - Proto += FT->getExceptionType(I).getAsString(SubPolicy);; + Proto += FT->getExceptionType(I).getAsString(SubPolicy); } Proto += ")"; } else if (FT && isNoexceptExceptionSpec(FT->getExceptionSpecType())) { @@ -550,7 +558,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Out << " = 0"; else if (D->isDeletedAsWritten()) Out << " = delete"; - else if (D->doesThisDeclarationHaveABody()) { + else if (D->doesThisDeclarationHaveABody() && !Policy.TerseOutput) { if (!D->hasPrototype() && D->getNumParams()) { // This is a K&R function definition, so we need to print the // parameters. @@ -621,13 +629,13 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { ImplicitInit = D->getInitStyle() == VarDecl::CallInit && Construct->getNumArgs() == 0 && !Construct->isListInitialization(); if (!ImplicitInit) { - if (D->getInitStyle() == VarDecl::CallInit) + if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init)) Out << "("; else if (D->getInitStyle() == VarDecl::CInit) { Out << " = "; } Init->printPretty(Out, 0, Policy, Indentation); - if (D->getInitStyle() == VarDecl::CallInit) + if ((D->getInitStyle() == VarDecl::CallInit) && !isa<ParenListExpr>(Init)) Out << ")"; } } @@ -869,7 +877,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { if (OMD->isVariadic()) Out << ", ..."; - if (OMD->getBody()) { + if (OMD->getBody() && !Policy.TerseOutput) { Out << ' '; OMD->getBody()->printPretty(Out, 0, Policy); Out << '\n'; diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index a7e89994afe8..a70983f4c962 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -32,9 +32,25 @@ TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, NamedDecl **Params, unsigned NumParams, SourceLocation RAngleLoc) : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), - NumParams(NumParams) { - for (unsigned Idx = 0; Idx < NumParams; ++Idx) - begin()[Idx] = Params[Idx]; + NumParams(NumParams), ContainsUnexpandedParameterPack(false) { + assert(this->NumParams == NumParams && "Too many template parameters"); + for (unsigned Idx = 0; Idx < NumParams; ++Idx) { + NamedDecl *P = Params[Idx]; + begin()[Idx] = P; + + if (!P->isTemplateParameterPack()) { + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) + if (NTTP->getType()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) + if (TTP->getTemplateParameters()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + + // FIXME: If a default argument contains an unexpanded parameter pack, the + // template parameter list does too. + } + } } TemplateParameterList * @@ -577,6 +593,19 @@ SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { void TemplateTemplateParmDecl::anchor() { } +TemplateTemplateParmDecl::TemplateTemplateParmDecl( + DeclContext *DC, SourceLocation L, unsigned D, unsigned P, + IdentifierInfo *Id, TemplateParameterList *Params, + unsigned NumExpansions, TemplateParameterList * const *Expansions) + : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), + TemplateParmPosition(D, P), DefaultArgument(), + DefaultArgumentWasInherited(false), ParameterPack(true), + ExpandedParameterPack(true), NumExpandedParams(NumExpansions) { + if (Expansions) + std::memcpy(reinterpret_cast<void*>(this + 1), Expansions, + sizeof(TemplateParameterList*) * NumExpandedParams); +} + TemplateTemplateParmDecl * TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, @@ -587,12 +616,35 @@ TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, } TemplateTemplateParmDecl * +TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, + SourceLocation L, unsigned D, unsigned P, + IdentifierInfo *Id, + TemplateParameterList *Params, + llvm::ArrayRef<TemplateParameterList*> Expansions) { + void *Mem = C.Allocate(sizeof(TemplateTemplateParmDecl) + + sizeof(TemplateParameterList*) * Expansions.size()); + return new (Mem) TemplateTemplateParmDecl(DC, L, D, P, Id, Params, + Expansions.size(), + Expansions.data()); +} + +TemplateTemplateParmDecl * TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(TemplateTemplateParmDecl)); return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, false, 0, 0); } +TemplateTemplateParmDecl * +TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID, + unsigned NumExpansions) { + unsigned Size = sizeof(TemplateTemplateParmDecl) + + sizeof(TemplateParameterList*) * NumExpansions; + void *Mem = AllocateDeserializedDecl(C, ID, Size); + return new (Mem) TemplateTemplateParmDecl(0, SourceLocation(), 0, 0, 0, 0, + NumExpansions, 0); +} + //===----------------------------------------------------------------------===// // TemplateArgumentList Implementation //===----------------------------------------------------------------------===// @@ -712,13 +764,27 @@ ClassTemplateSpecializationDecl::getSpecializedTemplate() const { SourceRange ClassTemplateSpecializationDecl::getSourceRange() const { if (ExplicitInfo) { - SourceLocation Begin = getExternLoc(); - if (Begin.isInvalid()) - Begin = getTemplateKeywordLoc(); - SourceLocation End = getRBraceLoc(); - if (End.isInvalid()) - End = getTypeAsWritten()->getTypeLoc().getEndLoc(); - return SourceRange(Begin, End); + SourceLocation Begin = getTemplateKeywordLoc(); + if (Begin.isValid()) { + // Here we have an explicit (partial) specialization or instantiation. + assert(getSpecializationKind() == TSK_ExplicitSpecialization || + getSpecializationKind() == TSK_ExplicitInstantiationDeclaration || + getSpecializationKind() == TSK_ExplicitInstantiationDefinition); + if (getExternLoc().isValid()) + Begin = getExternLoc(); + SourceLocation End = getRBraceLoc(); + if (End.isInvalid()) + End = getTypeAsWritten()->getTypeLoc().getEndLoc(); + return SourceRange(Begin, End); + } + // An implicit instantiation of a class template partial specialization + // uses ExplicitInfo to record the TypeAsWritten, but the source + // locations should be retrieved from the instantiation pattern. + typedef ClassTemplatePartialSpecializationDecl CTPSDecl; + CTPSDecl *ctpsd = const_cast<CTPSDecl*>(cast<CTPSDecl>(this)); + CTPSDecl *inst_from = ctpsd->getInstantiatedFromMember(); + assert(inst_from != 0); + return inst_from->getSourceRange(); } else { // No explicit info available. diff --git a/lib/AST/DumpXML.cpp b/lib/AST/DumpXML.cpp index 84f3fc491cb0..5f43fbc251a0 100644 --- a/lib/AST/DumpXML.cpp +++ b/lib/AST/DumpXML.cpp @@ -1,4 +1,4 @@ -//===--- DumpXML.cpp - Detailed XML dumping ---------------------*- C++ -*-===// +//===--- DumpXML.cpp - Detailed XML dumping -------------------------------===// // // The LLVM Compiler Infrastructure // @@ -64,6 +64,8 @@ template <class Impl> struct XMLDeclVisitor { static_cast<Impl*>(this)->NAME(static_cast<CLASS*>(D)) void dispatch(Decl *D) { + if (D->isUsed()) + static_cast<Impl*>(this)->set("used", "1"); switch (D->getKind()) { #define DECL(DERIVED, BASE) \ case Decl::DERIVED: \ @@ -316,12 +318,12 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, } case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: + case TemplateArgument::NullPtr: // FIXME: Implement! break; case TemplateArgument::Declaration: { - if (Decl *D = A.getAsDecl()) - visitDeclRef(D); + visitDeclRef(A.getAsDecl()); break; } case TemplateArgument::Integral: { @@ -841,7 +843,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, setFlag("instance", D->isInstanceMethod()); setFlag("variadic", D->isVariadic()); - setFlag("synthesized", D->isSynthesized()); + setFlag("property_accessor", D->isPropertyAccessor()); setFlag("defined", D->isDefined()); setFlag("related_result_type", D->hasRelatedResultType()); } @@ -920,6 +922,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, case CC_X86Pascal: return set("cc", "x86_pascal"); case CC_AAPCS: return set("cc", "aapcs"); case CC_AAPCS_VFP: return set("cc", "aapcs_vfp"); + case CC_PnaclCall: return set("cc", "pnaclcall"); } } @@ -974,6 +977,16 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, setFlag("const", T->isConst()); setFlag("volatile", T->isVolatile()); setFlag("restrict", T->isRestrict()); + switch (T->getExceptionSpecType()) { + case EST_None: break; + case EST_DynamicNone: set("exception_spec", "throw()"); break; + case EST_Dynamic: set("exception_spec", "throw(T)"); break; + case EST_MSAny: set("exception_spec", "throw(...)"); break; + case EST_BasicNoexcept: set("exception_spec", "noexcept"); break; + case EST_ComputedNoexcept: set("exception_spec", "noexcept(expr)"); break; + case EST_Unevaluated: set("exception_spec", "unevaluated"); break; + case EST_Uninstantiated: set("exception_spec", "uninstantiated"); break; + } } void visitFunctionProtoTypeChildren(FunctionProtoType *T) { push("parameters"); @@ -1023,7 +1036,7 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, } void Decl::dumpXML() const { - dump(llvm::errs()); + dumpXML(llvm::errs()); } void Decl::dumpXML(raw_ostream &out) const { diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 24361efafa6c..f3a2e0563872 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -48,6 +48,75 @@ const CXXRecordDecl *Expr::getBestDynamicClassType() const { return cast<CXXRecordDecl>(D); } +const Expr * +Expr::skipRValueSubobjectAdjustments( + SmallVectorImpl<SubobjectAdjustment> &Adjustments) const { + const Expr *E = this; + while (true) { + E = E->IgnoreParens(); + + if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { + if ((CE->getCastKind() == CK_DerivedToBase || + CE->getCastKind() == CK_UncheckedDerivedToBase) && + E->getType()->isRecordType()) { + E = CE->getSubExpr(); + CXXRecordDecl *Derived + = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); + Adjustments.push_back(SubobjectAdjustment(CE, Derived)); + continue; + } + + if (CE->getCastKind() == CK_NoOp) { + E = CE->getSubExpr(); + continue; + } + } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + if (!ME->isArrow() && ME->getBase()->isRValue()) { + assert(ME->getBase()->getType()->isRecordType()); + if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) { + E = ME->getBase(); + Adjustments.push_back(SubobjectAdjustment(Field)); + continue; + } + } + } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + if (BO->isPtrMemOp()) { + assert(BO->getRHS()->isRValue()); + E = BO->getLHS(); + const MemberPointerType *MPT = + BO->getRHS()->getType()->getAs<MemberPointerType>(); + Adjustments.push_back(SubobjectAdjustment(MPT, BO->getRHS())); + } + } + + // Nothing changed. + break; + } + return E; +} + +const Expr * +Expr::findMaterializedTemporary(const MaterializeTemporaryExpr *&MTE) const { + const Expr *E = this; + // Look through single-element init lists that claim to be lvalues. They're + // just syntactic wrappers in this case. + if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) { + if (ILE->getNumInits() == 1 && ILE->isGLValue()) + E = ILE->getInit(0); + } + + // Look through expressions for materialized temporaries (for now). + if (const MaterializeTemporaryExpr *M + = dyn_cast<MaterializeTemporaryExpr>(E)) { + MTE = M; + E = M->GetTemporaryExpr(); + } + + if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E)) + E = DAE->getExpr(); + return E; +} + /// isKnownToHaveBooleanValue - Return true if this is an integer expression /// that is known to return 0 or 1. This happens for _Bool/bool expressions /// but also int expressions which are produced by things like comparisons in @@ -784,19 +853,19 @@ void StringLiteral::setString(ASTContext &C, StringRef Str, switch(CharByteWidth) { case 1: { char *AStrData = new (C) char[Length]; - std::memcpy(AStrData,Str.data(),Str.size()); + std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData)); StrData.asChar = AStrData; break; } case 2: { uint16_t *AStrData = new (C) uint16_t[Length]; - std::memcpy(AStrData,Str.data(),Str.size()); + std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData)); StrData.asUInt16 = AStrData; break; } case 4: { uint32_t *AStrData = new (C) uint32_t[Length]; - std::memcpy(AStrData,Str.data(),Str.size()); + std::memcpy(AStrData,Str.data(),Length*sizeof(*AStrData)); StrData.asUInt32 = AStrData; break; } @@ -869,7 +938,7 @@ getLocationOfByte(unsigned ByteNo, const SourceManager &SM, /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "sizeof" or "[pre]++". -const char *UnaryOperator::getOpcodeStr(Opcode Op) { +StringRef UnaryOperator::getOpcodeStr(Opcode Op) { switch (Op) { case UO_PostInc: return "++"; case UO_PostDec: return "--"; @@ -923,18 +992,18 @@ OverloadedOperatorKind UnaryOperator::getOverloadedOperator(Opcode Opc) { //===----------------------------------------------------------------------===// CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, - Expr **args, unsigned numargs, QualType t, ExprValueKind VK, + ArrayRef<Expr*> args, QualType t, ExprValueKind VK, SourceLocation rparenloc) : Expr(SC, t, VK, OK_Ordinary, fn->isTypeDependent(), fn->isValueDependent(), fn->isInstantiationDependent(), fn->containsUnexpandedParameterPack()), - NumArgs(numargs) { + NumArgs(args.size()) { - SubExprs = new (C) Stmt*[numargs+PREARGS_START+NumPreArgs]; + SubExprs = new (C) Stmt*[args.size()+PREARGS_START+NumPreArgs]; SubExprs[FN] = fn; - for (unsigned i = 0; i != numargs; ++i) { + for (unsigned i = 0; i != args.size(); ++i) { if (args[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) @@ -951,18 +1020,18 @@ CallExpr::CallExpr(ASTContext& C, StmtClass SC, Expr *fn, unsigned NumPreArgs, RParenLoc = rparenloc; } -CallExpr::CallExpr(ASTContext& C, Expr *fn, Expr **args, unsigned numargs, +CallExpr::CallExpr(ASTContext& C, Expr *fn, ArrayRef<Expr*> args, QualType t, ExprValueKind VK, SourceLocation rparenloc) : Expr(CallExprClass, t, VK, OK_Ordinary, fn->isTypeDependent(), fn->isValueDependent(), fn->isInstantiationDependent(), fn->containsUnexpandedParameterPack()), - NumArgs(numargs) { + NumArgs(args.size()) { - SubExprs = new (C) Stmt*[numargs+PREARGS_START]; + SubExprs = new (C) Stmt*[args.size()+PREARGS_START]; SubExprs[FN] = fn; - for (unsigned i = 0; i != numargs; ++i) { + for (unsigned i = 0; i != args.size(); ++i) { if (args[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) @@ -1123,15 +1192,15 @@ SourceLocation CallExpr::getLocEnd() const { OffsetOfExpr *OffsetOfExpr::Create(ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, - OffsetOfNode* compsPtr, unsigned numComps, - Expr** exprsPtr, unsigned numExprs, + ArrayRef<OffsetOfNode> comps, + ArrayRef<Expr*> exprs, SourceLocation RParenLoc) { void *Mem = C.Allocate(sizeof(OffsetOfExpr) + - sizeof(OffsetOfNode) * numComps + - sizeof(Expr*) * numExprs); + sizeof(OffsetOfNode) * comps.size() + + sizeof(Expr*) * exprs.size()); - return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, compsPtr, numComps, - exprsPtr, numExprs, RParenLoc); + return new (Mem) OffsetOfExpr(C, type, OperatorLoc, tsi, comps, exprs, + RParenLoc); } OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, @@ -1144,8 +1213,7 @@ OffsetOfExpr *OffsetOfExpr::CreateEmpty(ASTContext &C, OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, SourceLocation OperatorLoc, TypeSourceInfo *tsi, - OffsetOfNode* compsPtr, unsigned numComps, - Expr** exprsPtr, unsigned numExprs, + ArrayRef<OffsetOfNode> comps, ArrayRef<Expr*> exprs, SourceLocation RParenLoc) : Expr(OffsetOfExprClass, type, VK_RValue, OK_Ordinary, /*TypeDependent=*/false, @@ -1153,19 +1221,19 @@ OffsetOfExpr::OffsetOfExpr(ASTContext &C, QualType type, tsi->getType()->isInstantiationDependentType(), tsi->getType()->containsUnexpandedParameterPack()), OperatorLoc(OperatorLoc), RParenLoc(RParenLoc), TSInfo(tsi), - NumComps(numComps), NumExprs(numExprs) + NumComps(comps.size()), NumExprs(exprs.size()) { - for(unsigned i = 0; i < numComps; ++i) { - setComponent(i, compsPtr[i]); + for (unsigned i = 0; i != comps.size(); ++i) { + setComponent(i, comps[i]); } - for(unsigned i = 0; i < numExprs; ++i) { - if (exprsPtr[i]->isTypeDependent() || exprsPtr[i]->isValueDependent()) + for (unsigned i = 0; i != exprs.size(); ++i) { + if (exprs[i]->isTypeDependent() || exprs[i]->isValueDependent()) ExprBits.ValueDependent = true; - if (exprsPtr[i]->containsUnexpandedParameterPack()) + if (exprs[i]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; - setIndexExpr(i, exprsPtr[i]); + setIndexExpr(i, exprs[i]); } } @@ -1259,9 +1327,12 @@ SourceLocation MemberExpr::getLocStart() const { return MemberLoc; } SourceLocation MemberExpr::getLocEnd() const { + SourceLocation EndLoc = getMemberNameInfo().getEndLoc(); if (hasExplicitTemplateArgs()) - return getRAngleLoc(); - return getMemberNameInfo().getEndLoc(); + EndLoc = getRAngleLoc(); + else if (EndLoc.isInvalid()) + EndLoc = getBase()->getLocEnd(); + return EndLoc; } void CastExpr::CheckCastConsistency() const { @@ -1311,12 +1382,16 @@ void CastExpr::CheckCastConsistency() const { assert(getType()->isBlockPointerType()); assert(getSubExpr()->getType()->isBlockPointerType()); goto CheckNoBasePath; - + + case CK_FunctionToPointerDecay: + assert(getType()->isPointerType()); + assert(getSubExpr()->getType()->isFunctionType()); + goto CheckNoBasePath; + // These should not have an inheritance path. case CK_Dynamic: case CK_ToUnion: case CK_ArrayToPointerDecay: - case CK_FunctionToPointerDecay: case CK_NullToMemberPointer: case CK_NullToPointer: case CK_ConstructorConversion: @@ -1357,6 +1432,7 @@ void CastExpr::CheckCastConsistency() const { case CK_IntegralComplexToBoolean: case CK_LValueBitCast: // -> bool& case CK_UserDefinedConversion: // operator bool() + case CK_BuiltinFnToFnPtr: CheckNoBasePath: assert(path_empty() && "Cast kind should not have a base path!"); break; @@ -1469,6 +1545,8 @@ const char *CastExpr::getCastKindName() const { return "NonAtomicToAtomic"; case CK_CopyAndAutoreleaseBlockObject: return "CopyAndAutoreleaseBlockObject"; + case CK_BuiltinFnToFnPtr: + return "BuiltinFnToFnPtr"; } llvm_unreachable("Unhandled cast kind!"); @@ -1564,7 +1642,7 @@ CStyleCastExpr *CStyleCastExpr::CreateEmpty(ASTContext &C, unsigned PathSize) { /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". -const char *BinaryOperator::getOpcodeStr(Opcode Op) { +StringRef BinaryOperator::getOpcodeStr(Opcode Op) { switch (Op) { case BO_PtrMemD: return ".*"; case BO_PtrMemI: return "->*"; @@ -1666,16 +1744,15 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) { } InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, - Expr **initExprs, unsigned numInits, - SourceLocation rbraceloc) + ArrayRef<Expr*> initExprs, SourceLocation rbraceloc) : Expr(InitListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, false, false), - InitExprs(C, numInits), - LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), SyntacticForm(0) + InitExprs(C, initExprs.size()), + LBraceLoc(lbraceloc), RBraceLoc(rbraceloc), AltForm(0, true) { sawArrayRangeDesignator(false); setInitializesStdInitializerList(false); - for (unsigned I = 0; I != numInits; ++I) { + for (unsigned I = 0; I != initExprs.size(); ++I) { if (initExprs[I]->isTypeDependent()) ExprBits.TypeDependent = true; if (initExprs[I]->isValueDependent()) @@ -1686,7 +1763,7 @@ InitListExpr::InitListExpr(ASTContext &C, SourceLocation lbraceloc, ExprBits.ContainsUnexpandedParameterPack = true; } - InitExprs.insert(C, InitExprs.end(), initExprs, initExprs+numInits); + InitExprs.insert(C, InitExprs.end(), initExprs.begin(), initExprs.end()); } void InitListExpr::reserveInits(ASTContext &C, unsigned NumInits) { @@ -1723,15 +1800,15 @@ void InitListExpr::setArrayFiller(Expr *filler) { bool InitListExpr::isStringLiteralInit() const { if (getNumInits() != 1) return false; - const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(getType()); - if (!CAT || !CAT->getElementType()->isIntegerType()) + const ArrayType *AT = getType()->getAsArrayTypeUnsafe(); + if (!AT || !AT->getElementType()->isIntegerType()) return false; - const Expr *Init = getInit(0)->IgnoreParenImpCasts(); + const Expr *Init = getInit(0)->IgnoreParens(); return isa<StringLiteral>(Init) || isa<ObjCEncodeExpr>(Init); } SourceRange InitListExpr::getSourceRange() const { - if (SyntacticForm) + if (InitListExpr *SyntacticForm = getSyntacticForm()) return SyntacticForm->getSourceRange(); SourceLocation Beg = LBraceLoc, End = RBraceLoc; if (Beg.isInvalid()) { @@ -1945,6 +2022,11 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, return false; } + // If we don't know precisely what we're looking at, let's not warn. + case UnresolvedLookupExprClass: + case CXXUnresolvedConstructExprClass: + return false; + case CXXTemporaryObjectExprClass: case CXXConstructExprClass: return false; @@ -2014,6 +2096,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, R1 = getSourceRange(); return true; } + case CXXFunctionalCastExprClass: case CStyleCastExprClass: { // Ignore an explicit cast to void unless the operand is a non-trivial // volatile lvalue. @@ -2032,6 +2115,10 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, return false; } + // Ignore casts within macro expansions. + if (getExprLoc().isMacroID()) + return CE->getSubExpr()->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); + // If this is a cast to a constructor conversion, check the operand. // Otherwise, the result of the cast is unused. if (CE->getCastKind() == CK_ConstructorConversion) @@ -2641,6 +2728,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case UnresolvedMemberExprClass: case PackExpansionExprClass: case SubstNonTypeTemplateParmPackExprClass: + case FunctionParmPackExprClass: llvm_unreachable("shouldn't see dependent / unresolved nodes here"); case DeclRefExprClass: @@ -2995,6 +3083,24 @@ const ObjCPropertyRefExpr *Expr::getObjCProperty() const { return cast<ObjCPropertyRefExpr>(E); } +bool Expr::isObjCSelfExpr() const { + const Expr *E = IgnoreParenImpCasts(); + + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E); + if (!DRE) + return false; + + const ImplicitParamDecl *Param = dyn_cast<ImplicitParamDecl>(DRE->getDecl()); + if (!Param) + return false; + + const ObjCMethodDecl *M = dyn_cast<ObjCMethodDecl>(Param->getDeclContext()); + if (!M) + return false; + + return M->getSelfDecl() == Param; +} + FieldDecl *Expr::getBitField() { Expr *E = this->IgnoreParens(); @@ -3339,33 +3445,29 @@ Selector ObjCMessageExpr::getSelector() const { return Selector(SelectorOrMethod); } -ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { +QualType ObjCMessageExpr::getReceiverType() const { switch (getReceiverKind()) { case Instance: - if (const ObjCObjectPointerType *Ptr - = getInstanceReceiver()->getType()->getAs<ObjCObjectPointerType>()) - return Ptr->getInterfaceDecl(); - break; - + return getInstanceReceiver()->getType(); case Class: - if (const ObjCObjectType *Ty - = getClassReceiver()->getAs<ObjCObjectType>()) - return Ty->getInterface(); - break; - + return getClassReceiver(); case SuperInstance: - if (const ObjCObjectPointerType *Ptr - = getSuperType()->getAs<ObjCObjectPointerType>()) - return Ptr->getInterfaceDecl(); - break; - case SuperClass: - if (const ObjCObjectType *Iface - = getSuperType()->getAs<ObjCObjectType>()) - return Iface->getInterface(); - break; + return getSuperType(); } + llvm_unreachable("unexpected receiver kind"); +} + +ObjCInterfaceDecl *ObjCMessageExpr::getReceiverInterface() const { + QualType T = getReceiverType(); + + if (const ObjCObjectPointerType *Ptr = T->getAs<ObjCObjectPointerType>()) + return Ptr->getInterfaceDecl(); + + if (const ObjCObjectType *Ty = T->getAs<ObjCObjectType>()) + return Ty->getInterface(); + return 0; } @@ -3386,17 +3488,17 @@ bool ChooseExpr::isConditionTrue(const ASTContext &C) const { return getCond()->EvaluateKnownConstInt(C) != 0; } -ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, Expr **args, unsigned nexpr, +ShuffleVectorExpr::ShuffleVectorExpr(ASTContext &C, ArrayRef<Expr*> args, QualType Type, SourceLocation BLoc, SourceLocation RP) : Expr(ShuffleVectorExprClass, Type, VK_RValue, OK_Ordinary, Type->isDependentType(), Type->isDependentType(), Type->isInstantiationDependentType(), Type->containsUnexpandedParameterPack()), - BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(nexpr) + BuiltinLoc(BLoc), RParenLoc(RP), NumExprs(args.size()) { - SubExprs = new (C) Stmt*[nexpr]; - for (unsigned i = 0; i < nexpr; i++) { + SubExprs = new (C) Stmt*[args.size()]; + for (unsigned i = 0; i != args.size(); i++) { if (args[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) @@ -3421,8 +3523,9 @@ void ShuffleVectorExpr::setExprs(ASTContext &C, Expr ** Exprs, GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, - TypeSourceInfo **AssocTypes, Expr **AssocExprs, - unsigned NumAssocs, SourceLocation DefaultLoc, + ArrayRef<TypeSourceInfo*> AssocTypes, + ArrayRef<Expr*> AssocExprs, + SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack, unsigned ResultIndex) @@ -3434,19 +3537,21 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, AssocExprs[ResultIndex]->isValueDependent(), AssocExprs[ResultIndex]->isInstantiationDependent(), ContainsUnexpandedParameterPack), - AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]), - SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs), - ResultIndex(ResultIndex), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), - RParenLoc(RParenLoc) { + AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]), + SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]), + NumAssocs(AssocExprs.size()), ResultIndex(ResultIndex), + GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) { SubExprs[CONTROLLING] = ControllingExpr; - std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes); - std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR); + assert(AssocTypes.size() == AssocExprs.size()); + std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes); + std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR); } GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, SourceLocation GenericLoc, Expr *ControllingExpr, - TypeSourceInfo **AssocTypes, Expr **AssocExprs, - unsigned NumAssocs, SourceLocation DefaultLoc, + ArrayRef<TypeSourceInfo*> AssocTypes, + ArrayRef<Expr*> AssocExprs, + SourceLocation DefaultLoc, SourceLocation RParenLoc, bool ContainsUnexpandedParameterPack) : Expr(GenericSelectionExprClass, @@ -3457,13 +3562,14 @@ GenericSelectionExpr::GenericSelectionExpr(ASTContext &Context, /*isValueDependent=*/true, /*isInstantiationDependent=*/true, ContainsUnexpandedParameterPack), - AssocTypes(new (Context) TypeSourceInfo*[NumAssocs]), - SubExprs(new (Context) Stmt*[END_EXPR+NumAssocs]), NumAssocs(NumAssocs), - ResultIndex(-1U), GenericLoc(GenericLoc), DefaultLoc(DefaultLoc), - RParenLoc(RParenLoc) { + AssocTypes(new (Context) TypeSourceInfo*[AssocTypes.size()]), + SubExprs(new (Context) Stmt*[END_EXPR+AssocExprs.size()]), + NumAssocs(AssocExprs.size()), ResultIndex(-1U), GenericLoc(GenericLoc), + DefaultLoc(DefaultLoc), RParenLoc(RParenLoc) { SubExprs[CONTROLLING] = ControllingExpr; - std::copy(AssocTypes, AssocTypes+NumAssocs, this->AssocTypes); - std::copy(AssocExprs, AssocExprs+NumAssocs, SubExprs+END_EXPR); + assert(AssocTypes.size() == AssocExprs.size()); + std::copy(AssocTypes.begin(), AssocTypes.end(), this->AssocTypes); + std::copy(AssocExprs.begin(), AssocExprs.end(), SubExprs+END_EXPR); } //===----------------------------------------------------------------------===// @@ -3483,8 +3589,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, const Designator *Designators, SourceLocation EqualOrColonLoc, bool GNUSyntax, - Expr **IndexExprs, - unsigned NumIndexExprs, + ArrayRef<Expr*> IndexExprs, Expr *Init) : Expr(DesignatedInitExprClass, Ty, Init->getValueKind(), Init->getObjectKind(), @@ -3492,7 +3597,7 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, Init->isInstantiationDependent(), Init->containsUnexpandedParameterPack()), EqualOrColonLoc(EqualOrColonLoc), GNUSyntax(GNUSyntax), - NumDesignators(NumDesignators), NumSubExprs(NumIndexExprs + 1) { + NumDesignators(NumDesignators), NumSubExprs(IndexExprs.size() + 1) { this->Designators = new (C) Designator[NumDesignators]; // Record the initializer itself. @@ -3542,20 +3647,20 @@ DesignatedInitExpr::DesignatedInitExpr(ASTContext &C, QualType Ty, } } - assert(IndexIdx == NumIndexExprs && "Wrong number of index expressions"); + assert(IndexIdx == IndexExprs.size() && "Wrong number of index expressions"); } DesignatedInitExpr * DesignatedInitExpr::Create(ASTContext &C, Designator *Designators, unsigned NumDesignators, - Expr **IndexExprs, unsigned NumIndexExprs, + ArrayRef<Expr*> IndexExprs, SourceLocation ColonOrEqualLoc, bool UsesColonSyntax, Expr *Init) { void *Mem = C.Allocate(sizeof(DesignatedInitExpr) + - sizeof(Stmt *) * (NumIndexExprs + 1), 8); + sizeof(Stmt *) * (IndexExprs.size() + 1), 8); return new (Mem) DesignatedInitExpr(C, C.VoidTy, NumDesignators, Designators, ColonOrEqualLoc, UsesColonSyntax, - IndexExprs, NumIndexExprs, Init); + IndexExprs, Init); } DesignatedInitExpr *DesignatedInitExpr::CreateEmpty(ASTContext &C, @@ -3651,13 +3756,13 @@ void DesignatedInitExpr::ExpandDesignator(ASTContext &C, unsigned Idx, } ParenListExpr::ParenListExpr(ASTContext& C, SourceLocation lparenloc, - Expr **exprs, unsigned nexprs, + ArrayRef<Expr*> exprs, SourceLocation rparenloc) : Expr(ParenListExprClass, QualType(), VK_RValue, OK_Ordinary, false, false, false, false), - NumExprs(nexprs), LParenLoc(lparenloc), RParenLoc(rparenloc) { - Exprs = new (C) Stmt*[nexprs]; - for (unsigned i = 0; i != nexprs; ++i) { + NumExprs(exprs.size()), LParenLoc(lparenloc), RParenLoc(rparenloc) { + Exprs = new (C) Stmt*[exprs.size()]; + for (unsigned i = 0; i != exprs.size(); ++i) { if (exprs[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (exprs[i]->isValueDependent()) @@ -3902,14 +4007,14 @@ ObjCSubscriptRefExpr *ObjCSubscriptRefExpr::Create(ASTContext &C, getMethod, setMethod, RB); } -AtomicExpr::AtomicExpr(SourceLocation BLoc, Expr **args, unsigned nexpr, +AtomicExpr::AtomicExpr(SourceLocation BLoc, ArrayRef<Expr*> args, QualType t, AtomicOp op, SourceLocation RP) : Expr(AtomicExprClass, t, VK_RValue, OK_Ordinary, false, false, false, false), - NumSubExprs(nexpr), BuiltinLoc(BLoc), RParenLoc(RP), Op(op) + NumSubExprs(args.size()), BuiltinLoc(BLoc), RParenLoc(RP), Op(op) { - assert(nexpr == getNumSubExprs(op) && "wrong number of subexpressions"); - for (unsigned i = 0; i < nexpr; i++) { + assert(args.size() == getNumSubExprs(op) && "wrong number of subexpressions"); + for (unsigned i = 0; i != args.size(); i++) { if (args[i]->isTypeDependent()) ExprBits.TypeDependent = true; if (args[i]->isValueDependent()) diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 3fa49e0e18b9..55722a2a99af 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -51,6 +51,26 @@ QualType CXXUuidofExpr::getTypeOperand() const { .getUnqualifiedType(); } +// static +UuidAttr *CXXUuidofExpr::GetUuidAttrOfType(QualType QT) { + // Optionally remove one level of pointer, reference or array indirection. + const Type *Ty = QT.getTypePtr(); + if (QT->isPointerType() || QT->isReferenceType()) + Ty = QT->getPointeeType().getTypePtr(); + else if (QT->isArrayType()) + Ty = cast<ArrayType>(QT)->getElementType().getTypePtr(); + + // Loop all record redeclaration looking for an uuid attribute. + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(), + E = RD->redecls_end(); I != E; ++I) { + if (UuidAttr *Uuid = I->getAttr<UuidAttr>()) + return Uuid; + } + + return 0; +} + // CXXScalarValueInitExpr SourceRange CXXScalarValueInitExpr::getSourceRange() const { SourceLocation Start = RParenLoc; @@ -63,24 +83,24 @@ SourceRange CXXScalarValueInitExpr::getSourceRange() const { CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize, - Expr **placementArgs, unsigned numPlaceArgs, + ArrayRef<Expr*> placementArgs, SourceRange typeIdParens, Expr *arraySize, InitializationStyle initializationStyle, Expr *initializer, QualType ty, TypeSourceInfo *allocatedTypeInfo, - SourceLocation startLoc, SourceRange directInitRange) + SourceRange Range, SourceRange directInitRange) : Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary, ty->isDependentType(), ty->isDependentType(), ty->isInstantiationDependentType(), ty->containsUnexpandedParameterPack()), SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete), AllocatedTypeInfo(allocatedTypeInfo), TypeIdParens(typeIdParens), - StartLoc(startLoc), DirectInitRange(directInitRange), + Range(Range), DirectInitRange(directInitRange), GlobalNew(globalNew), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize) { assert((initializer != 0 || initializationStyle == NoInit) && "Only NoInit can have no initializer."); StoredInitializationStyle = initializer ? initializationStyle + 1 : 0; - AllocateArgsArray(C, arraySize != 0, numPlaceArgs, initializer != 0); + AllocateArgsArray(C, arraySize != 0, placementArgs.size(), initializer != 0); unsigned i = 0; if (Array) { if (arraySize->isInstantiationDependent()) @@ -102,7 +122,7 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, SubExprs[i++] = initializer; } - for (unsigned j = 0; j < NumPlacementArgs; ++j) { + for (unsigned j = 0; j != placementArgs.size(); ++j) { if (placementArgs[j]->isInstantiationDependent()) ExprBits.InstantiationDependent = true; if (placementArgs[j]->containsUnexpandedParameterPack()) @@ -110,6 +130,14 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew, SubExprs[i++] = placementArgs[j]; } + + switch (getInitializationStyle()) { + case CallInit: + this->Range.setEnd(DirectInitRange.getEnd()); break; + case ListInit: + this->Range.setEnd(getInitializer()->getSourceRange().getEnd()); break; + default: break; + } } void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray, @@ -127,18 +155,6 @@ bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const { castAs<FunctionProtoType>()->isNothrow(Ctx); } -SourceLocation CXXNewExpr::getEndLoc() const { - switch (getInitializationStyle()) { - case NoInit: - return AllocatedTypeInfo->getTypeLoc().getEndLoc(); - case CallInit: - return DirectInitRange.getEnd(); - case ListInit: - return getInitializer()->getSourceRange().getEnd(); - } - llvm_unreachable("bogus initialization style"); -} - // CXXDeleteExpr QualType CXXDeleteExpr::getDestroyedType() const { const Expr *Arg = getArgument(); @@ -227,7 +243,7 @@ UnresolvedLookupExpr::Create(ASTContext &C, return new (Mem) UnresolvedLookupExpr(C, NamingClass, QualifierLoc, TemplateKWLoc, NameInfo, ADL, /*Overload*/ true, Args, - Begin, End, /*StdIsAssociated=*/false); + Begin, End); } UnresolvedLookupExpr * @@ -697,15 +713,14 @@ CXXBindTemporaryExpr *CXXBindTemporaryExpr::Create(ASTContext &C, CXXTemporaryObjectExpr::CXXTemporaryObjectExpr(ASTContext &C, CXXConstructorDecl *Cons, TypeSourceInfo *Type, - Expr **Args, - unsigned NumArgs, + ArrayRef<Expr*> Args, SourceRange parenRange, bool HadMultipleCandidates, bool ZeroInitialization) : CXXConstructExpr(C, CXXTemporaryObjectExprClass, Type->getType().getNonReferenceType(), Type->getTypeLoc().getBeginLoc(), - Cons, false, Args, NumArgs, + Cons, false, Args, HadMultipleCandidates, /*FIXME*/false, ZeroInitialization, CXXConstructExpr::CK_Complete, parenRange), Type(Type) { @@ -719,14 +734,14 @@ SourceRange CXXTemporaryObjectExpr::getSourceRange() const { CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool Elidable, - Expr **Args, unsigned NumArgs, + ArrayRef<Expr*> Args, bool HadMultipleCandidates, bool ListInitialization, bool ZeroInitialization, ConstructionKind ConstructKind, SourceRange ParenRange) { return new (C) CXXConstructExpr(C, CXXConstructExprClass, T, Loc, D, - Elidable, Args, NumArgs, + Elidable, Args, HadMultipleCandidates, ListInitialization, ZeroInitialization, ConstructKind, ParenRange); @@ -735,7 +750,7 @@ CXXConstructExpr *CXXConstructExpr::Create(ASTContext &C, QualType T, CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, SourceLocation Loc, CXXConstructorDecl *D, bool elidable, - Expr **args, unsigned numargs, + ArrayRef<Expr*> args, bool HadMultipleCandidates, bool ListInitialization, bool ZeroInitialization, @@ -745,16 +760,16 @@ CXXConstructExpr::CXXConstructExpr(ASTContext &C, StmtClass SC, QualType T, T->isDependentType(), T->isDependentType(), T->isInstantiationDependentType(), T->containsUnexpandedParameterPack()), - Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(numargs), + Constructor(D), Loc(Loc), ParenRange(ParenRange), NumArgs(args.size()), Elidable(elidable), HadMultipleCandidates(HadMultipleCandidates), ListInitialization(ListInitialization), ZeroInitialization(ZeroInitialization), ConstructKind(ConstructKind), Args(0) { if (NumArgs) { - Args = new (C) Stmt*[NumArgs]; + Args = new (C) Stmt*[args.size()]; - for (unsigned i = 0; i != NumArgs; ++i) { + for (unsigned i = 0; i != args.size(); ++i) { assert(args[i] && "NULL argument in CXXConstructExpr"); if (args[i]->isValueDependent()) @@ -877,9 +892,12 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, QualType T = Context.getTypeDeclType(Class); unsigned Size = sizeof(LambdaExpr) + sizeof(Stmt *) * (Captures.size() + 1); - if (!ArrayIndexVars.empty()) - Size += sizeof(VarDecl *) * ArrayIndexVars.size() - + sizeof(unsigned) * (Captures.size() + 1); + if (!ArrayIndexVars.empty()) { + Size += sizeof(unsigned) * (Captures.size() + 1); + // Realign for following VarDecl array. + Size = llvm::RoundUpToAlignment(Size, llvm::alignOf<VarDecl*>()); + Size += sizeof(VarDecl *) * ArrayIndexVars.size(); + } void *Mem = Context.Allocate(Size); return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault, Captures, ExplicitParams, ExplicitResultType, @@ -997,8 +1015,7 @@ ExprWithCleanups *ExprWithCleanups::Create(ASTContext &C, EmptyShell empty, CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, SourceLocation LParenLoc, - Expr **Args, - unsigned NumArgs, + ArrayRef<Expr*> Args, SourceLocation RParenLoc) : Expr(CXXUnresolvedConstructExprClass, Type->getType().getNonReferenceType(), @@ -1011,9 +1028,9 @@ CXXUnresolvedConstructExpr::CXXUnresolvedConstructExpr(TypeSourceInfo *Type, Type(Type), LParenLoc(LParenLoc), RParenLoc(RParenLoc), - NumArgs(NumArgs) { + NumArgs(Args.size()) { Stmt **StoredArgs = reinterpret_cast<Stmt **>(this + 1); - for (unsigned I = 0; I != NumArgs; ++I) { + for (unsigned I = 0; I != Args.size(); ++I) { if (Args[I]->containsUnexpandedParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -1025,13 +1042,11 @@ CXXUnresolvedConstructExpr * CXXUnresolvedConstructExpr::Create(ASTContext &C, TypeSourceInfo *Type, SourceLocation LParenLoc, - Expr **Args, - unsigned NumArgs, + ArrayRef<Expr*> Args, SourceLocation RParenLoc) { void *Mem = C.Allocate(sizeof(CXXUnresolvedConstructExpr) + - sizeof(Expr *) * NumArgs); - return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc, - Args, NumArgs, RParenLoc); + sizeof(Expr *) * Args.size()); + return new (Mem) CXXUnresolvedConstructExpr(Type, LParenLoc, Args, RParenLoc); } CXXUnresolvedConstructExpr * @@ -1300,6 +1315,34 @@ TemplateArgument SubstNonTypeTemplateParmPackExpr::getArgumentPack() const { return TemplateArgument(Arguments, NumArguments); } +FunctionParmPackExpr::FunctionParmPackExpr(QualType T, ParmVarDecl *ParamPack, + SourceLocation NameLoc, + unsigned NumParams, + Decl * const *Params) + : Expr(FunctionParmPackExprClass, T, VK_LValue, OK_Ordinary, + true, true, true, true), + ParamPack(ParamPack), NameLoc(NameLoc), NumParameters(NumParams) { + if (Params) + std::uninitialized_copy(Params, Params + NumParams, + reinterpret_cast<Decl**>(this+1)); +} + +FunctionParmPackExpr * +FunctionParmPackExpr::Create(ASTContext &Context, QualType T, + ParmVarDecl *ParamPack, SourceLocation NameLoc, + llvm::ArrayRef<Decl*> Params) { + return new (Context.Allocate(sizeof(FunctionParmPackExpr) + + sizeof(ParmVarDecl*) * Params.size())) + FunctionParmPackExpr(T, ParamPack, NameLoc, Params.size(), Params.data()); +} + +FunctionParmPackExpr * +FunctionParmPackExpr::CreateEmpty(ASTContext &Context, unsigned NumParams) { + return new (Context.Allocate(sizeof(FunctionParmPackExpr) + + sizeof(ParmVarDecl*) * NumParams)) + FunctionParmPackExpr(QualType(), 0, SourceLocation(), 0, 0); +} + TypeTraitExpr::TypeTraitExpr(QualType T, SourceLocation Loc, TypeTrait Kind, ArrayRef<TypeSourceInfo *> Args, SourceLocation RParenLoc, diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index f16d70b5da1b..24ec6bb02074 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -134,6 +134,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // ObjC instance variables are lvalues // FIXME: ObjC++0x might have different rules case Expr::ObjCIvarRefExprClass: + case Expr::FunctionParmPackExprClass: return Cl::CL_LValue; // C99 6.5.2.5p5 says that compound literals are lvalues. diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 06c41a2e7ea2..6e0b5fca60c0 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -953,7 +953,7 @@ static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) { if (VD) Info.Note(VD->getLocation(), diag::note_declared_at); else - Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(), + Info.Note(Base.get<const Expr*>()->getExprLoc(), diag::note_constexpr_temporary_here); } @@ -987,6 +987,14 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, LVal.getLValueCallIndex() == 0) && "have call index for global lvalue"); + // Check if this is a thread-local variable. + if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { + if (const VarDecl *Var = dyn_cast<const VarDecl>(VD)) { + if (Var->isThreadSpecified()) + return false; + } + } + // Allow address constant expressions to be past-the-end pointers. This is // an extension: the standard requires them to point to an object. if (!IsReferenceType) @@ -2586,7 +2594,7 @@ public: const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); if (!FD) return Error(E); assert(!FD->getType()->isReferenceType() && "prvalue reference?"); - assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() == + assert(BaseTy->castAs<RecordType>()->getDecl()->getCanonicalDecl() == FD->getParent()->getCanonicalDecl() && "record / field mismatch"); SubobjectDesignator Designator(BaseTy); @@ -2665,7 +2673,7 @@ public: if (E->isArrow()) { if (!EvaluatePointer(E->getBase(), Result, this->Info)) return false; - BaseTy = E->getBase()->getType()->getAs<PointerType>()->getPointeeType(); + BaseTy = E->getBase()->getType()->castAs<PointerType>()->getPointeeType(); } else if (E->getBase()->isRValue()) { assert(E->getBase()->getType()->isRecordType()); if (!EvaluateTemporary(E->getBase(), Result, this->Info)) @@ -2878,19 +2886,13 @@ LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) { } bool LValueExprEvaluator::VisitCXXTypeidExpr(const CXXTypeidExpr *E) { - if (E->isTypeOperand()) + if (!E->isPotentiallyEvaluated()) return Success(E); - CXXRecordDecl *RD = E->getExprOperand()->getType()->getAsCXXRecordDecl(); - // FIXME: The standard says "a typeid expression whose operand is of a - // polymorphic class type" is not a constant expression, but it probably - // means "a typeid expression whose operand is potentially evaluated". - if (RD && RD->isPolymorphic()) { - Info.Diag(E, diag::note_constexpr_typeid_polymorphic) - << E->getExprOperand()->getType() - << E->getExprOperand()->getSourceRange(); - return false; - } - return Success(E); + + Info.Diag(E, diag::note_constexpr_typeid_polymorphic) + << E->getExprOperand()->getType() + << E->getExprOperand()->getSourceRange(); + return false; } bool LValueExprEvaluator::VisitCXXUuidofExpr(const CXXUuidofExpr *E) { @@ -3036,7 +3038,7 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (E->getOpcode() == BO_Sub) AdditionalOffset = -AdditionalOffset; - QualType Pointee = PExp->getType()->getAs<PointerType>()->getPointeeType(); + QualType Pointee = PExp->getType()->castAs<PointerType>()->getPointeeType(); return HandleLValueArrayAdjustment(Info, E, Result, Pointee, AdditionalOffset); } @@ -4288,6 +4290,16 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { return Error(E); } + case Builtin::BI__builtin_bswap16: + case Builtin::BI__builtin_bswap32: + case Builtin::BI__builtin_bswap64: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + + return Success(Val.byteSwap(), E); + } + case Builtin::BI__builtin_classify_type: return Success(EvaluateBuiltinClassifyType(E), E); @@ -4902,7 +4914,7 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (!LHSValue.Offset.isZero() || !RHSValue.Offset.isZero()) return false; const Expr *LHSExpr = LHSValue.Base.dyn_cast<const Expr*>(); - const Expr *RHSExpr = LHSValue.Base.dyn_cast<const Expr*>(); + const Expr *RHSExpr = RHSValue.Base.dyn_cast<const Expr*>(); if (!LHSExpr || !RHSExpr) return false; const AddrLabelExpr *LHSAddrExpr = dyn_cast<AddrLabelExpr>(LHSExpr); @@ -5176,7 +5188,7 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( QualType Ty = E->getTypeOfArgument(); if (Ty->isVectorType()) { - unsigned n = Ty->getAs<VectorType>()->getNumElements(); + unsigned n = Ty->castAs<VectorType>()->getNumElements(); // The vec_step built-in functions that take a 3-component // vector return 4. (OpenCL 1.1 spec 6.11.12) @@ -5349,6 +5361,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_IntegralRealToComplex: case CK_IntegralComplexCast: case CK_IntegralComplexToFloatingComplex: + case CK_BuiltinFnToFnPtr: llvm_unreachable("invalid cast kind for integral value"); case CK_BitCast: @@ -5753,7 +5766,7 @@ static bool EvaluateComplex(const Expr *E, ComplexValue &Result, } bool ComplexExprEvaluator::ZeroInitialization(const Expr *E) { - QualType ElemTy = E->getType()->getAs<ComplexType>()->getElementType(); + QualType ElemTy = E->getType()->castAs<ComplexType>()->getElementType(); if (ElemTy->isRealFloatingType()) { Result.makeComplexFloat(); APFloat Zero = APFloat::getZero(Info.Ctx.getFloatTypeSemantics(ElemTy)); @@ -5835,6 +5848,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: case CK_CopyAndAutoreleaseBlockObject: + case CK_BuiltinFnToFnPtr: llvm_unreachable("invalid cast kind for complex value"); case CK_LValueToRValue: @@ -5911,9 +5925,9 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { if (!Visit(E->getSubExpr())) return false; - QualType To = E->getType()->getAs<ComplexType>()->getElementType(); + QualType To = E->getType()->castAs<ComplexType>()->getElementType(); QualType From - = E->getSubExpr()->getType()->getAs<ComplexType>()->getElementType(); + = E->getSubExpr()->getType()->castAs<ComplexType>()->getElementType(); Result.makeComplexFloat(); return HandleIntToFloatCast(Info, E, From, Result.IntReal, To, Result.FloatReal) && @@ -6177,11 +6191,9 @@ static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) { return false; Result = Info.CurrentCall->Temporaries[E]; } else if (E->getType()->isVoidType()) { - if (Info.getLangOpts().CPlusPlus0x) + if (!Info.getLangOpts().CPlusPlus0x) Info.CCEDiag(E, diag::note_constexpr_nonliteral) << E->getType(); - else - Info.CCEDiag(E, diag::note_invalid_subexpr_in_const_expr); if (!EvaluateVoid(E, Info)) return false; } else if (Info.getLangOpts().CPlusPlus0x) { @@ -6470,6 +6482,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::OpaqueValueExprClass: case Expr::PackExpansionExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::FunctionParmPackExprClass: case Expr::AsTypeExprClass: case Expr::ObjCIndirectCopyRestoreExprClass: case Expr::MaterializeTemporaryExprClass: diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 7c7a5e5de387..851944a42b6e 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -343,17 +343,10 @@ private: void mangleCXXDtorType(CXXDtorType T); void mangleTemplateArgs(const ASTTemplateArgumentListInfo &TemplateArgs); - void mangleTemplateArgs(TemplateName Template, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs); - void mangleTemplateArgs(const TemplateParameterList &PL, - const TemplateArgument *TemplateArgs, + void mangleTemplateArgs(const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs); - void mangleTemplateArgs(const TemplateParameterList &PL, - const TemplateArgumentList &AL); - void mangleTemplateArg(const NamedDecl *P, TemplateArgument A); - void mangleUnresolvedTemplateArgs(const TemplateArgument *args, - unsigned numArgs); + void mangleTemplateArgs(const TemplateArgumentList &AL); + void mangleTemplateArg(TemplateArgument A); void mangleTemplateParameter(unsigned Index); @@ -570,8 +563,7 @@ void CXXNameMangler::mangleName(const NamedDecl *ND) { const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleUnscopedTemplateName(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + mangleTemplateArgs(*TemplateArgs); return; } @@ -593,8 +585,7 @@ void CXXNameMangler::mangleName(const TemplateDecl *TD, if (DC->isTranslationUnit() || isStdNamespace(DC)) { mangleUnscopedTemplateName(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs); + mangleTemplateArgs(TemplateArgs, NumTemplateArgs); } else { mangleNestedName(TD, TemplateArgs, NumTemplateArgs); } @@ -693,9 +684,10 @@ void CXXNameMangler::mangleFloat(const llvm::APFloat &f) { void CXXNameMangler::mangleNumber(const llvm::APSInt &Value) { if (Value.isSigned() && Value.isNegative()) { Out << 'n'; - Value.abs().print(Out, true); - } else - Value.print(Out, Value.isSigned()); + Value.abs().print(Out, /*signed*/ false); + } else { + Value.print(Out, /*signed*/ false); + } } void CXXNameMangler::mangleNumber(int64_t Number) { @@ -737,8 +729,7 @@ void CXXNameMangler::manglePrefix(QualType type) { // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(TST->getTemplateName(), TST->getArgs(), - TST->getNumArgs()); + mangleTemplateArgs(TST->getArgs(), TST->getNumArgs()); addSubstitution(QualType(TST, 0)); } } else if (const DependentTemplateSpecializationType *DTST @@ -751,7 +742,7 @@ void CXXNameMangler::manglePrefix(QualType type) { // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(Template, DTST->getArgs(), DTST->getNumArgs()); + mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs()); } else { // We use the QualType mangle type variant here because it handles // substitutions. @@ -942,7 +933,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, } } - mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs()); + mangleTemplateArgs(tst->getArgs(), tst->getNumArgs()); break; } @@ -959,7 +950,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, const DependentTemplateSpecializationType *tst = cast<DependentTemplateSpecializationType>(type); mangleSourceName(tst->getIdentifier()); - mangleUnresolvedTemplateArgs(tst->getArgs(), tst->getNumArgs()); + mangleTemplateArgs(tst->getArgs(), tst->getNumArgs()); break; } } @@ -1228,8 +1219,7 @@ void CXXNameMangler::mangleNestedName(const NamedDecl *ND, const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleTemplatePrefix(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + mangleTemplateArgs(*TemplateArgs); } else { manglePrefix(DC, NoFunction); @@ -1246,8 +1236,7 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD, Out << 'N'; mangleTemplatePrefix(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, TemplateArgs, NumTemplateArgs); + mangleTemplateArgs(TemplateArgs, NumTemplateArgs); Out << 'E'; } @@ -1341,11 +1330,8 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) { } Out << "Ul"; - DeclarationName Name - = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); - const FunctionProtoType *Proto - = cast<CXXMethodDecl>(*Lambda->lookup(Name).first)->getType()-> - getAs<FunctionProtoType>(); + const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()-> + getAs<FunctionProtoType>(); mangleBareFunctionType(Proto, /*MangleReturnType=*/false); Out << "E"; @@ -1423,8 +1409,7 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) { const TemplateArgumentList *TemplateArgs = 0; if (const TemplateDecl *TD = isTemplate(ND, TemplateArgs)) { mangleTemplatePrefix(TD); - TemplateParameterList *TemplateParameters = TD->getTemplateParameters(); - mangleTemplateArgs(*TemplateParameters, *TemplateArgs); + mangleTemplateArgs(*TemplateArgs); } else if(NoFunction && (isa<FunctionDecl>(ND) || isa<ObjCMethodDecl>(ND))) return; @@ -2110,6 +2095,7 @@ void CXXNameMangler::mangleNeonVectorType(const VectorType *T) { // ::= Dv [<dimension expression>] _ <element type> // <extended element type> ::= <element type> // ::= p # AltiVec vector pixel +// ::= b # Altivec vector bool void CXXNameMangler::mangleType(const VectorType *T) { if ((T->getVectorKind() == VectorType::NeonVector || T->getVectorKind() == VectorType::NeonPolyVector)) { @@ -2174,7 +2160,7 @@ void CXXNameMangler::mangleType(const TemplateSpecializationType *T) { // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(T->getTemplateName(), T->getArgs(), T->getNumArgs()); + mangleTemplateArgs(T->getArgs(), T->getNumArgs()); addSubstitution(QualType(T, 0)); } } @@ -2200,7 +2186,7 @@ void CXXNameMangler::mangleType(const DependentTemplateSpecializationType *T) { // FIXME: GCC does not appear to mangle the template arguments when // the template in question is a dependent template name. Should we // emulate that badness? - mangleTemplateArgs(Prefix, T->getArgs(), T->getNumArgs()); + mangleTemplateArgs(T->getArgs(), T->getNumArgs()); Out << 'E'; } @@ -2414,7 +2400,6 @@ recurse: case Expr::ExpressionTraitExprClass: case Expr::VAArgExprClass: case Expr::CXXUuidofExprClass: - case Expr::CXXNoexceptExprClass: case Expr::CUDAKernelCallExprClass: case Expr::AsTypeExprClass: case Expr::PseudoObjectExprClass: @@ -2606,6 +2591,11 @@ recurse: Out <<"_E"; break; + case Expr::CXXNoexceptExprClass: + Out << "nx"; + mangleExpression(cast<CXXNoexceptExpr>(E)->getOperand()); + break; + case Expr::UnaryExprOrTypeTraitExprClass: { const UnaryExprOrTypeTraitExpr *SAE = cast<UnaryExprOrTypeTraitExpr>(E); @@ -2808,7 +2798,15 @@ recurse: // }; Out << "_SUBSTPACK_"; break; - + + case Expr::FunctionParmPackExprClass: { + // FIXME: not clear how to mangle this! + const FunctionParmPackExpr *FPPE = cast<FunctionParmPackExpr>(E); + Out << "v110_SUBSTPACK"; + mangleFunctionParam(FPPE->getParameterPack()); + break; + } + case Expr::DependentScopeDeclRefExprClass: { const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E); mangleUnresolvedName(DRE->getQualifier(), 0, DRE->getDeclName(), Arity); @@ -3043,50 +3041,28 @@ void CXXNameMangler::mangleTemplateArgs( // <template-args> ::= I <template-arg>+ E Out << 'I'; for (unsigned i = 0, e = TemplateArgs.NumTemplateArgs; i != e; ++i) - mangleTemplateArg(0, TemplateArgs.getTemplateArgs()[i].getArgument()); - Out << 'E'; -} - -void CXXNameMangler::mangleTemplateArgs(TemplateName Template, - const TemplateArgument *TemplateArgs, - unsigned NumTemplateArgs) { - if (TemplateDecl *TD = Template.getAsTemplateDecl()) - return mangleTemplateArgs(*TD->getTemplateParameters(), TemplateArgs, - NumTemplateArgs); - - mangleUnresolvedTemplateArgs(TemplateArgs, NumTemplateArgs); -} - -void CXXNameMangler::mangleUnresolvedTemplateArgs(const TemplateArgument *args, - unsigned numArgs) { - // <template-args> ::= I <template-arg>+ E - Out << 'I'; - for (unsigned i = 0; i != numArgs; ++i) - mangleTemplateArg(0, args[i]); + mangleTemplateArg(TemplateArgs.getTemplateArgs()[i].getArgument()); Out << 'E'; } -void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, - const TemplateArgumentList &AL) { +void CXXNameMangler::mangleTemplateArgs(const TemplateArgumentList &AL) { // <template-args> ::= I <template-arg>+ E Out << 'I'; for (unsigned i = 0, e = AL.size(); i != e; ++i) - mangleTemplateArg(PL.getParam(i), AL[i]); + mangleTemplateArg(AL[i]); Out << 'E'; } -void CXXNameMangler::mangleTemplateArgs(const TemplateParameterList &PL, - const TemplateArgument *TemplateArgs, +void CXXNameMangler::mangleTemplateArgs(const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { // <template-args> ::= I <template-arg>+ E Out << 'I'; for (unsigned i = 0; i != NumTemplateArgs; ++i) - mangleTemplateArg(PL.getParam(i), TemplateArgs[i]); + mangleTemplateArg(TemplateArgs[i]); Out << 'E'; } -void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, - TemplateArgument A) { +void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { // <template-arg> ::= <type> # type or template // ::= X <expression> E # expression // ::= <expr-primary> # simple expressions @@ -3135,25 +3111,12 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, mangleIntegerLiteral(A.getIntegralType(), A.getAsIntegral()); break; case TemplateArgument::Declaration: { - assert(P && "Missing template parameter for declaration argument"); // <expr-primary> ::= L <mangled-name> E # external name - // <expr-primary> ::= L <type> 0 E // Clang produces AST's where pointer-to-member-function expressions // and pointer-to-function expressions are represented as a declaration not // an expression. We compensate for it here to produce the correct mangling. - const NonTypeTemplateParmDecl *Parameter = cast<NonTypeTemplateParmDecl>(P); - - // Handle NULL pointer arguments. - if (!A.getAsDecl()) { - Out << "L"; - mangleType(Parameter->getType()); - Out << "0E"; - break; - } - - - NamedDecl *D = cast<NamedDecl>(A.getAsDecl()); - bool compensateMangling = !Parameter->getType()->isReferenceType(); + ValueDecl *D = A.getAsDecl(); + bool compensateMangling = !A.isDeclForReferenceParam(); if (compensateMangling) { Out << 'X'; mangleOperatorName(OO_Amp, 1); @@ -3176,14 +3139,20 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, break; } - + case TemplateArgument::NullPtr: { + // <expr-primary> ::= L <type> 0 E + Out << 'L'; + mangleType(A.getNullPtrType()); + Out << "0E"; + break; + } case TemplateArgument::Pack: { // Note: proposal by Mike Herrick on 12/20/10 Out << 'J'; for (TemplateArgument::pack_iterator PA = A.pack_begin(), PAEnd = A.pack_end(); PA != PAEnd; ++PA) - mangleTemplateArg(P, *PA); + mangleTemplateArg(*PA); Out << 'E'; } } diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index e2cee7f52cfb..5d5b83d9a30b 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -20,6 +20,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/ABI.h" +#include "clang/Basic/DiagnosticOptions.h" #include <map> @@ -56,7 +57,7 @@ public: void mangleVariableEncoding(const VarDecl *VD); void mangleNumber(int64_t Number); void mangleNumber(const llvm::APSInt &Value); - void mangleType(QualType T, SourceRange Range); + void mangleType(QualType T, SourceRange Range, bool MangleQualifiers = true); private: void disableBackReferences() { UseNameBackReferences = false; } @@ -68,6 +69,7 @@ private: void manglePostfix(const DeclContext *DC, bool NoFunction=false); void mangleOperatorName(OverloadedOperatorKind OO, SourceLocation Loc); void mangleQualifiers(Qualifiers Quals, bool IsMember); + void manglePointerQualifiers(Qualifiers Quals); void mangleUnscopedTemplateName(const TemplateDecl *ND); void mangleTemplateInstantiationName(const TemplateDecl *TD, @@ -75,7 +77,7 @@ private: void mangleObjCMethodName(const ObjCMethodDecl *MD); void mangleLocalName(const FunctionDecl *FD); - void mangleTypeRepeated(QualType T, SourceRange Range); + void mangleArgumentType(QualType T, SourceRange Range); // Declare manglers for every type class. #define ABSTRACT_TYPE(CLASS, PARENT) @@ -95,6 +97,7 @@ private: void mangleFunctionClass(const FunctionDecl *FD); void mangleCallingConvention(const FunctionType *T, bool IsInstMethod = false); void mangleIntegerLiteral(QualType T, const llvm::APSInt &Number); + void mangleExpression(const Expr *E); void mangleThrowSpecification(const FunctionProtoType *T); void mangleTemplateArgs( @@ -266,18 +269,18 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { Out << '4'; // Now mangle the type. // <variable-type> ::= <type> <cvr-qualifiers> - // ::= <type> A # pointers, references, arrays + // ::= <type> <pointee-cvr-qualifiers> # pointers, references // Pointers and references are odd. The type of 'int * const foo;' gets // mangled as 'QAHA' instead of 'PAHB', for example. TypeLoc TL = VD->getTypeSourceInfo()->getTypeLoc(); QualType Ty = TL.getType(); if (Ty->isPointerType() || Ty->isReferenceType()) { mangleType(Ty, TL.getSourceRange()); - Out << 'A'; + mangleQualifiers(Ty->getPointeeType().getQualifiers(), false); } else if (const ArrayType *AT = getASTContext().getAsArrayType(Ty)) { // Global arrays are funny, too. mangleType(AT, true); - Out << 'A'; + mangleQualifiers(Ty.getQualifiers(), false); } else { mangleType(Ty.getLocalUnqualifiedType(), TL.getSourceRange()); mangleQualifiers(Ty.getLocalQualifiers(), false); @@ -304,39 +307,23 @@ void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { } void MicrosoftCXXNameMangler::mangleNumber(int64_t Number) { - // <number> ::= [?] <decimal digit> # 1 <= Number <= 10 - // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc... - // ::= [?] @ # 0 (alternate mangling, not emitted by VC) - if (Number < 0) { - Out << '?'; - Number = -Number; - } - // There's a special shorter mangling for 0, but Microsoft - // chose not to use it. Instead, 0 gets mangled as "A@". Oh well... - if (Number >= 1 && Number <= 10) - Out << Number-1; - else { - // We have to build up the encoding in reverse order, so it will come - // out right when we write it out. - char Encoding[16]; - char *EndPtr = Encoding+sizeof(Encoding); - char *CurPtr = EndPtr; - do { - *--CurPtr = 'A' + (Number % 16); - Number /= 16; - } while (Number); - Out.write(CurPtr, EndPtr-CurPtr); - Out << '@'; - } + llvm::APSInt APSNumber(/*BitWidth=*/64, /*isUnsigned=*/false); + APSNumber = Number; + mangleNumber(APSNumber); } void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) { + // <number> ::= [?] <decimal digit> # 1 <= Number <= 10 + // ::= [?] <hex digit>+ @ # 0 or > 9; A = 0, B = 1, etc... + // ::= [?] @ # 0 (alternate mangling, not emitted by VC) if (Value.isSigned() && Value.isNegative()) { Out << '?'; mangleNumber(llvm::APSInt(Value.abs())); return; } llvm::APSInt Temp(Value); + // There's a special shorter mangling for 0, but Microsoft + // chose not to use it. Instead, 0 gets mangled as "A@". Oh well... if (Value.uge(1) && Value.ule(10)) { --Temp; Temp.print(Out, false); @@ -348,10 +335,10 @@ void MicrosoftCXXNameMangler::mangleNumber(const llvm::APSInt &Value) { char *CurPtr = EndPtr; llvm::APSInt NibbleMask(Value.getBitWidth(), Value.isUnsigned()); NibbleMask = 0xf; - for (int i = 0, e = Value.getActiveBits() / 4; i != e; ++i) { + do { *--CurPtr = 'A' + Temp.And(NibbleMask).getLimitedValue(0xf); Temp = Temp.lshr(4); - } + } while (Temp != 0); Out.write(CurPtr, EndPtr-CurPtr); Out << '@'; } @@ -386,7 +373,7 @@ isTemplate(const NamedDecl *ND, dyn_cast<ClassTemplateSpecializationDecl>(ND)) { TypeSourceInfo *TSI = Spec->getTypeAsWritten(); if (TSI) { - TemplateSpecializationTypeLoc &TSTL = + TemplateSpecializationTypeLoc TSTL = cast<TemplateSpecializationTypeLoc>(TSI->getTypeLoc()); TemplateArgumentListInfo LI(TSTL.getLAngleLoc(), TSTL.getRAngleLoc()); for (unsigned i = 0, e = TSTL.getNumArgs(); i != e; ++i) @@ -784,6 +771,23 @@ MicrosoftCXXNameMangler::mangleIntegerLiteral(QualType T, } void +MicrosoftCXXNameMangler::mangleExpression(const Expr *E) { + // See if this is a constant expression. + llvm::APSInt Value; + if (E->isIntegerConstantExpr(Value, Context.getASTContext())) { + mangleIntegerLiteral(E->getType(), Value); + return; + } + + // As bad as this diagnostic is, it's better than crashing. + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot yet mangle expression type %0"); + Diags.Report(E->getExprLoc(), DiagID) + << E->getStmtClassName() << E->getSourceRange(); +} + +void MicrosoftCXXNameMangler::mangleTemplateArgs( const SmallVectorImpl<TemplateArgumentLoc> &TemplateArgs) { // <template-args> ::= {<type> | <integer-literal>}+ @ @@ -800,21 +804,19 @@ MicrosoftCXXNameMangler::mangleTemplateArgs( case TemplateArgument::Integral: mangleIntegerLiteral(TA.getIntegralType(), TA.getAsIntegral()); break; - case TemplateArgument::Expression: { - // See if this is a constant expression. - Expr *TAE = TA.getAsExpr(); - llvm::APSInt Value; - if (TAE->isIntegerConstantExpr(Value, Context.getASTContext())) { - mangleIntegerLiteral(TAE->getType(), Value); - break; - } - /* fallthrough */ - } default: { + case TemplateArgument::Expression: + mangleExpression(TA.getAsExpr()); + break; + case TemplateArgument::Template: + case TemplateArgument::TemplateExpansion: + case TemplateArgument::Declaration: + case TemplateArgument::NullPtr: + case TemplateArgument::Pack: { // Issue a diagnostic. DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this %select{ERROR|ERROR|pointer/reference|ERROR|" - "template|template pack expansion|expression|parameter pack}0 " + "cannot mangle this %select{ERROR|ERROR|pointer/reference|nullptr|" + "integral|template|template pack expansion|ERROR|parameter pack}0 " "template argument yet"); Diags.Report(TAL.getLocation(), DiagID) << TA.getKind() @@ -879,43 +881,60 @@ void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, // ::= 3 # ? // ::= 4 # ? // ::= 5 # not really based + bool HasConst = Quals.hasConst(), + HasVolatile = Quals.hasVolatile(); if (!IsMember) { - if (!Quals.hasVolatile()) { - if (!Quals.hasConst()) - Out << 'A'; - else - Out << 'B'; + if (HasConst && HasVolatile) { + Out << 'D'; + } else if (HasVolatile) { + Out << 'C'; + } else if (HasConst) { + Out << 'B'; } else { - if (!Quals.hasConst()) - Out << 'C'; - else - Out << 'D'; + Out << 'A'; } } else { - if (!Quals.hasVolatile()) { - if (!Quals.hasConst()) - Out << 'Q'; - else - Out << 'R'; + if (HasConst && HasVolatile) { + Out << 'T'; + } else if (HasVolatile) { + Out << 'S'; + } else if (HasConst) { + Out << 'R'; } else { - if (!Quals.hasConst()) - Out << 'S'; - else - Out << 'T'; + Out << 'Q'; } } // FIXME: For now, just drop all extension qualifiers on the floor. } -void MicrosoftCXXNameMangler::mangleTypeRepeated(QualType T, SourceRange Range) { +void MicrosoftCXXNameMangler::manglePointerQualifiers(Qualifiers Quals) { + // <pointer-cvr-qualifiers> ::= P # no qualifiers + // ::= Q # const + // ::= R # volatile + // ::= S # const volatile + bool HasConst = Quals.hasConst(), + HasVolatile = Quals.hasVolatile(); + if (HasConst && HasVolatile) { + Out << 'S'; + } else if (HasVolatile) { + Out << 'R'; + } else if (HasConst) { + Out << 'Q'; + } else { + Out << 'P'; + } +} + +void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, + SourceRange Range) { void *TypePtr = getASTContext().getCanonicalType(T).getAsOpaquePtr(); ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); if (Found == TypeBackReferences.end()) { size_t OutSizeBefore = Out.GetNumBytesInBuffer(); - mangleType(T,Range); + mangleType(T, Range, false); // See if it's worth creating a back reference. // Only types longer than 1 character are considered @@ -930,38 +949,30 @@ void MicrosoftCXXNameMangler::mangleTypeRepeated(QualType T, SourceRange Range) } } -void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range) { +void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, + bool MangleQualifiers) { // Only operate on the canonical type! T = getASTContext().getCanonicalType(T); - + Qualifiers Quals = T.getLocalQualifiers(); - if (Quals) { - // We have to mangle these now, while we still have enough information. - // <pointer-cvr-qualifiers> ::= P # pointer - // ::= Q # const pointer - // ::= R # volatile pointer - // ::= S # const volatile pointer - if (T->isAnyPointerType() || T->isMemberPointerType() || - T->isBlockPointerType()) { - if (!Quals.hasVolatile()) - Out << 'Q'; - else { - if (!Quals.hasConst()) - Out << 'R'; - else - Out << 'S'; - } - } else - // Just emit qualifiers like normal. - // NB: When we mangle a pointer/reference type, and the pointee - // type has no qualifiers, the lack of qualifier gets mangled - // in there. - mangleQualifiers(Quals, false); - } else if (T->isAnyPointerType() || T->isMemberPointerType() || - T->isBlockPointerType()) { - Out << 'P'; + // We have to mangle these now, while we still have enough information. + if (T->isAnyPointerType() || T->isMemberPointerType() || + T->isBlockPointerType()) { + manglePointerQualifiers(Quals); + } else if (Quals && MangleQualifiers) { + mangleQualifiers(Quals, false); } - switch (T->getTypeClass()) { + + SplitQualType split = T.split(); + const Type *ty = split.Ty; + + // If we're mangling a qualified array type, push the qualifiers to + // the element type. + if (split.Quals && isa<ArrayType>(T)) { + ty = Context.getASTContext().getAsArrayType(T); + } + + switch (ty->getTypeClass()) { #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) \ case Type::CLASS: \ @@ -969,7 +980,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range) { return; #define TYPE(CLASS, PARENT) \ case Type::CLASS: \ - mangleType(static_cast<const CLASS##Type*>(T.getTypePtr()), Range); \ + mangleType(cast<CLASS##Type>(ty), Range); \ break; #include "clang/AST/TypeNodes.def" #undef ABSTRACT_TYPE @@ -1059,6 +1070,8 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, SourceRange) { // Structors only appear in decls, so at this point we know it's not a // structor type. + // FIXME: This may not be lambda-friendly. + Out << "$$A6"; mangleType(T, NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, @@ -1117,14 +1130,14 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionType *T, ParmEnd = D->param_end(); Parm != ParmEnd; ++Parm) { TypeSourceInfo *TSI = (*Parm)->getTypeSourceInfo(); QualType Type = TSI ? TSI->getType() : (*Parm)->getType(); - mangleTypeRepeated(Type, (*Parm)->getSourceRange()); + mangleArgumentType(Type, (*Parm)->getSourceRange()); } } else { // Happens for function pointer type arguments for example. for (FunctionProtoType::arg_type_iterator Arg = Proto->arg_type_begin(), ArgEnd = Proto->arg_type_end(); Arg != ArgEnd; ++Arg) - mangleTypeRepeated(*Arg, SourceRange()); + mangleArgumentType(*Arg, SourceRange()); } // <builtin-type> ::= Z # ellipsis if (Proto->isVariadic()) @@ -1214,7 +1227,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T, if (CC == CC_Default) { if (IsInstMethod) { const FunctionProtoType *FPT = - T->getCanonicalTypeUnqualified().getAs<FunctionProtoType>(); + T->getCanonicalTypeUnqualified().castAs<FunctionProtoType>(); bool isVariadic = FPT->isVariadic(); CC = getASTContext().getDefaultCXXMethodCallConv(isVariadic); } else { @@ -1260,10 +1273,10 @@ void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T, // <class-type> ::= V <name> // <enum-type> ::= W <size> <name> void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) { - mangleType(static_cast<const TagType*>(T)); + mangleType(cast<TagType>(T)); } void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) { - mangleType(static_cast<const TagType*>(T)); + mangleType(cast<TagType>(T)); } void MicrosoftCXXNameMangler::mangleType(const TagType *T) { switch (T->getDecl()->getTagKind()) { @@ -1271,6 +1284,7 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { Out << 'T'; break; case TTK_Struct: + case TTK_Interface: Out << 'U'; break; case TTK_Class: @@ -1286,37 +1300,39 @@ void MicrosoftCXXNameMangler::mangleType(const TagType *T) { } // <type> ::= <array-type> -// <array-type> ::= P <cvr-qualifiers> [Y <dimension-count> <dimension>+] -// <element-type> # as global +// <array-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> +// [Y <dimension-count> <dimension>+] +// <element-type> # as global // ::= Q <cvr-qualifiers> [Y <dimension-count> <dimension>+] -// <element-type> # as param +// <element-type> # as param // It's supposed to be the other way around, but for some strange reason, it // isn't. Today this behavior is retained for the sole purpose of backwards // compatibility. void MicrosoftCXXNameMangler::mangleType(const ArrayType *T, bool IsGlobal) { // This isn't a recursive mangling, so now we have to do it all in this // one call. - if (IsGlobal) - Out << 'P'; - else + if (IsGlobal) { + manglePointerQualifiers(T->getElementType().getQualifiers()); + } else { Out << 'Q'; + } mangleExtraDimensions(T->getElementType()); } void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, SourceRange) { - mangleType(static_cast<const ArrayType *>(T), false); + mangleType(cast<ArrayType>(T), false); } void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, SourceRange) { - mangleType(static_cast<const ArrayType *>(T), false); + mangleType(cast<ArrayType>(T), false); } void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T, SourceRange) { - mangleType(static_cast<const ArrayType *>(T), false); + mangleType(cast<ArrayType>(T), false); } void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T, SourceRange) { - mangleType(static_cast<const ArrayType *>(T), false); + mangleType(cast<ArrayType>(T), false); } void MicrosoftCXXNameMangler::mangleExtraDimensions(QualType ElementTy) { SmallVector<llvm::APInt, 3> Dimensions; @@ -1409,10 +1425,8 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Out << '6'; mangleType(FT, NULL, false, false); } else { - if (!PointeeTy.hasQualifiers()) - // Lack of qualifiers is mangled as 'A'. - Out << 'A'; - mangleType(PointeeTy, Range); + mangleQualifiers(PointeeTy.getQualifiers(), false); + mangleType(PointeeTy, Range, false); } } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, @@ -1497,7 +1511,9 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, SourceRange Range) { Out << "_E"; - mangleType(T->getPointeeType(), Range); + + QualType pointee = T->getPointeeType(); + mangleType(pointee->castAs<FunctionProtoType>(), NULL, false, false); } void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *T, diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp index 39077d1766e8..0837509194bc 100644 --- a/lib/AST/NSAPI.cpp +++ b/lib/AST/NSAPI.cpp @@ -344,6 +344,7 @@ NSAPI::getNSNumberFactoryMethodKind(QualType T) const { case BuiltinType::ARCUnbridgedCast: case BuiltinType::Half: case BuiltinType::PseudoObject: + case BuiltinType::BuiltinFn: break; } diff --git a/lib/AST/ParentMap.cpp b/lib/AST/ParentMap.cpp index fa87afd0fa22..113592860b77 100644 --- a/lib/AST/ParentMap.cpp +++ b/lib/AST/ParentMap.cpp @@ -20,22 +20,63 @@ using namespace clang; typedef llvm::DenseMap<Stmt*, Stmt*> MapTy; -static void BuildParentMap(MapTy& M, Stmt* S) { - for (Stmt::child_range I = S->children(); I; ++I) - if (*I) { - // Prefer the first time we see this statement in the traversal. - // This is important for PseudoObjectExprs. - Stmt *&Parent = M[*I]; - if (!Parent) { - Parent = S; - BuildParentMap(M, *I); +enum OpaqueValueMode { + OV_Transparent, + OV_Opaque +}; + +static void BuildParentMap(MapTy& M, Stmt* S, + OpaqueValueMode OVMode = OV_Transparent) { + + switch (S->getStmtClass()) { + case Stmt::PseudoObjectExprClass: { + assert(OVMode == OV_Transparent && "Should not appear alongside OVEs"); + PseudoObjectExpr *POE = cast<PseudoObjectExpr>(S); + + M[POE->getSyntacticForm()] = S; + BuildParentMap(M, POE->getSyntacticForm(), OV_Transparent); + + for (PseudoObjectExpr::semantics_iterator I = POE->semantics_begin(), + E = POE->semantics_end(); + I != E; ++I) { + M[*I] = S; + BuildParentMap(M, *I, OV_Opaque); + } + break; + } + case Stmt::BinaryConditionalOperatorClass: { + assert(OVMode == OV_Transparent && "Should not appear alongside OVEs"); + BinaryConditionalOperator *BCO = cast<BinaryConditionalOperator>(S); + + M[BCO->getCommon()] = S; + BuildParentMap(M, BCO->getCommon(), OV_Transparent); + + M[BCO->getCond()] = S; + BuildParentMap(M, BCO->getCond(), OV_Opaque); + + M[BCO->getTrueExpr()] = S; + BuildParentMap(M, BCO->getTrueExpr(), OV_Opaque); + + M[BCO->getFalseExpr()] = S; + BuildParentMap(M, BCO->getFalseExpr(), OV_Transparent); + + break; + } + case Stmt::OpaqueValueExprClass: + if (OVMode == OV_Transparent) { + OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(S); + M[OVE->getSourceExpr()] = S; + BuildParentMap(M, OVE->getSourceExpr(), OV_Transparent); + } + break; + default: + for (Stmt::child_range I = S->children(); I; ++I) { + if (*I) { + M[*I] = S; + BuildParentMap(M, *I, OVMode); } } - - // Also include the source expr tree of an OpaqueValueExpr in the map. - if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) { - M[OVE->getSourceExpr()] = S; - BuildParentMap(M, OVE->getSourceExpr()); + break; } } diff --git a/lib/AST/RawCommentList.cpp b/lib/AST/RawCommentList.cpp index a5a32870577a..80b627293e42 100644 --- a/lib/AST/RawCommentList.cpp +++ b/lib/AST/RawCommentList.cpp @@ -143,11 +143,10 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const { // a separate allocator for all temporary stuff. llvm::BumpPtrAllocator Allocator; - comments::CommandTraits Traits; - comments::Lexer L(Allocator, Traits, - Range.getBegin(), comments::CommentOptions(), + comments::Lexer L(Allocator, Context.getCommentCommandTraits(), + Range.getBegin(), RawText.begin(), RawText.end()); - comments::BriefParser P(L, Traits); + comments::BriefParser P(L, Context.getCommentCommandTraits()); const std::string Result = P.Parse(); const unsigned BriefTextLength = Result.size(); @@ -160,19 +159,22 @@ const char *RawComment::extractBriefText(const ASTContext &Context) const { } comments::FullComment *RawComment::parse(const ASTContext &Context, + const Preprocessor *PP, const Decl *D) const { // Make sure that RawText is valid. getRawText(Context.getSourceManager()); - comments::CommandTraits Traits; - comments::Lexer L(Context.getAllocator(), Traits, - getSourceRange().getBegin(), comments::CommentOptions(), + comments::Lexer L(Context.getAllocator(), Context.getCommentCommandTraits(), + getSourceRange().getBegin(), RawText.begin(), RawText.end()); comments::Sema S(Context.getAllocator(), Context.getSourceManager(), - Context.getDiagnostics(), Traits); + Context.getDiagnostics(), + Context.getCommentCommandTraits(), + PP); S.setDecl(D); comments::Parser P(L, S, Context.getAllocator(), Context.getSourceManager(), - Context.getDiagnostics(), Traits); + Context.getDiagnostics(), + Context.getCommentCommandTraits()); return P.parseFullComment(); } @@ -182,26 +184,22 @@ bool containsOnlyWhitespace(StringRef Str) { return Str.find_first_not_of(" \t\f\v\r\n") == StringRef::npos; } -bool onlyWhitespaceBetweenComments(SourceManager &SM, - const RawComment &C1, const RawComment &C2) { - std::pair<FileID, unsigned> C1EndLocInfo = SM.getDecomposedLoc( - C1.getSourceRange().getEnd()); - std::pair<FileID, unsigned> C2BeginLocInfo = SM.getDecomposedLoc( - C2.getSourceRange().getBegin()); +bool onlyWhitespaceBetween(SourceManager &SM, + SourceLocation Loc1, SourceLocation Loc2) { + std::pair<FileID, unsigned> Loc1Info = SM.getDecomposedLoc(Loc1); + std::pair<FileID, unsigned> Loc2Info = SM.getDecomposedLoc(Loc2); - // Question does not make sense if comments are located in different files. - if (C1EndLocInfo.first != C2BeginLocInfo.first) + // Question does not make sense if locations are in different files. + if (Loc1Info.first != Loc2Info.first) return false; bool Invalid = false; - const char *Buffer = SM.getBufferData(C1EndLocInfo.first, &Invalid).data(); + const char *Buffer = SM.getBufferData(Loc1Info.first, &Invalid).data(); if (Invalid) return false; - StringRef TextBetweenComments(Buffer + C1EndLocInfo.second, - C2BeginLocInfo.second - C1EndLocInfo.second); - - return containsOnlyWhitespace(TextBetweenComments); + StringRef Text(Buffer + Loc1Info.second, Loc2Info.second - Loc1Info.second); + return containsOnlyWhitespace(Text); } } // unnamed namespace @@ -221,11 +219,13 @@ void RawCommentList::addComment(const RawComment &RC, } if (OnlyWhitespaceSeen) { - if (!onlyWhitespaceBetweenComments(SourceMgr, LastComment, RC)) + if (!onlyWhitespaceBetween(SourceMgr, + PrevCommentEndLoc, + RC.getSourceRange().getBegin())) OnlyWhitespaceSeen = false; } - LastComment = RC; + PrevCommentEndLoc = RC.getSourceRange().getEnd(); // Ordinary comments are not interesting for us. if (RC.isOrdinary()) @@ -244,15 +244,20 @@ void RawCommentList::addComment(const RawComment &RC, // Merge comments only if there is only whitespace between them. // Can't merge trailing and non-trailing comments. - // Merge trailing comments if they are on same or consecutive lines. + // Merge comments if they are on same or consecutive lines. + bool Merged = false; if (OnlyWhitespaceSeen && - (C1.isTrailingComment() == C2.isTrailingComment()) && - (!C1.isTrailingComment() || - C1.getEndLine(SourceMgr) + 1 >= C2.getBeginLine(SourceMgr))) { - SourceRange MergedRange(C1.getSourceRange().getBegin(), - C2.getSourceRange().getEnd()); - *Comments.back() = RawComment(SourceMgr, MergedRange, true); - } else + (C1.isTrailingComment() == C2.isTrailingComment())) { + unsigned C1EndLine = C1.getEndLine(SourceMgr); + unsigned C2BeginLine = C2.getBeginLine(SourceMgr); + if (C1EndLine + 1 == C2BeginLine || C1EndLine == C2BeginLine) { + SourceRange MergedRange(C1.getSourceRange().getBegin(), + C2.getSourceRange().getEnd()); + *Comments.back() = RawComment(SourceMgr, MergedRange, true); + Merged = true; + } + } + if (!Merged) Comments.push_back(new (Allocator) RawComment(RC)); OnlyWhitespaceSeen = true; diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index d5df63f7d151..4dfffc45e49c 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -789,8 +789,8 @@ protected: void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); } void setDataSize(uint64_t NewSize) { DataSize = NewSize; } - RecordLayoutBuilder(const RecordLayoutBuilder&); // DO NOT IMPLEMENT - void operator=(const RecordLayoutBuilder&); // DO NOT IMPLEMENT + RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION; + void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION; public: static const CXXMethodDecl *ComputeKeyFunction(const CXXRecordDecl *RD); }; @@ -1557,6 +1557,13 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { bool Allowed = EmptySubobjects->CanPlaceBaseAtOffset(Base, Offset); (void)Allowed; assert(Allowed && "Base subobject externally placed at overlapping offset"); + + if (InferAlignment && Offset < getDataSize().RoundUpToAlignment(BaseAlign)){ + // The externally-supplied base offset is before the base offset we + // computed. Assume that the structure is packed. + Alignment = CharUnits::One(); + InferAlignment = false; + } } if (!Base->Class->isEmpty()) { @@ -1574,12 +1581,12 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { } void RecordLayoutBuilder::InitializeLayout(const Decl *D) { - if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) + if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) { IsUnion = RD->isUnion(); + IsMsStruct = RD->isMsStruct(Context); + } - Packed = D->hasAttr<PackedAttr>(); - - IsMsStruct = D->hasAttr<MsStructAttr>(); + Packed = D->hasAttr<PackedAttr>(); // Honor the default struct packing maximum alignment flag. if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) { @@ -1616,7 +1623,6 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) { if (ExternalLayout) { if (ExternalAlign > 0) { Alignment = Context.toCharUnitsFromBits(ExternalAlign); - UnpackedAlignment = Alignment; } else { // The external source didn't have alignment information; infer it. InferAlignment = true; @@ -2085,7 +2091,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { ZeroLengthBitfield = 0; } - if (Context.getLangOpts().MSBitfields || IsMsStruct) { + if (IsMsStruct) { // If MS bitfield layout is required, figure out what type is being // laid out and align the field to the width of that type. @@ -2166,11 +2172,6 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { } void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { - if (ExternalLayout) { - setSize(ExternalSize); - return; - } - // In C++, records cannot be of size 0. if (Context.getLangOpts().CPlusPlus && getSizeInBits() == 0) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { @@ -2184,20 +2185,37 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { setSize(CharUnits::One()); } + // Finally, round the size of the record up to the alignment of the + // record itself. + uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte; + uint64_t UnpackedSizeInBits = + llvm::RoundUpToAlignment(getSizeInBits(), + Context.toBits(UnpackedAlignment)); + CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits); + uint64_t RoundedSize + = llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment)); + + if (ExternalLayout) { + // If we're inferring alignment, and the external size is smaller than + // our size after we've rounded up to alignment, conservatively set the + // alignment to 1. + if (InferAlignment && ExternalSize < RoundedSize) { + Alignment = CharUnits::One(); + InferAlignment = false; + } + setSize(ExternalSize); + return; + } + + // MSVC doesn't round up to the alignment of the record with virtual bases. if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { if (isMicrosoftCXXABI() && RD->getNumVBases()) return; } - // Finally, round the size of the record up to the alignment of the - // record itself. - uint64_t UnpaddedSize = getSizeInBits() - UnfilledBitsInLastByte; - uint64_t UnpackedSizeInBits = - llvm::RoundUpToAlignment(getSizeInBits(), - Context.toBits(UnpackedAlignment)); - CharUnits UnpackedSize = Context.toCharUnitsFromBits(UnpackedSizeInBits); - setSize(llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment))); + // Set the size to the final size. + setSize(RoundedSize); unsigned CharBitNum = Context.getTargetInfo().getCharWidth(); if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) { @@ -2255,7 +2273,7 @@ RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field, if (InferAlignment && ExternalFieldOffset < ComputedOffset) { // The externally-supplied field offset is before the field offset we // computed. Assume that the structure is packed. - Alignment = CharUnits::fromQuantity(1); + Alignment = CharUnits::One(); InferAlignment = false; } @@ -2263,6 +2281,20 @@ RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field, return ExternalFieldOffset; } +/// \brief Get diagnostic %select index for tag kind for +/// field padding diagnostic message. +/// WARNING: Indexes apply to particular diagnostics only! +/// +/// \returns diagnostic %select index. +static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) { + switch (Tag) { + case TTK_Struct: return 0; + case TTK_Interface: return 1; + case TTK_Class: return 2; + default: llvm_unreachable("Invalid tag kind for field padding diagnostic!"); + } +} + void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset, uint64_t UnpackedOffset, @@ -2291,14 +2323,14 @@ void RecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, } if (D->getIdentifier()) Diag(D->getLocation(), diag::warn_padded_struct_field) - << (D->getParent()->isStruct() ? 0 : 1) // struct|class + << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) << Context.getTypeDeclType(D->getParent()) << PadSize << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1) // plural or not << D->getIdentifier(); else Diag(D->getLocation(), diag::warn_padded_struct_anon_field) - << (D->getParent()->isStruct() ? 0 : 1) // struct|class + << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) << Context.getTypeDeclType(D->getParent()) << PadSize << (InBits ? 1 : 0) /*(byte|bit)*/ << (PadSize > 1); // plural or not @@ -2508,8 +2540,8 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, assert(D && D->isThisDeclarationADefinition() && "Invalid interface decl!"); // Look up this layout, if already laid out, return what we have. - ObjCContainerDecl *Key = - Impl ? (ObjCContainerDecl*) Impl : (ObjCContainerDecl*) D; + const ObjCContainerDecl *Key = + Impl ? (const ObjCContainerDecl*) Impl : (const ObjCContainerDecl*) D; if (const ASTRecordLayout *Entry = ObjCLayouts[Key]) return *Entry; diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 77452c9d9d1c..eafcf92eee82 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -20,6 +20,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -320,15 +321,52 @@ bool Stmt::hasImplicitControlFlow() const { } } -Expr *AsmStmt::getOutputExpr(unsigned i) { - return cast<Expr>(Exprs[i]); +std::string AsmStmt::generateAsmString(ASTContext &C) const { + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->generateAsmString(C); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->generateAsmString(C); + llvm_unreachable("unknown asm statement kind!"); } -/// getOutputConstraint - Return the constraint string for the specified -/// output operand. All output constraints are known to be non-empty (either -/// '=' or '+'). StringRef AsmStmt::getOutputConstraint(unsigned i) const { - return getOutputConstraintLiteral(i)->getString(); + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->getOutputConstraint(i); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->getOutputConstraint(i); + llvm_unreachable("unknown asm statement kind!"); +} + +const Expr *AsmStmt::getOutputExpr(unsigned i) const { + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->getOutputExpr(i); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->getOutputExpr(i); + llvm_unreachable("unknown asm statement kind!"); +} + +StringRef AsmStmt::getInputConstraint(unsigned i) const { + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->getInputConstraint(i); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->getInputConstraint(i); + llvm_unreachable("unknown asm statement kind!"); +} + +const Expr *AsmStmt::getInputExpr(unsigned i) const { + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->getInputExpr(i); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->getInputExpr(i); + llvm_unreachable("unknown asm statement kind!"); +} + +StringRef AsmStmt::getClobber(unsigned i) const { + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(this)) + return gccAsmStmt->getClobber(i); + if (const MSAsmStmt *msAsmStmt = dyn_cast<MSAsmStmt>(this)) + return msAsmStmt->getClobber(i); + llvm_unreachable("unknown asm statement kind!"); } /// getNumPlusOperands - Return the number of output operands that have a "+" @@ -341,22 +379,35 @@ unsigned AsmStmt::getNumPlusOperands() const { return Res; } -Expr *AsmStmt::getInputExpr(unsigned i) { +StringRef GCCAsmStmt::getClobber(unsigned i) const { + return getClobberStringLiteral(i)->getString(); +} + +Expr *GCCAsmStmt::getOutputExpr(unsigned i) { + return cast<Expr>(Exprs[i]); +} + +/// getOutputConstraint - Return the constraint string for the specified +/// output operand. All output constraints are known to be non-empty (either +/// '=' or '+'). +StringRef GCCAsmStmt::getOutputConstraint(unsigned i) const { + return getOutputConstraintLiteral(i)->getString(); +} + +Expr *GCCAsmStmt::getInputExpr(unsigned i) { return cast<Expr>(Exprs[i + NumOutputs]); } -void AsmStmt::setInputExpr(unsigned i, Expr *E) { +void GCCAsmStmt::setInputExpr(unsigned i, Expr *E) { Exprs[i + NumOutputs] = E; } - /// getInputConstraint - Return the specified input constraint. Unlike output /// constraints, these can be empty. -StringRef AsmStmt::getInputConstraint(unsigned i) const { +StringRef GCCAsmStmt::getInputConstraint(unsigned i) const { return getInputConstraintLiteral(i)->getString(); } - -void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, +void GCCAsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, IdentifierInfo **Names, StringLiteral **Constraints, Stmt **Exprs, @@ -390,7 +441,7 @@ void AsmStmt::setOutputsAndInputsAndClobbers(ASTContext &C, /// getNamedOperand - Given a symbolic operand reference like %[foo], /// translate this into a numeric value needed to reference the same operand. /// This returns -1 if the operand name is invalid. -int AsmStmt::getNamedOperand(StringRef SymbolicName) const { +int GCCAsmStmt::getNamedOperand(StringRef SymbolicName) const { unsigned NumPlusOperands = 0; // Check if this is an output operand. @@ -410,7 +461,7 @@ int AsmStmt::getNamedOperand(StringRef SymbolicName) const { /// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. -unsigned AsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, +unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, ASTContext &C, unsigned &DiagOffs) const { StringRef Str = getAsmString()->getString(); const char *StrStart = Str.begin(); @@ -548,6 +599,44 @@ unsigned AsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, } } +/// Assemble final IR asm string (GCC-style). +std::string GCCAsmStmt::generateAsmString(ASTContext &C) const { + // Analyze the asm string to decompose it into its pieces. We know that Sema + // has already done this, so it is guaranteed to be successful. + SmallVector<GCCAsmStmt::AsmStringPiece, 4> Pieces; + unsigned DiagOffs; + AnalyzeAsmString(Pieces, C, DiagOffs); + + std::string AsmString; + for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { + if (Pieces[i].isString()) + AsmString += Pieces[i].getString(); + else if (Pieces[i].getModifier() == '\0') + AsmString += '$' + llvm::utostr(Pieces[i].getOperandNo()); + else + AsmString += "${" + llvm::utostr(Pieces[i].getOperandNo()) + ':' + + Pieces[i].getModifier() + '}'; + } + return AsmString; +} + +/// Assemble final IR asm string (MS-style). +std::string MSAsmStmt::generateAsmString(ASTContext &C) const { + // FIXME: This needs to be translated into the IR string representation. + return AsmStr; +} + +Expr *MSAsmStmt::getOutputExpr(unsigned i) { + return cast<Expr>(Exprs[i]); +} + +Expr *MSAsmStmt::getInputExpr(unsigned i) { + return cast<Expr>(Exprs[i + NumOutputs]); +} +void MSAsmStmt::setInputExpr(unsigned i, Expr *E) { + Exprs[i + NumOutputs] = E; +} + QualType CXXCatchStmt::getCaughtType() const { if (ExceptionDecl) return ExceptionDecl->getType(); @@ -558,15 +647,14 @@ QualType CXXCatchStmt::getCaughtType() const { // Constructors //===----------------------------------------------------------------------===// -AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, - bool isvolatile, bool msasm, - unsigned numoutputs, unsigned numinputs, - IdentifierInfo **names, StringLiteral **constraints, - Expr **exprs, StringLiteral *asmstr, unsigned numclobbers, - StringLiteral **clobbers, SourceLocation rparenloc) - : Stmt(AsmStmtClass), AsmLoc(asmloc), RParenLoc(rparenloc), AsmStr(asmstr) - , IsSimple(issimple), IsVolatile(isvolatile), MSAsm(msasm) - , NumOutputs(numoutputs), NumInputs(numinputs), NumClobbers(numclobbers) { +GCCAsmStmt::GCCAsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, + bool isvolatile, unsigned numoutputs, unsigned numinputs, + IdentifierInfo **names, StringLiteral **constraints, + Expr **exprs, StringLiteral *asmstr, + unsigned numclobbers, StringLiteral **clobbers, + SourceLocation rparenloc) + : AsmStmt(GCCAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, + numinputs, numclobbers), RParenLoc(rparenloc), AsmStr(asmstr) { unsigned NumExprs = NumOutputs + NumInputs; @@ -585,26 +673,37 @@ AsmStmt::AsmStmt(ASTContext &C, SourceLocation asmloc, bool issimple, MSAsmStmt::MSAsmStmt(ASTContext &C, SourceLocation asmloc, SourceLocation lbraceloc, bool issimple, bool isvolatile, - ArrayRef<Token> asmtoks, ArrayRef<IdentifierInfo*> inputs, - ArrayRef<IdentifierInfo*> outputs, StringRef asmstr, - ArrayRef<StringRef> clobbers, SourceLocation endloc) - : Stmt(MSAsmStmtClass), AsmLoc(asmloc), LBraceLoc(lbraceloc), EndLoc(endloc), - AsmStr(asmstr.str()), IsSimple(issimple), IsVolatile(isvolatile), - NumAsmToks(asmtoks.size()), NumInputs(inputs.size()), - NumOutputs(outputs.size()), NumClobbers(clobbers.size()) { + ArrayRef<Token> asmtoks, unsigned numoutputs, + unsigned numinputs, ArrayRef<IdentifierInfo*> names, + ArrayRef<StringRef> constraints, ArrayRef<Expr*> exprs, + StringRef asmstr, ArrayRef<StringRef> clobbers, + SourceLocation endloc) + : AsmStmt(MSAsmStmtClass, asmloc, issimple, isvolatile, numoutputs, + numinputs, clobbers.size()), LBraceLoc(lbraceloc), + EndLoc(endloc), AsmStr(asmstr.str()), NumAsmToks(asmtoks.size()) { unsigned NumExprs = NumOutputs + NumInputs; Names = new (C) IdentifierInfo*[NumExprs]; - for (unsigned i = 0, e = NumOutputs; i != e; ++i) - Names[i] = outputs[i]; - for (unsigned i = NumOutputs, e = NumExprs; i != e; ++i) - Names[i] = inputs[i]; + for (unsigned i = 0, e = NumExprs; i != e; ++i) + Names[i] = names[i]; + + Exprs = new (C) Stmt*[NumExprs]; + for (unsigned i = 0, e = NumExprs; i != e; ++i) + Exprs[i] = exprs[i]; AsmToks = new (C) Token[NumAsmToks]; for (unsigned i = 0, e = NumAsmToks; i != e; ++i) AsmToks[i] = asmtoks[i]; + Constraints = new (C) StringRef[NumExprs]; + for (unsigned i = 0, e = NumExprs; i != e; ++i) { + size_t size = constraints[i].size(); + char *dest = new (C) char[size]; + std::strncpy(dest, constraints[i].data(), size); + Constraints[i] = StringRef(dest, size); + } + Clobbers = new (C) StringRef[NumClobbers]; for (unsigned i = 0, e = NumClobbers; i != e; ++i) { // FIXME: Avoid the allocation/copy if at all possible. diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 962e35269c18..fbc990f6b3c2 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements the Stmt::dump/Stmt::print methods, which dump out the +// This file implements the Stmt::dump method, which dumps out the // AST in a form that exposes type details and other fields. // //===----------------------------------------------------------------------===// @@ -30,6 +30,7 @@ namespace { SourceManager *SM; raw_ostream &OS; unsigned IndentLevel; + bool IsFirstLine; /// MaxDepth - When doing a normal dump (not dumpAll) we only want to dump /// the first few levels of an AST. This keeps track of how many ast levels @@ -41,46 +42,64 @@ namespace { const char *LastLocFilename; unsigned LastLocLine; + class IndentScope { + StmtDumper &Dumper; + public: + IndentScope(StmtDumper &Dumper) : Dumper(Dumper) { + Dumper.indent(); + } + ~IndentScope() { + Dumper.unindent(); + } + }; + public: StmtDumper(SourceManager *sm, raw_ostream &os, unsigned maxDepth) - : SM(sm), OS(os), IndentLevel(0-1), MaxDepth(maxDepth) { + : SM(sm), OS(os), IndentLevel(0), IsFirstLine(true), MaxDepth(maxDepth) { LastLocFilename = ""; LastLocLine = ~0U; } + ~StmtDumper() { + OS << "\n"; + } + void DumpSubTree(Stmt *S) { // Prune the recursion if not using dump all. if (MaxDepth == 0) return; - ++IndentLevel; - if (S) { - if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) - VisitDeclStmt(DS); - else { - Visit(S); - - // Print out children. - Stmt::child_range CI = S->children(); - if (CI) { - while (CI) { - OS << '\n'; - DumpSubTree(*CI++); - } - } - } - OS << ')'; - } else { - Indent(); + IndentScope Indent(*this); + + if (!S) { OS << "<<<NULL>>>"; + return; + } + + if (DeclStmt* DS = dyn_cast<DeclStmt>(S)) { + VisitDeclStmt(DS); + return; } - --IndentLevel; + + Visit(S); + for (Stmt::child_range CI = S->children(); CI; CI++) + DumpSubTree(*CI); } void DumpDeclarator(Decl *D); - void Indent() const { - for (int i = 0, e = IndentLevel; i < e; ++i) - OS << " "; + void indent() { + if (IsFirstLine) + IsFirstLine = false; + else + OS << "\n"; + OS.indent(IndentLevel * 2); + OS << "("; + IndentLevel++; + } + + void unindent() { + OS << ")"; + IndentLevel--; } void DumpType(QualType T) { @@ -96,9 +115,8 @@ namespace { } void DumpDeclRef(Decl *node); void DumpStmt(const Stmt *Node) { - Indent(); - OS << "(" << Node->getStmtClassName() - << " " << (void*)Node; + OS << Node->getStmtClassName() + << " " << (const void*)Node; DumpSourceRange(Node); } void DumpValueKind(ExprValueKind K) { @@ -262,7 +280,7 @@ void StmtDumper::DumpDeclarator(Decl *D) { // If this is a vardecl with an initializer, emit it. if (VarDecl *V = dyn_cast<VarDecl>(VD)) { if (V->getInit()) { - OS << " =\n"; + OS << " ="; DumpSubTree(V->getInit()); } } @@ -294,9 +312,9 @@ void StmtDumper::DumpDeclarator(Decl *D) { } else if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) { OS << "label " << *LD; } else if (StaticAssertDecl *SAD = dyn_cast<StaticAssertDecl>(D)) { - OS << "\"static_assert(\n"; + OS << "\"static_assert("; DumpSubTree(SAD->getAssertExpr()); - OS << ",\n"; + OS << ","; DumpSubTree(SAD->getMessage()); OS << ");\""; } else { @@ -306,17 +324,12 @@ void StmtDumper::DumpDeclarator(Decl *D) { void StmtDumper::VisitDeclStmt(DeclStmt *Node) { DumpStmt(Node); - OS << "\n"; for (DeclStmt::decl_iterator DI = Node->decl_begin(), DE = Node->decl_end(); DI != DE; ++DI) { + IndentScope Indent(*this); Decl* D = *DI; - ++IndentLevel; - Indent(); OS << (void*) D << " "; DumpDeclarator(D); - if (DI+1 != DE) - OS << "\n"; - --IndentLevel; } } @@ -503,35 +516,29 @@ void StmtDumper::VisitBlockExpr(BlockExpr *Node) { BlockDecl *block = Node->getBlockDecl(); OS << " decl=" << block; - IndentLevel++; if (block->capturesCXXThis()) { - OS << '\n'; Indent(); OS << "(capture this)"; + IndentScope Indent(*this); + OS << "capture this"; } for (BlockDecl::capture_iterator i = block->capture_begin(), e = block->capture_end(); i != e; ++i) { - OS << '\n'; - Indent(); - OS << "(capture "; + IndentScope Indent(*this); + OS << "capture "; if (i->isByRef()) OS << "byref "; if (i->isNested()) OS << "nested "; if (i->getVariable()) DumpDeclRef(i->getVariable()); if (i->hasCopyExpr()) DumpSubTree(i->getCopyExpr()); - OS << ")"; } - IndentLevel--; - OS << '\n'; DumpSubTree(block->getBody()); } void StmtDumper::VisitOpaqueValueExpr(OpaqueValueExpr *Node) { DumpExpr(Node); - if (Expr *Source = Node->getSourceExpr()) { - OS << '\n'; + if (Expr *Source = Node->getSourceExpr()) DumpSubTree(Source); - } } // GNU extensions. @@ -589,15 +596,11 @@ void StmtDumper::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { void StmtDumper::VisitExprWithCleanups(ExprWithCleanups *Node) { DumpExpr(Node); - ++IndentLevel; for (unsigned i = 0, e = Node->getNumObjects(); i != e; ++i) { - OS << "\n"; - Indent(); - OS << "(cleanup "; + IndentScope Indent(*this); + OS << "cleanup "; DumpDeclRef(Node->getObject(i)); - OS << ")"; } - --IndentLevel; } void StmtDumper::DumpCXXTemporary(CXXTemporary *Temporary) { @@ -734,7 +737,6 @@ void Stmt::dump(SourceManager &SM) const { void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { StmtDumper P(&SM, OS, 4); P.DumpSubTree(const_cast<Stmt*>(this)); - OS << "\n"; } /// dump - This does a local dump of the specified AST fragment. It dumps the @@ -743,19 +745,16 @@ void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { void Stmt::dump() const { StmtDumper P(0, llvm::errs(), 4); P.DumpSubTree(const_cast<Stmt*>(this)); - llvm::errs() << "\n"; } /// dumpAll - This does a dump of the specified AST fragment and all subtrees. void Stmt::dumpAll(SourceManager &SM) const { StmtDumper P(&SM, llvm::errs(), ~0U); P.DumpSubTree(const_cast<Stmt*>(this)); - llvm::errs() << "\n"; } /// dumpAll - This does a dump of the specified AST fragment and all subtrees. void Stmt::dumpAll() const { StmtDumper P(0, llvm::errs(), ~0U); P.DumpSubTree(const_cast<Stmt*>(this)); - llvm::errs() << "\n"; } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index c0960ce6a244..57eb1a95181c 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -61,7 +61,7 @@ namespace { void PrintRawCompoundStmt(CompoundStmt *S); void PrintRawDecl(Decl *D); - void PrintRawDeclStmt(DeclStmt *S); + void PrintRawDeclStmt(const DeclStmt *S); void PrintRawIfStmt(IfStmt *If); void PrintRawCXXCatchStmt(CXXCatchStmt *Catch); void PrintCallArgs(CallExpr *E); @@ -121,8 +121,8 @@ void StmtPrinter::PrintRawDecl(Decl *D) { D->print(OS, Policy, IndentLevel); } -void StmtPrinter::PrintRawDeclStmt(DeclStmt *S) { - DeclStmt::decl_iterator Begin = S->decl_begin(), End = S->decl_end(); +void StmtPrinter::PrintRawDeclStmt(const DeclStmt *S) { + DeclStmt::const_decl_iterator Begin = S->decl_begin(), End = S->decl_end(); SmallVector<Decl*, 2> Decls; for ( ; Begin != End; ++Begin) Decls.push_back(*Begin); @@ -187,7 +187,10 @@ void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) { void StmtPrinter::PrintRawIfStmt(IfStmt *If) { OS << "if ("; - PrintExpr(If->getCond()); + if (const DeclStmt *DS = If->getConditionVariableDeclStmt()) + PrintRawDeclStmt(DS); + else + PrintExpr(If->getCond()); OS << ')'; if (CompoundStmt *CS = dyn_cast<CompoundStmt>(If->getThen())) { @@ -224,7 +227,10 @@ void StmtPrinter::VisitIfStmt(IfStmt *If) { void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { Indent() << "switch ("; - PrintExpr(Node->getCond()); + if (const DeclStmt *DS = Node->getConditionVariableDeclStmt()) + PrintRawDeclStmt(DS); + else + PrintExpr(Node->getCond()); OS << ")"; // Pretty print compoundstmt bodies (very common). @@ -240,7 +246,10 @@ void StmtPrinter::VisitSwitchStmt(SwitchStmt *Node) { void StmtPrinter::VisitWhileStmt(WhileStmt *Node) { Indent() << "while ("; - PrintExpr(Node->getCond()); + if (const DeclStmt *DS = Node->getConditionVariableDeclStmt()) + PrintRawDeclStmt(DS); + else + PrintExpr(Node->getCond()); OS << ")\n"; PrintStmt(Node->getBody()); } @@ -366,7 +375,7 @@ void StmtPrinter::VisitReturnStmt(ReturnStmt *Node) { } -void StmtPrinter::VisitAsmStmt(AsmStmt *Node) { +void StmtPrinter::VisitGCCAsmStmt(GCCAsmStmt *Node) { Indent() << "asm "; if (Node->isVolatile()) @@ -422,7 +431,7 @@ void StmtPrinter::VisitAsmStmt(AsmStmt *Node) { if (i != 0) OS << ", "; - VisitStringLiteral(Node->getClobber(i)); + VisitStringLiteral(Node->getClobberStringLiteral(i)); } OS << ");\n"; @@ -734,10 +743,30 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { case BuiltinType::UInt128: OS << "Ui128"; break; } } -void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) { + +static void PrintFloatingLiteral(raw_ostream &OS, FloatingLiteral *Node, + bool PrintSuffix) { SmallString<16> Str; Node->getValue().toString(Str); OS << Str; + if (Str.find_first_not_of("-0123456789") == StringRef::npos) + OS << '.'; // Trailing dot in order to separate from ints. + + if (!PrintSuffix) + return; + + // Emit suffixes. Float literals are always a builtin float type. + switch (Node->getType()->getAs<BuiltinType>()->getKind()) { + default: llvm_unreachable("Unexpected type for float literal!"); + case BuiltinType::Half: break; // FIXME: suffix? + case BuiltinType::Double: break; // no suffix. + case BuiltinType::Float: OS << 'F'; break; + case BuiltinType::LongDouble: OS << 'L'; break; + } +} + +void StmtPrinter::VisitFloatingLiteral(FloatingLiteral *Node) { + PrintFloatingLiteral(OS, Node, /*PrintSuffix=*/true); } void StmtPrinter::VisitImaginaryLiteral(ImaginaryLiteral *Node) { @@ -907,7 +936,7 @@ void StmtPrinter::VisitExtVectorElementExpr(ExtVectorElementExpr *Node) { OS << Node->getAccessor().getName(); } void StmtPrinter::VisitCStyleCastExpr(CStyleCastExpr *Node) { - OS << "(" << Node->getType().getAsString(Policy) << ")"; + OS << "(" << Node->getTypeAsWritten().getAsString(Policy) << ")"; PrintExpr(Node->getSubExpr()); } void StmtPrinter::VisitCompoundLiteralExpr(CompoundLiteralExpr *Node) { @@ -1110,6 +1139,8 @@ void StmtPrinter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *Node) { PrintExpr(Node->getArg(0)); OS << ' ' << OpStrings[Kind]; } + } else if (Kind == OO_Arrow) { + PrintExpr(Node->getArg(0)); } else if (Kind == OO_Call) { PrintExpr(Node->getArg(0)); OS << '('; @@ -1217,7 +1248,12 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) { OS << Int->getValue().toString(10, /*isSigned*/false); break; } - case UserDefinedLiteral::LOK_Floating: + case UserDefinedLiteral::LOK_Floating: { + // Print floating literal without suffix. + FloatingLiteral *Float = cast<FloatingLiteral>(Node->getCookedLiteral()); + PrintFloatingLiteral(OS, Float, /*PrintSuffix=*/false); + break; + } case UserDefinedLiteral::LOK_String: case UserDefinedLiteral::LOK_Character: PrintExpr(Node->getCookedLiteral()); @@ -1379,10 +1415,12 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) { OS << "::"; OS << "new "; unsigned NumPlace = E->getNumPlacementArgs(); - if (NumPlace > 0) { + if (NumPlace > 0 && !isa<CXXDefaultArgExpr>(E->getPlacementArg(0))) { OS << "("; PrintExpr(E->getPlacementArg(0)); for (unsigned i = 1; i < NumPlace; ++i) { + if (isa<CXXDefaultArgExpr>(E->getPlacementArg(i))) + break; OS << ", "; PrintExpr(E->getPlacementArg(i)); } @@ -1429,6 +1467,7 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { OS << '.'; if (E->getQualifier()) E->getQualifier()->print(OS, Policy); + OS << "~"; std::string TypeS; if (IdentifierInfo *II = E->getDestroyedTypeIdentifier()) @@ -1531,6 +1570,7 @@ static const char *getTypeTraitName(UnaryTypeTrait UTT) { case UTT_IsFunction: return "__is_function"; case UTT_IsFundamental: return "__is_fundamental"; case UTT_IsIntegral: return "__is_integral"; + case UTT_IsInterfaceClass: return "__is_interface_class"; case UTT_IsLiteral: return "__is_literal"; case UTT_IsLvalueReference: return "__is_lvalue_reference"; case UTT_IsMemberFunctionPointer: return "__is_member_function_pointer"; @@ -1647,6 +1687,10 @@ void StmtPrinter::VisitSubstNonTypeTemplateParmExpr( Visit(Node->getReplacement()); } +void StmtPrinter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { + OS << *E->getParameterPack(); +} + void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){ PrintExpr(Node->GetTemporaryExpr()); } diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 2168b64d5b23..bfd3132506ec 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -158,7 +158,7 @@ void StmtProfiler::VisitReturnStmt(const ReturnStmt *S) { VisitStmt(S); } -void StmtProfiler::VisitAsmStmt(const AsmStmt *S) { +void StmtProfiler::VisitGCCAsmStmt(const GCCAsmStmt *S) { VisitStmt(S); ID.AddBoolean(S->isVolatile()); ID.AddBoolean(S->isSimple()); @@ -175,7 +175,7 @@ void StmtProfiler::VisitAsmStmt(const AsmStmt *S) { } ID.AddInteger(S->getNumClobbers()); for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) - VisitStringLiteral(S->getClobber(I)); + VisitStringLiteral(S->getClobberStringLiteral(I)); } void StmtProfiler::VisitMSAsmStmt(const MSAsmStmt *S) { @@ -973,6 +973,14 @@ void StmtProfiler::VisitSubstNonTypeTemplateParmExpr( Visit(E->getReplacement()); } +void StmtProfiler::VisitFunctionParmPackExpr(const FunctionParmPackExpr *S) { + VisitExpr(S); + VisitDecl(S->getParameterPack()); + ID.AddInteger(S->getNumExpansions()); + for (FunctionParmPackExpr::iterator I = S->begin(), E = S->end(); I != E; ++I) + VisitDecl(*I); +} + void StmtProfiler::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *S) { VisitExpr(S); @@ -1165,6 +1173,10 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { VisitDecl(Arg.getAsDecl()); break; + case TemplateArgument::NullPtr: + VisitType(Arg.getNullPtrType()); + break; + case TemplateArgument::Integral: Arg.getAsIntegral().Profile(ID); VisitType(Arg.getIntegralType()); diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index 95ff4edf1d6b..e9ee385457f8 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -77,7 +77,7 @@ TemplateArgument TemplateArgument::CreatePackCopy(ASTContext &Context, const TemplateArgument *Args, unsigned NumArgs) { if (NumArgs == 0) - return TemplateArgument(0, 0); + return getEmptyPack(); TemplateArgument *Storage = new (Context) TemplateArgument [NumArgs]; std::copy(Args, Args + NumArgs, Storage); @@ -99,12 +99,11 @@ bool TemplateArgument::isDependent() const { return true; case Declaration: - if (Decl *D = getAsDecl()) { - if (DeclContext *DC = dyn_cast<DeclContext>(D)) - return DC->isDependentContext(); - return D->getDeclContext()->isDependentContext(); - } - + if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl())) + return DC->isDependentContext(); + return getAsDecl()->getDeclContext()->isDependentContext(); + + case NullPtr: return false; case Integral: @@ -141,11 +140,11 @@ bool TemplateArgument::isInstantiationDependent() const { return true; case Declaration: - if (Decl *D = getAsDecl()) { - if (DeclContext *DC = dyn_cast<DeclContext>(D)) - return DC->isDependentContext(); - return D->getDeclContext()->isDependentContext(); - } + if (DeclContext *DC = dyn_cast<DeclContext>(getAsDecl())) + return DC->isDependentContext(); + return getAsDecl()->getDeclContext()->isDependentContext(); + + case NullPtr: return false; case Integral: @@ -174,6 +173,7 @@ bool TemplateArgument::isPackExpansion() const { case Integral: case Pack: case Template: + case NullPtr: return false; case TemplateExpansion: @@ -195,6 +195,7 @@ bool TemplateArgument::containsUnexpandedParameterPack() const { case Declaration: case Integral: case TemplateExpansion: + case NullPtr: break; case Type: @@ -286,12 +287,16 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const { switch (getKind()) { case Null: case Type: - case Declaration: case Expression: case Template: case TemplateExpansion: + case NullPtr: return TypeOrValue == Other.TypeOrValue; + case Declaration: + return getAsDecl() == Other.getAsDecl() && + isDeclForReferenceParam() && Other.isDeclForReferenceParam(); + case Integral: return getIntegralType() == Other.getIntegralType() && getAsIntegral() == Other.getAsIntegral(); @@ -319,12 +324,13 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const { case TemplateExpansion: return TemplateArgument(getAsTemplateOrTemplatePattern()); - + case Declaration: case Integral: case Pack: case Null: case Template: + case NullPtr: return TemplateArgument(); } @@ -348,18 +354,20 @@ void TemplateArgument::print(const PrintingPolicy &Policy, } case Declaration: { - if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(getAsDecl())) { - if (ND->getDeclName()) { - Out << *ND; - } else { - Out << "<anonymous>"; - } + NamedDecl *ND = cast<NamedDecl>(getAsDecl()); + if (ND->getDeclName()) { + // FIXME: distinguish between pointer and reference args? + Out << *ND; } else { - Out << "nullptr"; + Out << "<anonymous>"; } break; } - + + case NullPtr: + Out << "nullptr"; + break; + case Template: getAsTemplate().print(Out, Policy); break; @@ -411,6 +419,9 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { case TemplateArgument::Declaration: return getSourceDeclExpression()->getSourceRange(); + case TemplateArgument::NullPtr: + return getSourceNullPtrExpression()->getSourceRange(); + case TemplateArgument::Type: if (TypeSourceInfo *TSI = getTypeSourceInfo()) return TSI->getTypeLoc().getSourceRange(); @@ -430,6 +441,8 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { return SourceRange(getTemplateNameLoc(), getTemplateEllipsisLoc()); case TemplateArgument::Integral: + return getSourceIntegralExpression()->getSourceRange(); + case TemplateArgument::Pack: case TemplateArgument::Null: return SourceRange(); @@ -490,6 +503,7 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis, getTemplateNameLoc()); case TemplateArgument::Declaration: + case TemplateArgument::NullPtr: case TemplateArgument::Template: case TemplateArgument::Integral: case TemplateArgument::Pack: @@ -512,8 +526,9 @@ const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, return DB << Arg.getAsType(); case TemplateArgument::Declaration: - if (Decl *D = Arg.getAsDecl()) - return DB << D; + return DB << Arg.getAsDecl(); + + case TemplateArgument::NullPtr: return DB << "nullptr"; case TemplateArgument::Integral: diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index abefae44b2ba..580ec50ca1f8 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -288,18 +288,17 @@ QualType QualType::IgnoreParens(QualType T) { return T; } -/// \brief This will check for a TypedefType by removing any existing sugar -/// until it reaches a TypedefType or a non-sugared type. -template <> const TypedefType *Type::getAs() const { - const Type *Cur = this; - +/// \brief This will check for a T (which should be a Type which can act as +/// sugar, such as a TypedefType) by removing any existing sugar until it +/// reaches a T or a non-sugared type. +template<typename T> static const T *getAsSugar(const Type *Cur) { while (true) { - if (const TypedefType *TDT = dyn_cast<TypedefType>(Cur)) - return TDT; + if (const T *Sugar = dyn_cast<T>(Cur)) + return Sugar; switch (Cur->getTypeClass()) { #define ABSTRACT_TYPE(Class, Parent) #define TYPE(Class, Parent) \ - case Class: { \ + case Type::Class: { \ const Class##Type *Ty = cast<Class##Type>(Cur); \ if (!Ty->isSugared()) return 0; \ Cur = Ty->desugar().getTypePtr(); \ @@ -310,6 +309,14 @@ template <> const TypedefType *Type::getAs() const { } } +template <> const TypedefType *Type::getAs() const { + return getAsSugar<TypedefType>(this); +} + +template <> const TemplateSpecializationType *Type::getAs() const { + return getAsSugar<TemplateSpecializationType>(this); +} + /// getUnqualifiedDesugaredType - Pull any qualifiers and syntactic /// sugar off the given type. This should produce an object of the /// same dynamic type as the canonical type. @@ -357,9 +364,15 @@ bool Type::isStructureType() const { return RT->getDecl()->isStruct(); return false; } +bool Type::isInterfaceType() const { + if (const RecordType *RT = getAs<RecordType>()) + return RT->getDecl()->isInterface(); + return false; +} bool Type::isStructureOrClassType() const { if (const RecordType *RT = getAs<RecordType>()) - return RT->getDecl()->isStruct() || RT->getDecl()->isClass(); + return RT->getDecl()->isStruct() || RT->getDecl()->isClass() || + RT->getDecl()->isInterface(); return false; } bool Type::isVoidPointerType() const { @@ -499,10 +512,18 @@ const ObjCObjectPointerType *Type::getAsObjCInterfacePointerType() const { return 0; } -const CXXRecordDecl *Type::getCXXRecordDeclForPointerType() const { +const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const { + QualType PointeeType; if (const PointerType *PT = getAs<PointerType>()) - if (const RecordType *RT = PT->getPointeeType()->getAs<RecordType>()) - return dyn_cast<CXXRecordDecl>(RT->getDecl()); + PointeeType = PT->getPointeeType(); + else if (const ReferenceType *RT = getAs<ReferenceType>()) + PointeeType = RT->getPointeeType(); + else + return 0; + + if (const RecordType *RT = PointeeType->getAs<RecordType>()) + return dyn_cast<CXXRecordDecl>(RT->getDecl()); + return 0; } @@ -1205,8 +1226,6 @@ bool QualType::isCXX11PODType(ASTContext &Context) const { return false; case Qualifiers::OCL_None: - if (ty->isObjCLifetimeType()) - return false; break; } } @@ -1317,6 +1336,7 @@ TypeWithKeyword::getKeywordForTypeSpec(unsigned TypeSpec) { case TST_typename: return ETK_Typename; case TST_class: return ETK_Class; case TST_struct: return ETK_Struct; + case TST_interface: return ETK_Interface; case TST_union: return ETK_Union; case TST_enum: return ETK_Enum; } @@ -1327,6 +1347,7 @@ TypeWithKeyword::getTagTypeKindForTypeSpec(unsigned TypeSpec) { switch(TypeSpec) { case TST_class: return TTK_Class; case TST_struct: return TTK_Struct; + case TST_interface: return TTK_Interface; case TST_union: return TTK_Union; case TST_enum: return TTK_Enum; } @@ -1339,6 +1360,7 @@ TypeWithKeyword::getKeywordForTagTypeKind(TagTypeKind Kind) { switch (Kind) { case TTK_Class: return ETK_Class; case TTK_Struct: return ETK_Struct; + case TTK_Interface: return ETK_Interface; case TTK_Union: return ETK_Union; case TTK_Enum: return ETK_Enum; } @@ -1350,6 +1372,7 @@ TypeWithKeyword::getTagTypeKindForKeyword(ElaboratedTypeKeyword Keyword) { switch (Keyword) { case ETK_Class: return TTK_Class; case ETK_Struct: return TTK_Struct; + case ETK_Interface: return TTK_Interface; case ETK_Union: return TTK_Union; case ETK_Enum: return TTK_Enum; case ETK_None: // Fall through. @@ -1367,6 +1390,7 @@ TypeWithKeyword::KeywordIsTagTypeKind(ElaboratedTypeKeyword Keyword) { return false; case ETK_Class: case ETK_Struct: + case ETK_Interface: case ETK_Union: case ETK_Enum: return true; @@ -1381,6 +1405,7 @@ TypeWithKeyword::getKeywordName(ElaboratedTypeKeyword Keyword) { case ETK_Typename: return "typename"; case ETK_Class: return "class"; case ETK_Struct: return "struct"; + case ETK_Interface: return "__interface"; case ETK_Union: return "union"; case ETK_Enum: return "enum"; } @@ -1480,6 +1505,7 @@ StringRef BuiltinType::getName(const PrintingPolicy &Policy) const { case Dependent: return "<dependent type>"; case UnknownAny: return "<unknown type>"; case ARCUnbridgedCast: return "<ARC unbridged cast type>"; + case BuiltinFn: return "<builtin fn type>"; case ObjCId: return "id"; case ObjCClass: return "Class"; case ObjCSel: return "SEL"; @@ -1516,6 +1542,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_X86Pascal: return "pascal"; case CC_AAPCS: return "aapcs"; case CC_AAPCS_VFP: return "aapcs-vfp"; + case CC_PnaclCall: return "pnaclcall"; } llvm_unreachable("Invalid calling convention."); diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index c7bb7da4d17b..58c4cbd00c8a 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -98,23 +98,38 @@ void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, SourceLocation TypeLoc::getBeginLoc() const { TypeLoc Cur = *this; + TypeLoc LeftMost = Cur; while (true) { switch (Cur.getTypeLocClass()) { - // FIXME: Currently QualifiedTypeLoc does not have a source range - // case Qualified: case Elaborated: - case DependentName: - case DependentTemplateSpecialization: + LeftMost = Cur; break; + case FunctionProto: + if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) { + LeftMost = Cur; + break; + } + /* Fall through */ + case FunctionNoProto: + case ConstantArray: + case DependentSizedArray: + case IncompleteArray: + case VariableArray: + // FIXME: Currently QualifiedTypeLoc does not have a source range + case Qualified: + Cur = Cur.getNextTypeLoc(); + continue; default: - TypeLoc Next = Cur.getNextTypeLoc(); - if (Next.isNull()) break; - Cur = Next; + if (!Cur.getLocalSourceRange().getBegin().isInvalid()) + LeftMost = Cur; + Cur = Cur.getNextTypeLoc(); + if (Cur.isNull()) + break; continue; - } + } // switch break; - } - return Cur.getLocalSourceRange().getBegin(); + } // while + return LeftMost.getLocalSourceRange().getBegin(); } SourceLocation TypeLoc::getEndLoc() const { @@ -131,10 +146,15 @@ SourceLocation TypeLoc::getEndLoc() const { case DependentSizedArray: case IncompleteArray: case VariableArray: - case FunctionProto: case FunctionNoProto: Last = Cur; break; + case FunctionProto: + if (cast<FunctionProtoTypeLoc>(&Cur)->getTypePtr()->hasTrailingReturn()) + Last = TypeLoc(); + else + Last = Cur; + break; case Pointer: case BlockPointer: case MemberPointer: @@ -241,6 +261,7 @@ TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: + case BuiltinType::BuiltinFn: return TST_unspecified; } @@ -300,7 +321,9 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, case TemplateArgument::Null: case TemplateArgument::Declaration: case TemplateArgument::Integral: - case TemplateArgument::Pack: + case TemplateArgument::NullPtr: + llvm_unreachable("Impossible TemplateArgument"); + case TemplateArgument::Expression: ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr()); break; @@ -310,7 +333,7 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, Context.getTrivialTypeSourceInfo(Args[i].getAsType(), Loc)); break; - + case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { NestedNameSpecifierLocBuilder Builder; @@ -327,7 +350,11 @@ void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, ? SourceLocation() : Loc); break; - } + } + + case TemplateArgument::Pack: + ArgInfos[i] = TemplateArgumentLocInfo(); + break; } } } diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index c42117c82bf5..90b2ca9cce15 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -141,9 +141,6 @@ void TypePrinter::print(const Type *T, Qualifiers Quals, raw_ostream &OS, OS << "NULL TYPE"; return; } - - if (Policy.SuppressSpecifiers && T->isSpecifierType()) - return; SaveAndRestore<bool> PHVal(HasEmptyPlaceHolder, PlaceHolder.empty()); @@ -556,7 +553,8 @@ void TypePrinter::printExtVectorAfter(const ExtVectorType *T, raw_ostream &OS) { void FunctionProtoType::printExceptionSpecification(raw_ostream &OS, - PrintingPolicy Policy) const { + const PrintingPolicy &Policy) + const { if (hasDynamicExceptionSpec()) { OS << " throw("; @@ -646,6 +644,9 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, case CC_AAPCS_VFP: OS << " __attribute__((pcs(\"aapcs-vfp\")))"; break; + case CC_PnaclCall: + OS << " __attribute__((pnaclcall))"; + break; } if (Info.getNoReturn()) OS << " __attribute__((noreturn))"; @@ -798,6 +799,7 @@ void TypePrinter::printAtomicAfter(const AtomicType *T, raw_ostream &OS) { } /// Appends the given scope to the end of a string. void TypePrinter::AppendScope(DeclContext *DC, raw_ostream &OS) { if (DC->isTranslationUnit()) return; + if (DC->isFunctionOrMethod()) return; AppendScope(DC->getParent(), OS); if (NamespaceDecl *NS = dyn_cast<NamespaceDecl>(DC)) { @@ -1165,6 +1167,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, OS << ')'; break; } + case AttributedType::attr_pnaclcall: OS << "pnaclcall"; break; } OS << "))"; } @@ -1343,7 +1346,8 @@ PrintTemplateArgumentList(raw_ostream &OS, void FunctionProtoType::printExceptionSpecification(std::string &S, - PrintingPolicy Policy) const { + const PrintingPolicy &Policy) + const { if (hasDynamicExceptionSpec()) { S += " throw("; diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index 104530fc1305..33dad40c0c50 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -1891,6 +1891,9 @@ void VTableBuilder::dumpLayout(raw_ostream& Out) { if (MD->isPure()) Out << " [pure]"; + if (MD->isDeleted()) + Out << " [deleted]"; + ThunkInfo Thunk = VTableThunks.lookup(I); if (!Thunk.isEmpty()) { // If this function pointer has a return adjustment, dump it. diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp index 085049debdbe..8ecb26e8c19d 100644 --- a/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/lib/ASTMatchers/ASTMatchFinder.cpp @@ -27,10 +27,75 @@ namespace ast_matchers { namespace internal { namespace { +typedef MatchFinder::MatchCallback MatchCallback; + +/// \brief A \c RecursiveASTVisitor that builds a map from nodes to their +/// parents as defined by the \c RecursiveASTVisitor. +/// +/// Note that the relationship described here is purely in terms of AST +/// traversal - there are other relationships (for example declaration context) +/// in the AST that are better modeled by special matchers. +/// +/// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes. +class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> { +public: + /// \brief Maps from a node to its parent. + typedef llvm::DenseMap<const void*, ast_type_traits::DynTypedNode> ParentMap; + + /// \brief Builds and returns the translation unit's parent map. + /// + /// The caller takes ownership of the returned \c ParentMap. + static ParentMap *buildMap(TranslationUnitDecl &TU) { + ParentMapASTVisitor Visitor(new ParentMap); + Visitor.TraverseDecl(&TU); + return Visitor.Parents; + } + +private: + typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase; + + ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {} + + bool shouldVisitTemplateInstantiations() const { return true; } + bool shouldVisitImplicitCode() const { return true; } + + template <typename T> + bool TraverseNode(T *Node, bool (VisitorBase::*traverse)(T*)) { + if (Node == NULL) + return true; + if (ParentStack.size() > 0) + (*Parents)[Node] = ParentStack.back(); + ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node)); + bool Result = (this->*traverse)(Node); + ParentStack.pop_back(); + return Result; + } + + bool TraverseDecl(Decl *DeclNode) { + return TraverseNode(DeclNode, &VisitorBase::TraverseDecl); + } + + bool TraverseStmt(Stmt *StmtNode) { + return TraverseNode(StmtNode, &VisitorBase::TraverseStmt); + } + + ParentMap *Parents; + llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack; + + friend class RecursiveASTVisitor<ParentMapASTVisitor>; +}; + // We use memoization to avoid running the same matcher on the same // AST node twice. This pair is the key for looking up match // result. It consists of an ID of the MatcherInterface (for // identifying the matcher) and a pointer to the AST node. +// +// We currently only memoize on nodes whose pointers identify the +// nodes (\c Stmt and \c Decl, but not \c QualType or \c TypeLoc). +// For \c QualType and \c TypeLoc it is possible to implement +// generation of keys for each type. +// FIXME: Benchmark whether memoization of non-pointer typed nodes +// provides enough benefit for the additional amount of code. typedef std::pair<uint64_t, const void*> UntypedMatchInput; // Used to store the result of a match and possibly bound nodes. @@ -50,16 +115,16 @@ public: // descendants of a traversed node. max_depth is the maximum depth // to traverse: use 1 for matching the children and INT_MAX for // matching the descendants. - MatchChildASTVisitor(const UntypedBaseMatcher *BaseMatcher, + MatchChildASTVisitor(const DynTypedMatcher *Matcher, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, int MaxDepth, ASTMatchFinder::TraversalKind Traversal, ASTMatchFinder::BindKind Bind) - : BaseMatcher(BaseMatcher), + : Matcher(Matcher), Finder(Finder), Builder(Builder), - CurrentDepth(-1), + CurrentDepth(0), MaxDepth(MaxDepth), Traversal(Traversal), Bind(Bind), @@ -76,10 +141,23 @@ public: // Traverse*(c) for each child c of 'node'. // - Traverse*(c) in turn calls Traverse(c), completing the // recursion. - template <typename T> - bool findMatch(const T &Node) { + bool findMatch(const ast_type_traits::DynTypedNode &DynNode) { reset(); - traverse(Node); + if (const Decl *D = DynNode.get<Decl>()) + traverse(*D); + else if (const Stmt *S = DynNode.get<Stmt>()) + traverse(*S); + else if (const NestedNameSpecifier *NNS = + DynNode.get<NestedNameSpecifier>()) + traverse(*NNS); + else if (const NestedNameSpecifierLoc *NNSLoc = + DynNode.get<NestedNameSpecifierLoc>()) + traverse(*NNSLoc); + else if (const QualType *Q = DynNode.get<QualType>()) + traverse(*Q); + else if (const TypeLoc *T = DynNode.get<TypeLoc>()) + traverse(*T); + // FIXME: Add other base types after adding tests. return Matches; } @@ -87,9 +165,11 @@ public: // They are public only to allow CRTP to work. They are *not *part // of the public API of this class. bool TraverseDecl(Decl *DeclNode) { + ScopedIncrement ScopedDepth(&CurrentDepth); return (DeclNode == NULL) || traverse(*DeclNode); } bool TraverseStmt(Stmt *StmtNode) { + ScopedIncrement ScopedDepth(&CurrentDepth); const Stmt *StmtToTraverse = StmtNode; if (Traversal == ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses) { @@ -100,9 +180,39 @@ public: } return (StmtToTraverse == NULL) || traverse(*StmtToTraverse); } + // We assume that the QualType and the contained type are on the same + // hierarchy level. Thus, we try to match either of them. bool TraverseType(QualType TypeNode) { + ScopedIncrement ScopedDepth(&CurrentDepth); + // Match the Type. + if (!match(*TypeNode)) + return false; + // The QualType is matched inside traverse. return traverse(TypeNode); } + // We assume that the TypeLoc, contained QualType and contained Type all are + // on the same hierarchy level. Thus, we try to match all of them. + bool TraverseTypeLoc(TypeLoc TypeLocNode) { + ScopedIncrement ScopedDepth(&CurrentDepth); + // Match the Type. + if (!match(*TypeLocNode.getType())) + return false; + // Match the QualType. + if (!match(TypeLocNode.getType())) + return false; + // The TypeLoc is matched inside traverse. + return traverse(TypeLocNode); + } + bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { + ScopedIncrement ScopedDepth(&CurrentDepth); + return (NNS == NULL) || traverse(*NNS); + } + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { + ScopedIncrement ScopedDepth(&CurrentDepth); + if (!match(*NNS.getNestedNameSpecifier())) + return false; + return !NNS || traverse(NNS); + } bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { return true; } @@ -120,7 +230,7 @@ private: // Resets the state of this object. void reset() { Matches = false; - CurrentDepth = -1; + CurrentDepth = 0; } // Forwards the call to the corresponding Traverse*() method in the @@ -134,49 +244,57 @@ private: bool baseTraverse(QualType TypeNode) { return VisitorBase::TraverseType(TypeNode); } + bool baseTraverse(TypeLoc TypeLocNode) { + return VisitorBase::TraverseTypeLoc(TypeLocNode); + } + bool baseTraverse(const NestedNameSpecifier &NNS) { + return VisitorBase::TraverseNestedNameSpecifier( + const_cast<NestedNameSpecifier*>(&NNS)); + } + bool baseTraverse(NestedNameSpecifierLoc NNS) { + return VisitorBase::TraverseNestedNameSpecifierLoc(NNS); + } - // Traverses the subtree rooted at 'node'; returns true if the - // traversal should continue after this function returns; also sets - // matched_ to true if a match is found during the traversal. + // Sets 'Matched' to true if 'Matcher' matches 'Node' and: + // 0 < CurrentDepth <= MaxDepth. + // + // Returns 'true' if traversal should continue after this function + // returns, i.e. if no match is found or 'Bind' is 'BK_All'. template <typename T> - bool traverse(const T &Node) { - TOOLING_COMPILE_ASSERT(IsBaseType<T>::value, - traverse_can_only_be_instantiated_with_base_type); - ScopedIncrement ScopedDepth(&CurrentDepth); - if (CurrentDepth == 0) { - // We don't want to match the root node, so just recurse. - return baseTraverse(Node); + bool match(const T &Node) { + if (CurrentDepth == 0 || CurrentDepth > MaxDepth) { + return true; } if (Bind != ASTMatchFinder::BK_All) { - if (BaseMatcher->matches(Node, Finder, Builder)) { + if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), + Finder, Builder)) { Matches = true; return false; // Abort as soon as a match is found. } - if (CurrentDepth < MaxDepth) { - // The current node doesn't match, and we haven't reached the - // maximum depth yet, so recurse. - return baseTraverse(Node); - } - // The current node doesn't match, and we have reached the - // maximum depth, so don't recurse (but continue the traversal - // such that other nodes at the current level can be visited). - return true; } else { BoundNodesTreeBuilder RecursiveBuilder; - if (BaseMatcher->matches(Node, Finder, &RecursiveBuilder)) { + if (Matcher->matches(ast_type_traits::DynTypedNode::create(Node), + Finder, &RecursiveBuilder)) { // After the first match the matcher succeeds. Matches = true; Builder->addMatch(RecursiveBuilder.build()); } - if (CurrentDepth < MaxDepth) { - baseTraverse(Node); - } - // In kBindAll mode we always search for more matches. - return true; } + return true; } - const UntypedBaseMatcher *const BaseMatcher; + // Traverses the subtree rooted at 'Node'; returns true if the + // traversal should continue after this function returns. + template <typename T> + bool traverse(const T &Node) { + TOOLING_COMPILE_ASSERT(IsBaseType<T>::value, + traverse_can_only_be_instantiated_with_base_type); + if (!match(Node)) + return false; + return baseTraverse(Node); + } + + const DynTypedMatcher *const Matcher; ASTMatchFinder *const Finder; BoundNodesTreeBuilder *const Builder; int CurrentDepth; @@ -191,12 +309,21 @@ private: class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>, public ASTMatchFinder { public: - MatchASTVisitor(std::vector< std::pair<const UntypedBaseMatcher*, - MatchFinder::MatchCallback*> > *Triggers) - : Triggers(Triggers), + MatchASTVisitor(std::vector<std::pair<const internal::DynTypedMatcher*, + MatchCallback*> > *MatcherCallbackPairs) + : MatcherCallbackPairs(MatcherCallbackPairs), ActiveASTContext(NULL) { } + void onStartOfTranslationUnit() { + for (std::vector<std::pair<const internal::DynTypedMatcher*, + MatchCallback*> >::const_iterator + I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end(); + I != E; ++I) { + I->second->onStartOfTranslationUnit(); + } + } + void set_active_ast_context(ASTContext *NewActiveASTContext) { ActiveASTContext = NewActiveASTContext; } @@ -207,7 +334,7 @@ public: bool VisitTypedefDecl(TypedefDecl *DeclNode) { // When we see 'typedef A B', we add name 'B' to the set of names // A's canonical type maps to. This is necessary for implementing - // IsDerivedFrom(x) properly, where x can be the name of the base + // isDerivedFrom(x) properly, where x can be the name of the base // class or any of its aliases. // // In general, the is-alias-of (as defined by typedefs) relation @@ -228,7 +355,7 @@ public: // `- E // // It is wrong to assume that the relation is a chain. A correct - // implementation of IsDerivedFrom() needs to recognize that B and + // implementation of isDerivedFrom() needs to recognize that B and // E are aliases, even though neither is a typedef of the other. // Therefore, we cannot simply walk through one typedef chain to // find out whether the type name matches. @@ -243,23 +370,27 @@ public: bool TraverseStmt(Stmt *StmtNode); bool TraverseType(QualType TypeNode); bool TraverseTypeLoc(TypeLoc TypeNode); + bool TraverseNestedNameSpecifier(NestedNameSpecifier *NNS); + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS); // Matches children or descendants of 'Node' with 'BaseMatcher'. - template <typename T> - bool memoizedMatchesRecursively(const T &Node, - const UntypedBaseMatcher &BaseMatcher, + bool memoizedMatchesRecursively(const ast_type_traits::DynTypedNode &Node, + const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, int MaxDepth, TraversalKind Traversal, BindKind Bind) { - TOOLING_COMPILE_ASSERT((llvm::is_same<T, Decl>::value) || - (llvm::is_same<T, Stmt>::value), - type_does_not_support_memoization); - const UntypedMatchInput input(BaseMatcher.getID(), &Node); + const UntypedMatchInput input(Matcher.getID(), Node.getMemoizationData()); + + // For AST-nodes that don't have an identity, we can't memoize. + if (!input.second) + return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal, + Bind); + std::pair<MemoizationMap::iterator, bool> InsertResult = ResultCache.insert(std::make_pair(input, MemoizedMatchResult())); if (InsertResult.second) { BoundNodesTreeBuilder DescendantBoundNodesBuilder; InsertResult.first->second.ResultOfMatch = - matchesRecursively(Node, BaseMatcher, &DescendantBoundNodesBuilder, + matchesRecursively(Node, Matcher, &DescendantBoundNodesBuilder, MaxDepth, Traversal, Bind); InsertResult.first->second.Nodes = DescendantBoundNodesBuilder.build(); @@ -269,12 +400,12 @@ public: } // Matches children or descendants of 'Node' with 'BaseMatcher'. - template <typename T> - bool matchesRecursively(const T &Node, const UntypedBaseMatcher &BaseMatcher, + bool matchesRecursively(const ast_type_traits::DynTypedNode &Node, + const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, int MaxDepth, TraversalKind Traversal, BindKind Bind) { MatchChildASTVisitor Visitor( - &BaseMatcher, this, Builder, MaxDepth, Traversal, Bind); + &Matcher, this, Builder, MaxDepth, Traversal, Bind); return Visitor.findMatch(Node); } @@ -282,38 +413,54 @@ public: const Matcher<NamedDecl> &Base, BoundNodesTreeBuilder *Builder); - // Implements ASTMatchFinder::MatchesChildOf. - virtual bool matchesChildOf(const Decl &DeclNode, - const UntypedBaseMatcher &BaseMatcher, + // Implements ASTMatchFinder::matchesChildOf. + virtual bool matchesChildOf(const ast_type_traits::DynTypedNode &Node, + const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, TraversalKind Traversal, BindKind Bind) { - return matchesRecursively(DeclNode, BaseMatcher, Builder, 1, Traversal, + return matchesRecursively(Node, Matcher, Builder, 1, Traversal, Bind); } - virtual bool matchesChildOf(const Stmt &StmtNode, - const UntypedBaseMatcher &BaseMatcher, - BoundNodesTreeBuilder *Builder, - TraversalKind Traversal, - BindKind Bind) { - return matchesRecursively(StmtNode, BaseMatcher, Builder, 1, Traversal, - Bind); - } - - // Implements ASTMatchFinder::MatchesDescendantOf. - virtual bool matchesDescendantOf(const Decl &DeclNode, - const UntypedBaseMatcher &BaseMatcher, + // Implements ASTMatchFinder::matchesDescendantOf. + virtual bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node, + const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, BindKind Bind) { - return memoizedMatchesRecursively(DeclNode, BaseMatcher, Builder, INT_MAX, + return memoizedMatchesRecursively(Node, Matcher, Builder, INT_MAX, TK_AsIs, Bind); } - virtual bool matchesDescendantOf(const Stmt &StmtNode, - const UntypedBaseMatcher &BaseMatcher, - BoundNodesTreeBuilder *Builder, - BindKind Bind) { - return memoizedMatchesRecursively(StmtNode, BaseMatcher, Builder, INT_MAX, - TK_AsIs, Bind); + // Implements ASTMatchFinder::matchesAncestorOf. + virtual bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node, + const DynTypedMatcher &Matcher, + BoundNodesTreeBuilder *Builder, + AncestorMatchMode MatchMode) { + if (!Parents) { + // We always need to run over the whole translation unit, as + // \c hasAncestor can escape any subtree. + Parents.reset(ParentMapASTVisitor::buildMap( + *ActiveASTContext->getTranslationUnitDecl())); + } + ast_type_traits::DynTypedNode Ancestor = Node; + while (Ancestor.get<TranslationUnitDecl>() != + ActiveASTContext->getTranslationUnitDecl()) { + assert(Ancestor.getMemoizationData() && + "Invariant broken: only nodes that support memoization may be " + "used in the parent map."); + ParentMapASTVisitor::ParentMap::const_iterator I = + Parents->find(Ancestor.getMemoizationData()); + if (I == Parents->end()) { + assert(false && + "Found node that is not in the parent map."); + return false; + } + Ancestor = I->second; + if (Matcher.matches(Ancestor, this, Builder)) + return true; + if (MatchMode == ASTMatchFinder::AMM_ParentOnly) + return false; + } + return false; } bool shouldVisitTemplateInstantiations() const { return true; } @@ -358,21 +505,22 @@ private: // result callback for every node that matches. template <typename T> void match(const T &node) { - for (std::vector< std::pair<const UntypedBaseMatcher*, - MatchFinder::MatchCallback*> >::const_iterator - It = Triggers->begin(), End = Triggers->end(); - It != End; ++It) { + for (std::vector<std::pair<const internal::DynTypedMatcher*, + MatchCallback*> >::const_iterator + I = MatcherCallbackPairs->begin(), E = MatcherCallbackPairs->end(); + I != E; ++I) { BoundNodesTreeBuilder Builder; - if (It->first->matches(node, this, &Builder)) { + if (I->first->matches(ast_type_traits::DynTypedNode::create(node), + this, &Builder)) { BoundNodesTree BoundNodes = Builder.build(); - MatchVisitor Visitor(ActiveASTContext, It->second); + MatchVisitor Visitor(ActiveASTContext, I->second); BoundNodes.visitMatches(&Visitor); } } } - std::vector< std::pair<const UntypedBaseMatcher*, - MatchFinder::MatchCallback*> > *const Triggers; + std::vector<std::pair<const internal::DynTypedMatcher*, + MatchCallback*> > *const MatcherCallbackPairs; ASTContext *ActiveASTContext; // Maps a canonical type to its TypedefDecls. @@ -381,16 +529,16 @@ private: // Maps (matcher, node) -> the match result for memoization. typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap; MemoizationMap ResultCache; + + llvm::OwningPtr<ParentMapASTVisitor::ParentMap> Parents; }; // Returns true if the given class is directly or indirectly derived -// from a base type with the given name. A class is considered to be -// also derived from itself. +// from a base type with the given name. A class is not considered to be +// derived from itself. bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration, const Matcher<NamedDecl> &Base, BoundNodesTreeBuilder *Builder) { - if (Base.matches(*Declaration, this, Builder)) - return true; if (!Declaration->hasDefinition()) return false; typedef CXXRecordDecl::base_class_const_iterator BaseIterator; @@ -403,6 +551,7 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration, // Type::getAs<...>() drills through typedefs. if (TypeNode->getAs<DependentNameType>() != NULL || + TypeNode->getAs<DependentTemplateSpecializationType>() != NULL || TypeNode->getAs<TemplateTypeParmType>() != NULL) // Dependent names and template TypeNode parameters will be matched when // the template is instantiated. @@ -439,6 +588,8 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration, } assert(ClassDecl != NULL); assert(ClassDecl != Declaration); + if (Base.matches(*ClassDecl, this, Builder)) + return true; if (classIsDerivedFrom(ClassDecl, Base, Builder)) return true; } @@ -466,19 +617,40 @@ bool MatchASTVisitor::TraverseType(QualType TypeNode) { return RecursiveASTVisitor<MatchASTVisitor>::TraverseType(TypeNode); } -bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLoc) { - match(TypeLoc.getType()); - return RecursiveASTVisitor<MatchASTVisitor>:: - TraverseTypeLoc(TypeLoc); +bool MatchASTVisitor::TraverseTypeLoc(TypeLoc TypeLocNode) { + // The RecursiveASTVisitor only visits types if they're not within TypeLocs. + // We still want to find those types via matchers, so we match them here. Note + // that the TypeLocs are structurally a shadow-hierarchy to the expressed + // type, so we visit all involved parts of a compound type when matching on + // each TypeLoc. + match(TypeLocNode); + match(TypeLocNode.getType()); + return RecursiveASTVisitor<MatchASTVisitor>::TraverseTypeLoc(TypeLocNode); +} + +bool MatchASTVisitor::TraverseNestedNameSpecifier(NestedNameSpecifier *NNS) { + match(*NNS); + return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifier(NNS); +} + +bool MatchASTVisitor::TraverseNestedNameSpecifierLoc( + NestedNameSpecifierLoc NNS) { + match(NNS); + // We only match the nested name specifier here (as opposed to traversing it) + // because the traversal is already done in the parallel "Loc"-hierarchy. + match(*NNS.getNestedNameSpecifier()); + return + RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS); } class MatchASTConsumer : public ASTConsumer { public: - MatchASTConsumer(std::vector< std::pair<const UntypedBaseMatcher*, - MatchFinder::MatchCallback*> > *Triggers, - MatchFinder::ParsingDoneTestCallback *ParsingDone) - : Visitor(Triggers), - ParsingDone(ParsingDone) {} + MatchASTConsumer( + std::vector<std::pair<const internal::DynTypedMatcher*, + MatchCallback*> > *MatcherCallbackPairs, + MatchFinder::ParsingDoneTestCallback *ParsingDone) + : Visitor(MatcherCallbackPairs), + ParsingDone(ParsingDone) {} private: virtual void HandleTranslationUnit(ASTContext &Context) { @@ -486,6 +658,7 @@ private: ParsingDone->run(); } Visitor.set_active_ast_context(&Context); + Visitor.onStartOfTranslationUnit(); Visitor.TraverseDecl(Context.getTranslationUnitDecl()); Visitor.set_active_ast_context(NULL); } @@ -508,9 +681,9 @@ MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {} MatchFinder::MatchFinder() : ParsingDone(NULL) {} MatchFinder::~MatchFinder() { - for (std::vector< std::pair<const internal::UntypedBaseMatcher*, - MatchFinder::MatchCallback*> >::const_iterator - It = Triggers.begin(), End = Triggers.end(); + for (std::vector<std::pair<const internal::DynTypedMatcher*, + MatchCallback*> >::const_iterator + It = MatcherCallbackPairs.begin(), End = MatcherCallbackPairs.end(); It != End; ++It) { delete It->first; } @@ -518,24 +691,54 @@ MatchFinder::~MatchFinder() { void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action) { - Triggers.push_back(std::make_pair( - new internal::TypedBaseMatcher<Decl>(NodeMatch), Action)); + MatcherCallbackPairs.push_back(std::make_pair( + new internal::Matcher<Decl>(NodeMatch), Action)); } void MatchFinder::addMatcher(const TypeMatcher &NodeMatch, MatchCallback *Action) { - Triggers.push_back(std::make_pair( - new internal::TypedBaseMatcher<QualType>(NodeMatch), Action)); + MatcherCallbackPairs.push_back(std::make_pair( + new internal::Matcher<QualType>(NodeMatch), Action)); } void MatchFinder::addMatcher(const StatementMatcher &NodeMatch, MatchCallback *Action) { - Triggers.push_back(std::make_pair( - new internal::TypedBaseMatcher<Stmt>(NodeMatch), Action)); + MatcherCallbackPairs.push_back(std::make_pair( + new internal::Matcher<Stmt>(NodeMatch), Action)); +} + +void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch, + MatchCallback *Action) { + MatcherCallbackPairs.push_back(std::make_pair( + new NestedNameSpecifierMatcher(NodeMatch), Action)); +} + +void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch, + MatchCallback *Action) { + MatcherCallbackPairs.push_back(std::make_pair( + new NestedNameSpecifierLocMatcher(NodeMatch), Action)); +} + +void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch, + MatchCallback *Action) { + MatcherCallbackPairs.push_back(std::make_pair( + new TypeLocMatcher(NodeMatch), Action)); } ASTConsumer *MatchFinder::newASTConsumer() { - return new internal::MatchASTConsumer(&Triggers, ParsingDone); + return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone); +} + +void MatchFinder::findAll(const Decl &Node, ASTContext &Context) { + internal::MatchASTVisitor Visitor(&MatcherCallbackPairs); + Visitor.set_active_ast_context(&Context); + Visitor.TraverseDecl(const_cast<Decl*>(&Node)); +} + +void MatchFinder::findAll(const Stmt &Node, ASTContext &Context) { + internal::MatchASTVisitor Visitor(&MatcherCallbackPairs); + Visitor.set_active_ast_context(&Context); + Visitor.TraverseStmt(const_cast<Stmt*>(&Node)); } void MatchFinder::registerTestCallbackAfterParsing( diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp index 69c51905fe8f..408195d36902 100644 --- a/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -18,18 +18,29 @@ namespace clang { namespace ast_matchers { namespace internal { +void BoundNodesMap::copyTo(BoundNodesTreeBuilder *Builder) const { + for (IDToNodeMap::const_iterator It = NodeMap.begin(); + It != NodeMap.end(); + ++It) { + Builder->setBinding(It->first, It->second); + } +} + +void BoundNodesMap::copyTo(BoundNodesMap *Other) const { + copy(NodeMap.begin(), NodeMap.end(), + inserter(Other->NodeMap, Other->NodeMap.begin())); +} + BoundNodesTree::BoundNodesTree() {} BoundNodesTree::BoundNodesTree( - const std::map<std::string, const Decl*>& DeclBindings, - const std::map<std::string, const Stmt*>& StmtBindings, + const BoundNodesMap& Bindings, const std::vector<BoundNodesTree> RecursiveBindings) - : DeclBindings(DeclBindings), StmtBindings(StmtBindings), + : Bindings(Bindings), RecursiveBindings(RecursiveBindings) {} void BoundNodesTree::copyTo(BoundNodesTreeBuilder* Builder) const { - copyBindingsTo(DeclBindings, Builder); - copyBindingsTo(StmtBindings, Builder); + Bindings.copyTo(Builder); for (std::vector<BoundNodesTree>::const_iterator I = RecursiveBindings.begin(), E = RecursiveBindings.end(); @@ -38,63 +49,34 @@ void BoundNodesTree::copyTo(BoundNodesTreeBuilder* Builder) const { } } -template <typename T> -void BoundNodesTree::copyBindingsTo( - const T& Bindings, BoundNodesTreeBuilder* Builder) const { - for (typename T::const_iterator I = Bindings.begin(), - E = Bindings.end(); - I != E; ++I) { - Builder->setBinding(I->first, I->second); - } -} - void BoundNodesTree::visitMatches(Visitor* ResultVisitor) { - std::map<std::string, const Decl*> AggregatedDeclBindings; - std::map<std::string, const Stmt*> AggregatedStmtBindings; - visitMatchesRecursively(ResultVisitor, AggregatedDeclBindings, - AggregatedStmtBindings); + BoundNodesMap AggregatedBindings; + visitMatchesRecursively(ResultVisitor, AggregatedBindings); } void BoundNodesTree:: visitMatchesRecursively(Visitor* ResultVisitor, - std::map<std::string, const Decl*> - AggregatedDeclBindings, - std::map<std::string, const Stmt*> - AggregatedStmtBindings) { - copy(DeclBindings.begin(), DeclBindings.end(), - inserter(AggregatedDeclBindings, AggregatedDeclBindings.begin())); - copy(StmtBindings.begin(), StmtBindings.end(), - inserter(AggregatedStmtBindings, AggregatedStmtBindings.begin())); + const BoundNodesMap& AggregatedBindings) { + BoundNodesMap CombinedBindings(AggregatedBindings); + Bindings.copyTo(&CombinedBindings); if (RecursiveBindings.empty()) { - ResultVisitor->visitMatch(BoundNodes(AggregatedDeclBindings, - AggregatedStmtBindings)); + ResultVisitor->visitMatch(BoundNodes(CombinedBindings)); } else { for (unsigned I = 0; I < RecursiveBindings.size(); ++I) { RecursiveBindings[I].visitMatchesRecursively(ResultVisitor, - AggregatedDeclBindings, - AggregatedStmtBindings); + CombinedBindings); } } } BoundNodesTreeBuilder::BoundNodesTreeBuilder() {} -void BoundNodesTreeBuilder::setBinding(const std::string &Id, - const Decl *Node) { - DeclBindings[Id] = Node; -} - -void BoundNodesTreeBuilder::setBinding(const std::string &Id, - const Stmt *Node) { - StmtBindings[Id] = Node; -} - void BoundNodesTreeBuilder::addMatch(const BoundNodesTree& Bindings) { RecursiveBindings.push_back(Bindings); } BoundNodesTree BoundNodesTreeBuilder::build() const { - return BoundNodesTree(DeclBindings, StmtBindings, RecursiveBindings); + return BoundNodesTree(Bindings, RecursiveBindings); } } // end namespace internal diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index 7de7f395e8a7..e7df0a813b37 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -29,13 +29,15 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ErrorHandling.h" +#include "BodyFarm.h" + using namespace clang; typedef llvm::DenseMap<const void *, ManagedAnalysis *> ManagedAnalysisMap; AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *d, - const CFG::BuildOptions &buildOptions) + const Decl *d, + const CFG::BuildOptions &buildOptions) : Manager(Mgr), D(d), cfgBuildOptions(buildOptions), @@ -49,7 +51,7 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, } AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *d) + const Decl *d) : Manager(Mgr), D(d), forcedBlkExprs(0), @@ -62,11 +64,16 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, } AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, - bool addImplicitDtors, - bool addInitializers) { + bool addImplicitDtors, + bool addInitializers, + bool addTemporaryDtors, + bool synthesizeBodies) + : SynthesizeBodies(synthesizeBodies) +{ cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; cfgBuildOptions.AddImplicitDtors = addImplicitDtors; cfgBuildOptions.AddInitializers = addInitializers; + cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors; } void AnalysisDeclContextManager::clear() { @@ -75,9 +82,18 @@ void AnalysisDeclContextManager::clear() { Contexts.clear(); } +static BodyFarm &getBodyFarm(ASTContext &C) { + static BodyFarm *BF = new BodyFarm(C); + return *BF; +} + Stmt *AnalysisDeclContext::getBody() const { - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - return FD->getBody(); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + Stmt *Body = FD->getBody(); + if (!Body && Manager && Manager->synthesizeBodies()) + return getBodyFarm(getASTContext()).getBody(FD); + return Body; + } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) return MD->getBody(); else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) @@ -201,6 +217,13 @@ PseudoConstantAnalysis *AnalysisDeclContext::getPseudoConstantAnalysis() { } AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // Calling 'hasBody' replaces 'FD' in place with the FunctionDecl + // that has the body. + FD->hasBody(FD); + D = FD; + } + AnalysisDeclContext *&AC = Contexts[D]; if (!AC) AC = new AnalysisDeclContext(this, D, cfgBuildOptions); @@ -332,6 +355,10 @@ const StackFrameContext *LocationContext::getCurrentStackFrame() const { return NULL; } +bool LocationContext::inTopFrame() const { + return getCurrentStackFrame()->inTopFrame(); +} + bool LocationContext::isParentOf(const LocationContext *LC) const { do { const LocationContext *Parent = LC->getParent(); diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp new file mode 100644 index 000000000000..794ff9cc2bb1 --- /dev/null +++ b/lib/Analysis/BodyFarm.cpp @@ -0,0 +1,374 @@ +//== BodyFarm.cpp - Factory for conjuring up fake bodies ----------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// BodyFarm is a factory for creating faux implementations for functions/methods +// for analysis purposes. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringSwitch.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/ExprObjC.h" +#include "BodyFarm.h" + +using namespace clang; + +//===----------------------------------------------------------------------===// +// Helper creation functions for constructing faux ASTs. +//===----------------------------------------------------------------------===// + +static bool isDispatchBlock(QualType Ty) { + // Is it a block pointer? + const BlockPointerType *BPT = Ty->getAs<BlockPointerType>(); + if (!BPT) + return false; + + // Check if the block pointer type takes no arguments and + // returns void. + const FunctionProtoType *FT = + BPT->getPointeeType()->getAs<FunctionProtoType>(); + if (!FT || !FT->getResultType()->isVoidType() || + FT->getNumArgs() != 0) + return false; + + return true; +} + +namespace { +class ASTMaker { +public: + ASTMaker(ASTContext &C) : C(C) {} + + /// Create a new BinaryOperator representing a simple assignment. + BinaryOperator *makeAssignment(const Expr *LHS, const Expr *RHS, QualType Ty); + + /// Create a new BinaryOperator representing a comparison. + BinaryOperator *makeComparison(const Expr *LHS, const Expr *RHS, + BinaryOperator::Opcode Op); + + /// Create a new compound stmt using the provided statements. + CompoundStmt *makeCompound(ArrayRef<Stmt*>); + + /// Create a new DeclRefExpr for the referenced variable. + DeclRefExpr *makeDeclRefExpr(const VarDecl *D); + + /// Create a new UnaryOperator representing a dereference. + UnaryOperator *makeDereference(const Expr *Arg, QualType Ty); + + /// Create an implicit cast for an integer conversion. + Expr *makeIntegralCast(const Expr *Arg, QualType Ty); + + /// Create an implicit cast to a builtin boolean type. + ImplicitCastExpr *makeIntegralCastToBoolean(const Expr *Arg); + + // Create an implicit cast for lvalue-to-rvaluate conversions. + ImplicitCastExpr *makeLvalueToRvalue(const Expr *Arg, QualType Ty); + + /// Create an Objective-C bool literal. + ObjCBoolLiteralExpr *makeObjCBool(bool Val); + + /// Create a Return statement. + ReturnStmt *makeReturn(const Expr *RetVal); + +private: + ASTContext &C; +}; +} + +BinaryOperator *ASTMaker::makeAssignment(const Expr *LHS, const Expr *RHS, + QualType Ty) { + return new (C) BinaryOperator(const_cast<Expr*>(LHS), const_cast<Expr*>(RHS), + BO_Assign, Ty, VK_RValue, + OK_Ordinary, SourceLocation(), false); +} + +BinaryOperator *ASTMaker::makeComparison(const Expr *LHS, const Expr *RHS, + BinaryOperator::Opcode Op) { + assert(BinaryOperator::isLogicalOp(Op) || + BinaryOperator::isComparisonOp(Op)); + return new (C) BinaryOperator(const_cast<Expr*>(LHS), + const_cast<Expr*>(RHS), + Op, + C.getLogicalOperationType(), + VK_RValue, + OK_Ordinary, SourceLocation(), false); +} + +CompoundStmt *ASTMaker::makeCompound(ArrayRef<Stmt *> Stmts) { + return new (C) CompoundStmt(C, const_cast<Stmt**>(Stmts.data()), + Stmts.size(), + SourceLocation(), SourceLocation()); +} + +DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) { + DeclRefExpr *DR = + DeclRefExpr::Create(/* Ctx = */ C, + /* QualifierLoc = */ NestedNameSpecifierLoc(), + /* TemplateKWLoc = */ SourceLocation(), + /* D = */ const_cast<VarDecl*>(D), + /* isEnclosingLocal = */ false, + /* NameLoc = */ SourceLocation(), + /* T = */ D->getType(), + /* VK = */ VK_LValue); + return DR; +} + +UnaryOperator *ASTMaker::makeDereference(const Expr *Arg, QualType Ty) { + return new (C) UnaryOperator(const_cast<Expr*>(Arg), UO_Deref, Ty, + VK_LValue, OK_Ordinary, SourceLocation()); +} + +ImplicitCastExpr *ASTMaker::makeLvalueToRvalue(const Expr *Arg, QualType Ty) { + return ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue, + const_cast<Expr*>(Arg), 0, VK_RValue); +} + +Expr *ASTMaker::makeIntegralCast(const Expr *Arg, QualType Ty) { + if (Arg->getType() == Ty) + return const_cast<Expr*>(Arg); + + return ImplicitCastExpr::Create(C, Ty, CK_IntegralCast, + const_cast<Expr*>(Arg), 0, VK_RValue); +} + +ImplicitCastExpr *ASTMaker::makeIntegralCastToBoolean(const Expr *Arg) { + return ImplicitCastExpr::Create(C, C.BoolTy, CK_IntegralToBoolean, + const_cast<Expr*>(Arg), 0, VK_RValue); +} + +ObjCBoolLiteralExpr *ASTMaker::makeObjCBool(bool Val) { + QualType Ty = C.getBOOLDecl() ? C.getBOOLType() : C.ObjCBuiltinBoolTy; + return new (C) ObjCBoolLiteralExpr(Val, Ty, SourceLocation()); +} + +ReturnStmt *ASTMaker::makeReturn(const Expr *RetVal) { + return new (C) ReturnStmt(SourceLocation(), const_cast<Expr*>(RetVal), 0); +} + +//===----------------------------------------------------------------------===// +// Creation functions for faux ASTs. +//===----------------------------------------------------------------------===// + +typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D); + +/// Create a fake body for dispatch_once. +static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { + // Check if we have at least two parameters. + if (D->param_size() != 2) + return 0; + + // Check if the first parameter is a pointer to integer type. + const ParmVarDecl *Predicate = D->getParamDecl(0); + QualType PredicateQPtrTy = Predicate->getType(); + const PointerType *PredicatePtrTy = PredicateQPtrTy->getAs<PointerType>(); + if (!PredicatePtrTy) + return 0; + QualType PredicateTy = PredicatePtrTy->getPointeeType(); + if (!PredicateTy->isIntegerType()) + return 0; + + // Check if the second parameter is the proper block type. + const ParmVarDecl *Block = D->getParamDecl(1); + QualType Ty = Block->getType(); + if (!isDispatchBlock(Ty)) + return 0; + + // Everything checks out. Create a fakse body that checks the predicate, + // sets it, and calls the block. Basically, an AST dump of: + // + // void dispatch_once(dispatch_once_t *predicate, dispatch_block_t block) { + // if (!*predicate) { + // *predicate = 1; + // block(); + // } + // } + + ASTMaker M(C); + + // (1) Create the call. + DeclRefExpr *DR = M.makeDeclRefExpr(Block); + ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); + CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy, + VK_RValue, SourceLocation()); + + // (2) Create the assignment to the predicate. + IntegerLiteral *IL = + IntegerLiteral::Create(C, llvm::APInt(C.getTypeSize(C.IntTy), (uint64_t) 1), + C.IntTy, SourceLocation()); + BinaryOperator *B = + M.makeAssignment( + M.makeDereference( + M.makeLvalueToRvalue( + M.makeDeclRefExpr(Predicate), PredicateQPtrTy), + PredicateTy), + M.makeIntegralCast(IL, PredicateTy), + PredicateTy); + + // (3) Create the compound statement. + Stmt *Stmts[2]; + Stmts[0] = B; + Stmts[1] = CE; + CompoundStmt *CS = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2)); + + // (4) Create the 'if' condition. + ImplicitCastExpr *LValToRval = + M.makeLvalueToRvalue( + M.makeDereference( + M.makeLvalueToRvalue( + M.makeDeclRefExpr(Predicate), + PredicateQPtrTy), + PredicateTy), + PredicateTy); + + UnaryOperator *UO = new (C) UnaryOperator(LValToRval, UO_LNot, C.IntTy, + VK_RValue, OK_Ordinary, + SourceLocation()); + + // (5) Create the 'if' statement. + IfStmt *If = new (C) IfStmt(C, SourceLocation(), 0, UO, CS); + return If; +} + +/// Create a fake body for dispatch_sync. +static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) { + // Check if we have at least two parameters. + if (D->param_size() != 2) + return 0; + + // Check if the second parameter is a block. + const ParmVarDecl *PV = D->getParamDecl(1); + QualType Ty = PV->getType(); + if (!isDispatchBlock(Ty)) + return 0; + + // Everything checks out. Create a fake body that just calls the block. + // This is basically just an AST dump of: + // + // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) { + // block(); + // } + // + ASTMaker M(C); + DeclRefExpr *DR = M.makeDeclRefExpr(PV); + ImplicitCastExpr *ICE = M.makeLvalueToRvalue(DR, Ty); + CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy, + VK_RValue, SourceLocation()); + return CE; +} + +static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) +{ + // There are exactly 3 arguments. + if (D->param_size() != 3) + return 0; + + // Body for: + // if (oldValue == *theValue) { + // *theValue = newValue; + // return YES; + // } + // else return NO; + + QualType ResultTy = D->getResultType(); + bool isBoolean = ResultTy->isBooleanType(); + if (!isBoolean && !ResultTy->isIntegralType(C)) + return 0; + + const ParmVarDecl *OldValue = D->getParamDecl(0); + QualType OldValueTy = OldValue->getType(); + + const ParmVarDecl *NewValue = D->getParamDecl(1); + QualType NewValueTy = NewValue->getType(); + + assert(OldValueTy == NewValueTy); + + const ParmVarDecl *TheValue = D->getParamDecl(2); + QualType TheValueTy = TheValue->getType(); + const PointerType *PT = TheValueTy->getAs<PointerType>(); + if (!PT) + return 0; + QualType PointeeTy = PT->getPointeeType(); + + ASTMaker M(C); + // Construct the comparison. + Expr *Comparison = + M.makeComparison( + M.makeLvalueToRvalue(M.makeDeclRefExpr(OldValue), OldValueTy), + M.makeLvalueToRvalue( + M.makeDereference( + M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), + PointeeTy), + PointeeTy), + BO_EQ); + + // Construct the body of the IfStmt. + Stmt *Stmts[2]; + Stmts[0] = + M.makeAssignment( + M.makeDereference( + M.makeLvalueToRvalue(M.makeDeclRefExpr(TheValue), TheValueTy), + PointeeTy), + M.makeLvalueToRvalue(M.makeDeclRefExpr(NewValue), NewValueTy), + NewValueTy); + + Expr *BoolVal = M.makeObjCBool(true); + Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) + : M.makeIntegralCast(BoolVal, ResultTy); + Stmts[1] = M.makeReturn(RetVal); + CompoundStmt *Body = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2)); + + // Construct the else clause. + BoolVal = M.makeObjCBool(false); + RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) + : M.makeIntegralCast(BoolVal, ResultTy); + Stmt *Else = M.makeReturn(RetVal); + + /// Construct the If. + Stmt *If = + new (C) IfStmt(C, SourceLocation(), 0, Comparison, Body, + SourceLocation(), Else); + + return If; +} + +Stmt *BodyFarm::getBody(const FunctionDecl *D) { + D = D->getCanonicalDecl(); + + llvm::Optional<Stmt *> &Val = Bodies[D]; + if (Val.hasValue()) + return Val.getValue(); + + Val = 0; + + if (D->getIdentifier() == 0) + return 0; + + StringRef Name = D->getName(); + if (Name.empty()) + return 0; + + FunctionFarmer FF; + + if (Name.startswith("OSAtomicCompareAndSwap") || + Name.startswith("objc_atomicCompareAndSwap")) { + FF = create_OSAtomicCompareAndSwap; + } + else { + FF = llvm::StringSwitch<FunctionFarmer>(Name) + .Case("dispatch_sync", create_dispatch_sync) + .Case("dispatch_once", create_dispatch_once) + .Default(NULL); + } + + if (FF) { Val = FF(C, D); } + return Val.getValue(); +} + diff --git a/lib/Analysis/BodyFarm.h b/lib/Analysis/BodyFarm.h new file mode 100644 index 000000000000..d503cc1bcd07 --- /dev/null +++ b/lib/Analysis/BodyFarm.h @@ -0,0 +1,43 @@ +//== BodyFarm.h - Factory for conjuring up fake bodies -------------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// BodyFarm is a factory for creating faux implementations for functions/methods +// for analysis purposes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_BODYFARM_H +#define LLVM_CLANG_ANALYSIS_BODYFARM_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class ASTContext; +class Decl; +class FunctionDecl; +class Stmt; + +class BodyFarm { +public: + BodyFarm(ASTContext &C) : C(C) {} + + /// Factory method for creating bodies for ordinary functions. + Stmt *getBody(const FunctionDecl *D); + +private: + typedef llvm::DenseMap<const Decl *, llvm::Optional<Stmt *> > BodyMap; + + ASTContext &C; + BodyMap Bodies; +}; +} + +#endif diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 05c53850f568..315e54380b2f 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -467,6 +467,30 @@ private: CachedBoolEvals[S] = Result; // update or insert return Result; } + else { + switch (Bop->getOpcode()) { + default: break; + // For 'x & 0' and 'x * 0', we can determine that + // the value is always false. + case BO_Mul: + case BO_And: { + // If either operand is zero, we know the value + // must be false. + llvm::APSInt IntVal; + if (Bop->getLHS()->EvaluateAsInt(IntVal, *Context)) { + if (IntVal.getBoolValue() == false) { + return TryResult(false); + } + } + if (Bop->getRHS()->EvaluateAsInt(IntVal, *Context)) { + if (IntVal.getBoolValue() == false) { + return TryResult(false); + } + } + } + break; + } + } } return evaluateAsBooleanConditionNoCache(S); @@ -682,7 +706,7 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) { IsReference = FD->getType()->isReferenceType(); HasTemporaries = isa<ExprWithCleanups>(Init); - if (BuildOpts.AddImplicitDtors && HasTemporaries) { + if (BuildOpts.AddTemporaryDtors && HasTemporaries) { // Generate destructors for temporaries in initialization expression. VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(), IsReference); @@ -1022,6 +1046,14 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc) { case Stmt::ExprWithCleanupsClass: return VisitExprWithCleanups(cast<ExprWithCleanups>(S), asc); + case Stmt::CXXDefaultArgExprClass: + // FIXME: The expression inside a CXXDefaultArgExpr is owned by the + // called function's declaration, not by the caller. If we simply add + // this expression to the CFG, we could end up with the same Expr + // appearing multiple times. + // PR13385 / <rdar://problem/12156507> + return VisitStmt(S, asc); + case Stmt::CXXBindTemporaryExprClass: return VisitCXXBindTemporaryExpr(cast<CXXBindTemporaryExpr>(S), asc); @@ -1585,7 +1617,7 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { IsReference = VD->getType()->isReferenceType(); HasTemporaries = isa<ExprWithCleanups>(Init); - if (BuildOpts.AddImplicitDtors && HasTemporaries) { + if (BuildOpts.AddTemporaryDtors && HasTemporaries) { // Generate destructors for temporaries in initialization expression. VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(), IsReference); @@ -1616,8 +1648,10 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { // If the type of VD is a VLA, then we must process its size expressions. for (const VariableArrayType* VA = FindVA(VD->getType().getTypePtr()); - VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) - Block = addStmt(VA->getSizeExpr()); + VA != 0; VA = FindVA(VA->getElementType().getTypePtr())) { + if (CFGBlock *newBlock = addStmt(VA->getSizeExpr())) + LastBlock = newBlock; + } // Remove variable from local scope. if (ScopePos && VD == *ScopePos) @@ -1735,7 +1769,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { // Add the condition as the last statement in the new block. This may create // new blocks as the condition may contain control-flow. Any newly created // blocks will be pointed to be "Block". - Block = addStmt(I->getCond()); + CFGBlock *LastBlock = addStmt(I->getCond()); // Finally, if the IfStmt contains a condition variable, add both the IfStmt // and the condition variable initialization to the CFG. @@ -1743,11 +1777,11 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { if (Expr *Init = VD->getInit()) { autoCreateBlock(); appendStmt(Block, I->getConditionVariableDeclStmt()); - addStmt(Init); + LastBlock = addStmt(Init); } } - return Block; + return LastBlock; } @@ -2254,7 +2288,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { } // The default case when not handling logical operators. - EntryConditionBlock = ExitConditionBlock = createBlock(false); + ExitConditionBlock = createBlock(false); ExitConditionBlock->setTerminator(W); // Now add the actual condition to the condition block. @@ -2579,7 +2613,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) { // Add the terminator and condition in the switch block. SwitchTerminatedBlock->setTerminator(Terminator); Block = SwitchTerminatedBlock; - Block = addStmt(Terminator->getCond()); + CFGBlock *LastBlock = addStmt(Terminator->getCond()); // Finally, if the SwitchStmt contains a condition variable, add both the // SwitchStmt and the condition variable initialization to the CFG. @@ -2587,11 +2621,11 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) { if (Expr *Init = VD->getInit()) { autoCreateBlock(); appendStmt(Block, Terminator->getConditionVariableDeclStmt()); - addStmt(Init); + LastBlock = addStmt(Init); } } - return Block; + return LastBlock; } static bool shouldAddCase(bool &switchExclusivelyCovered, @@ -2775,8 +2809,7 @@ CFGBlock *CFGBuilder::VisitCXXTryStmt(CXXTryStmt *Terminator) { assert(Terminator->getTryBlock() && "try must contain a non-NULL body"); Block = NULL; - Block = addStmt(Terminator->getTryBlock()); - return Block; + return addStmt(Terminator->getTryBlock()); } CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) { @@ -2917,15 +2950,15 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) { addLocalScopeAndDtors(S->getLoopVarStmt()); // Populate a new block to contain the loop body and loop variable. - Block = addStmt(S->getBody()); + addStmt(S->getBody()); if (badCFG) return 0; - Block = addStmt(S->getLoopVarStmt()); + CFGBlock *LoopVarStmtBlock = addStmt(S->getLoopVarStmt()); if (badCFG) return 0; // This new body block is a successor to our condition block. - addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : Block); + addSuccessor(ConditionBlock, KnownVal.isFalse() ? 0 : LoopVarStmtBlock); } // Link up the condition block with the code that follows the loop (the @@ -2940,7 +2973,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) { CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E, AddStmtChoice asc) { - if (BuildOpts.AddImplicitDtors) { + if (BuildOpts.AddTemporaryDtors) { // If adding implicit destructors visit the full expression for adding // destructors of temporaries. VisitForTemporaryDtors(E->getSubExpr()); @@ -3020,6 +3053,8 @@ CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) { } CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary) { + assert(BuildOpts.AddImplicitDtors && BuildOpts.AddTemporaryDtors); + tryAgain: if (!E) { badCFG = true; @@ -3449,12 +3484,12 @@ class StmtPrinterHelper : public PrinterHelper { StmtMapTy StmtMap; DeclMapTy DeclMap; signed currentBlock; - unsigned currentStmt; + unsigned currStmt; const LangOptions &LangOpts; public: StmtPrinterHelper(const CFG* cfg, const LangOptions &LO) - : currentBlock(0), currentStmt(0), LangOpts(LO) + : currentBlock(0), currStmt(0), LangOpts(LO) { for (CFG::const_iterator I = cfg->begin(), E = cfg->end(); I != E; ++I ) { unsigned j = 1; @@ -3515,7 +3550,7 @@ public: const LangOptions &getLangOpts() const { return LangOpts; } void setBlockID(signed i) { currentBlock = i; } - void setStmtID(unsigned i) { currentStmt = i; } + void setStmtID(unsigned i) { currStmt = i; } virtual bool handledStmt(Stmt *S, raw_ostream &OS) { StmtMapTy::iterator I = StmtMap.find(S); @@ -3524,7 +3559,7 @@ public: return false; if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock - && I->second.second == currentStmt) { + && I->second.second == currStmt) { return false; } @@ -3539,7 +3574,7 @@ public: return false; if (currentBlock >= 0 && I->second.first == (unsigned) currentBlock - && I->second.second == currentStmt) { + && I->second.second == currStmt) { return false; } @@ -3831,8 +3866,8 @@ static void print_block(raw_ostream &OS, const CFG* cfg, if (Helper) Helper->setBlockID(-1); - CFGBlockTerminatorPrint TPrinter(OS, Helper, - PrintingPolicy(Helper->getLangOpts())); + PrintingPolicy PP(Helper ? Helper->getLangOpts() : LangOptions()); + CFGBlockTerminatorPrint TPrinter(OS, Helper, PP); TPrinter.Visit(const_cast<Stmt*>(B.getTerminator().getStmt())); OS << '\n'; diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index d57e4813ca02..ca166669fc89 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -1,13 +1,15 @@ add_clang_library(clangAnalysis AnalysisDeclContext.cpp - CallGraph.cpp + BodyFarm.cpp CFG.cpp CFGReachabilityAnalysis.cpp CFGStmtMap.cpp + CallGraph.cpp CocoaConventions.cpp Dominators.cpp FormatString.cpp LiveVariables.cpp + ObjCNoReturn.cpp PostOrderCFGView.cpp PrintfFormatString.cpp ProgramPoint.cpp diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp index e7ea48688dae..73063b5132c8 100644 --- a/lib/Analysis/FormatString.cpp +++ b/lib/Analysis/FormatString.cpp @@ -14,6 +14,7 @@ #include "FormatStringParsing.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/TargetInfo.h" using clang::analyze_format_string::ArgType; using clang::analyze_format_string::FormatStringHandler; @@ -489,9 +490,12 @@ analyze_format_string::LengthModifier::toString() const { const char *ConversionSpecifier::toString() const { switch (kind) { case dArg: return "d"; + case DArg: return "D"; case iArg: return "i"; case oArg: return "o"; + case OArg: return "O"; case uArg: return "u"; + case UArg: return "U"; case xArg: return "x"; case XArg: return "X"; case fArg: return "f"; @@ -523,6 +527,29 @@ const char *ConversionSpecifier::toString() const { return NULL; } +llvm::Optional<ConversionSpecifier> +ConversionSpecifier::getStandardSpecifier() const { + ConversionSpecifier::Kind NewKind; + + switch (getKind()) { + default: + return llvm::Optional<ConversionSpecifier>(); + case DArg: + NewKind = dArg; + break; + case UArg: + NewKind = uArg; + break; + case OArg: + NewKind = oArg; + break; + } + + ConversionSpecifier FixedCS(*this); + FixedCS.setKind(NewKind); + return FixedCS; +} + //===----------------------------------------------------------------------===// // Methods on OptionalAmount. //===----------------------------------------------------------------------===// @@ -548,7 +575,7 @@ void OptionalAmount::toString(raw_ostream &os) const { } } -bool FormatSpecifier::hasValidLengthModifier() const { +bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { switch (LM.getKind()) { case LengthModifier::None: return true; @@ -563,9 +590,12 @@ bool FormatSpecifier::hasValidLengthModifier() const { case LengthModifier::AsPtrDiff: switch (CS.getKind()) { case ConversionSpecifier::dArg: + case ConversionSpecifier::DArg: case ConversionSpecifier::iArg: case ConversionSpecifier::oArg: + case ConversionSpecifier::OArg: case ConversionSpecifier::uArg: + case ConversionSpecifier::UArg: case ConversionSpecifier::xArg: case ConversionSpecifier::XArg: case ConversionSpecifier::nArg: @@ -578,9 +608,12 @@ bool FormatSpecifier::hasValidLengthModifier() const { case LengthModifier::AsLong: switch (CS.getKind()) { case ConversionSpecifier::dArg: + case ConversionSpecifier::DArg: case ConversionSpecifier::iArg: case ConversionSpecifier::oArg: + case ConversionSpecifier::OArg: case ConversionSpecifier::uArg: + case ConversionSpecifier::UArg: case ConversionSpecifier::xArg: case ConversionSpecifier::XArg: case ConversionSpecifier::aArg: @@ -611,14 +644,15 @@ bool FormatSpecifier::hasValidLengthModifier() const { case ConversionSpecifier::gArg: case ConversionSpecifier::GArg: return true; - // GNU extension. + // GNU libc extension. case ConversionSpecifier::dArg: case ConversionSpecifier::iArg: case ConversionSpecifier::oArg: case ConversionSpecifier::uArg: case ConversionSpecifier::xArg: case ConversionSpecifier::XArg: - return true; + return !Target.getTriple().isOSDarwin() && + !Target.getTriple().isOSWindows(); default: return false; } @@ -697,6 +731,9 @@ bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt) return LangOpt.ObjC1 || LangOpt.ObjC2; case ConversionSpecifier::InvalidSpecifier: case ConversionSpecifier::PrintErrno: + case ConversionSpecifier::DArg: + case ConversionSpecifier::OArg: + case ConversionSpecifier::UArg: return false; } llvm_unreachable("Invalid ConversionSpecifier Kind!"); @@ -719,6 +756,20 @@ bool FormatSpecifier::hasStandardLengthConversionCombination() const { return true; } +llvm::Optional<LengthModifier> +FormatSpecifier::getCorrectedLengthModifier() const { + if (CS.isAnyIntArg() || CS.getKind() == ConversionSpecifier::nArg) { + if (LM.getKind() == LengthModifier::AsLongDouble || + LM.getKind() == LengthModifier::AsQuad) { + LengthModifier FixedLM(LM); + FixedLM.setKind(LengthModifier::AsLongLong); + return FixedLM; + } + } + + return llvm::Optional<LengthModifier>(); +} + bool FormatSpecifier::namedTypeToLengthModifier(QualType QT, LengthModifier &LM) { assert(isa<TypedefType>(QT) && "Expected a TypedefType"); diff --git a/lib/Analysis/ObjCNoReturn.cpp b/lib/Analysis/ObjCNoReturn.cpp new file mode 100644 index 000000000000..52d844bf9dd8 --- /dev/null +++ b/lib/Analysis/ObjCNoReturn.cpp @@ -0,0 +1,67 @@ +//= ObjCNoReturn.cpp - Handling of Cocoa APIs known not to return --*- C++ -*--- +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements special handling of recognizing ObjC API hooks that +// do not return but aren't marked as such in API headers. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTContext.h" +#include "clang/AST/ExprObjC.h" +#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h" + +using namespace clang; + +static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) { + if (!Class) + return false; + if (Class->getIdentifier() == II) + return true; + return isSubclass(Class->getSuperClass(), II); +} + +ObjCNoReturn::ObjCNoReturn(ASTContext &C) + : RaiseSel(GetNullarySelector("raise", C)), + NSExceptionII(&C.Idents.get("NSException")) +{ + // Generate selectors. + SmallVector<IdentifierInfo*, 3> II; + + // raise:format: + II.push_back(&C.Idents.get("raise")); + II.push_back(&C.Idents.get("format")); + NSExceptionInstanceRaiseSelectors[0] = + C.Selectors.getSelector(II.size(), &II[0]); + + // raise:format:arguments: + II.push_back(&C.Idents.get("arguments")); + NSExceptionInstanceRaiseSelectors[1] = + C.Selectors.getSelector(II.size(), &II[0]); +} + + +bool ObjCNoReturn::isImplicitNoReturn(const ObjCMessageExpr *ME) { + Selector S = ME->getSelector(); + + if (ME->isInstanceMessage()) { + // Check for the "raise" message. + return S == RaiseSel; + } + + if (const ObjCInterfaceDecl *ID = ME->getReceiverInterface()) { + if (isSubclass(ID, NSExceptionII)) { + for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) { + if (S == NSExceptionInstanceRaiseSelectors[i]) + return true; + } + } + } + + return false; +} diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 9e4c0fec4c04..2fa5a88f2c71 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Analyses/FormatString.h" +#include "clang/Basic/TargetInfo.h" #include "FormatStringParsing.h" using clang::analyze_format_string::ArgType; @@ -52,7 +53,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, unsigned &argIndex, - const LangOptions &LO) { + const LangOptions &LO, + const TargetInfo &Target) { using namespace clang::analyze_format_string; using namespace clang::analyze_printf; @@ -196,6 +198,19 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; + // Apple-specific + case 'D': + if (Target.getTriple().isOSDarwin()) + k = ConversionSpecifier::DArg; + break; + case 'O': + if (Target.getTriple().isOSDarwin()) + k = ConversionSpecifier::OArg; + break; + case 'U': + if (Target.getTriple().isOSDarwin()) + k = ConversionSpecifier::UArg; + break; } PrintfConversionSpecifier CS(conversionPosition, k); FS.setConversionSpecifier(CS); @@ -212,18 +227,19 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, const char *I, const char *E, - const LangOptions &LO) { + const LangOptions &LO, + const TargetInfo &Target) { unsigned argIndex = 0; // Keep looking for a format specifier until we have exhausted the string. while (I != E) { const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, - LO); + LO, Target); // Did a fail-stop error of any kind occur when parsing the specifier? // If so, don't do any more processing. if (FSR.shouldStop()) - return true;; + return true; // Did we exhaust the string or encounter an error that // we can recover from? if (!FSR.hasValue()) @@ -482,9 +498,11 @@ bool PrintfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, namedTypeToLengthModifier(QT, LM); // If fixing the length modifier was enough, we are done. - const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); - if (hasValidLengthModifier() && ATR.isValid() && ATR.matchesType(Ctx, QT)) - return true; + if (hasValidLengthModifier(Ctx.getTargetInfo())) { + const analyze_printf::ArgType &ATR = getArgType(Ctx, IsObjCLiteral); + if (ATR.isValid() && ATR.matchesType(Ctx, QT)) + return true; + } // Set conversion specifier and disable any flags which do not apply to it. // Let typedefs to char fall through to int, as %c is silly for uint8_t. @@ -549,6 +567,7 @@ bool PrintfSpecifier::hasValidPlusPrefix() const { // The plus prefix only makes sense for signed conversions switch (CS.getKind()) { case ConversionSpecifier::dArg: + case ConversionSpecifier::DArg: case ConversionSpecifier::iArg: case ConversionSpecifier::fArg: case ConversionSpecifier::FArg: @@ -572,6 +591,7 @@ bool PrintfSpecifier::hasValidAlternativeForm() const { // Alternate form flag only valid with the oxXaAeEfFgG conversions switch (CS.getKind()) { case ConversionSpecifier::oArg: + case ConversionSpecifier::OArg: case ConversionSpecifier::xArg: case ConversionSpecifier::XArg: case ConversionSpecifier::aArg: @@ -596,9 +616,12 @@ bool PrintfSpecifier::hasValidLeadingZeros() const { // Leading zeroes flag only valid with the diouxXaAeEfFgG conversions switch (CS.getKind()) { case ConversionSpecifier::dArg: + case ConversionSpecifier::DArg: case ConversionSpecifier::iArg: case ConversionSpecifier::oArg: + case ConversionSpecifier::OArg: case ConversionSpecifier::uArg: + case ConversionSpecifier::UArg: case ConversionSpecifier::xArg: case ConversionSpecifier::XArg: case ConversionSpecifier::aArg: @@ -623,6 +646,7 @@ bool PrintfSpecifier::hasValidSpacePrefix() const { // The space prefix only makes sense for signed conversions switch (CS.getKind()) { case ConversionSpecifier::dArg: + case ConversionSpecifier::DArg: case ConversionSpecifier::iArg: case ConversionSpecifier::fArg: case ConversionSpecifier::FArg: @@ -659,8 +683,10 @@ bool PrintfSpecifier::hasValidThousandsGroupingPrefix() const { switch (CS.getKind()) { case ConversionSpecifier::dArg: + case ConversionSpecifier::DArg: case ConversionSpecifier::iArg: case ConversionSpecifier::uArg: + case ConversionSpecifier::UArg: case ConversionSpecifier::fArg: case ConversionSpecifier::FArg: case ConversionSpecifier::gArg: @@ -678,9 +704,12 @@ bool PrintfSpecifier::hasValidPrecision() const { // Precision is only valid with the diouxXaAeEfFgGs conversions switch (CS.getKind()) { case ConversionSpecifier::dArg: + case ConversionSpecifier::DArg: case ConversionSpecifier::iArg: case ConversionSpecifier::oArg: + case ConversionSpecifier::OArg: case ConversionSpecifier::uArg: + case ConversionSpecifier::UArg: case ConversionSpecifier::xArg: case ConversionSpecifier::XArg: case ConversionSpecifier::aArg: diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp index bb63e2c18490..11f2ebe9ad2d 100644 --- a/lib/Analysis/ReachableCode.cpp +++ b/lib/Analysis/ReachableCode.cpp @@ -112,8 +112,8 @@ const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) { static int SrcCmp(const void *p1, const void *p2) { return - ((std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() < - ((std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart(); + ((const std::pair<const CFGBlock *, const Stmt *>*) p2)->second->getLocStart() < + ((const std::pair<const CFGBlock *, const Stmt *>*) p1)->second->getLocStart(); } unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start, diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp index 2942400621d1..574e56a5e068 100644 --- a/lib/Analysis/ScanfFormatString.cpp +++ b/lib/Analysis/ScanfFormatString.cpp @@ -13,6 +13,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Analyses/FormatString.h" +#include "clang/Basic/TargetInfo.h" #include "FormatStringParsing.h" using clang::analyze_format_string::ArgType; @@ -67,7 +68,8 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, const char *&Beg, const char *E, unsigned &argIndex, - const LangOptions &LO) { + const LangOptions &LO, + const TargetInfo &Target) { using namespace clang::analyze_scanf; const char *I = Beg; @@ -172,6 +174,20 @@ static ScanfSpecifierResult ParseScanfSpecifier(FormatStringHandler &H, case 'o': k = ConversionSpecifier::oArg; break; case 's': k = ConversionSpecifier::sArg; break; case 'p': k = ConversionSpecifier::pArg; break; + // Apple extensions + // Apple-specific + case 'D': + if (Target.getTriple().isOSDarwin()) + k = ConversionSpecifier::DArg; + break; + case 'O': + if (Target.getTriple().isOSDarwin()) + k = ConversionSpecifier::OArg; + break; + case 'U': + if (Target.getTriple().isOSDarwin()) + k = ConversionSpecifier::UArg; + break; } ScanfConversionSpecifier CS(conversionPosition, k); if (k == ScanfConversionSpecifier::ScanListArg) { @@ -202,6 +218,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { switch(CS.getKind()) { // Signed int. case ConversionSpecifier::dArg: + case ConversionSpecifier::DArg: case ConversionSpecifier::iArg: switch (LM.getKind()) { case LengthModifier::None: @@ -233,7 +250,9 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { // Unsigned int. case ConversionSpecifier::oArg: + case ConversionSpecifier::OArg: case ConversionSpecifier::uArg: + case ConversionSpecifier::UArg: case ConversionSpecifier::xArg: case ConversionSpecifier::XArg: switch (LM.getKind()) { @@ -430,9 +449,11 @@ bool ScanfSpecifier::fixType(QualType QT, const LangOptions &LangOpt, namedTypeToLengthModifier(PT, LM); // If fixing the length modifier was enough, we are done. - const analyze_scanf::ArgType &AT = getArgType(Ctx); - if (hasValidLengthModifier() && AT.isValid() && AT.matchesType(Ctx, QT)) - return true; + if (hasValidLengthModifier(Ctx.getTargetInfo())) { + const analyze_scanf::ArgType &AT = getArgType(Ctx); + if (AT.isValid() && AT.matchesType(Ctx, QT)) + return true; + } // Figure out the conversion specifier. if (PT->isRealFloatingType()) @@ -463,18 +484,19 @@ void ScanfSpecifier::toString(raw_ostream &os) const { bool clang::analyze_format_string::ParseScanfString(FormatStringHandler &H, const char *I, const char *E, - const LangOptions &LO) { + const LangOptions &LO, + const TargetInfo &Target) { unsigned argIndex = 0; // Keep looking for a format specifier until we have exhausted the string. while (I != E) { const ScanfSpecifierResult &FSR = ParseScanfSpecifier(H, I, E, argIndex, - LO); + LO, Target); // Did a fail-stop error of any kind occur when parsing the specifier? // If so, don't do any more processing. if (FSR.shouldStop()) - return true;; + return true; // Did we exhaust the string or encounter an error that // we can recover from? if (!FSR.hasValue()) diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index 5954682579d8..c7f1f62cb57d 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -70,27 +70,28 @@ namespace { class SExpr { private: enum ExprOp { - EOP_Nop, //< No-op - EOP_Wildcard, //< Matches anything. - EOP_This, //< This keyword. - EOP_NVar, //< Named variable. - EOP_LVar, //< Local variable. - EOP_Dot, //< Field access - EOP_Call, //< Function call - EOP_MCall, //< Method call - EOP_Index, //< Array index - EOP_Unary, //< Unary operation - EOP_Binary, //< Binary operation - EOP_Unknown //< Catchall for everything else + EOP_Nop, ///< No-op + EOP_Wildcard, ///< Matches anything. + EOP_Universal, ///< Universal lock. + EOP_This, ///< This keyword. + EOP_NVar, ///< Named variable. + EOP_LVar, ///< Local variable. + EOP_Dot, ///< Field access + EOP_Call, ///< Function call + EOP_MCall, ///< Method call + EOP_Index, ///< Array index + EOP_Unary, ///< Unary operation + EOP_Binary, ///< Binary operation + EOP_Unknown ///< Catchall for everything else }; class SExprNode { private: - unsigned char Op; //< Opcode of the root node - unsigned char Flags; //< Additional opcode-specific data - unsigned short Sz; //< Number of child nodes - const void* Data; //< Additional opcode-specific data + unsigned char Op; ///< Opcode of the root node + unsigned char Flags; ///< Additional opcode-specific data + unsigned short Sz; ///< Number of child nodes + const void* Data; ///< Additional opcode-specific data public: SExprNode(ExprOp O, unsigned F, const void* D) @@ -118,18 +119,19 @@ private: unsigned arity() const { switch (Op) { - case EOP_Nop: return 0; - case EOP_Wildcard: return 0; - case EOP_NVar: return 0; - case EOP_LVar: return 0; - case EOP_This: return 0; - case EOP_Dot: return 1; - case EOP_Call: return Flags+1; // First arg is function. - case EOP_MCall: return Flags+1; // First arg is implicit obj. - case EOP_Index: return 2; - case EOP_Unary: return 1; - case EOP_Binary: return 2; - case EOP_Unknown: return Flags; + case EOP_Nop: return 0; + case EOP_Wildcard: return 0; + case EOP_Universal: return 0; + case EOP_NVar: return 0; + case EOP_LVar: return 0; + case EOP_This: return 0; + case EOP_Dot: return 1; + case EOP_Call: return Flags+1; // First arg is function. + case EOP_MCall: return Flags+1; // First arg is implicit obj. + case EOP_Index: return 2; + case EOP_Unary: return 1; + case EOP_Binary: return 2; + case EOP_Unknown: return Flags; } return 0; } @@ -194,6 +196,11 @@ private: return NodeVec.size()-1; } + unsigned makeUniversal() { + NodeVec.push_back(SExprNode(EOP_Universal, 0, 0)); + return NodeVec.size()-1; + } + unsigned makeNamedVar(const NamedDecl *D) { NodeVec.push_back(SExprNode(EOP_NVar, 0, D)); return NodeVec.size()-1; @@ -219,8 +226,21 @@ private: return NodeVec.size()-1; } - unsigned makeMCall(unsigned NumArgs, const NamedDecl *D) { - NodeVec.push_back(SExprNode(EOP_MCall, NumArgs, D)); + // Grab the very first declaration of virtual method D + const CXXMethodDecl* getFirstVirtualDecl(const CXXMethodDecl *D) { + while (true) { + D = D->getCanonicalDecl(); + CXXMethodDecl::method_iterator I = D->begin_overridden_methods(), + E = D->end_overridden_methods(); + if (I == E) + return D; // Method does not override anything + D = *I; // FIXME: this does not work with multiple inheritance. + } + return 0; + } + + unsigned makeMCall(unsigned NumArgs, const CXXMethodDecl *D) { + NodeVec.push_back(SExprNode(EOP_MCall, NumArgs, getFirstVirtualDecl(D))); return NodeVec.size()-1; } @@ -300,8 +320,9 @@ private: } else if (CXXMemberCallExpr *CMCE = dyn_cast<CXXMemberCallExpr>(Exp)) { // When calling a function with a lock_returned attribute, replace // the function call with the expression in lock_returned. - if (LockReturnedAttr* At = - CMCE->getMethodDecl()->getAttr<LockReturnedAttr>()) { + CXXMethodDecl* MD = + cast<CXXMethodDecl>(CMCE->getMethodDecl()->getMostRecentDecl()); + if (LockReturnedAttr* At = MD->getAttr<LockReturnedAttr>()) { CallingContext LRCallCtx(CMCE->getMethodDecl()); LRCallCtx.SelfArg = CMCE->getImplicitObjectArgument(); LRCallCtx.SelfArrow = @@ -320,8 +341,7 @@ private: return buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx, NDeref); } unsigned NumCallArgs = CMCE->getNumArgs(); - unsigned Root = - makeMCall(NumCallArgs, CMCE->getMethodDecl()->getCanonicalDecl()); + unsigned Root = makeMCall(NumCallArgs, CMCE->getMethodDecl()); unsigned Sz = buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx); Expr** CallArgs = CMCE->getArgs(); for (unsigned i = 0; i < NumCallArgs; ++i) { @@ -330,8 +350,9 @@ private: NodeVec[Root].setSize(Sz + 1); return Sz + 1; } else if (CallExpr *CE = dyn_cast<CallExpr>(Exp)) { - if (LockReturnedAttr* At = - CE->getDirectCallee()->getAttr<LockReturnedAttr>()) { + FunctionDecl* FD = + cast<FunctionDecl>(CE->getDirectCallee()->getMostRecentDecl()); + if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) { CallingContext LRCallCtx(CE->getDirectCallee()); LRCallCtx.NumArgs = CE->getNumArgs(); LRCallCtx.FunArgs = CE->getArgs(); @@ -442,9 +463,23 @@ private: /// \param DeclExp An expression involving the Decl on which the attribute /// occurs. /// \param D The declaration to which the lock/unlock attribute is attached. - void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D) { + void buildSExprFromExpr(Expr *MutexExp, Expr *DeclExp, const NamedDecl *D, + VarDecl *SelfDecl = 0) { CallingContext CallCtx(D); + if (MutexExp) { + if (StringLiteral* SLit = dyn_cast<StringLiteral>(MutexExp)) { + if (SLit->getString() == StringRef("*")) + // The "*" expr is a universal lock, which essentially turns off + // checks until it is removed from the lockset. + makeUniversal(); + else + // Ignore other string literals for now. + makeNop(); + return; + } + } + // If we are processing a raw attribute expression, with no substitutions. if (DeclExp == 0) { buildSExpr(MutexExp, 0); @@ -465,7 +500,7 @@ private: CallCtx.NumArgs = CE->getNumArgs(); CallCtx.FunArgs = CE->getArgs(); } else if (CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(DeclExp)) { - CallCtx.SelfArg = 0; // FIXME -- get the parent from DeclStmt + CallCtx.SelfArg = 0; // Will be set below CallCtx.NumArgs = CE->getNumArgs(); CallCtx.FunArgs = CE->getArgs(); } else if (D && isa<CXXDestructorDecl>(D)) { @@ -473,14 +508,26 @@ private: CallCtx.SelfArg = DeclExp; } - // If the attribute has no arguments, then assume the argument is "this". - if (MutexExp == 0) { - buildSExpr(CallCtx.SelfArg, 0); + // Hack to handle constructors, where self cannot be recovered from + // the expression. + if (SelfDecl && !CallCtx.SelfArg) { + DeclRefExpr SelfDRE(SelfDecl, false, SelfDecl->getType(), VK_LValue, + SelfDecl->getLocation()); + CallCtx.SelfArg = &SelfDRE; + + // If the attribute has no arguments, then assume the argument is "this". + if (MutexExp == 0) + buildSExpr(CallCtx.SelfArg, 0); + else // For most attributes. + buildSExpr(MutexExp, &CallCtx); return; } - // For most attributes. - buildSExpr(MutexExp, &CallCtx); + // If the attribute has no arguments, then assume the argument is "this". + if (MutexExp == 0) + buildSExpr(CallCtx.SelfArg, 0); + else // For most attributes. + buildSExpr(MutexExp, &CallCtx); } /// \brief Get index of next sibling of node i. @@ -496,8 +543,9 @@ public: /// occurs. /// \param D The declaration to which the lock/unlock attribute is attached. /// Caller must check isValid() after construction. - SExpr(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D) { - buildSExprFromExpr(MutexExp, DeclExp, D); + SExpr(Expr* MutexExp, Expr *DeclExp, const NamedDecl* D, + VarDecl *SelfDecl=0) { + buildSExprFromExpr(MutexExp, DeclExp, D, SelfDecl); } /// Return true if this is a valid decl sequence. @@ -506,6 +554,17 @@ public: return !NodeVec.empty(); } + bool shouldIgnore() const { + // Nop is a mutex that we have decided to deliberately ignore. + assert(NodeVec.size() > 0 && "Invalid Mutex"); + return NodeVec[0].kind() == EOP_Nop; + } + + bool isUniversal() const { + assert(NodeVec.size() > 0 && "Invalid Mutex"); + return NodeVec[0].kind() == EOP_Universal; + } + /// Issue a warning about an invalid lock expression static void warnInvalidLock(ThreadSafetyHandler &Handler, Expr* MutexExp, Expr *DeclExp, const NamedDecl* D) { @@ -528,7 +587,9 @@ public: bool matches(const SExpr &Other, unsigned i = 0, unsigned j = 0) const { if (NodeVec[i].matches(Other.NodeVec[j])) { - unsigned n = NodeVec[i].arity(); + unsigned ni = NodeVec[i].arity(); + unsigned nj = Other.NodeVec[j].arity(); + unsigned n = (ni < nj) ? ni : nj; bool Result = true; unsigned ci = i+1; // first child of i unsigned cj = j+1; // first child of j @@ -541,6 +602,15 @@ public: return false; } + // A partial match between a.mu and b.mu returns true a and b have the same + // type (and thus mu refers to the same mutex declaration), regardless of + // whether a and b are different objects or not. + bool partiallyMatches(const SExpr &Other) const { + if (NodeVec[0].kind() == EOP_Dot) + return NodeVec[0].matches(Other.NodeVec[0]); + return false; + } + /// \brief Pretty print a lock expression for use in error messages. std::string toString(unsigned i = 0) const { assert(isValid()); @@ -553,6 +623,8 @@ public: return "_"; case EOP_Wildcard: return "(?)"; + case EOP_Universal: + return "*"; case EOP_This: return "this"; case EOP_NVar: @@ -695,6 +767,10 @@ struct LockData { ID.AddInteger(AcquireLoc.getRawEncoding()); ID.AddInteger(LKind); } + + bool isAtLeast(LockKind LK) { + return (LK == LK_Shared) || (LKind == LK_Exclusive); + } }; @@ -780,9 +856,28 @@ public: return false; } - LockData* findLock(FactManager& FM, const SExpr& M) const { + LockData* findLock(FactManager &FM, const SExpr &M) const { + for (const_iterator I = begin(), E = end(); I != E; ++I) { + const SExpr &Exp = FM[*I].MutID; + if (Exp.matches(M)) + return &FM[*I].LDat; + } + return 0; + } + + LockData* findLockUniv(FactManager &FM, const SExpr &M) const { + for (const_iterator I = begin(), E = end(); I != E; ++I) { + const SExpr &Exp = FM[*I].MutID; + if (Exp.matches(M) || Exp.isUniversal()) + return &FM[*I].LDat; + } + return 0; + } + + FactEntry* findPartialMatch(FactManager &FM, const SExpr &M) const { for (const_iterator I=begin(), E=end(); I != E; ++I) { - if (FM[*I].MutID.matches(M)) return &FM[*I].LDat; + const SExpr& Exp = FM[*I].MutID; + if (Exp.partiallyMatches(M)) return &FM[*I]; } return 0; } @@ -811,6 +906,7 @@ struct CFGBlockInfo { SourceLocation EntryLoc; // Location of first statement in block SourceLocation ExitLoc; // Location of last statement in block. unsigned EntryIndex; // Used to replay contexts later + bool Reachable; // Is this block reachable? const FactSet &getSet(CFGBlockSide Side) const { return Side == CBS_Entry ? EntrySet : ExitSet; @@ -821,7 +917,7 @@ struct CFGBlockInfo { private: CFGBlockInfo(LocalVarContext EmptyCtx) - : EntryContext(EmptyCtx), ExitContext(EmptyCtx) + : EntryContext(EmptyCtx), ExitContext(EmptyCtx), Reachable(false) { } public: @@ -939,7 +1035,7 @@ public: return; } Dec->printName(llvm::errs()); - llvm::errs() << "." << i << " " << ((void*) Dec); + llvm::errs() << "." << i << " " << ((const void*) Dec); } /// Dumps an ASCII representation of the variable map to llvm::errs() @@ -1339,7 +1435,7 @@ public: template <typename AttrType> void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp, - const NamedDecl *D); + const NamedDecl *D, VarDecl *SelfDecl=0); template <class AttrType> void getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, Expr *Exp, @@ -1376,6 +1472,9 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex, const LockData &LDat) { // FIXME: deal with acquired before/after annotations. // FIXME: Don't always warn when we have support for reentrant locks. + if (Mutex.shouldIgnore()) + return; + if (FSet.findLock(FactMan, Mutex)) { Handler.handleDoubleLock(Mutex.toString(), LDat.AcquireLoc); } else { @@ -1385,12 +1484,15 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, const SExpr &Mutex, /// \brief Remove a lock from the lockset, warning if the lock is not there. -/// \param LockExp The lock expression corresponding to the lock to be removed +/// \param Mutex The lock expression corresponding to the lock to be removed /// \param UnlockLoc The source location of the unlock (only used in error msg) void ThreadSafetyAnalyzer::removeLock(FactSet &FSet, const SExpr &Mutex, SourceLocation UnlockLoc, bool FullyRemove) { + if (Mutex.shouldIgnore()) + return; + const LockData *LDat = FSet.findLock(FactMan, Mutex); if (!LDat) { Handler.handleUnmatchedUnlock(Mutex.toString(), UnlockLoc); @@ -1423,12 +1525,13 @@ void ThreadSafetyAnalyzer::removeLock(FactSet &FSet, /// and push them onto Mtxs, discarding any duplicates. template <typename AttrType> void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, - Expr *Exp, const NamedDecl *D) { + Expr *Exp, const NamedDecl *D, + VarDecl *SelfDecl) { typedef typename AttrType::args_iterator iterator_type; if (Attr->args_size() == 0) { // The mutex held is the "this" object. - SExpr Mu(0, Exp, D); + SExpr Mu(0, Exp, D, SelfDecl); if (!Mu.isValid()) SExpr::warnInvalidLock(Handler, 0, Exp, D); else @@ -1437,7 +1540,7 @@ void ThreadSafetyAnalyzer::getMutexIDs(MutexIDList &Mtxs, AttrType *Attr, } for (iterator_type I=Attr->args_begin(), E=Attr->args_end(); I != E; ++I) { - SExpr Mu(*I, Exp, D); + SExpr Mu(*I, Exp, D, SelfDecl); if (!Mu.isValid()) SExpr::warnInvalidLock(Handler, *I, Exp, D); else @@ -1512,6 +1615,9 @@ const CallExpr* ThreadSafetyAnalyzer::getTrylockCallExpr(const Stmt *Cond, else if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(Cond)) { return getTrylockCallExpr(CE->getSubExpr(), C, Negate); } + else if (const ExprWithCleanups* EWC = dyn_cast<ExprWithCleanups>(Cond)) { + return getTrylockCallExpr(EWC->getSubExpr(), C, Negate); + } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Cond)) { const Expr *E = LocalVarMap.lookupExpr(DRE->getDecl(), C); return getTrylockCallExpr(E, C, Negate); @@ -1591,7 +1697,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result, case attr::SharedTrylockFunction: { SharedTrylockFunctionAttr *A = cast<SharedTrylockFunctionAttr>(Attr); - getMutexIDs(ExclusiveLocksToAdd, A, Exp, FunDecl, + getMutexIDs(SharedLocksToAdd, A, Exp, FunDecl, PredBlock, CurrBlock, A->getSuccessValue(), Negate); break; } @@ -1631,39 +1737,12 @@ class BuildLockset : public StmtVisitor<BuildLockset> { void warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, AccessKind AK, Expr *MutexExp, ProtectedOperationKind POK); + void warnIfMutexHeld(const NamedDecl *D, Expr *Exp, Expr *MutexExp); void checkAccess(Expr *Exp, AccessKind AK); void checkDereference(Expr *Exp, AccessKind AK); void handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD = 0); - /// \brief Returns true if the lockset contains a lock, regardless of whether - /// the lock is held exclusively or shared. - bool locksetContains(const SExpr &Mu) const { - return FSet.findLock(Analyzer->FactMan, Mu); - } - - /// \brief Returns true if the lockset contains a lock with the passed in - /// locktype. - bool locksetContains(const SExpr &Mu, LockKind KindRequested) const { - const LockData *LockHeld = FSet.findLock(Analyzer->FactMan, Mu); - return (LockHeld && KindRequested == LockHeld->LKind); - } - - /// \brief Returns true if the lockset contains a lock with at least the - /// passed in locktype. So for example, if we pass in LK_Shared, this function - /// returns true if the lock is held LK_Shared or LK_Exclusive. If we pass in - /// LK_Exclusive, this function returns true if the lock is held LK_Exclusive. - bool locksetContainsAtLeast(const SExpr &Lock, - LockKind KindRequested) const { - switch (KindRequested) { - case LK_Shared: - return locksetContains(Lock); - case LK_Exclusive: - return locksetContains(Lock, KindRequested); - } - llvm_unreachable("Unknown LockKind"); - } - public: BuildLockset(ThreadSafetyAnalyzer *Anlzr, CFGBlockInfo &Info) : StmtVisitor<BuildLockset>(), @@ -1701,13 +1780,57 @@ void BuildLockset::warnIfMutexNotHeld(const NamedDecl *D, Expr *Exp, LockKind LK = getLockKindFromAccessKind(AK); SExpr Mutex(MutexExp, Exp, D); - if (!Mutex.isValid()) + if (!Mutex.isValid()) { SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D); - else if (!locksetContainsAtLeast(Mutex, LK)) + return; + } else if (Mutex.shouldIgnore()) { + return; + } + + LockData* LDat = FSet.findLockUniv(Analyzer->FactMan, Mutex); + bool NoError = true; + if (!LDat) { + // No exact match found. Look for a partial match. + FactEntry* FEntry = FSet.findPartialMatch(Analyzer->FactMan, Mutex); + if (FEntry) { + // Warn that there's no precise match. + LDat = &FEntry->LDat; + std::string PartMatchStr = FEntry->MutID.toString(); + StringRef PartMatchName(PartMatchStr); + Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK, + Exp->getExprLoc(), &PartMatchName); + } else { + // Warn that there's no match at all. + Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK, + Exp->getExprLoc()); + } + NoError = false; + } + // Make sure the mutex we found is the right kind. + if (NoError && LDat && !LDat->isAtLeast(LK)) Analyzer->Handler.handleMutexNotHeld(D, POK, Mutex.toString(), LK, Exp->getExprLoc()); } +/// \brief Warn if the LSet contains the given lock. +void BuildLockset::warnIfMutexHeld(const NamedDecl *D, Expr* Exp, + Expr *MutexExp) { + SExpr Mutex(MutexExp, Exp, D); + if (!Mutex.isValid()) { + SExpr::warnInvalidLock(Analyzer->Handler, MutexExp, Exp, D); + return; + } + + LockData* LDat = FSet.findLock(Analyzer->FactMan, Mutex); + if (LDat) { + std::string DeclName = D->getNameAsString(); + StringRef DeclNameSR (DeclName); + Analyzer->Handler.handleFunExcludesLock(DeclNameSR, Mutex.toString(), + Exp->getExprLoc()); + } +} + + /// \brief This method identifies variable dereferences and checks pt_guarded_by /// and pt_guarded_var annotations. Note that we only check these annotations /// at the time a pointer is dereferenced. @@ -1776,7 +1899,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { // to our lockset with kind exclusive. case attr::ExclusiveLockFunction: { ExclusiveLockFunctionAttr *A = cast<ExclusiveLockFunctionAttr>(At); - Analyzer->getMutexIDs(ExclusiveLocksToAdd, A, Exp, D); + Analyzer->getMutexIDs(ExclusiveLocksToAdd, A, Exp, D, VD); break; } @@ -1784,7 +1907,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { // to our lockset with kind shared. case attr::SharedLockFunction: { SharedLockFunctionAttr *A = cast<SharedLockFunctionAttr>(At); - Analyzer->getMutexIDs(SharedLocksToAdd, A, Exp, D); + Analyzer->getMutexIDs(SharedLocksToAdd, A, Exp, D, VD); break; } @@ -1792,7 +1915,7 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { // mutexes from the lockset, and flag a warning if they are not there. case attr::UnlockFunction: { UnlockFunctionAttr *A = cast<UnlockFunctionAttr>(At); - Analyzer->getMutexIDs(LocksToRemove, A, Exp, D); + Analyzer->getMutexIDs(LocksToRemove, A, Exp, D, VD); break; } @@ -1816,15 +1939,10 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { case attr::LocksExcluded: { LocksExcludedAttr *A = cast<LocksExcludedAttr>(At); + for (LocksExcludedAttr::args_iterator I = A->args_begin(), E = A->args_end(); I != E; ++I) { - SExpr Mutex(*I, Exp, D); - if (!Mutex.isValid()) - SExpr::warnInvalidLock(Analyzer->Handler, *I, Exp, D); - else if (locksetContains(Mutex)) - Analyzer->Handler.handleFunExcludesLock(D->getName(), - Mutex.toString(), - Exp->getExprLoc()); + warnIfMutexHeld(D, Exp, *I); } break; } @@ -1973,8 +2091,8 @@ void BuildLockset::VisitDeclStmt(DeclStmt *S) { /// are the same. In the event of a difference, we use the intersection of these /// two locksets at the start of D. /// -/// \param LSet1 The first lockset. -/// \param LSet2 The second lockset. +/// \param FSet1 The first lockset. +/// \param FSet2 The second lockset. /// \param JoinLoc The location of the join point for error reporting /// \param LEK1 The error message to report if a mutex is missing from LSet1 /// \param LEK2 The error message to report if a mutex is missing from Lset2 @@ -2012,7 +2130,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1, JoinLoc, LEK1); } } - else if (!LDat2.Managed) + else if (!LDat2.Managed && !FSet2Mutex.isUniversal()) Handler.handleMutexHeldEndOfScope(FSet2Mutex.toString(), LDat2.AcquireLoc, JoinLoc, LEK1); @@ -2035,7 +2153,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1, JoinLoc, LEK1); } } - else if (!LDat1.Managed) + else if (!LDat1.Managed && !FSet1Mutex.isUniversal()) Handler.handleMutexHeldEndOfScope(FSet1Mutex.toString(), LDat1.AcquireLoc, JoinLoc, LEK2); @@ -2081,6 +2199,9 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>(); PostOrderCFGView::CFGBlockSet VisitedBlocks(CFGraph); + // Mark entry block as reachable + BlockInfo[CFGraph->getEntry().getBlockID()].Reachable = true; + // Compute SSA names for local variables LocalVarMap.traverseCFG(CFGraph, SortedGraph, BlockInfo); @@ -2168,10 +2289,16 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { if (*PI == 0 || !VisitedBlocks.alreadySet(*PI)) continue; + int PrevBlockID = (*PI)->getBlockID(); + CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID]; + // Ignore edges from blocks that can't return. - if ((*PI)->hasNoReturnElement()) + if ((*PI)->hasNoReturnElement() || !PrevBlockInfo->Reachable) continue; + // Okay, we can reach this block from the entry. + CurrBlockInfo->Reachable = true; + // If the previous block ended in a 'continue' or 'break' statement, then // a difference in locksets is probably due to a bug in that block, rather // than in some other predecessor. In that case, keep the other @@ -2183,8 +2310,7 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { } } - int PrevBlockID = (*PI)->getBlockID(); - CFGBlockInfo *PrevBlockInfo = &BlockInfo[PrevBlockID]; + FactSet PrevLockset; getEdgeLockset(PrevLockset, PrevBlockInfo->ExitSet, *PI, CurrBlock); @@ -2198,6 +2324,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { } } + // Skip rest of block if it's not reachable. + if (!CurrBlockInfo->Reachable) + continue; + // Process continue and break blocks. Assume that the lockset for the // resulting block is unaffected by any discrepancies in them. for (unsigned SpecialI = 0, SpecialN = SpecialBlocks.size(); @@ -2287,6 +2417,10 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { CFGBlockInfo *Initial = &BlockInfo[CFGraph->getEntry().getBlockID()]; CFGBlockInfo *Final = &BlockInfo[CFGraph->getExit().getBlockID()]; + // Skip the final check if the exit block is unreachable. + if (!Final->Reachable) + return; + // FIXME: Should we call this function for all blocks which exit the function? intersectAndWarn(Initial->EntrySet, Final->ExitSet, Final->ExitLoc, diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index 858be4561caf..b2e27cad1f39 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -13,6 +13,7 @@ #include <utility> #include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/PackedVector.h" #include "llvm/ADT/DenseMap.h" @@ -22,6 +23,7 @@ #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" #include "clang/Analysis/Analyses/UninitializedValues.h" +#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h" #include "llvm/Support/SaveAndRestore.h" using namespace clang; @@ -97,22 +99,21 @@ static bool isAlwaysUninit(const Value v) { namespace { -typedef llvm::PackedVector<Value, 2> ValueVector; +typedef llvm::PackedVector<Value, 2, llvm::SmallBitVector> ValueVector; class CFGBlockValues { const CFG &cfg; - std::vector<ValueVector*> vals; + SmallVector<ValueVector, 8> vals; ValueVector scratch; DeclToIndex declToIndex; public: CFGBlockValues(const CFG &cfg); - ~CFGBlockValues(); unsigned getNumEntries() const { return declToIndex.size(); } void computeSetOfDeclarations(const DeclContext &dc); ValueVector &getValueVector(const CFGBlock *block) { - return *vals[block->getBlockID()]; + return vals[block->getBlockID()]; } void setAllScratchValues(Value V); @@ -138,12 +139,6 @@ public: CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {} -CFGBlockValues::~CFGBlockValues() { - for (std::vector<ValueVector*>::iterator I = vals.begin(), E = vals.end(); - I != E; ++I) - delete *I; -} - void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) { declToIndex.computeMap(dc); unsigned decls = declToIndex.size(); @@ -153,7 +148,7 @@ void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) { return; vals.resize(n); for (unsigned i = 0; i < n; ++i) - vals[i] = new ValueVector(decls); + vals[i].resize(decls); } #if DEBUG_LOGGING @@ -412,6 +407,7 @@ class TransferFunctions : public StmtVisitor<TransferFunctions> { const CFGBlock *block; AnalysisDeclContext ∾ const ClassifyRefs &classification; + ObjCNoReturn objCNoRet; UninitVariablesHandler *handler; public: @@ -420,16 +416,18 @@ public: const ClassifyRefs &classification, UninitVariablesHandler *handler) : vals(vals), cfg(cfg), block(block), ac(ac), - classification(classification), handler(handler) {} + classification(classification), objCNoRet(ac.getASTContext()), + handler(handler) {} void reportUse(const Expr *ex, const VarDecl *vd); - void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS); + void VisitBinaryOperator(BinaryOperator *bo); void VisitBlockExpr(BlockExpr *be); void VisitCallExpr(CallExpr *ce); - void VisitDeclStmt(DeclStmt *ds); void VisitDeclRefExpr(DeclRefExpr *dr); - void VisitBinaryOperator(BinaryOperator *bo); + void VisitDeclStmt(DeclStmt *ds); + void VisitObjCForCollectionStmt(ObjCForCollectionStmt *FS); + void VisitObjCMessageExpr(ObjCMessageExpr *ME); bool isTrackedVar(const VarDecl *vd) { return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl())); @@ -605,14 +603,26 @@ void TransferFunctions::VisitBlockExpr(BlockExpr *be) { } void TransferFunctions::VisitCallExpr(CallExpr *ce) { - // After a call to a function like setjmp or vfork, any variable which is - // initialized anywhere within this function may now be initialized. For now, - // just assume such a call initializes all variables. - // FIXME: Only mark variables as initialized if they have an initializer which - // is reachable from here. - Decl *Callee = ce->getCalleeDecl(); - if (Callee && Callee->hasAttr<ReturnsTwiceAttr>()) - vals.setAllScratchValues(Initialized); + if (Decl *Callee = ce->getCalleeDecl()) { + if (Callee->hasAttr<ReturnsTwiceAttr>()) { + // After a call to a function like setjmp or vfork, any variable which is + // initialized anywhere within this function may now be initialized. For + // now, just assume such a call initializes all variables. FIXME: Only + // mark variables as initialized if they have an initializer which is + // reachable from here. + vals.setAllScratchValues(Initialized); + } + else if (Callee->hasAttr<AnalyzerNoReturnAttr>()) { + // Functions labeled like "analyzer_noreturn" are often used to denote + // "panic" functions that in special debug situations can still return, + // but for the most part should not be treated as returning. This is a + // useful annotation borrowed from the static analyzer that is useful for + // suppressing branch-specific false positives when we call one of these + // functions but keep pretending the path continues (when in reality the + // user doesn't care). + vals.setAllScratchValues(Unknown); + } + } } void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) { @@ -677,6 +687,14 @@ void TransferFunctions::VisitDeclStmt(DeclStmt *DS) { } } +void TransferFunctions::VisitObjCMessageExpr(ObjCMessageExpr *ME) { + // If the Objective-C message expression is an implicit no-return that + // is not modeled in the CFG, set the tracked dataflow values to Unknown. + if (objCNoRet.isImplicitNoReturn(ME)) { + vals.setAllScratchValues(Unknown); + } +} + //------------------------------------------------------------------------====// // High-level "driver" logic for uninitialized values analysis. //====------------------------------------------------------------------------// diff --git a/lib/Basic/ConvertUTF.c b/lib/Basic/ConvertUTF.c index 4793b251f603..d16965ddd872 100644 --- a/lib/Basic/ConvertUTF.c +++ b/lib/Basic/ConvertUTF.c @@ -111,7 +111,6 @@ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC * into an inline function. */ -#ifdef CLANG_NEEDS_THESE_ONE_DAY /* --------------------------------------------------------------------- */ @@ -285,7 +284,6 @@ ConversionResult ConvertUTF16toUTF8 ( *targetStart = target; return result; } -#endif /* --------------------------------------------------------------------- */ @@ -361,7 +359,7 @@ static Boolean isLegalUTF8(const UTF8 *source, int length) { /* Everything else falls through when "true"... */ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 2: if ((a = (*--srcptr)) > 0xBF) return false; + case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; switch (*source) { /* no fall-through in this inner switch */ @@ -395,15 +393,25 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { /* --------------------------------------------------------------------- */ /* + * Exported function to return the total number of bytes in a codepoint + * represented in UTF-8, given the value of the first byte. + */ +unsigned getNumBytesForUTF8(UTF8 first) { + return trailingBytesForUTF8[first] + 1; +} + +/* --------------------------------------------------------------------- */ + +/* * Exported function to return whether a UTF-8 string is legal or not. * This is not used here; it's just exported. */ -Boolean isLegalUTF8String(const UTF8 *source, const UTF8 *sourceEnd) { - while (source != sourceEnd) { - int length = trailingBytesForUTF8[*source] + 1; - if (length > sourceEnd - source || !isLegalUTF8(source, length)) +Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd) { + while (*source != sourceEnd) { + int length = trailingBytesForUTF8[**source] + 1; + if (length > sourceEnd - *source || !isLegalUTF8(*source, length)) return false; - source += length; + *source += length; } return true; } diff --git a/lib/Basic/ConvertUTFWrapper.cpp b/lib/Basic/ConvertUTFWrapper.cpp index a1b3f7fd9da3..6be3828d2868 100644 --- a/lib/Basic/ConvertUTFWrapper.cpp +++ b/lib/Basic/ConvertUTFWrapper.cpp @@ -13,16 +13,19 @@ namespace clang { bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source, - char *&ResultPtr) { + char *&ResultPtr, const UTF8 *&ErrorPtr) { assert(WideCharWidth == 1 || WideCharWidth == 2 || WideCharWidth == 4); ConversionResult result = conversionOK; // Copy the character span over. if (WideCharWidth == 1) { - if (!isLegalUTF8String(reinterpret_cast<const UTF8*>(Source.begin()), - reinterpret_cast<const UTF8*>(Source.end()))) + const UTF8 *Pos = reinterpret_cast<const UTF8*>(Source.begin()); + if (!isLegalUTF8String(&Pos, reinterpret_cast<const UTF8*>(Source.end()))) { result = sourceIllegal; - memcpy(ResultPtr, Source.data(), Source.size()); - ResultPtr += Source.size(); + ErrorPtr = Pos; + } else { + memcpy(ResultPtr, Source.data(), Source.size()); + ResultPtr += Source.size(); + } } else if (WideCharWidth == 2) { const UTF8 *sourceStart = (const UTF8*)Source.data(); // FIXME: Make the type of the result buffer correct instead of @@ -34,6 +37,8 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source, &targetStart, targetStart + 2*Source.size(), flags); if (result == conversionOK) ResultPtr = reinterpret_cast<char*>(targetStart); + else + ErrorPtr = sourceStart; } else if (WideCharWidth == 4) { const UTF8 *sourceStart = (const UTF8*)Source.data(); // FIXME: Make the type of the result buffer correct instead of @@ -45,6 +50,8 @@ bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source, &targetStart, targetStart + 4*Source.size(), flags); if (result == conversionOK) ResultPtr = reinterpret_cast<char*>(targetStart); + else + ErrorPtr = sourceStart; } assert((result != targetExhausted) && "ConvertUTF8toUTFXX exhausted target buffer"); @@ -67,4 +74,3 @@ bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) { } } // end namespace clang - diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 8065b2d98f32..854c4c56bb7f 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -12,9 +12,11 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/PartialDiagnostic.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/CrashRecoveryContext.h" #include <cctype> @@ -36,9 +38,10 @@ static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT, DiagnosticsEngine::DiagnosticsEngine( const IntrusiveRefCntPtr<DiagnosticIDs> &diags, + DiagnosticOptions *DiagOpts, DiagnosticConsumer *client, bool ShouldOwnClient) - : Diags(diags), Client(client), OwnsDiagClient(ShouldOwnClient), - SourceMgr(0) { + : Diags(diags), DiagOpts(DiagOpts), Client(client), + OwnsDiagClient(ShouldOwnClient), SourceMgr(0) { ArgToStringFn = DummyArgToStringFn; ArgToStringCookie = 0; @@ -515,23 +518,7 @@ static void HandleOrdinalModifier(unsigned ValNo, // We could use text forms for the first N ordinals, but the numeric // forms are actually nicer in diagnostics because they stand out. - Out << ValNo; - - // It is critically important that we do this perfectly for - // user-written sequences with over 100 elements. - switch (ValNo % 100) { - case 11: - case 12: - case 13: - Out << "th"; return; - default: - switch (ValNo % 10) { - case 1: Out << "st"; return; - case 2: Out << "nd"; return; - case 3: Out << "rd"; return; - default: Out << "th"; return; - } - } + Out << ValNo << llvm::getOrdinalSuffix(ValNo); } diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp index ca96fd2b9b24..ed976436e284 100644 --- a/lib/Basic/DiagnosticIDs.cpp +++ b/lib/Basic/DiagnosticIDs.cpp @@ -628,9 +628,9 @@ bool DiagnosticIDs::ProcessDiag(DiagnosticsEngine &Diag) const { if (DiagLevel >= DiagnosticIDs::Error) { if (isUnrecoverable(DiagID)) Diag.UnrecoverableErrorOccurred = true; - + + Diag.ErrorOccurred = true; if (Diag.Client->IncludeInDiagnosticCounts()) { - Diag.ErrorOccurred = true; ++Diag.NumErrors; } @@ -686,4 +686,3 @@ bool DiagnosticIDs::isARCDiagnostic(unsigned DiagID) { unsigned cat = getCategoryNumberForDiag(DiagID); return DiagnosticIDs::getCategoryNameFromID(cat).startswith("ARC "); } - diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index c6b894c7e2fe..a816969b9144 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -36,6 +36,9 @@ #include <sys/uio.h> #else #include <io.h> +#ifndef S_ISFIFO +#define S_ISFIFO(x) (0) +#endif #endif using namespace clang; @@ -57,6 +60,10 @@ FileEntry::~FileEntry() { if (FD != -1) ::close(FD); } +bool FileEntry::isNamedPipe() const { + return S_ISFIFO(FileMode); +} + //===----------------------------------------------------------------------===// // Windows. //===----------------------------------------------------------------------===// diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 4869ae1056be..1965bf99338b 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -17,7 +17,6 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" #include <cctype> @@ -33,6 +32,7 @@ IdentifierInfo::IdentifierInfo() { TokenID = tok::identifier; ObjCOrBuiltinID = 0; HasMacro = false; + HadMacro = false; IsExtension = false; IsCXX11CompatKeyword = false; IsPoisoned = false; @@ -105,6 +105,7 @@ namespace { KEYC11 = 0x400, KEYARC = 0x800, KEYNOMS = 0x01000, + WCHARSUPPORT = 0x02000, KEYALL = (0xffff & ~KEYNOMS) // Because KEYNOMS is used to exclude. }; } @@ -129,6 +130,7 @@ static void AddKeyword(StringRef Keyword, else if (LangOpts.MicrosoftExt && (Flags & KEYMS)) AddResult = 1; else if (LangOpts.Borland && (Flags & KEYBORLAND)) AddResult = 1; else if (LangOpts.Bool && (Flags & BOOLSUPPORT)) AddResult = 2; + else if (LangOpts.WChar && (Flags & WCHARSUPPORT)) AddResult = 2; else if (LangOpts.AltiVec && (Flags & KEYALTIVEC)) AddResult = 2; else if (LangOpts.OpenCL && (Flags & KEYOPENCL)) AddResult = 2; else if (!LangOpts.CPlusPlus && (Flags & KEYNOCXX)) AddResult = 2; diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index 634884074e14..76c7f8b364eb 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -23,8 +23,8 @@ using namespace clang; Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, bool IsFramework, bool IsExplicit) - : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), - Umbrella(), IsAvailable(true), IsFromModuleFile(false), + : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), + Umbrella(), ASTFile(0), IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false), InferSubmodules(false), InferExplicitSubmodules(false), InferExportWildcard(false), NameVisibility(Hidden) @@ -219,6 +219,13 @@ void Module::print(llvm::raw_ostream &OS, unsigned Indent) const { OS.write_escaped(Headers[I]->getName()); OS << "\"\n"; } + + for (unsigned I = 0, N = ExcludedHeaders.size(); I != N; ++I) { + OS.indent(Indent + 2); + OS << "exclude header \""; + OS.write_escaped(ExcludedHeaders[I]->getName()); + OS << "\"\n"; + } for (submodule_const_iterator MI = submodule_begin(), MIEnd = submodule_end(); MI != MIEnd; ++MI) diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp index bb5a10a9c7e4..0d62f7bb4b8c 100644 --- a/lib/Basic/SourceLocation.cpp +++ b/lib/Basic/SourceLocation.cpp @@ -61,6 +61,13 @@ void SourceLocation::print(raw_ostream &OS, const SourceManager &SM)const{ OS << '>'; } +std::string SourceLocation::printToString(const SourceManager &SM) const { + std::string S; + llvm::raw_string_ostream OS(S); + print(OS, SM); + return S; +} + void SourceLocation::dump(const SourceManager &SM) const { print(llvm::errs(), SM); } diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 9ec247429945..cd0284a18e5d 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -1029,6 +1029,17 @@ unsigned SourceManager::getColumnNumber(FileID FID, unsigned FilePos, return 1; } + // See if we just calculated the line number for this FilePos and can use + // that to lookup the start of the line instead of searching for it. + if (LastLineNoFileIDQuery == FID && + LastLineNoContentCache->SourceLineCache != 0) { + unsigned *SourceLineCache = LastLineNoContentCache->SourceLineCache; + unsigned LineStart = SourceLineCache[LastLineNoResult - 1]; + unsigned LineEnd = SourceLineCache[LastLineNoResult]; + if (FilePos >= LineStart && FilePos < LineEnd) + return FilePos - LineStart + 1; + } + const char *Buf = MemBuf->getBufferStart(); unsigned LineStart = FilePos; while (LineStart && Buf[LineStart-1] != '\n' && Buf[LineStart-1] != '\r') @@ -1112,7 +1123,7 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI, // Scan 16 byte chunks for '\r' and '\n'. Ignore '\0'. while (NextBuf+16 <= End) { - __m128i Chunk = *(__m128i*)NextBuf; + const __m128i Chunk = *(const __m128i*)NextBuf; __m128i Cmp = _mm_or_si128(_mm_cmpeq_epi8(Chunk, CRs), _mm_cmpeq_epi8(Chunk, LFs)); unsigned Mask = _mm_movemask_epi8(Cmp); @@ -1577,6 +1588,7 @@ FileID SourceManager::translateFile(const FileEntry *SourceFile) const { } } + (void) SourceFile; return FirstFID; } @@ -1693,46 +1705,91 @@ void SourceManager::computeMacroArgsCache(MacroArgsMap *&CachePtr, if (!ExpInfo.isMacroArgExpansion()) continue; - SourceLocation SpellLoc = ExpInfo.getSpellingLoc(); - while (!SpellLoc.isFileID()) { - std::pair<FileID, unsigned> LocInfo = getDecomposedLoc(SpellLoc); - const ExpansionInfo &Info = getSLocEntry(LocInfo.first).getExpansion(); - if (!Info.isMacroArgExpansion()) - break; - SpellLoc = Info.getSpellingLoc().getLocWithOffset(LocInfo.second); + associateFileChunkWithMacroArgExp(MacroArgsCache, FID, + ExpInfo.getSpellingLoc(), + SourceLocation::getMacroLoc(Entry.getOffset()), + getFileIDSize(FileID::get(ID))); + } +} + +void SourceManager::associateFileChunkWithMacroArgExp( + MacroArgsMap &MacroArgsCache, + FileID FID, + SourceLocation SpellLoc, + SourceLocation ExpansionLoc, + unsigned ExpansionLength) const { + if (!SpellLoc.isFileID()) { + unsigned SpellBeginOffs = SpellLoc.getOffset(); + unsigned SpellEndOffs = SpellBeginOffs + ExpansionLength; + + // The spelling range for this macro argument expansion can span multiple + // consecutive FileID entries. Go through each entry contained in the + // spelling range and if one is itself a macro argument expansion, recurse + // and associate the file chunk that it represents. + + FileID SpellFID; // Current FileID in the spelling range. + unsigned SpellRelativeOffs; + llvm::tie(SpellFID, SpellRelativeOffs) = getDecomposedLoc(SpellLoc); + while (1) { + const SLocEntry &Entry = getSLocEntry(SpellFID); + unsigned SpellFIDBeginOffs = Entry.getOffset(); + unsigned SpellFIDSize = getFileIDSize(SpellFID); + unsigned SpellFIDEndOffs = SpellFIDBeginOffs + SpellFIDSize; + const ExpansionInfo &Info = Entry.getExpansion(); + if (Info.isMacroArgExpansion()) { + unsigned CurrSpellLength; + if (SpellFIDEndOffs < SpellEndOffs) + CurrSpellLength = SpellFIDSize - SpellRelativeOffs; + else + CurrSpellLength = ExpansionLength; + associateFileChunkWithMacroArgExp(MacroArgsCache, FID, + Info.getSpellingLoc().getLocWithOffset(SpellRelativeOffs), + ExpansionLoc, CurrSpellLength); + } + + if (SpellFIDEndOffs >= SpellEndOffs) + return; // we covered all FileID entries in the spelling range. + + // Move to the next FileID entry in the spelling range. + unsigned advance = SpellFIDSize - SpellRelativeOffs + 1; + ExpansionLoc = ExpansionLoc.getLocWithOffset(advance); + ExpansionLength -= advance; + ++SpellFID.ID; + SpellRelativeOffs = 0; } - if (!SpellLoc.isFileID()) - continue; - - unsigned BeginOffs; - if (!isInFileID(SpellLoc, FID, &BeginOffs)) - continue; - unsigned EndOffs = BeginOffs + getFileIDSize(FileID::get(ID)); - - // Add a new chunk for this macro argument. A previous macro argument chunk - // may have been lexed again, so e.g. if the map is - // 0 -> SourceLocation() - // 100 -> Expanded loc #1 - // 110 -> SourceLocation() - // and we found a new macro FileID that lexed from offet 105 with length 3, - // the new map will be: - // 0 -> SourceLocation() - // 100 -> Expanded loc #1 - // 105 -> Expanded loc #2 - // 108 -> Expanded loc #1 - // 110 -> SourceLocation() - // - // Since re-lexed macro chunks will always be the same size or less of - // previous chunks, we only need to find where the ending of the new macro - // chunk is mapped to and update the map with new begin/end mappings. - - MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs); - --I; - SourceLocation EndOffsMappedLoc = I->second; - MacroArgsCache[BeginOffs] = SourceLocation::getMacroLoc(Entry.getOffset()); - MacroArgsCache[EndOffs] = EndOffsMappedLoc; } + + assert(SpellLoc.isFileID()); + + unsigned BeginOffs; + if (!isInFileID(SpellLoc, FID, &BeginOffs)) + return; + + unsigned EndOffs = BeginOffs + ExpansionLength; + + // Add a new chunk for this macro argument. A previous macro argument chunk + // may have been lexed again, so e.g. if the map is + // 0 -> SourceLocation() + // 100 -> Expanded loc #1 + // 110 -> SourceLocation() + // and we found a new macro FileID that lexed from offet 105 with length 3, + // the new map will be: + // 0 -> SourceLocation() + // 100 -> Expanded loc #1 + // 105 -> Expanded loc #2 + // 108 -> Expanded loc #1 + // 110 -> SourceLocation() + // + // Since re-lexed macro chunks will always be the same size or less of + // previous chunks, we only need to find where the ending of the new macro + // chunk is mapped to and update the map with new begin/end mappings. + + MacroArgsMap::iterator I = MacroArgsCache.upper_bound(EndOffs); + --I; + SourceLocation EndOffsMappedLoc = I->second; + MacroArgsCache[BeginOffs] = ExpansionLoc; + MacroArgsCache[EndOffs] = EndOffsMappedLoc; } /// \brief If \arg Loc points inside a function macro argument, the returned diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index db5941a5d921..83d4e2bf63c9 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -24,7 +24,8 @@ using namespace clang; static const LangAS::Map DefaultAddrSpaceMap = { 0 }; // TargetInfo Constructor. -TargetInfo::TargetInfo(const std::string &T) : Triple(T) { +TargetInfo::TargetInfo(const std::string &T) : TargetOpts(), Triple(T) +{ // Set defaults. Defaults are set for a 32-bit RISC platform, like PPC or // SPARC. These should be overridden by concrete targets as needed. BigEndian = true; @@ -59,6 +60,7 @@ TargetInfo::TargetInfo(const std::string &T) : Triple(T) { Char32Type = UnsignedInt; Int64Type = SignedLongLong; SigAtomicType = SignedInt; + ProcessIDType = SignedInt; UseSignedCharForObjCBool = true; UseBitFieldTypeAlignment = true; UseZeroLengthBitfieldAlignment = false; @@ -363,6 +365,8 @@ bool TargetInfo::validateOutputConstraint(ConstraintInfo &Info) const { break; case '?': // Disparage slightly code. case '!': // Disparage severely. + case '#': // Ignore as constraint. + case '*': // Ignore for choosing register preferences. break; // Pass them. } @@ -482,6 +486,8 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, break; case '?': // Disparage slightly code. case '!': // Disparage severely. + case '#': // Ignore as constraint. + case '*': // Ignore for choosing register preferences. break; // Pass them. } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 1d495f1f6412..f36ef826d0b2 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -92,6 +92,9 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, Builder.defineMacro("__APPLE__"); Builder.defineMacro("__MACH__"); Builder.defineMacro("OBJC_NEW_PROPERTIES"); + // AddressSanitizer doesn't play well with source fortification, which is on + // by default on Darwin. + if (Opts.SanitizeAddress) Builder.defineMacro("_FORTIFY_SOURCE", "0"); if (!Opts.ObjCAutoRefCount) { // __weak is always defined, for use in blocks and with objc pointers. @@ -316,7 +319,7 @@ protected: DefineStd(Builder, "linux", Opts); Builder.defineMacro("__gnu_linux__"); Builder.defineMacro("__ELF__"); - if (Triple.getEnvironment() == llvm::Triple::ANDROIDEABI) + if (Triple.getEnvironment() == llvm::Triple::Android) Builder.defineMacro("__ANDROID__", "1"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); @@ -587,6 +590,48 @@ public: : OSTargetInfo<Target>(triple) {} }; +template <typename Target> +class NaClTargetInfo : public OSTargetInfo<Target> { + protected: + virtual void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const { + if (Opts.POSIXThreads) + Builder.defineMacro("_REENTRANT"); + if (Opts.CPlusPlus) + Builder.defineMacro("_GNU_SOURCE"); + + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__native_client__"); + } + public: + NaClTargetInfo(const std::string &triple) + : OSTargetInfo<Target>(triple) { + this->UserLabelPrefix = ""; + this->LongAlign = 32; + this->LongWidth = 32; + this->PointerAlign = 32; + this->PointerWidth = 32; + this->IntMaxType = TargetInfo::SignedLongLong; + this->UIntMaxType = TargetInfo::UnsignedLongLong; + this->Int64Type = TargetInfo::SignedLongLong; + this->DoubleAlign = 64; + this->LongDoubleWidth = 64; + this->LongDoubleAlign = 64; + this->SizeType = TargetInfo::UnsignedInt; + this->PtrDiffType = TargetInfo::SignedInt; + this->IntPtrType = TargetInfo::SignedInt; + this->RegParmMax = 2; + this->LongDoubleFormat = &llvm::APFloat::IEEEdouble; + this->DescriptionString = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-" + "f32:32:32-f64:64:64-p:32:32:32-v128:32:32"; + } + virtual typename Target::CallingConvCheckResult checkCallingConvention( + CallingConv CC) const { + return CC == CC_PnaclCall ? Target::CCCR_OK : + Target::checkCallingConvention(CC); + } +}; } // end anonymous namespace. //===----------------------------------------------------------------------===// @@ -641,6 +686,8 @@ public: .Case("970", true) .Case("g5", true) .Case("a2", true) + .Case("e500mc", true) + .Case("e5500", true) .Case("pwr6", true) .Case("pwr7", true) .Case("ppc", true) @@ -990,6 +1037,9 @@ public: LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; } + + // PPC32 supports atomics up to 4 bytes. + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 32; } virtual BuiltinVaListKind getBuiltinVaListKind() const { @@ -1007,13 +1057,20 @@ public: IntMaxType = SignedLong; UIntMaxType = UnsignedLong; Int64Type = SignedLong; - DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" - "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64"; if (getTriple().getOS() == llvm::Triple::FreeBSD) { LongDoubleWidth = LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; - } + DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-f128:64:64-" + "v128:128:128-n32:64"; + } else + DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-f128:128:128-" + "v128:128:128-n32:64"; + + // PPC64 supports atomics up to 8 bytes. + MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; } virtual BuiltinVaListKind getBuiltinVaListKind() const { return TargetInfo::CharPtrBuiltinVaList; @@ -1047,6 +1104,8 @@ public: : DarwinTargetInfo<PPC64TargetInfo>(triple) { HasAlignMac68kSupport = true; SuitableAlign = 128; + DescriptionString = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" + "i64:64:64-f32:32:32-f64:64:64-v128:128:128-n32:64"; } }; } // end anonymous namespace. @@ -1172,6 +1231,71 @@ namespace { } namespace { + +static const unsigned R600AddrSpaceMap[] = { + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 1, // cuda_device + 2, // cuda_constant + 3 // cuda_shared +}; + +class R600TargetInfo : public TargetInfo { +public: + R600TargetInfo(const std::string& triple) : TargetInfo(triple) { + DescriptionString = + "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16" + "-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:32:32" + "-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64" + "-v96:128:128-v128:128:128-v192:256:256-v256:256:256" + "-v512:512:512-v1024:1024:1024-v2048:2048:2048" + "-n8:16:32:64"; + AddrSpaceMap = &R600AddrSpaceMap; + } + + virtual const char * getClobbers() const { + return ""; + } + + virtual void getGCCRegNames(const char * const *&Names, + unsigned &numNames) const { + Names = NULL; + numNames = 0; + } + + virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const { + Aliases = NULL; + NumAliases = 0; + } + + virtual bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &info) const { + return true; + } + + virtual void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const { + Records = NULL; + NumRecords = 0; + } + + + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + Builder.defineMacro("__R600__"); + } + + virtual BuiltinVaListKind getBuiltinVaListKind() const { + return TargetInfo::CharPtrBuiltinVaList; + } + +}; + +} // end anonymous namespace + +namespace { // MBlaze abstract base class class MBlazeTargetInfo : public TargetInfo { static const char * const GCCRegNames[]; @@ -1351,10 +1475,12 @@ class X86TargetInfo : public TargetInfo { bool HasBMI; bool HasBMI2; bool HasPOPCNT; + bool HasRTM; bool HasSSE4a; bool HasFMA4; bool HasFMA; bool HasXOP; + bool HasF16C; /// \brief Enumeration of all of the X86 CPUs supported by Clang. /// @@ -1500,8 +1626,9 @@ public: X86TargetInfo(const std::string& triple) : TargetInfo(triple), SSELevel(NoSSE), MMX3DNowLevel(NoMMX3DNow), HasAES(false), HasPCLMUL(false), HasLZCNT(false), HasRDRND(false), - HasBMI(false), HasBMI2(false), HasPOPCNT(false), HasSSE4a(false), - HasFMA4(false), HasFMA(false), HasXOP(false), CPU(CK_Generic) { + HasBMI(false), HasBMI2(false), HasPOPCNT(false), HasRTM(false), + HasSSE4a(false), HasFMA4(false), HasFMA(false), HasXOP(false), + HasF16C(false), CPU(CK_Generic) { BigEndian = false; LongDoubleFormat = &llvm::APFloat::x87DoubleExtended; } @@ -1544,9 +1671,10 @@ public: virtual bool hasFeature(StringRef Feature) const; virtual void HandleTargetFeatures(std::vector<std::string> &Features); virtual const char* getABI() const { - if (PointerWidth == 64 && SSELevel >= AVX) + if (getTriple().getArch() == llvm::Triple::x86_64 && SSELevel >= AVX) return "avx"; - else if (PointerWidth == 32 && MMX3DNowLevel == NoMMX3DNow) + else if (getTriple().getArch() == llvm::Triple::x86 && + MMX3DNowLevel == NoMMX3DNow) return "no-mmx"; return ""; } @@ -1640,7 +1768,7 @@ public: case CK_AthlonMP: case CK_Geode: // Only accept certain architectures when compiling in 32-bit mode. - if (PointerWidth != 32) + if (getTriple().getArch() != llvm::Triple::x86) return false; // Fallthrough @@ -1668,6 +1796,19 @@ public: } llvm_unreachable("Unhandled CPU kind"); } + + virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const { + // We accept all non-ARM calling conventions + return (CC == CC_X86ThisCall || + CC == CC_X86FastCall || + CC == CC_X86StdCall || + CC == CC_C || + CC == CC_X86Pascal) ? CCCR_OK : CCCR_Warning; + } + + virtual CallingConv getDefaultCallingConv() const { + return CC_C; + } }; void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { @@ -1691,14 +1832,16 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { Features["bmi"] = false; Features["bmi2"] = false; Features["popcnt"] = false; + Features["rtm"] = false; Features["fma4"] = false; Features["fma"] = false; Features["xop"] = false; + Features["f16c"] = false; // FIXME: This *really* should not be here. // X86_64 always has SSE2. - if (PointerWidth == 64) + if (getTriple().getArch() == llvm::Triple::x86_64) Features["sse2"] = Features["sse"] = Features["mmx"] = true; switch (CPU) { @@ -1770,6 +1913,7 @@ void X86TargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { setFeatureEnabled(Features, "rdrnd", true); setFeatureEnabled(Features, "bmi", true); setFeatureEnabled(Features, "bmi2", true); + setFeatureEnabled(Features, "rtm", true); setFeatureEnabled(Features, "fma", true); break; case CK_K6: @@ -1904,6 +2048,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, Features["bmi2"] = true; else if (Name == "popcnt") Features["popcnt"] = true; + else if (Name == "f16c") + Features["f16c"] = true; + else if (Name == "rtm") + Features["rtm"] = true; } else { if (Name == "mmx") Features["mmx"] = Features["3dnow"] = Features["3dnowa"] = false; @@ -1964,6 +2112,10 @@ bool X86TargetInfo::setFeatureEnabled(llvm::StringMap<bool> &Features, Features["fma4"] = Features["xop"] = false; else if (Name == "xop") Features["xop"] = false; + else if (Name == "f16c") + Features["f16c"] = false; + else if (Name == "rtm") + Features["rtm"] = false; } return true; @@ -2015,6 +2167,11 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) { continue; } + if (Feature == "rtm") { + HasRTM = true; + continue; + } + if (Feature == "sse4a") { HasSSE4a = true; continue; @@ -2035,6 +2192,11 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) { continue; } + if (Feature == "f16c") { + HasF16C = true; + continue; + } + assert(Features[i][0] == '+' && "Invalid target feature!"); X86SSEEnum Level = llvm::StringSwitch<X86SSEEnum>(Feature) .Case("avx2", AVX2) @@ -2071,7 +2233,7 @@ void X86TargetInfo::HandleTargetFeatures(std::vector<std::string> &Features) { void X86TargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Target identification. - if (PointerWidth == 64) { + if (getTriple().getArch() == llvm::Triple::x86_64) { Builder.defineMacro("__amd64__"); Builder.defineMacro("__amd64"); Builder.defineMacro("__x86_64"); @@ -2231,6 +2393,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasPOPCNT) Builder.defineMacro("__POPCNT__"); + if (HasRTM) + Builder.defineMacro("__RTM__"); + if (HasSSE4a) Builder.defineMacro("__SSE4A__"); @@ -2243,6 +2408,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasXOP) Builder.defineMacro("__XOP__"); + if (HasF16C) + Builder.defineMacro("__F16C__"); + // Each case falls through to the previous one here. switch (SSELevel) { case AVX2: @@ -2267,7 +2435,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, break; } - if (Opts.MicrosoftExt && PointerWidth == 32) { + if (Opts.MicrosoftExt && getTriple().getArch() == llvm::Triple::x86) { switch (SSELevel) { case AVX2: case AVX: @@ -2315,6 +2483,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("mmx", MMX3DNowLevel >= MMX) .Case("pclmul", HasPCLMUL) .Case("popcnt", HasPOPCNT) + .Case("rtm", HasRTM) .Case("sse", SSELevel >= SSE1) .Case("sse2", SSELevel >= SSE2) .Case("sse3", SSELevel >= SSE3) @@ -2323,9 +2492,10 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const { .Case("sse42", SSELevel >= SSE42) .Case("sse4a", HasSSE4a) .Case("x86", true) - .Case("x86_32", PointerWidth == 32) - .Case("x86_64", PointerWidth == 64) + .Case("x86_32", getTriple().getArch() == llvm::Triple::x86) + .Case("x86_64", getTriple().getArch() == llvm::Triple::x86_64) .Case("xop", HasXOP) + .Case("f16c", HasF16C) .Default(false); } @@ -2595,7 +2765,9 @@ public: SizeType = UnsignedLong; IntPtrType = SignedLong; PtrDiffType = SignedLong; + ProcessIDType = SignedLong; this->UserLabelPrefix = ""; + this->TLSSupported = false; } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { @@ -2703,6 +2875,15 @@ public: if (RegNo == 1) return 1; return -1; } + + virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const { + return TargetInfo::checkCallingConvention(CC); + } + + virtual CallingConv getDefaultCallingConv() const { + return CC_Default; + } + }; } // end anonymous namespace @@ -2820,14 +3001,14 @@ namespace { class ARMTargetInfo : public TargetInfo { // Possible FPU choices. enum FPUMode { - NoFPU, - VFP2FPU, - VFP3FPU, - NeonFPU + VFP2FPU = (1 << 0), + VFP3FPU = (1 << 1), + VFP4FPU = (1 << 2), + NeonFPU = (1 << 3) }; static bool FPUModeIsVFP(FPUMode Mode) { - return Mode >= VFP2FPU && Mode <= NeonFPU; + return Mode & (VFP2FPU | VFP3FPU | VFP4FPU | NeonFPU); } static const TargetInfo::GCCRegAlias GCCRegAliases[]; @@ -2835,8 +3016,9 @@ class ARMTargetInfo : public TargetInfo { std::string ABI, CPU; - unsigned FPU : 3; + unsigned FPU : 4; + unsigned IsAAPCS : 1; unsigned IsThumb : 1; // Initialized via features. @@ -2847,7 +3029,7 @@ class ARMTargetInfo : public TargetInfo { public: ARMTargetInfo(const std::string &TripleStr) - : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s") + : TargetInfo(TripleStr), ABI("aapcs-linux"), CPU("arm1136j-s"), IsAAPCS(true) { BigEndian = false; SizeType = UnsignedInt; @@ -2910,6 +3092,8 @@ public: /// gcc. ZeroLengthBitfieldBoundary = 32; + IsAAPCS = false; + if (IsThumb) { // Thumb1 add sp, #imm requires the immediate value be multiple of 4, // so set preferred for small types to 32. @@ -2923,10 +3107,11 @@ public: } // FIXME: Override "preferred align" for double and long long. - } else if (Name == "aapcs") { + } else if (Name == "aapcs" || Name == "aapcs-vfp") { + IsAAPCS = true; // FIXME: Enumerated types are variable width in straight AAPCS. } else if (Name == "aapcs-linux") { - ; + IsAAPCS = true; } else return false; @@ -2936,16 +3121,21 @@ public: void getDefaultFeatures(llvm::StringMap<bool> &Features) const { if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore") Features["vfp2"] = true; - else if (CPU == "cortex-a8" || CPU == "cortex-a9") + else if (CPU == "cortex-a8" || CPU == "cortex-a15" || + CPU == "cortex-a9" || CPU == "cortex-a9-mp") + Features["neon"] = true; + else if (CPU == "swift") { + Features["vfp4"] = true; Features["neon"] = true; + } } virtual bool setFeatureEnabled(llvm::StringMap<bool> &Features, StringRef Name, bool Enabled) const { if (Name == "soft-float" || Name == "soft-float-abi" || - Name == "vfp2" || Name == "vfp3" || Name == "neon" || Name == "d16" || - Name == "neonfp") { + Name == "vfp2" || Name == "vfp3" || Name == "vfp4" || Name == "neon" || + Name == "d16" || Name == "neonfp") { Features[Name] = Enabled; } else return false; @@ -2954,7 +3144,7 @@ public: } virtual void HandleTargetFeatures(std::vector<std::string> &Features) { - FPU = NoFPU; + FPU = 0; SoftFloat = SoftFloatABI = false; for (unsigned i = 0, e = Features.size(); i != e; ++i) { if (Features[i] == "+soft-float") @@ -2962,11 +3152,13 @@ public: else if (Features[i] == "+soft-float-abi") SoftFloatABI = true; else if (Features[i] == "+vfp2") - FPU = VFP2FPU; + FPU |= VFP2FPU; else if (Features[i] == "+vfp3") - FPU = VFP3FPU; + FPU |= VFP3FPU; + else if (Features[i] == "+vfp4") + FPU |= VFP4FPU; else if (Features[i] == "+neon") - FPU = NeonFPU; + FPU |= NeonFPU; } // Remove front-end specific options which the backend handles differently. @@ -2988,6 +3180,7 @@ public: StringRef(getCPUDefineSuffix(CPU)).startswith("7")) .Default(false); } + // FIXME: Should we actually have some table instead of these switches? static const char *getCPUDefineSuffix(StringRef Name) { return llvm::StringSwitch<const char*>(Name) .Cases("arm8", "arm810", "4") @@ -3004,12 +3197,19 @@ public: .Cases("arm1176jz-s", "arm1176jzf-s", "6ZK") .Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K") .Cases("arm1156t2-s", "arm1156t2f-s", "6T2") - .Cases("cortex-a8", "cortex-a9", "7A") - .Case("cortex-m3", "7M") - .Case("cortex-m4", "7M") + .Cases("cortex-a8", "cortex-a9", "cortex-a15", "7A") + .Case("cortex-a9-mp", "7F") + .Case("swift", "7S") + .Cases("cortex-m3", "cortex-m4", "7M") .Case("cortex-m0", "6M") .Default(0); } + static const char *getCPUProfile(StringRef Name) { + return llvm::StringSwitch<const char*>(Name) + .Cases("cortex-a8", "cortex-a9", "A") + .Cases("cortex-m3", "cortex-m4", "cortex-m0", "M") + .Default(""); + } virtual bool setCPU(const std::string &Name) { if (!getCPUDefineSuffix(Name)) return false; @@ -3030,7 +3230,11 @@ public: StringRef CPUArch = getCPUDefineSuffix(CPU); Builder.defineMacro("__ARM_ARCH_" + CPUArch + "__"); - + Builder.defineMacro("__ARM_ARCH", CPUArch.substr(0, 1)); + StringRef CPUProfile = getCPUProfile(CPU); + if (!CPUProfile.empty()) + Builder.defineMacro("__ARM_ARCH_PROFILE", CPUProfile); + // Subtarget options. // FIXME: It's more complicated than this and we don't really support @@ -3038,8 +3242,15 @@ public: if ('5' <= CPUArch[0] && CPUArch[0] <= '7') Builder.defineMacro("__THUMB_INTERWORK__"); - if (ABI == "aapcs" || ABI == "aapcs-linux") - Builder.defineMacro("__ARM_EABI__"); + if (ABI == "aapcs" || ABI == "aapcs-linux" || ABI == "aapcs-vfp") { + // M-class CPUs on Darwin follow AAPCS, but not EABI. + if (!(getTriple().isOSDarwin() && CPUProfile == "M")) + Builder.defineMacro("__ARM_EABI__"); + Builder.defineMacro("__ARM_PCS", "1"); + + if ((!SoftFloat && !SoftFloatABI) || ABI == "aapcs-vfp") + Builder.defineMacro("__ARM_PCS_VFP", "1"); + } if (SoftFloat) Builder.defineMacro("__SOFTFP__"); @@ -3058,14 +3269,21 @@ public: // Note, this is always on in gcc, even though it doesn't make sense. Builder.defineMacro("__APCS_32__"); - if (FPUModeIsVFP((FPUMode) FPU)) + if (FPUModeIsVFP((FPUMode) FPU)) { Builder.defineMacro("__VFP_FP__"); - + if (FPU & VFP2FPU) + Builder.defineMacro("__ARM_VFPV2__"); + if (FPU & VFP3FPU) + Builder.defineMacro("__ARM_VFPV3__"); + if (FPU & VFP4FPU) + Builder.defineMacro("__ARM_VFPV4__"); + } + // This only gets set when Neon instructions are actually available, unlike // the VFP define, hence the soft float and arch check. This is subtly // different from gcc, we follow the intent which was that it should be set // when Neon instructions are actually available. - if (FPU == NeonFPU && !SoftFloat && IsARMv7) + if ((FPU & NeonFPU) && !SoftFloat && IsARMv7) Builder.defineMacro("__ARM_NEON__"); } virtual void getTargetBuiltins(const Builtin::Info *&Records, @@ -3075,7 +3293,7 @@ public: } virtual bool isCLZForZeroUndef() const { return false; } virtual BuiltinVaListKind getBuiltinVaListKind() const { - return TargetInfo::VoidPtrBuiltinVaList; + return IsAAPCS ? AAPCSABIBuiltinVaList : TargetInfo::VoidPtrBuiltinVaList; } virtual void getGCCRegNames(const char * const *&Names, unsigned &NumNames) const; @@ -3127,10 +3345,38 @@ public: } return R; } + virtual bool validateConstraintModifier(StringRef Constraint, + const char Modifier, + unsigned Size) const { + // Strip off constraint modifiers. + while (Constraint[0] == '=' || + Constraint[0] == '+' || + Constraint[0] == '&') + Constraint = Constraint.substr(1); + + switch (Constraint[0]) { + default: break; + case 'r': { + switch (Modifier) { + default: + return Size == 32; + case 'q': + // A register of size 32 cannot fit a vector type. + return false; + } + } + } + + return true; + } virtual const char *getClobbers() const { // FIXME: Is this really right? return ""; } + + virtual CallingConvCheckResult checkCallingConvention(CallingConv CC) const { + return (CC == CC_AAPCS || CC == CC_AAPCS_VFP) ? CCCR_OK : CCCR_Warning; + } }; const char * const ARMTargetInfo::GCCRegNames[] = { @@ -3701,8 +3947,12 @@ public: Features[CPU] = true; } - virtual void getArchDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + DefineStd(Builder, "mips", Opts); + Builder.defineMacro("_mips"); + Builder.defineMacro("__REGISTER_PREFIX__", ""); + switch (FloatABI) { case HardFloat: Builder.defineMacro("__mips_hard_float", Twine(1)); @@ -3736,10 +3986,11 @@ public: Builder.defineMacro("_MIPS_SZPTR", Twine(getPointerWidth(0))); Builder.defineMacro("_MIPS_SZINT", Twine(getIntWidth())); Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth())); + + Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\""); + Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper()); } - virtual void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const = 0; virtual void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const { Records = BuiltinInfo; @@ -3859,9 +4110,9 @@ public: } else return false; } - virtual void getArchDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - MipsTargetInfoBase::getArchDefines(Opts, Builder); + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + MipsTargetInfoBase::getTargetDefines(Opts, Builder); if (ABI == "o32") { Builder.defineMacro("__mips_o32"); @@ -3921,12 +4172,9 @@ public: } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { - DefineStd(Builder, "mips", Opts); - Builder.defineMacro("_mips"); DefineStd(Builder, "MIPSEB", Opts); Builder.defineMacro("_MIPSEB"); - Builder.defineMacro("__REGISTER_PREFIX__", ""); - getArchDefines(Opts, Builder); + Mips32TargetInfoBase::getTargetDefines(Opts, Builder); } }; @@ -3939,12 +4187,9 @@ public: } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { - DefineStd(Builder, "mips", Opts); - Builder.defineMacro("_mips"); DefineStd(Builder, "MIPSEL", Opts); Builder.defineMacro("_MIPSEL"); - Builder.defineMacro("__REGISTER_PREFIX__", ""); - getArchDefines(Opts, Builder); + Mips32TargetInfoBase::getTargetDefines(Opts, Builder); } }; @@ -3974,9 +4219,12 @@ public: return true; } - virtual void getArchDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { - MipsTargetInfoBase::getArchDefines(Opts, Builder); + virtual void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const { + MipsTargetInfoBase::getTargetDefines(Opts, Builder); + + Builder.defineMacro("__mips64"); + Builder.defineMacro("__mips64__"); if (ABI == "n32") { Builder.defineMacro("__mips_n32"); @@ -4048,12 +4296,9 @@ public: } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { - DefineStd(Builder, "mips", Opts); - Builder.defineMacro("_mips"); DefineStd(Builder, "MIPSEB", Opts); Builder.defineMacro("_MIPSEB"); - Builder.defineMacro("__REGISTER_PREFIX__", ""); - getArchDefines(Opts, Builder); + Mips64TargetInfoBase::getTargetDefines(Opts, Builder); } }; @@ -4075,12 +4320,9 @@ public: } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { - DefineStd(Builder, "mips", Opts); - Builder.defineMacro("_mips"); DefineStd(Builder, "MIPSEL", Opts); Builder.defineMacro("_MIPSEL"); - Builder.defineMacro("__REGISTER_PREFIX__", ""); - getArchDefines(Opts, Builder); + Mips64TargetInfoBase::getTargetDefines(Opts, Builder); } }; } // end anonymous namespace. @@ -4118,15 +4360,7 @@ public: } virtual void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { - DefineStd(Builder, "unix", Opts); - Builder.defineMacro("__ELF__"); - if (Opts.POSIXThreads) - Builder.defineMacro("_REENTRANT"); - if (Opts.CPlusPlus) - Builder.defineMacro("_GNU_SOURCE"); - Builder.defineMacro("__LITTLE_ENDIAN__"); - Builder.defineMacro("__native_client__"); getArchDefines(Opts, Builder); } virtual bool hasFeature(StringRef Feature) const { @@ -4199,6 +4433,8 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new BitrigTargetInfo<ARMTargetInfo>(T); case llvm::Triple::RTEMS: return new RTEMSTargetInfo<ARMTargetInfo>(T); + case llvm::Triple::NativeClient: + return new NaClTargetInfo<ARMTargetInfo>(T); default: return new ARMTargetInfo(T); } @@ -4269,7 +4505,7 @@ static TargetInfo *AllocateTarget(const std::string &T) { case llvm::Triple::le32: switch (os) { case llvm::Triple::NativeClient: - return new PNaClTargetInfo(T); + return new NaClTargetInfo<PNaClTargetInfo>(T); default: return NULL; } @@ -4316,6 +4552,9 @@ static TargetInfo *AllocateTarget(const std::string &T) { case llvm::Triple::mblaze: return new MBlazeTargetInfo(T); + case llvm::Triple::r600: + return new R600TargetInfo(T); + case llvm::Triple::sparc: switch (os) { case llvm::Triple::Linux: @@ -4374,6 +4613,8 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new HaikuX86_32TargetInfo(T); case llvm::Triple::RTEMS: return new RTEMSX86_32TargetInfo(T); + case llvm::Triple::NativeClient: + return new NaClTargetInfo<X86_32TargetInfo>(T); default: return new X86_32TargetInfo(T); } @@ -4403,6 +4644,8 @@ static TargetInfo *AllocateTarget(const std::string &T) { return new MinGWX86_64TargetInfo(T); case llvm::Triple::Win32: // This is what Triple.h supports now. return new VisualStudioWindowsX86_64TargetInfo(T); + case llvm::Triple::NativeClient: + return new NaClTargetInfo<X86_64TargetInfo>(T); default: return new X86_64TargetInfo(T); } @@ -4421,6 +4664,7 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, Diags.Report(diag::err_target_unknown_triple) << Triple.str(); return 0; } + Target->setTargetOpts(Opts); // Set the target CPU if specified. if (!Opts.CPU.empty() && !Target->setCPU(Opts.CPU)) { @@ -4447,8 +4691,10 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, // Apply the user specified deltas. // First the enables. - for (std::vector<std::string>::const_iterator it = Opts.Features.begin(), - ie = Opts.Features.end(); it != ie; ++it) { + for (std::vector<std::string>::const_iterator + it = Opts.FeaturesAsWritten.begin(), + ie = Opts.FeaturesAsWritten.end(); + it != ie; ++it) { const char *Name = it->c_str(); if (Name[0] != '+') @@ -4462,8 +4708,10 @@ TargetInfo *TargetInfo::CreateTargetInfo(DiagnosticsEngine &Diags, } // Then the disables. - for (std::vector<std::string>::const_iterator it = Opts.Features.begin(), - ie = Opts.Features.end(); it != ie; ++it) { + for (std::vector<std::string>::const_iterator + it = Opts.FeaturesAsWritten.begin(), + ie = Opts.FeaturesAsWritten.end(); + it != ie; ++it) { const char *Name = it->c_str(); if (Name[0] == '+') diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index 9daa30a4cad0..286e96e0f376 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -32,7 +32,7 @@ std::string getClangRepositoryPath() { // If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us // pick up a tag in an SVN export, for example. - static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"); + static StringRef SVNRepository("$URL: http://llvm.org/svn/llvm-project/cfe/branches/release_32/lib/Basic/Version.cpp $"); if (URL.empty()) { URL = SVNRepository.slice(SVNRepository.find(':'), SVNRepository.find("/lib/Basic")); diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h index 86f53803d527..da6d035dfaf0 100644 --- a/lib/CodeGen/ABIInfo.h +++ b/lib/CodeGen/ABIInfo.h @@ -16,7 +16,7 @@ namespace llvm { class Value; class LLVMContext; - class TargetData; + class DataLayout; } namespace clang { @@ -70,46 +70,52 @@ namespace clang { private: Kind TheKind; llvm::Type *TypeData; - llvm::Type *PaddingType; // Currently allowed only for Direct. + llvm::Type *PaddingType; unsigned UIntData; bool BoolData0; bool BoolData1; bool InReg; + bool PaddingInReg; ABIArgInfo(Kind K, llvm::Type *TD, unsigned UI, bool B0, bool B1, bool IR, - llvm::Type* P) + bool PIR, llvm::Type* P) : TheKind(K), TypeData(TD), PaddingType(P), UIntData(UI), BoolData0(B0), - BoolData1(B1), InReg(IR) {} + BoolData1(B1), InReg(IR), PaddingInReg(PIR) {} public: ABIArgInfo() : TheKind(Direct), TypeData(0), UIntData(0) {} static ABIArgInfo getDirect(llvm::Type *T = 0, unsigned Offset = 0, llvm::Type *Padding = 0) { - return ABIArgInfo(Direct, T, Offset, false, false, false, Padding); + return ABIArgInfo(Direct, T, Offset, false, false, false, false, Padding); } - static ABIArgInfo getDirectInReg(llvm::Type *T) { - return ABIArgInfo(Direct, T, 0, false, false, true, 0); + static ABIArgInfo getDirectInReg(llvm::Type *T = 0) { + return ABIArgInfo(Direct, T, 0, false, false, true, false, 0); } static ABIArgInfo getExtend(llvm::Type *T = 0) { - return ABIArgInfo(Extend, T, 0, false, false, false, 0); + return ABIArgInfo(Extend, T, 0, false, false, false, false, 0); } static ABIArgInfo getExtendInReg(llvm::Type *T = 0) { - return ABIArgInfo(Extend, T, 0, false, false, true, 0); + return ABIArgInfo(Extend, T, 0, false, false, true, false, 0); } static ABIArgInfo getIgnore() { - return ABIArgInfo(Ignore, 0, 0, false, false, false, 0); + return ABIArgInfo(Ignore, 0, 0, false, false, false, false, 0); } static ABIArgInfo getIndirect(unsigned Alignment, bool ByVal = true , bool Realign = false) { - return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, 0); + return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, false, false, 0); } static ABIArgInfo getIndirectInReg(unsigned Alignment, bool ByVal = true , bool Realign = false) { - return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, 0); + return ABIArgInfo(Indirect, 0, Alignment, ByVal, Realign, true, false, 0); } static ABIArgInfo getExpand() { - return ABIArgInfo(Expand, 0, 0, false, false, false, 0); + return ABIArgInfo(Expand, 0, 0, false, false, false, false, 0); + } + static ABIArgInfo getExpandWithPadding(bool PaddingInReg, + llvm::Type *Padding) { + return ABIArgInfo(Expand, 0, 0, false, false, false, PaddingInReg, + Padding); } Kind getKind() const { return TheKind; } @@ -133,6 +139,10 @@ namespace clang { return PaddingType; } + bool getPaddingInReg() const { + return PaddingInReg; + } + llvm::Type *getCoerceToType() const { assert(canHaveCoerceToType() && "Invalid kind!"); return TypeData; @@ -178,7 +188,7 @@ namespace clang { ASTContext &getContext() const; llvm::LLVMContext &getVMContext() const; - const llvm::TargetData &getTargetData() const; + const llvm::DataLayout &getDataLayout() const; virtual void computeInfo(CodeGen::CGFunctionInfo &FI) const = 0; diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 0a1915b485d7..62f87c983bfa 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -27,7 +27,7 @@ #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" @@ -54,36 +54,67 @@ class EmitAssemblyHelper { mutable FunctionPassManager *PerFunctionPasses; private: - PassManager *getCodeGenPasses() const { + PassManager *getCodeGenPasses(TargetMachine *TM) const { if (!CodeGenPasses) { CodeGenPasses = new PassManager(); - CodeGenPasses->add(new TargetData(TheModule)); + CodeGenPasses->add(new DataLayout(TheModule)); + // Add TargetTransformInfo. + if (TM) { + TargetTransformInfo *TTI = + new TargetTransformInfo(TM->getScalarTargetTransformInfo(), + TM->getVectorTargetTransformInfo()); + CodeGenPasses->add(TTI); + } } return CodeGenPasses; } - PassManager *getPerModulePasses() const { + PassManager *getPerModulePasses(TargetMachine *TM) const { if (!PerModulePasses) { PerModulePasses = new PassManager(); - PerModulePasses->add(new TargetData(TheModule)); + PerModulePasses->add(new DataLayout(TheModule)); + if (TM) { + TargetTransformInfo *TTI = + new TargetTransformInfo(TM->getScalarTargetTransformInfo(), + TM->getVectorTargetTransformInfo()); + PerModulePasses->add(TTI); + } } return PerModulePasses; } - FunctionPassManager *getPerFunctionPasses() const { + FunctionPassManager *getPerFunctionPasses(TargetMachine *TM) const { if (!PerFunctionPasses) { PerFunctionPasses = new FunctionPassManager(TheModule); - PerFunctionPasses->add(new TargetData(TheModule)); + PerFunctionPasses->add(new DataLayout(TheModule)); + if (TM) { + TargetTransformInfo *TTI = + new TargetTransformInfo(TM->getScalarTargetTransformInfo(), + TM->getVectorTargetTransformInfo()); + PerFunctionPasses->add(TTI); + } } return PerFunctionPasses; } - void CreatePasses(); + + void CreatePasses(TargetMachine *TM); + + /// CreateTargetMachine - Generates the TargetMachine. + /// Returns Null if it is unable to create the target machine. + /// Some of our clang tests specify triples which are not built + /// into clang. This is okay because these tests check the generated + /// IR, and they require DataLayout which depends on the triple. + /// In this case, we allow this method to fail and not report an error. + /// When MustCreateTM is used, we print an error if we are unable to load + /// the requested target. + TargetMachine *CreateTargetMachine(bool MustCreateTM); /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR. /// /// \return True on success. - bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS); + bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS, + TargetMachine *TM); public: EmitAssemblyHelper(DiagnosticsEngine &_Diags, @@ -137,9 +168,9 @@ static void addThreadSanitizerPass(const PassManagerBuilder &Builder, PM.add(createThreadSanitizerPass()); } -void EmitAssemblyHelper::CreatePasses() { +void EmitAssemblyHelper::CreatePasses(TargetMachine *TM) { unsigned OptLevel = CodeGenOpts.OptimizationLevel; - CodeGenOptions::InliningMethod Inlining = CodeGenOpts.Inlining; + CodeGenOptions::InliningMethod Inlining = CodeGenOpts.getInlining(); // Handle disabling of LLVM optimization, where we want to preserve the // internal module before any optimization. @@ -174,14 +205,14 @@ void EmitAssemblyHelper::CreatePasses() { addBoundsCheckingPass); } - if (LangOpts.AddressSanitizer) { - PMBuilder.addExtension(PassManagerBuilder::EP_ScalarOptimizerLate, + if (LangOpts.SanitizeAddress) { + PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, addAddressSanitizerPass); PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, addAddressSanitizerPass); } - if (LangOpts.ThreadSanitizer) { + if (LangOpts.SanitizeThread) { PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, addThreadSanitizerPass); PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, @@ -218,38 +249,36 @@ void EmitAssemblyHelper::CreatePasses() { break; } - // Set up the per-function pass manager. - FunctionPassManager *FPM = getPerFunctionPasses(); + FunctionPassManager *FPM = getPerFunctionPasses(TM); if (CodeGenOpts.VerifyModule) FPM->add(createVerifierPass()); PMBuilder.populateFunctionPassManager(*FPM); // Set up the per-module pass manager. - PassManager *MPM = getPerModulePasses(); + PassManager *MPM = getPerModulePasses(TM); if (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) { MPM->add(createGCOVProfilerPass(CodeGenOpts.EmitGcovNotes, CodeGenOpts.EmitGcovArcs, TargetTriple.isMacOSX())); - if (CodeGenOpts.DebugInfo == CodeGenOptions::NoDebugInfo) + if (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo) MPM->add(createStripSymbolsPass(true)); } - - + PMBuilder.populateModulePassManager(*MPM); } -bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, - formatted_raw_ostream &OS) { +TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) { // Create the TargetMachine for generating code. std::string Error; std::string Triple = TheModule->getTargetTriple(); const llvm::Target *TheTarget = TargetRegistry::lookupTarget(Triple, Error); if (!TheTarget) { - Diags.Report(diag::err_fe_unable_to_create_target) << Error; - return false; + if (MustCreateTM) + Diags.Report(diag::err_fe_unable_to_create_target) << Error; + return 0; } // FIXME: Expose these capabilities via actual APIs!!!! Aside from just @@ -361,7 +390,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, break; case LangOptions::FPC_Fast: Options.AllowFPOpFusion = llvm::FPOpFusion::Fast; - break; + break; } Options.LessPreciseFPMADOption = CodeGenOpts.LessPreciseFPMAD; @@ -375,6 +404,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, Options.DisableTailCalls = CodeGenOpts.DisableTailCalls; Options.TrapFuncName = CodeGenOpts.TrapFuncName; Options.PositionIndependentExecutable = LangOpts.PIELevel != 0; + Options.SSPBufferSize = CodeGenOpts.SSPBufferSize; TargetMachine *TM = TheTarget->createTargetMachine(Triple, TargetOpts.CPU, FeaturesStr, Options, @@ -391,15 +421,27 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, if (CodeGenOpts.NoExecStack) TM->setMCNoExecStack(true); + return TM; +} + +bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, + formatted_raw_ostream &OS, + TargetMachine *TM) { + // Create the code generator passes. - PassManager *PM = getCodeGenPasses(); + PassManager *PM = getCodeGenPasses(TM); // Add LibraryInfo. - TargetLibraryInfo *TLI = new TargetLibraryInfo(); + llvm::Triple TargetTriple(TheModule->getTargetTriple()); + TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple); if (!CodeGenOpts.SimplifyLibCalls) TLI->disableAllFunctions(); PM->add(TLI); + // Add TargetTransformInfo. + PM->add(new TargetTransformInfo(TM->getScalarTargetTransformInfo(), + TM->getVectorTargetTransformInfo())); + // Normal mode, emit a .s or .o file by running the code generator. Note, // this also adds codegenerator level optimization passes. TargetMachine::CodeGenFileType CGFT = TargetMachine::CGFT_AssemblyFile; @@ -430,23 +472,28 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) { TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : 0); llvm::formatted_raw_ostream FormattedOS; - CreatePasses(); + bool UsesCodeGen = (Action != Backend_EmitNothing && + Action != Backend_EmitBC && + Action != Backend_EmitLL); + TargetMachine *TM = CreateTargetMachine(UsesCodeGen); + CreatePasses(TM); + switch (Action) { case Backend_EmitNothing: break; case Backend_EmitBC: - getPerModulePasses()->add(createBitcodeWriterPass(*OS)); + getPerModulePasses(TM)->add(createBitcodeWriterPass(*OS)); break; case Backend_EmitLL: FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM); - getPerModulePasses()->add(createPrintModulePass(&FormattedOS)); + getPerModulePasses(TM)->add(createPrintModulePass(&FormattedOS)); break; default: FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM); - if (!AddEmitPasses(Action, FormattedOS)) + if (!AddEmitPasses(Action, FormattedOS, TM)) return; } diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 37ef4af24690..6742f36cf80f 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -19,7 +19,7 @@ #include "clang/AST/DeclObjC.h" #include "llvm/Module.h" #include "llvm/ADT/SmallSet.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include <algorithm> using namespace clang; @@ -27,7 +27,8 @@ using namespace CodeGen; CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name) : Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false), - HasCXXObject(false), UsesStret(false), StructureType(0), Block(block), + HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false), + StructureType(0), Block(block), DominatingIP(0) { // Skip asm prefix, if any. 'name' is usually taken directly from @@ -56,7 +57,18 @@ static llvm::Constant *buildDisposeHelper(CodeGenModule &CGM, return CodeGenFunction(CGM).GenerateDestroyHelperFunction(blockInfo); } -/// Build the block descriptor constant for a block. +/// buildBlockDescriptor - Build the block descriptor meta-data for a block. +/// buildBlockDescriptor is accessed from 5th field of the Block_literal +/// meta-data and contains stationary information about the block literal. +/// Its definition will have 4 (or optinally 6) words. +/// struct Block_descriptor { +/// unsigned long reserved; +/// unsigned long size; // size of Block_literal metadata in bytes. +/// void *copy_func_helper_decl; // optional copy helper. +/// void *destroy_func_decl; // optioanl destructor helper. +/// void *block_method_encoding_address;//@encode for block literal signature. +/// void *block_layout_info; // encoding of captured block variables. +/// }; static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { ASTContext &C = CGM.getContext(); @@ -92,8 +104,12 @@ static llvm::Constant *buildBlockDescriptor(CodeGenModule &CGM, CGM.GetAddrOfConstantCString(typeAtEncoding), i8p)); // GC layout. - if (C.getLangOpts().ObjC1) - elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo)); + if (C.getLangOpts().ObjC1) { + if (CGM.getLangOpts().getGC() != LangOptions::NonGC) + elements.push_back(CGM.getObjCRuntime().BuildGCBlockLayout(CGM, blockInfo)); + else + elements.push_back(CGM.getObjCRuntime().BuildRCBlockLayout(CGM, blockInfo)); + } else elements.push_back(llvm::Constant::getNullValue(i8p)); @@ -293,7 +309,10 @@ static void computeBlockInfo(CodeGenModule &CGM, CodeGenFunction *CGF, info.CanBeGlobal = true; return; } - + else if (C.getLangOpts().ObjC1 && + CGM.getLangOpts().getGC() == LangOptions::NonGC) + info.HasCapturedVariableLayout = true; + // Collect the layout chunks. SmallVector<BlockLayoutChunk, 16> layout; layout.reserve(block->capturesCXXThis() + @@ -652,6 +671,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // Compute the initial on-stack block flags. BlockFlags flags = BLOCK_HAS_SIGNATURE; + if (blockInfo.HasCapturedVariableLayout) flags |= BLOCK_HAS_EXTENDED_LAYOUT; if (blockInfo.NeedsCopyDispose) flags |= BLOCK_HAS_COPY_DISPOSE; if (blockInfo.HasCXXObject) flags |= BLOCK_HAS_CXX_OBJ; if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; @@ -1001,8 +1021,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const BlockDecl *blockDecl = blockInfo.getBlockDecl(); // Check if we should generate debug info for this block function. - if (CGM.getModuleDebugInfo()) - DebugInfo = CGM.getModuleDebugInfo(); + maybeInitializeDebugInfo(); CurGD = GD; BlockInfo = &blockInfo; @@ -1135,7 +1154,8 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const VarDecl *variable = ci->getVariable(); DI->EmitLocation(Builder, variable->getLocation()); - if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) { + if (CGM.getCodeGenOpts().getDebugInfo() + >= CodeGenOptions::LimitedDebugInfo) { const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); if (capture.isConstant()) { DI->EmitDeclareOfAutoVariable(variable, LocalDeclMap[variable], @@ -1207,8 +1227,7 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { = &CGM.getContext().Idents.get("__copy_helper_block_"); // Check if we should generate debug info for this block helper function. - if (CGM.getModuleDebugInfo()) - DebugInfo = CGM.getModuleDebugInfo(); + maybeInitializeDebugInfo(); FunctionDecl *FD = FunctionDecl::Create(C, C.getTranslationUnitDecl(), @@ -1243,7 +1262,8 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { const Expr *copyExpr = ci->getCopyExpr(); BlockFieldFlags flags; - bool isARCWeakCapture = false; + bool useARCWeakCopy = false; + bool useARCStrongCopy = false; if (copyExpr) { assert(!ci->isByRef()); @@ -1256,21 +1276,35 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { } else if (type->isObjCRetainableType()) { flags = BLOCK_FIELD_IS_OBJECT; - if (type->isBlockPointerType()) + bool isBlockPointer = type->isBlockPointerType(); + if (isBlockPointer) flags = BLOCK_FIELD_IS_BLOCK; // Special rules for ARC captures: if (getLangOpts().ObjCAutoRefCount) { Qualifiers qs = type.getQualifiers(); - // Don't generate special copy logic for a captured object - // unless it's __strong or __weak. - if (!qs.hasStrongOrWeakObjCLifetime()) + // We need to register __weak direct captures with the runtime. + if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) { + useARCWeakCopy = true; + + // We need to retain the copied value for __strong direct captures. + } else if (qs.getObjCLifetime() == Qualifiers::OCL_Strong) { + // If it's a block pointer, we have to copy the block and + // assign that to the destination pointer, so we might as + // well use _Block_object_assign. Otherwise we can avoid that. + if (!isBlockPointer) + useARCStrongCopy = true; + + // Otherwise the memcpy is fine. + } else { continue; + } - // Support __weak direct captures. - if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) - isARCWeakCapture = true; + // Non-ARC captures of retainable pointers are strong and + // therefore require a call to _Block_object_assign. + } else { + // fall through } } else { continue; @@ -1283,14 +1317,36 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { // If there's an explicit copy expression, we do that. if (copyExpr) { EmitSynthesizedCXXCopyCtor(dstField, srcField, copyExpr); - } else if (isARCWeakCapture) { + } else if (useARCWeakCopy) { EmitARCCopyWeak(dstField, srcField); } else { llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src"); - srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy); - llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy); - Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue, - llvm::ConstantInt::get(Int32Ty, flags.getBitMask())); + if (useARCStrongCopy) { + // At -O0, store null into the destination field (so that the + // storeStrong doesn't over-release) and then call storeStrong. + // This is a workaround to not having an initStrong call. + if (CGM.getCodeGenOpts().OptimizationLevel == 0) { + llvm::PointerType *ty = cast<llvm::PointerType>(srcValue->getType()); + llvm::Value *null = llvm::ConstantPointerNull::get(ty); + Builder.CreateStore(null, dstField); + EmitARCStoreStrongCall(dstField, srcValue, true); + + // With optimization enabled, take advantage of the fact that + // the blocks runtime guarantees a memcpy of the block data, and + // just emit a retain of the src field. + } else { + EmitARCRetainNonBlock(srcValue); + + // We don't need this anymore, so kill it. It's not quite + // worth the annoyance to avoid creating it in the first place. + cast<llvm::Instruction>(dstField)->eraseFromParent(); + } + } else { + srcValue = Builder.CreateBitCast(srcValue, VoidPtrTy); + llvm::Value *dstAddr = Builder.CreateBitCast(dstField, VoidPtrTy); + Builder.CreateCall3(CGM.getBlockObjectAssign(), dstAddr, srcValue, + llvm::ConstantInt::get(Int32Ty, flags.getBitMask())); + } } } @@ -1321,8 +1377,7 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { "__destroy_helper_block_", &CGM.getModule()); // Check if we should generate debug info for this block destroy function. - if (CGM.getModuleDebugInfo()) - DebugInfo = CGM.getModuleDebugInfo(); + maybeInitializeDebugInfo(); IdentifierInfo *II = &CGM.getContext().Idents.get("__destroy_helper_block_"); @@ -1356,7 +1411,8 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { BlockFieldFlags flags; const CXXDestructorDecl *dtor = 0; - bool isARCWeakCapture = false; + bool useARCWeakDestroy = false; + bool useARCStrongDestroy = false; if (ci->isByRef()) { flags = BLOCK_FIELD_IS_BYREF; @@ -1382,7 +1438,11 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { // Support __weak direct captures. if (qs.getObjCLifetime() == Qualifiers::OCL_Weak) - isARCWeakCapture = true; + useARCWeakDestroy = true; + + // Tools really want us to use objc_storeStrong here. + else + useARCStrongDestroy = true; } } else { continue; @@ -1396,9 +1456,13 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { PushDestructorCleanup(dtor, srcField); // If this is a __weak capture, emit the release directly. - } else if (isARCWeakCapture) { + } else if (useARCWeakDestroy) { EmitARCDestroyWeak(srcField); + // Destroy strong objects with a call if requested. + } else if (useARCStrongDestroy) { + EmitARCDestroyStrong(srcField, /*precise*/ false); + // Otherwise we call _Block_object_dispose. It wouldn't be too // hard to just emit this as a cleanup if we wanted to make sure // that things were done in reverse. @@ -1497,10 +1561,7 @@ public: } void emitDispose(CodeGenFunction &CGF, llvm::Value *field) { - llvm::LoadInst *value = CGF.Builder.CreateLoad(field); - value->setAlignment(Alignment.getQuantity()); - - CGF.EmitARCRelease(value, /*precise*/ false); + CGF.EmitARCDestroyStrong(field, /*precise*/ false); } void profileImpl(llvm::FoldingSetNodeID &id) const { @@ -1530,10 +1591,7 @@ public: } void emitDispose(CodeGenFunction &CGF, llvm::Value *field) { - llvm::LoadInst *value = CGF.Builder.CreateLoad(field); - value->setAlignment(Alignment.getQuantity()); - - CGF.EmitARCRelease(value, /*precise*/ false); + CGF.EmitARCDestroyStrong(field, /*precise*/ false); } void profileImpl(llvm::FoldingSetNodeID &id) const { @@ -1612,6 +1670,8 @@ generateByrefCopyHelper(CodeGenFunction &CGF, SC_None, false, false); + // Initialize debug info if necessary. + CGF.maybeInitializeDebugInfo(); CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation()); if (byrefInfo.needsCopy()) { @@ -1682,6 +1742,8 @@ generateByrefDisposeHelper(CodeGenFunction &CGF, SC_Static, SC_None, false, false); + // Initialize debug info if necessary. + CGF.maybeInitializeDebugInfo(); CGF.StartFunction(FD, R, Fn, FI, args, SourceLocation()); if (byrefInfo.needsDispose()) { @@ -1879,7 +1941,7 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { // And either 2 or 4 pointers. CurrentOffsetInBytes += (HasCopyAndDispose ? 4 : 2) * - CGM.getTargetData().getTypeAllocSize(Int8PtrTy); + CGM.getDataLayout().getTypeAllocSize(Int8PtrTy); // Align the offset. unsigned AlignedOffsetInBytes = diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h index 095cfdb259c3..f85701af781a 100644 --- a/lib/CodeGen/CGBlocks.h +++ b/lib/CodeGen/CGBlocks.h @@ -33,7 +33,7 @@ namespace llvm { class Constant; class Function; class GlobalValue; - class TargetData; + class DataLayout; class FunctionType; class PointerType; class Value; @@ -47,12 +47,24 @@ namespace CodeGen { class CodeGenModule; class CGBlockInfo; -enum BlockFlag_t { +// Flags stored in __block variables. +enum BlockByrefFlags { + BLOCK_BYREF_HAS_COPY_DISPOSE = (1 << 25), // compiler + BLOCK_BYREF_LAYOUT_MASK = (0xF << 28), // compiler + BLOCK_BYREF_LAYOUT_EXTENDED = (1 << 28), + BLOCK_BYREF_LAYOUT_NON_OBJECT = (2 << 28), + BLOCK_BYREF_LAYOUT_STRONG = (3 << 28), + BLOCK_BYREF_LAYOUT_WEAK = (4 << 28), + BLOCK_BYREF_LAYOUT_UNRETAINED = (5 << 28) +}; + +enum BlockLiteralFlags { BLOCK_HAS_COPY_DISPOSE = (1 << 25), BLOCK_HAS_CXX_OBJ = (1 << 26), BLOCK_IS_GLOBAL = (1 << 28), BLOCK_USE_STRET = (1 << 29), - BLOCK_HAS_SIGNATURE = (1 << 30) + BLOCK_HAS_SIGNATURE = (1 << 30), + BLOCK_HAS_EXTENDED_LAYOUT = (1 << 31) }; class BlockFlags { uint32_t flags; @@ -60,7 +72,7 @@ class BlockFlags { BlockFlags(uint32_t flags) : flags(flags) {} public: BlockFlags() : flags(0) {} - BlockFlags(BlockFlag_t flag) : flags(flag) {} + BlockFlags(BlockLiteralFlags flag) : flags(flag) {} uint32_t getBitMask() const { return flags; } bool empty() const { return flags == 0; } @@ -76,7 +88,7 @@ public: return (l.flags & r.flags); } }; -inline BlockFlags operator|(BlockFlag_t l, BlockFlag_t r) { +inline BlockFlags operator|(BlockLiteralFlags l, BlockLiteralFlags r) { return BlockFlags(l) | BlockFlags(r); } @@ -182,6 +194,10 @@ public: /// UsesStret : True if the block uses an stret return. Mutable /// because it gets set later in the block-creation process. mutable bool UsesStret : 1; + + /// HasCapturedVariableLayout : True if block has captured variables + /// and their layout meta-data has been generated. + bool HasCapturedVariableLayout : 1; /// The mapping of allocated indexes within the block. llvm::DenseMap<const VarDecl*, Capture> Captures; diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 59ed31361616..e8c05d3a46d0 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -20,7 +20,7 @@ #include "clang/AST/Decl.h" #include "clang/Basic/TargetBuiltins.h" #include "llvm/Intrinsics.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" using namespace clang; using namespace CodeGen; @@ -86,8 +86,7 @@ static RValue EmitBinaryAtomic(CodeGenFunction &CGF, assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType())); llvm::Value *DestPtr = CGF.EmitScalarExpr(E->getArg(0)); - unsigned AddrSpace = - cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace(); + unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace(); llvm::IntegerType *IntType = llvm::IntegerType::get(CGF.getLLVMContext(), @@ -121,8 +120,7 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF, assert(CGF.getContext().hasSameUnqualifiedType(T, E->getArg(1)->getType())); llvm::Value *DestPtr = CGF.EmitScalarExpr(E->getArg(0)); - unsigned AddrSpace = - cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace(); + unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace(); llvm::IntegerType *IntType = llvm::IntegerType::get(CGF.getLLVMContext(), @@ -148,7 +146,7 @@ static RValue EmitBinaryAtomicPost(CodeGenFunction &CGF, static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) { const BuiltinType *ValTyP = ValTy->getAs<BuiltinType>(); assert(ValTyP && "isn't scalar fp type!"); - + StringRef FnName; switch (ValTyP->getKind()) { default: llvm_unreachable("Isn't a scalar fp type!"); @@ -156,7 +154,7 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V, QualType ValTy) { case BuiltinType::Double: FnName = "fabs"; break; case BuiltinType::LongDouble: FnName = "fabsl"; break; } - + // The prototype is something that takes and returns whatever V's type is. llvm::FunctionType *FT = llvm::FunctionType::get(V->getType(), V->getType(), false); @@ -214,7 +212,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Builder.CreateCall2(CGM.getIntrinsic(Intrinsic::vacopy), DstPtr, SrcPtr)); } - case Builtin::BI__builtin_abs: + case Builtin::BI__builtin_abs: case Builtin::BI__builtin_labs: case Builtin::BI__builtin_llabs: { Value *ArgValue = EmitScalarExpr(E->getArg(0)); @@ -229,18 +227,18 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(Result); } - + case Builtin::BI__builtin_conj: case Builtin::BI__builtin_conjf: case Builtin::BI__builtin_conjl: { ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0)); Value *Real = ComplexVal.first; Value *Imag = ComplexVal.second; - Value *Zero = - Imag->getType()->isFPOrFPVectorTy() + Value *Zero = + Imag->getType()->isFPOrFPVectorTy() ? llvm::ConstantFP::getZeroValueForNegation(Imag->getType()) : llvm::Constant::getNullValue(Imag->getType()); - + Imag = Builder.CreateFSub(Zero, Imag, "sub"); return RValue::getComplex(std::make_pair(Real, Imag)); } @@ -250,14 +248,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0)); return RValue::get(ComplexVal.first); } - + case Builtin::BI__builtin_cimag: case Builtin::BI__builtin_cimagf: case Builtin::BI__builtin_cimagl: { ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0)); return RValue::get(ComplexVal.second); } - + case Builtin::BI__builtin_ctzs: case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: @@ -356,6 +354,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, "expval"); return RValue::get(Result); } + case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: { Value *ArgValue = EmitScalarExpr(E->getArg(0)); @@ -371,15 +370,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // We pass this builtin onto the optimizer so that it can // figure out the object size in more complex cases. llvm::Type *ResType = ConvertType(E->getType()); - + // LLVM only supports 0 and 2, make sure that we pass along that // as a boolean. Value *Ty = EmitScalarExpr(E->getArg(1)); ConstantInt *CI = dyn_cast<ConstantInt>(Ty); assert(CI); uint64_t val = CI->getZExtValue(); - CI = ConstantInt::get(Builder.getInt1Ty(), (val & 0x2) >> 1); - + CI = ConstantInt::get(Builder.getInt1Ty(), (val & 0x2) >> 1); + Value *F = CGM.getIntrinsic(Intrinsic::objectsize, ResType); return RValue::get(Builder.CreateCall2(F, EmitScalarExpr(E->getArg(0)),CI)); } @@ -402,9 +401,15 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *F = CGM.getIntrinsic(Intrinsic::trap); return RValue::get(Builder.CreateCall(F)); } + case Builtin::BI__debugbreak: { + Value *F = CGM.getIntrinsic(Intrinsic::debugtrap); + return RValue::get(Builder.CreateCall(F)); + } case Builtin::BI__builtin_unreachable: { - if (CatchUndefined) - EmitBranch(getTrapBB()); + if (getLangOpts().SanitizeUnreachable) + EmitCheck(Builder.getFalse(), "builtin_unreachable", + EmitCheckSourceLocation(E->getExprLoc()), + llvm::ArrayRef<llvm::Value *>()); else Builder.CreateUnreachable(); @@ -413,7 +418,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, return RValue::get(0); } - + case Builtin::BI__builtin_powi: case Builtin::BI__builtin_powif: case Builtin::BI__builtin_powil: { @@ -464,16 +469,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, V = Builder.CreateFCmpUNO(V, V, "cmp"); return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()))); } - + case Builtin::BI__builtin_isinf: { // isinf(x) --> fabs(x) == infinity Value *V = EmitScalarExpr(E->getArg(0)); V = EmitFAbs(*this, V, E->getArg(0)->getType()); - + V = Builder.CreateFCmpOEQ(V, ConstantFP::getInfinity(V->getType()),"isinf"); return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()))); } - + // TODO: BI__builtin_isinf_sign // isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0 @@ -499,11 +504,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // isfinite(x) --> x == x && fabs(x) != infinity; Value *V = EmitScalarExpr(E->getArg(0)); Value *Eq = Builder.CreateFCmpOEQ(V, V, "iseq"); - + Value *Abs = EmitFAbs(*this, V, E->getArg(0)->getType()); Value *IsNotInf = Builder.CreateFCmpUNE(Abs, ConstantFP::getInfinity(V->getType()),"isinf"); - + V = Builder.CreateAnd(Eq, IsNotInf, "and"); return RValue::get(Builder.CreateZExt(V, ConvertType(E->getType()))); } @@ -565,7 +570,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Builder.SetInsertPoint(End); return RValue::get(Result); } - + case Builtin::BIalloca: case Builtin::BI__builtin_alloca: { Value *Size = EmitScalarExpr(E->getArg(0)); @@ -573,85 +578,90 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, } case Builtin::BIbzero: case Builtin::BI__builtin_bzero: { - Value *Address = EmitScalarExpr(E->getArg(0)); + std::pair<llvm::Value*, unsigned> Dest = + EmitPointerWithAlignment(E->getArg(0)); Value *SizeVal = EmitScalarExpr(E->getArg(1)); - unsigned Align = GetPointeeAlignment(E->getArg(0)); - Builder.CreateMemSet(Address, Builder.getInt8(0), SizeVal, Align, false); - return RValue::get(Address); + Builder.CreateMemSet(Dest.first, Builder.getInt8(0), SizeVal, + Dest.second, false); + return RValue::get(Dest.first); } case Builtin::BImemcpy: case Builtin::BI__builtin_memcpy: { - Value *Address = EmitScalarExpr(E->getArg(0)); - Value *SrcAddr = EmitScalarExpr(E->getArg(1)); + std::pair<llvm::Value*, unsigned> Dest = + EmitPointerWithAlignment(E->getArg(0)); + std::pair<llvm::Value*, unsigned> Src = + EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = EmitScalarExpr(E->getArg(2)); - unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)), - GetPointeeAlignment(E->getArg(1))); - Builder.CreateMemCpy(Address, SrcAddr, SizeVal, Align, false); - return RValue::get(Address); + unsigned Align = std::min(Dest.second, Src.second); + Builder.CreateMemCpy(Dest.first, Src.first, SizeVal, Align, false); + return RValue::get(Dest.first); } - + case Builtin::BI__builtin___memcpy_chk: { - // fold __builtin_memcpy_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. + // fold __builtin_memcpy_chk(x, y, cst1, cst2) to memcpy iff cst1<=cst2. llvm::APSInt Size, DstSize; if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) || !E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext())) break; if (Size.ugt(DstSize)) break; - Value *Dest = EmitScalarExpr(E->getArg(0)); - Value *Src = EmitScalarExpr(E->getArg(1)); + std::pair<llvm::Value*, unsigned> Dest = + EmitPointerWithAlignment(E->getArg(0)); + std::pair<llvm::Value*, unsigned> Src = + EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); - unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)), - GetPointeeAlignment(E->getArg(1))); - Builder.CreateMemCpy(Dest, Src, SizeVal, Align, false); - return RValue::get(Dest); + unsigned Align = std::min(Dest.second, Src.second); + Builder.CreateMemCpy(Dest.first, Src.first, SizeVal, Align, false); + return RValue::get(Dest.first); } - + case Builtin::BI__builtin_objc_memmove_collectable: { Value *Address = EmitScalarExpr(E->getArg(0)); Value *SrcAddr = EmitScalarExpr(E->getArg(1)); Value *SizeVal = EmitScalarExpr(E->getArg(2)); - CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, + CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, Address, SrcAddr, SizeVal); return RValue::get(Address); } case Builtin::BI__builtin___memmove_chk: { - // fold __builtin_memmove_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. + // fold __builtin_memmove_chk(x, y, cst1, cst2) to memmove iff cst1<=cst2. llvm::APSInt Size, DstSize; if (!E->getArg(2)->EvaluateAsInt(Size, CGM.getContext()) || !E->getArg(3)->EvaluateAsInt(DstSize, CGM.getContext())) break; if (Size.ugt(DstSize)) break; - Value *Dest = EmitScalarExpr(E->getArg(0)); - Value *Src = EmitScalarExpr(E->getArg(1)); + std::pair<llvm::Value*, unsigned> Dest = + EmitPointerWithAlignment(E->getArg(0)); + std::pair<llvm::Value*, unsigned> Src = + EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); - unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)), - GetPointeeAlignment(E->getArg(1))); - Builder.CreateMemMove(Dest, Src, SizeVal, Align, false); - return RValue::get(Dest); + unsigned Align = std::min(Dest.second, Src.second); + Builder.CreateMemMove(Dest.first, Src.first, SizeVal, Align, false); + return RValue::get(Dest.first); } case Builtin::BImemmove: case Builtin::BI__builtin_memmove: { - Value *Address = EmitScalarExpr(E->getArg(0)); - Value *SrcAddr = EmitScalarExpr(E->getArg(1)); + std::pair<llvm::Value*, unsigned> Dest = + EmitPointerWithAlignment(E->getArg(0)); + std::pair<llvm::Value*, unsigned> Src = + EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = EmitScalarExpr(E->getArg(2)); - unsigned Align = std::min(GetPointeeAlignment(E->getArg(0)), - GetPointeeAlignment(E->getArg(1))); - Builder.CreateMemMove(Address, SrcAddr, SizeVal, Align, false); - return RValue::get(Address); + unsigned Align = std::min(Dest.second, Src.second); + Builder.CreateMemMove(Dest.first, Src.first, SizeVal, Align, false); + return RValue::get(Dest.first); } case Builtin::BImemset: case Builtin::BI__builtin_memset: { - Value *Address = EmitScalarExpr(E->getArg(0)); + std::pair<llvm::Value*, unsigned> Dest = + EmitPointerWithAlignment(E->getArg(0)); Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)), Builder.getInt8Ty()); Value *SizeVal = EmitScalarExpr(E->getArg(2)); - unsigned Align = GetPointeeAlignment(E->getArg(0)); - Builder.CreateMemSet(Address, ByteVal, SizeVal, Align, false); - return RValue::get(Address); + Builder.CreateMemSet(Dest.first, ByteVal, SizeVal, Dest.second, false); + return RValue::get(Dest.first); } case Builtin::BI__builtin___memset_chk: { // fold __builtin_memset_chk(x, y, cst1, cst2) to memset iff cst1<=cst2. @@ -661,14 +671,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, break; if (Size.ugt(DstSize)) break; - Value *Address = EmitScalarExpr(E->getArg(0)); + std::pair<llvm::Value*, unsigned> Dest = + EmitPointerWithAlignment(E->getArg(0)); Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)), Builder.getInt8Ty()); Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); - unsigned Align = GetPointeeAlignment(E->getArg(0)); - Builder.CreateMemSet(Address, ByteVal, SizeVal, Align, false); - - return RValue::get(Address); + Builder.CreateMemSet(Dest.first, ByteVal, SizeVal, Dest.second, false); + return RValue::get(Dest.first); } case Builtin::BI__builtin_dwarf_cfa: { // The offset in bytes from the first argument to the CFA. @@ -682,7 +691,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, int32_t Offset = 0; Value *F = CGM.getIntrinsic(Intrinsic::eh_dwarf_cfa); - return RValue::get(Builder.CreateCall(F, + return RValue::get(Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, Offset))); } case Builtin::BI__builtin_return_address: { @@ -907,9 +916,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_val_compare_and_swap_16: { QualType T = E->getType(); llvm::Value *DestPtr = EmitScalarExpr(E->getArg(0)); - unsigned AddrSpace = - cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace(); - + unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace(); + llvm::IntegerType *IntType = llvm::IntegerType::get(getLLVMContext(), getContext().getTypeSize(T)); @@ -935,9 +943,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__sync_bool_compare_and_swap_16: { QualType T = E->getArg(1)->getType(); llvm::Value *DestPtr = EmitScalarExpr(E->getArg(0)); - unsigned AddrSpace = - cast<llvm::PointerType>(DestPtr->getType())->getAddressSpace(); - + unsigned AddrSpace = DestPtr->getType()->getPointerAddressSpace(); + llvm::IntegerType *IntType = llvm::IntegerType::get(getLLVMContext(), getContext().getTypeSize(T)); @@ -982,7 +989,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::Type *ITy = llvm::IntegerType::get(getLLVMContext(), StoreSize.getQuantity() * 8); Ptr = Builder.CreateBitCast(Ptr, ITy->getPointerTo()); - llvm::StoreInst *Store = + llvm::StoreInst *Store = Builder.CreateStore(llvm::Constant::getNullValue(ITy), Ptr); Store->setAlignment(StoreSize.getQuantity()); Store->setAtomic(llvm::Release); @@ -993,7 +1000,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, // We assume this is supposed to correspond to a C++0x-style // sequentially-consistent fence (i.e. this is only usable for // synchonization, not device I/O or anything like that). This intrinsic - // is really badly designed in the sense that in theory, there isn't + // is really badly designed in the sense that in theory, there isn't // any way to safely use it... but in practice, it mostly works // to use it with non-atomic loads and stores to get acquire/release // semantics. @@ -1033,8 +1040,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified(); Value *Ptr = EmitScalarExpr(E->getArg(0)); - unsigned AddrSpace = - cast<llvm::PointerType>(Ptr->getType())->getAddressSpace(); + unsigned AddrSpace = Ptr->getType()->getPointerAddressSpace(); Ptr = Builder.CreateBitCast(Ptr, Int8Ty->getPointerTo(AddrSpace)); Value *NewVal = Builder.getInt8(1); Value *Order = EmitScalarExpr(E->getArg(1)); @@ -1120,8 +1126,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, PtrTy->castAs<PointerType>()->getPointeeType().isVolatileQualified(); Value *Ptr = EmitScalarExpr(E->getArg(0)); - unsigned AddrSpace = - cast<llvm::PointerType>(Ptr->getType())->getAddressSpace(); + unsigned AddrSpace = Ptr->getType()->getPointerAddressSpace(); Ptr = Builder.CreateBitCast(Ptr, Int8Ty->getPointerTo(AddrSpace)); Value *NewVal = Builder.getInt8(0); Value *Order = EmitScalarExpr(E->getArg(1)); @@ -1310,6 +1315,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::StringRef Str = cast<StringLiteral>(AnnotationStrExpr)->getString(); return RValue::get(EmitAnnotationCall(F, AnnVal, Str, E->getExprLoc())); } + case Builtin::BI__noop: + return RValue::get(0); } // If this is an alias for a lib function (e.g. __builtin_sin), emit @@ -1318,7 +1325,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, if (getContext().BuiltinInfo.isLibFunction(BuiltinID)) return emitLibraryCall(*this, FD, E, CGM.getBuiltinLibFunction(FD, BuiltinID)); - + // If this is a predefined lib function (e.g. malloc), emit the call // using exactly the normal call path. if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID)) @@ -1350,7 +1357,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, if ((ICEArguments & (1 << i)) == 0) { ArgValue = EmitScalarExpr(E->getArg(i)); } else { - // If this is required to be a constant, constant fold it so that we + // If this is required to be a constant, constant fold it so that we // know that the generated intrinsic gets a ConstantInt. llvm::APSInt Result; bool IsConst = E->getArg(i)->isIntegerConstantExpr(Result,getContext()); @@ -1375,7 +1382,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, QualType BuiltinRetType = E->getType(); llvm::Type *RetTy = VoidTy; - if (!BuiltinRetType->isVoidType()) + if (!BuiltinRetType->isVoidType()) RetTy = ConvertType(BuiltinRetType); if (RetTy != V->getType()) { @@ -1457,10 +1464,10 @@ Value *CodeGenFunction::EmitNeonCall(Function *F, SmallVectorImpl<Value*> &Ops, return Builder.CreateCall(F, Ops, name); } -Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty, +Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty, bool neg) { int SV = cast<ConstantInt>(V)->getSExtValue(); - + llvm::VectorType *VTy = cast<llvm::VectorType>(Ty); llvm::Constant *C = ConstantInt::get(VTy->getElementType(), neg ? -SV : SV); return llvm::ConstantVector::getSplat(VTy->getNumElements(), C); @@ -1469,34 +1476,56 @@ Value *CodeGenFunction::EmitNeonShiftVector(Value *V, llvm::Type *Ty, /// GetPointeeAlignment - Given an expression with a pointer type, find the /// alignment of the type referenced by the pointer. Skip over implicit /// casts. -unsigned CodeGenFunction::GetPointeeAlignment(const Expr *Addr) { - unsigned Align = 1; - // Check if the type is a pointer. The implicit cast operand might not be. - while (Addr->getType()->isPointerType()) { - QualType PtTy = Addr->getType()->getPointeeType(); - - // Can't get alignment of incomplete types. - if (!PtTy->isIncompleteType()) { - unsigned NewA = getContext().getTypeAlignInChars(PtTy).getQuantity(); - if (NewA > Align) - Align = NewA; +std::pair<llvm::Value*, unsigned> +CodeGenFunction::EmitPointerWithAlignment(const Expr *Addr) { + assert(Addr->getType()->isPointerType()); + Addr = Addr->IgnoreParens(); + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(Addr)) { + if ((ICE->getCastKind() == CK_BitCast || ICE->getCastKind() == CK_NoOp) && + ICE->getSubExpr()->getType()->isPointerType()) { + std::pair<llvm::Value*, unsigned> Ptr = + EmitPointerWithAlignment(ICE->getSubExpr()); + Ptr.first = Builder.CreateBitCast(Ptr.first, + ConvertType(Addr->getType())); + return Ptr; + } else if (ICE->getCastKind() == CK_ArrayToPointerDecay) { + LValue LV = EmitLValue(ICE->getSubExpr()); + unsigned Align = LV.getAlignment().getQuantity(); + if (!Align) { + // FIXME: Once LValues are fixed to always set alignment, + // zap this code. + QualType PtTy = ICE->getSubExpr()->getType(); + if (!PtTy->isIncompleteType()) + Align = getContext().getTypeAlignInChars(PtTy).getQuantity(); + else + Align = 1; + } + return std::make_pair(LV.getAddress(), Align); } - - // If the address is an implicit cast, repeat with the cast operand. - if (const ImplicitCastExpr *CastAddr = dyn_cast<ImplicitCastExpr>(Addr)) { - Addr = CastAddr->getSubExpr(); - continue; + } + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(Addr)) { + if (UO->getOpcode() == UO_AddrOf) { + LValue LV = EmitLValue(UO->getSubExpr()); + unsigned Align = LV.getAlignment().getQuantity(); + if (!Align) { + // FIXME: Once LValues are fixed to always set alignment, + // zap this code. + QualType PtTy = UO->getSubExpr()->getType(); + if (!PtTy->isIncompleteType()) + Align = getContext().getTypeAlignInChars(PtTy).getQuantity(); + else + Align = 1; + } + return std::make_pair(LV.getAddress(), Align); } - break; } - return Align; -} -/// GetPointeeAlignmentValue - Given an expression with a pointer type, find -/// the alignment of the type referenced by the pointer. Skip over implicit -/// casts. Return the alignment as an llvm::Value. -Value *CodeGenFunction::GetPointeeAlignmentValue(const Expr *Addr) { - return llvm::ConstantInt::get(Int32Ty, GetPointeeAlignment(Addr)); + unsigned Align = 1; + QualType PtTy = Addr->getType()->getPointeeType(); + if (!PtTy->isIncompleteType()) + Align = getContext().getTypeAlignInChars(PtTy).getQuantity(); + + return std::make_pair(EmitScalarExpr(Addr), Align); } Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, @@ -1549,8 +1578,69 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, } SmallVector<Value*, 4> Ops; - for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) + llvm::Value *Align = 0; + for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) { + if (i == 0) { + switch (BuiltinID) { + case ARM::BI__builtin_neon_vld1_v: + case ARM::BI__builtin_neon_vld1q_v: + case ARM::BI__builtin_neon_vld1q_lane_v: + case ARM::BI__builtin_neon_vld1_lane_v: + case ARM::BI__builtin_neon_vld1_dup_v: + case ARM::BI__builtin_neon_vld1q_dup_v: + case ARM::BI__builtin_neon_vst1_v: + case ARM::BI__builtin_neon_vst1q_v: + case ARM::BI__builtin_neon_vst1q_lane_v: + case ARM::BI__builtin_neon_vst1_lane_v: + case ARM::BI__builtin_neon_vst2_v: + case ARM::BI__builtin_neon_vst2q_v: + case ARM::BI__builtin_neon_vst2_lane_v: + case ARM::BI__builtin_neon_vst2q_lane_v: + case ARM::BI__builtin_neon_vst3_v: + case ARM::BI__builtin_neon_vst3q_v: + case ARM::BI__builtin_neon_vst3_lane_v: + case ARM::BI__builtin_neon_vst3q_lane_v: + case ARM::BI__builtin_neon_vst4_v: + case ARM::BI__builtin_neon_vst4q_v: + case ARM::BI__builtin_neon_vst4_lane_v: + case ARM::BI__builtin_neon_vst4q_lane_v: + // Get the alignment for the argument in addition to the value; + // we'll use it later. + std::pair<llvm::Value*, unsigned> Src = + EmitPointerWithAlignment(E->getArg(0)); + Ops.push_back(Src.first); + Align = Builder.getInt32(Src.second); + continue; + } + } + if (i == 1) { + switch (BuiltinID) { + case ARM::BI__builtin_neon_vld2_v: + case ARM::BI__builtin_neon_vld2q_v: + case ARM::BI__builtin_neon_vld3_v: + case ARM::BI__builtin_neon_vld3q_v: + case ARM::BI__builtin_neon_vld4_v: + case ARM::BI__builtin_neon_vld4q_v: + case ARM::BI__builtin_neon_vld2_lane_v: + case ARM::BI__builtin_neon_vld2q_lane_v: + case ARM::BI__builtin_neon_vld3_lane_v: + case ARM::BI__builtin_neon_vld3q_lane_v: + case ARM::BI__builtin_neon_vld4_lane_v: + case ARM::BI__builtin_neon_vld4q_lane_v: + case ARM::BI__builtin_neon_vld2_dup_v: + case ARM::BI__builtin_neon_vld3_dup_v: + case ARM::BI__builtin_neon_vld4_dup_v: + // Get the alignment for the argument in addition to the value; + // we'll use it later. + std::pair<llvm::Value*, unsigned> Src = + EmitPointerWithAlignment(E->getArg(1)); + Ops.push_back(Src.first); + Align = Builder.getInt32(Src.second); + continue; + } + } Ops.push_back(EmitScalarExpr(E->getArg(i))); + } // vget_lane and vset_lane are not overloaded and do not have an extra // argument that specifies the vector type. @@ -1596,7 +1686,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ty = FloatTy; else Ty = DoubleTy; - + // Determine whether this is an unsigned conversion or not. bool usgn = Result.getZExtValue() == 1; unsigned Int = usgn ? Intrinsic::arm_vcvtru : Intrinsic::arm_vcvtr; @@ -1605,7 +1695,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Function *F = CGM.getIntrinsic(Int, Ty); return Builder.CreateCall(F, Ops, "vcvtr"); } - + // Determine the type of this overloaded NEON intrinsic. NeonTypeFlags Type(Result.getZExtValue()); bool usgn = Type.isUnsigned(); @@ -1620,6 +1710,10 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, unsigned Int; switch (BuiltinID) { default: return 0; + case ARM::BI__builtin_neon_vbsl_v: + case ARM::BI__builtin_neon_vbslq_v: + return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vbsl, Ty), + Ops, "vbsl"); case ARM::BI__builtin_neon_vabd_v: case ARM::BI__builtin_neon_vabdq_v: Int = usgn ? Intrinsic::arm_neon_vabdu : Intrinsic::arm_neon_vabds; @@ -1690,7 +1784,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vcvtq_f32_v: Ops[0] = Builder.CreateBitCast(Ops[0], Ty); Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad)); - return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt") + return usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt") : Builder.CreateSIToFP(Ops[0], Ty, "vcvt"); case ARM::BI__builtin_neon_vcvt_s32_v: case ARM::BI__builtin_neon_vcvt_u32_v: @@ -1699,7 +1793,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, llvm::Type *FloatTy = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, quad)); Ops[0] = Builder.CreateBitCast(Ops[0], FloatTy); - return usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt") + return usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt") : Builder.CreateFPToSI(Ops[0], Ty, "vcvt"); } case ARM::BI__builtin_neon_vcvt_n_f32_v: @@ -1730,7 +1824,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, SmallVector<Constant*, 16> Indices; for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) Indices.push_back(ConstantInt::get(Int32Ty, i+CV)); - + Ops[0] = Builder.CreateBitCast(Ops[0], Ty); Ops[1] = Builder.CreateBitCast(Ops[1], Ty); Value *SV = llvm::ConstantVector::get(Indices); @@ -1746,7 +1840,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vhsub"); case ARM::BI__builtin_neon_vld1_v: case ARM::BI__builtin_neon_vld1q_v: - Ops.push_back(GetPointeeAlignmentValue(E->getArg(0))); + Ops.push_back(Align); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Ty), Ops, "vld1"); case ARM::BI__builtin_neon_vld1q_lane_v: @@ -1761,8 +1855,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, // Load the value as a one-element vector. Ty = llvm::VectorType::get(VTy->getElementType(), 1); Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld1, Ty); - Value *Ld = Builder.CreateCall2(F, Ops[0], - GetPointeeAlignmentValue(E->getArg(0))); + Value *Ld = Builder.CreateCall2(F, Ops[0], Align); // Combine them. SmallVector<Constant*, 2> Indices; Indices.push_back(ConstantInt::get(Int32Ty, 1-Lane)); @@ -1776,7 +1869,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ty = llvm::PointerType::getUnqual(VTy->getElementType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); LoadInst *Ld = Builder.CreateLoad(Ops[0]); - Value *Align = GetPointeeAlignmentValue(E->getArg(0)); Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue()); return Builder.CreateInsertElement(Ops[1], Ld, Ops[2], "vld1_lane"); } @@ -1786,7 +1878,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ty = llvm::PointerType::getUnqual(VTy->getElementType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); LoadInst *Ld = Builder.CreateLoad(Ops[0]); - Value *Align = GetPointeeAlignmentValue(E->getArg(0)); Ld->setAlignment(cast<ConstantInt>(Align)->getZExtValue()); llvm::Constant *CI = ConstantInt::get(Int32Ty, 0); Ops[0] = Builder.CreateInsertElement(V, Ld, CI); @@ -1795,7 +1886,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vld2_v: case ARM::BI__builtin_neon_vld2q_v: { Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2, Ty); - Value *Align = GetPointeeAlignmentValue(E->getArg(1)); Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld2"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); @@ -1804,7 +1894,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vld3_v: case ARM::BI__builtin_neon_vld3q_v: { Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld3, Ty); - Value *Align = GetPointeeAlignmentValue(E->getArg(1)); Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld3"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); @@ -1813,7 +1902,6 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vld4_v: case ARM::BI__builtin_neon_vld4q_v: { Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld4, Ty); - Value *Align = GetPointeeAlignmentValue(E->getArg(1)); Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld4"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); @@ -1824,7 +1912,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Function *F = CGM.getIntrinsic(Intrinsic::arm_neon_vld2lane, Ty); Ops[2] = Builder.CreateBitCast(Ops[2], Ty); Ops[3] = Builder.CreateBitCast(Ops[3], Ty); - Ops.push_back(GetPointeeAlignmentValue(E->getArg(1))); + Ops.push_back(Align); Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld2_lane"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); @@ -1836,7 +1924,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops[2] = Builder.CreateBitCast(Ops[2], Ty); Ops[3] = Builder.CreateBitCast(Ops[3], Ty); Ops[4] = Builder.CreateBitCast(Ops[4], Ty); - Ops.push_back(GetPointeeAlignmentValue(E->getArg(1))); + Ops.push_back(Align); Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); @@ -1849,7 +1937,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops[3] = Builder.CreateBitCast(Ops[3], Ty); Ops[4] = Builder.CreateBitCast(Ops[4], Ty); Ops[5] = Builder.CreateBitCast(Ops[5], Ty); - Ops.push_back(GetPointeeAlignmentValue(E->getArg(1))); + Ops.push_back(Align); Ops[1] = Builder.CreateCall(F, makeArrayRef(Ops).slice(1), "vld3_lane"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); @@ -1861,47 +1949,46 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, // Handle 64-bit elements as a special-case. There is no "dup" needed. if (VTy->getElementType()->getPrimitiveSizeInBits() == 64) { switch (BuiltinID) { - case ARM::BI__builtin_neon_vld2_dup_v: - Int = Intrinsic::arm_neon_vld2; + case ARM::BI__builtin_neon_vld2_dup_v: + Int = Intrinsic::arm_neon_vld2; break; case ARM::BI__builtin_neon_vld3_dup_v: - Int = Intrinsic::arm_neon_vld3; + Int = Intrinsic::arm_neon_vld3; break; case ARM::BI__builtin_neon_vld4_dup_v: - Int = Intrinsic::arm_neon_vld4; + Int = Intrinsic::arm_neon_vld4; break; default: llvm_unreachable("unknown vld_dup intrinsic?"); } Function *F = CGM.getIntrinsic(Int, Ty); - Value *Align = GetPointeeAlignmentValue(E->getArg(1)); Ops[1] = Builder.CreateCall2(F, Ops[1], Align, "vld_dup"); Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); Ops[0] = Builder.CreateBitCast(Ops[0], Ty); return Builder.CreateStore(Ops[1], Ops[0]); } switch (BuiltinID) { - case ARM::BI__builtin_neon_vld2_dup_v: - Int = Intrinsic::arm_neon_vld2lane; + case ARM::BI__builtin_neon_vld2_dup_v: + Int = Intrinsic::arm_neon_vld2lane; break; case ARM::BI__builtin_neon_vld3_dup_v: - Int = Intrinsic::arm_neon_vld3lane; + Int = Intrinsic::arm_neon_vld3lane; break; case ARM::BI__builtin_neon_vld4_dup_v: - Int = Intrinsic::arm_neon_vld4lane; + Int = Intrinsic::arm_neon_vld4lane; break; default: llvm_unreachable("unknown vld_dup intrinsic?"); } Function *F = CGM.getIntrinsic(Int, Ty); llvm::StructType *STy = cast<llvm::StructType>(F->getReturnType()); - + SmallVector<Value*, 6> Args; Args.push_back(Ops[1]); Args.append(STy->getNumElements(), UndefValue::get(Ty)); llvm::Constant *CI = ConstantInt::get(Int32Ty, 0); Args.push_back(CI); - Args.push_back(GetPointeeAlignmentValue(E->getArg(1))); - + Args.push_back(Align); + Ops[1] = Builder.CreateCall(F, Args, "vld_dup"); // splat lane 0 to all elts in each vector of the result. for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { @@ -1944,6 +2031,14 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Int = usgn ? Intrinsic::arm_neon_vmullu : Intrinsic::arm_neon_vmulls; Int = Type.isPoly() ? (unsigned)Intrinsic::arm_neon_vmullp : Int; return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vmull"); + case ARM::BI__builtin_neon_vfma_v: + case ARM::BI__builtin_neon_vfmaq_v: { + Value *F = CGM.getIntrinsic(Intrinsic::fma, Ty); + Ops[0] = Builder.CreateBitCast(Ops[0], Ty); + Ops[1] = Builder.CreateBitCast(Ops[1], Ty); + Ops[2] = Builder.CreateBitCast(Ops[2], Ty); + return Builder.CreateCall3(F, Ops[0], Ops[1], Ops[2]); + } case ARM::BI__builtin_neon_vpadal_v: case ARM::BI__builtin_neon_vpadalq_v: { Int = usgn ? Intrinsic::arm_neon_vpadalu : Intrinsic::arm_neon_vpadals; @@ -2016,7 +2111,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Int = usgn ? Intrinsic::arm_neon_vqrshiftu : Intrinsic::arm_neon_vqrshifts; return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshl"); case ARM::BI__builtin_neon_vqrshrn_n_v: - Int = usgn ? Intrinsic::arm_neon_vqrshiftnu : Intrinsic::arm_neon_vqrshiftns; + Int = + usgn ? Intrinsic::arm_neon_vqrshiftnu : Intrinsic::arm_neon_vqrshiftns; return EmitNeonCall(CGM.getIntrinsic(Int, Ty), Ops, "vqrshrn_n", 1, true); case ARM::BI__builtin_neon_vqrshrun_n_v: @@ -2086,7 +2182,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops[1] = Builder.CreateBitCast(Ops[1], Ty); Ops[2] = EmitNeonShiftVector(Ops[2], Ty, true); Int = usgn ? Intrinsic::arm_neon_vrshiftu : Intrinsic::arm_neon_vrshifts; - Ops[1] = Builder.CreateCall2(CGM.getIntrinsic(Int, Ty), Ops[1], Ops[2]); + Ops[1] = Builder.CreateCall2(CGM.getIntrinsic(Int, Ty), Ops[1], Ops[2]); return Builder.CreateAdd(Ops[0], Ops[1], "vrsra_n"); case ARM::BI__builtin_neon_vrsubhn_v: return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vrsubhn, Ty), @@ -2101,7 +2197,8 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, case ARM::BI__builtin_neon_vshl_n_v: case ARM::BI__builtin_neon_vshlq_n_v: Ops[1] = EmitNeonShiftVector(Ops[1], Ty, false); - return Builder.CreateShl(Builder.CreateBitCast(Ops[0],Ty), Ops[1], "vshl_n"); + return Builder.CreateShl(Builder.CreateBitCast(Ops[0],Ty), Ops[1], + "vshl_n"); case ARM::BI__builtin_neon_vshrn_n_v: return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vshiftn, Ty), Ops, "vshrn_n", 1, true); @@ -2133,7 +2230,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, return Builder.CreateAdd(Ops[0], Ops[1]); case ARM::BI__builtin_neon_vst1_v: case ARM::BI__builtin_neon_vst1q_v: - Ops.push_back(GetPointeeAlignmentValue(E->getArg(0))); + Ops.push_back(Align); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1, Ty), Ops, ""); case ARM::BI__builtin_neon_vst1q_lane_v: @@ -2143,7 +2240,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops[1] = Builder.CreateBitCast(Ops[1], Ty); Value *SV = llvm::ConstantVector::get(cast<llvm::Constant>(Ops[2])); Ops[1] = Builder.CreateShuffleVector(Ops[1], Ops[1], SV); - Ops[2] = GetPointeeAlignmentValue(E->getArg(0)); + Ops[2] = Align; return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst1, Ops[1]->getType()), Ops); } @@ -2154,38 +2251,37 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ty = llvm::PointerType::getUnqual(Ops[1]->getType()); StoreInst *St = Builder.CreateStore(Ops[1], Builder.CreateBitCast(Ops[0], Ty)); - Value *Align = GetPointeeAlignmentValue(E->getArg(0)); St->setAlignment(cast<ConstantInt>(Align)->getZExtValue()); return St; } case ARM::BI__builtin_neon_vst2_v: case ARM::BI__builtin_neon_vst2q_v: - Ops.push_back(GetPointeeAlignmentValue(E->getArg(0))); + Ops.push_back(Align); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2, Ty), Ops, ""); case ARM::BI__builtin_neon_vst2_lane_v: case ARM::BI__builtin_neon_vst2q_lane_v: - Ops.push_back(GetPointeeAlignmentValue(E->getArg(0))); + Ops.push_back(Align); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst2lane, Ty), Ops, ""); case ARM::BI__builtin_neon_vst3_v: case ARM::BI__builtin_neon_vst3q_v: - Ops.push_back(GetPointeeAlignmentValue(E->getArg(0))); + Ops.push_back(Align); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3, Ty), Ops, ""); case ARM::BI__builtin_neon_vst3_lane_v: case ARM::BI__builtin_neon_vst3q_lane_v: - Ops.push_back(GetPointeeAlignmentValue(E->getArg(0))); + Ops.push_back(Align); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst3lane, Ty), Ops, ""); case ARM::BI__builtin_neon_vst4_v: case ARM::BI__builtin_neon_vst4q_v: - Ops.push_back(GetPointeeAlignmentValue(E->getArg(0))); + Ops.push_back(Align); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4, Ty), Ops, ""); case ARM::BI__builtin_neon_vst4_lane_v: case ARM::BI__builtin_neon_vst4q_lane_v: - Ops.push_back(GetPointeeAlignmentValue(E->getArg(0))); + Ops.push_back(Align); return EmitNeonCall(CGM.getIntrinsic(Intrinsic::arm_neon_vst4lane, Ty), Ops, ""); case ARM::BI__builtin_neon_vsubhn_v: @@ -2220,7 +2316,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops[0] = Builder.CreateBitCast(Ops[0], Ty); Ops[1] = Builder.CreateBitCast(Ops[1], Ty); Ops[0] = Builder.CreateAnd(Ops[0], Ops[1]); - Ops[0] = Builder.CreateICmp(ICmpInst::ICMP_NE, Ops[0], + Ops[0] = Builder.CreateICmp(ICmpInst::ICMP_NE, Ops[0], ConstantAggregateZero::get(Ty)); return Builder.CreateSExt(Ops[0], Ty, "vtst"); } @@ -2250,7 +2346,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, Ops[1] = Builder.CreateBitCast(Ops[1], Ty); Ops[2] = Builder.CreateBitCast(Ops[2], Ty); Value *SV = 0; - + for (unsigned vi = 0; vi != 2; ++vi) { SmallVector<Constant*, 16> Indices; for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) @@ -2263,13 +2359,13 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, } return SV; } - case ARM::BI__builtin_neon_vzip_v: + case ARM::BI__builtin_neon_vzip_v: case ARM::BI__builtin_neon_vzipq_v: { Ops[0] = Builder.CreateBitCast(Ops[0], llvm::PointerType::getUnqual(Ty)); Ops[1] = Builder.CreateBitCast(Ops[1], Ty); Ops[2] = Builder.CreateBitCast(Ops[2], Ty); Value *SV = 0; - + for (unsigned vi = 0; vi != 2; ++vi) { SmallVector<Constant*, 16> Indices; for (unsigned i = 0, e = VTy->getNumElements(); i != e; i += 2) { @@ -2382,62 +2478,62 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, } case X86::BI__builtin_ia32_palignr: { unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue(); - + // If palignr is shifting the pair of input vectors less than 9 bytes, // emit a shuffle instruction. if (shiftVal <= 8) { SmallVector<llvm::Constant*, 8> Indices; for (unsigned i = 0; i != 8; ++i) Indices.push_back(llvm::ConstantInt::get(Int32Ty, shiftVal + i)); - + Value* SV = llvm::ConstantVector::get(Indices); return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr"); } - + // If palignr is shifting the pair of input vectors more than 8 but less // than 16 bytes, emit a logical right shift of the destination. if (shiftVal < 16) { // MMX has these as 1 x i64 vectors for some odd optimization reasons. llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 1); - + Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast"); Ops[1] = llvm::ConstantInt::get(VecTy, (shiftVal-8) * 8); - + // create i32 constant llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_mmx_psrl_q); return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr"); } - + // If palignr is shifting the pair of vectors more than 16 bytes, emit zero. return llvm::Constant::getNullValue(ConvertType(E->getType())); } case X86::BI__builtin_ia32_palignr128: { unsigned shiftVal = cast<llvm::ConstantInt>(Ops[2])->getZExtValue(); - + // If palignr is shifting the pair of input vectors less than 17 bytes, // emit a shuffle instruction. if (shiftVal <= 16) { SmallVector<llvm::Constant*, 16> Indices; for (unsigned i = 0; i != 16; ++i) Indices.push_back(llvm::ConstantInt::get(Int32Ty, shiftVal + i)); - + Value* SV = llvm::ConstantVector::get(Indices); return Builder.CreateShuffleVector(Ops[1], Ops[0], SV, "palignr"); } - + // If palignr is shifting the pair of input vectors more than 16 but less // than 32 bytes, emit a logical right shift of the destination. if (shiftVal < 32) { llvm::Type *VecTy = llvm::VectorType::get(Int64Ty, 2); - + Ops[0] = Builder.CreateBitCast(Ops[0], VecTy, "cast"); Ops[1] = llvm::ConstantInt::get(Int32Ty, (shiftVal-16) * 8); - + // create i32 constant llvm::Function *F = CGM.getIntrinsic(Intrinsic::x86_sse2_psrl_dq); return Builder.CreateCall(F, makeArrayRef(&Ops[0], 2), "palignr"); } - + // If palignr is shifting the pair of vectors more than 32 bytes, emit zero. return llvm::Constant::getNullValue(ConvertType(E->getType())); } diff --git a/lib/CodeGen/CGCXXABI.cpp b/lib/CodeGen/CGCXXABI.cpp index aba5d755d5c4..91795b9ded29 100644 --- a/lib/CodeGen/CGCXXABI.cpp +++ b/lib/CodeGen/CGCXXABI.cpp @@ -189,7 +189,7 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, llvm::Value *ptr, llvm::Value *&numElements, llvm::Value *&allocPtr, CharUnits &cookieSize) { // Derive a char* in the same address space as the pointer. - unsigned AS = cast<llvm::PointerType>(ptr->getType())->getAddressSpace(); + unsigned AS = ptr->getType()->getPointerAddressSpace(); llvm::Type *charPtrTy = CGF.Int8Ty->getPointerTo(AS); ptr = CGF.Builder.CreateBitCast(ptr, charPtrTy); diff --git a/lib/CodeGen/CGCXXABI.h b/lib/CodeGen/CGCXXABI.h index a0dcdfdcc686..570aeb040f55 100644 --- a/lib/CodeGen/CGCXXABI.h +++ b/lib/CodeGen/CGCXXABI.h @@ -154,6 +154,15 @@ protected: llvm::Constant *getMemberPointerAdjustment(const CastExpr *E); public: + /// Adjust the given non-null pointer to an object of polymorphic + /// type to point to the complete object. + /// + /// The IR type of the result should be a pointer but is otherwise + /// irrelevant. + virtual llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF, + llvm::Value *ptr, + QualType type) = 0; + /// Build the signature of the given constructor variant by adding /// any required parameters. For convenience, ResTy has been /// initialized to 'void', and ArgTys has been initialized with the @@ -196,6 +205,9 @@ public: /// Gets the pure virtual member call function. virtual StringRef GetPureVirtualCallName() = 0; + /// Gets the deleted virtual member call name. + virtual StringRef GetDeletedVirtualCallName() = 0; + /**************************** Array cookies ******************************/ /// Returns the extra size required in order to store the array diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 7d2b9d355ec6..2d1d152894fd 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -25,7 +25,7 @@ #include "clang/Frontend/CodeGenOptions.h" #include "llvm/Attributes.h" #include "llvm/Support/CallSite.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include "llvm/InlineAsm.h" #include "llvm/Transforms/Utils/Local.h" using namespace clang; @@ -148,6 +148,9 @@ static CallingConv getCallingConventionForDecl(const Decl *D) { if (PcsAttr *PCS = D->getAttr<PcsAttr>()) return (PCS->getPCS() == PcsAttr::AAPCS ? CC_AAPCS : CC_AAPCS_VFP); + if (D->hasAttr<PnaclCallAttr>()) + return CC_PnaclCall; + return CC_C; } @@ -588,9 +591,9 @@ EnterStructPointerForCoercedAccess(llvm::Value *SrcPtr, // If the first elt is at least as large as what we're looking for, or if the // first element is the same size as the whole struct, we can enter it. uint64_t FirstEltSize = - CGF.CGM.getTargetData().getTypeAllocSize(FirstElt); + CGF.CGM.getDataLayout().getTypeAllocSize(FirstElt); if (FirstEltSize < DstSize && - FirstEltSize < CGF.CGM.getTargetData().getTypeAllocSize(SrcSTy)) + FirstEltSize < CGF.CGM.getDataLayout().getTypeAllocSize(SrcSTy)) return SrcPtr; // GEP into the first element. @@ -653,14 +656,14 @@ static llvm::Value *CreateCoercedLoad(llvm::Value *SrcPtr, if (SrcTy == Ty) return CGF.Builder.CreateLoad(SrcPtr); - uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(Ty); + uint64_t DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(Ty); if (llvm::StructType *SrcSTy = dyn_cast<llvm::StructType>(SrcTy)) { SrcPtr = EnterStructPointerForCoercedAccess(SrcPtr, SrcSTy, DstSize, CGF); SrcTy = cast<llvm::PointerType>(SrcPtr->getType())->getElementType(); } - uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy); + uint64_t SrcSize = CGF.CGM.getDataLayout().getTypeAllocSize(SrcTy); // If the source and destination are integer or pointer types, just do an // extension or truncation to the desired type. @@ -740,7 +743,7 @@ static void CreateCoercedStore(llvm::Value *Src, return; } - uint64_t SrcSize = CGF.CGM.getTargetData().getTypeAllocSize(SrcTy); + uint64_t SrcSize = CGF.CGM.getDataLayout().getTypeAllocSize(SrcTy); if (llvm::StructType *DstSTy = dyn_cast<llvm::StructType>(DstTy)) { DstPtr = EnterStructPointerForCoercedAccess(DstPtr, DstSTy, SrcSize, CGF); @@ -756,7 +759,7 @@ static void CreateCoercedStore(llvm::Value *Src, return; } - uint64_t DstSize = CGF.CGM.getTargetData().getTypeAllocSize(DstTy); + uint64_t DstSize = CGF.CGM.getDataLayout().getTypeAllocSize(DstTy); // If store is legal, just bitcast the src pointer. if (SrcSize <= DstSize) { @@ -864,6 +867,10 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) { ie = FI.arg_end(); it != ie; ++it) { const ABIArgInfo &argAI = it->info; + // Insert a padding type to ensure proper alignment. + if (llvm::Type *PaddingType = argAI.getPaddingType()) + argTypes.push_back(PaddingType); + switch (argAI.getKind()) { case ABIArgInfo::Ignore: break; @@ -877,9 +884,6 @@ CodeGenTypes::GetFunctionType(const CGFunctionInfo &FI) { case ABIArgInfo::Extend: case ABIArgInfo::Direct: { - // Insert a padding type to ensure proper alignment. - if (llvm::Type *PaddingType = argAI.getPaddingType()) - argTypes.push_back(PaddingType); // If the coerce-to type is a first class aggregate, flatten it. Either // way is semantically identical, but fast-isel and the optimizer // generally likes scalar values better than FCAs. @@ -924,50 +928,52 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, const Decl *TargetDecl, AttributeListType &PAL, unsigned &CallingConv) { - llvm::Attributes FuncAttrs; - llvm::Attributes RetAttrs; + llvm::AttrBuilder FuncAttrs; + llvm::AttrBuilder RetAttrs; CallingConv = FI.getEffectiveCallingConvention(); if (FI.isNoReturn()) - FuncAttrs |= llvm::Attribute::NoReturn; + FuncAttrs.addAttribute(llvm::Attributes::NoReturn); // FIXME: handle sseregparm someday... if (TargetDecl) { if (TargetDecl->hasAttr<ReturnsTwiceAttr>()) - FuncAttrs |= llvm::Attribute::ReturnsTwice; + FuncAttrs.addAttribute(llvm::Attributes::ReturnsTwice); if (TargetDecl->hasAttr<NoThrowAttr>()) - FuncAttrs |= llvm::Attribute::NoUnwind; + FuncAttrs.addAttribute(llvm::Attributes::NoUnwind); else if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) { const FunctionProtoType *FPT = Fn->getType()->getAs<FunctionProtoType>(); if (FPT && FPT->isNothrow(getContext())) - FuncAttrs |= llvm::Attribute::NoUnwind; + FuncAttrs.addAttribute(llvm::Attributes::NoUnwind); } if (TargetDecl->hasAttr<NoReturnAttr>()) - FuncAttrs |= llvm::Attribute::NoReturn; + FuncAttrs.addAttribute(llvm::Attributes::NoReturn); if (TargetDecl->hasAttr<ReturnsTwiceAttr>()) - FuncAttrs |= llvm::Attribute::ReturnsTwice; + FuncAttrs.addAttribute(llvm::Attributes::ReturnsTwice); // 'const' and 'pure' attribute functions are also nounwind. if (TargetDecl->hasAttr<ConstAttr>()) { - FuncAttrs |= llvm::Attribute::ReadNone; - FuncAttrs |= llvm::Attribute::NoUnwind; + FuncAttrs.addAttribute(llvm::Attributes::ReadNone); + FuncAttrs.addAttribute(llvm::Attributes::NoUnwind); } else if (TargetDecl->hasAttr<PureAttr>()) { - FuncAttrs |= llvm::Attribute::ReadOnly; - FuncAttrs |= llvm::Attribute::NoUnwind; + FuncAttrs.addAttribute(llvm::Attributes::ReadOnly); + FuncAttrs.addAttribute(llvm::Attributes::NoUnwind); } if (TargetDecl->hasAttr<MallocAttr>()) - RetAttrs |= llvm::Attribute::NoAlias; + RetAttrs.addAttribute(llvm::Attributes::NoAlias); } if (CodeGenOpts.OptimizeSize) - FuncAttrs |= llvm::Attribute::OptimizeForSize; + FuncAttrs.addAttribute(llvm::Attributes::OptimizeForSize); + if (CodeGenOpts.OptimizeSize == 2) + FuncAttrs.addAttribute(llvm::Attributes::MinSize); if (CodeGenOpts.DisableRedZone) - FuncAttrs |= llvm::Attribute::NoRedZone; + FuncAttrs.addAttribute(llvm::Attributes::NoRedZone); if (CodeGenOpts.NoImplicitFloat) - FuncAttrs |= llvm::Attribute::NoImplicitFloat; + FuncAttrs.addAttribute(llvm::Attributes::NoImplicitFloat); QualType RetTy = FI.getReturnType(); unsigned Index = 1; @@ -975,24 +981,28 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, switch (RetAI.getKind()) { case ABIArgInfo::Extend: if (RetTy->hasSignedIntegerRepresentation()) - RetAttrs |= llvm::Attribute::SExt; + RetAttrs.addAttribute(llvm::Attributes::SExt); else if (RetTy->hasUnsignedIntegerRepresentation()) - RetAttrs |= llvm::Attribute::ZExt; + RetAttrs.addAttribute(llvm::Attributes::ZExt); break; case ABIArgInfo::Direct: case ABIArgInfo::Ignore: break; case ABIArgInfo::Indirect: { - llvm::Attributes SRETAttrs = llvm::Attribute::StructRet; + llvm::AttrBuilder SRETAttrs; + SRETAttrs.addAttribute(llvm::Attributes::StructRet); if (RetAI.getInReg()) - SRETAttrs |= llvm::Attribute::InReg; - PAL.push_back(llvm::AttributeWithIndex::get(Index, SRETAttrs)); + SRETAttrs.addAttribute(llvm::Attributes::InReg); + PAL.push_back(llvm:: + AttributeWithIndex::get(Index, + llvm::Attributes::get(getLLVMContext(), + SRETAttrs))); ++Index; // sret disables readnone and readonly - FuncAttrs &= ~(llvm::Attribute::ReadOnly | - llvm::Attribute::ReadNone); + FuncAttrs.removeAttribute(llvm::Attributes::ReadOnly) + .removeAttribute(llvm::Attributes::ReadNone); break; } @@ -1000,14 +1010,29 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, llvm_unreachable("Invalid ABI kind for return argument"); } - if (RetAttrs) - PAL.push_back(llvm::AttributeWithIndex::get(0, RetAttrs)); + if (RetAttrs.hasAttributes()) + PAL.push_back(llvm:: + AttributeWithIndex::get(llvm::AttrListPtr::ReturnIndex, + llvm::Attributes::get(getLLVMContext(), + RetAttrs))); for (CGFunctionInfo::const_arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) { QualType ParamType = it->type; const ABIArgInfo &AI = it->info; - llvm::Attributes Attrs; + llvm::AttrBuilder Attrs; + + if (AI.getPaddingType()) { + if (AI.getPaddingInReg()) { + llvm::AttrBuilder PadAttrs; + PadAttrs.addAttribute(llvm::Attributes::InReg); + + llvm::Attributes A =llvm::Attributes::get(getLLVMContext(), PadAttrs); + PAL.push_back(llvm::AttributeWithIndex::get(Index, A)); + } + // Increment Index if there is padding. + ++Index; + } // 'restrict' -> 'noalias' is done in EmitFunctionProlog when we // have the corresponding parameter variable. It doesn't make @@ -1015,38 +1040,40 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, switch (AI.getKind()) { case ABIArgInfo::Extend: if (ParamType->isSignedIntegerOrEnumerationType()) - Attrs |= llvm::Attribute::SExt; + Attrs.addAttribute(llvm::Attributes::SExt); else if (ParamType->isUnsignedIntegerOrEnumerationType()) - Attrs |= llvm::Attribute::ZExt; + Attrs.addAttribute(llvm::Attributes::ZExt); // FALL THROUGH case ABIArgInfo::Direct: if (AI.getInReg()) - Attrs |= llvm::Attribute::InReg; + Attrs.addAttribute(llvm::Attributes::InReg); // FIXME: handle sseregparm someday... - // Increment Index if there is padding. - Index += (AI.getPaddingType() != 0); - if (llvm::StructType *STy = dyn_cast<llvm::StructType>(AI.getCoerceToType())) { unsigned Extra = STy->getNumElements()-1; // 1 will be added below. - if (Attrs != llvm::Attribute::None) + if (Attrs.hasAttributes()) for (unsigned I = 0; I < Extra; ++I) - PAL.push_back(llvm::AttributeWithIndex::get(Index + I, Attrs)); + PAL.push_back(llvm::AttributeWithIndex::get(Index + I, + llvm::Attributes::get(getLLVMContext(), + Attrs))); Index += Extra; } break; case ABIArgInfo::Indirect: + if (AI.getInReg()) + Attrs.addAttribute(llvm::Attributes::InReg); + if (AI.getIndirectByVal()) - Attrs |= llvm::Attribute::ByVal; + Attrs.addAttribute(llvm::Attributes::ByVal); + + Attrs.addAlignmentAttr(AI.getIndirectAlign()); - Attrs |= - llvm::Attribute::constructAlignmentFromInt(AI.getIndirectAlign()); // byval disables readnone and readonly. - FuncAttrs &= ~(llvm::Attribute::ReadOnly | - llvm::Attribute::ReadNone); + FuncAttrs.removeAttribute(llvm::Attributes::ReadOnly) + .removeAttribute(llvm::Attributes::ReadNone); break; case ABIArgInfo::Ignore: @@ -1064,12 +1091,17 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, } } - if (Attrs) - PAL.push_back(llvm::AttributeWithIndex::get(Index, Attrs)); + if (Attrs.hasAttributes()) + PAL.push_back(llvm::AttributeWithIndex::get(Index, + llvm::Attributes::get(getLLVMContext(), + Attrs))); ++Index; } - if (FuncAttrs) - PAL.push_back(llvm::AttributeWithIndex::get(~0, FuncAttrs)); + if (FuncAttrs.hasAttributes()) + PAL.push_back(llvm:: + AttributeWithIndex::get(llvm::AttrListPtr::FunctionIndex, + llvm::Attributes::get(getLLVMContext(), + FuncAttrs))); } /// An argument came in as a promoted argument; demote it back to its @@ -1117,7 +1149,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // Name the struct return argument. if (CGM.ReturnTypeUsesSRet(FI)) { AI->setName("agg.result"); - AI->addAttr(llvm::Attribute::NoAlias); + AI->addAttr(llvm::Attributes::get(getLLVMContext(), + llvm::Attributes::NoAlias)); ++AI; } @@ -1134,6 +1167,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, bool isPromoted = isa<ParmVarDecl>(Arg) && cast<ParmVarDecl>(Arg)->isKNRPromoted(); + // Skip the dummy padding argument. + if (ArgI.getPaddingType()) + ++AI; + switch (ArgI.getKind()) { case ABIArgInfo::Indirect: { llvm::Value *V = AI; @@ -1175,9 +1212,6 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, case ABIArgInfo::Extend: case ABIArgInfo::Direct: { - // Skip the dummy padding argument. - if (ArgI.getPaddingType()) - ++AI; // If we have the trivial case, handle it with no muss and fuss. if (!isa<llvm::StructType>(ArgI.getCoerceToType()) && @@ -1187,7 +1221,8 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, llvm::Value *V = AI; if (Arg->getType().isRestrictQualified()) - AI->addAttr(llvm::Attribute::NoAlias); + AI->addAttr(llvm::Attributes::get(getLLVMContext(), + llvm::Attributes::NoAlias)); // Ensure the argument is the correct type. if (V->getType() != ArgI.getCoerceToType()) @@ -1205,7 +1240,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // The alignment we need to use is the max of the requested alignment for // the argument plus the alignment required by our access code below. unsigned AlignmentToUse = - CGM.getTargetData().getABITypeAlignment(ArgI.getCoerceToType()); + CGM.getDataLayout().getABITypeAlignment(ArgI.getCoerceToType()); AlignmentToUse = std::max(AlignmentToUse, (unsigned)getContext().getDeclAlign(Arg).getQuantity()); @@ -1226,10 +1261,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, // and the optimizer generally likes scalar values better than FCAs. llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgI.getCoerceToType()); if (STy && STy->getNumElements() > 1) { - uint64_t SrcSize = CGM.getTargetData().getTypeAllocSize(STy); + uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(STy); llvm::Type *DstTy = cast<llvm::PointerType>(Ptr->getType())->getElementType(); - uint64_t DstSize = CGM.getTargetData().getTypeAllocSize(DstTy); + uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(DstTy); if (SrcSize <= DstSize) { Ptr = Builder.CreateBitCast(Ptr, llvm::PointerType::getUnqual(STy)); @@ -1363,12 +1398,23 @@ static llvm::Value *tryEmitFusedAutoreleaseOfResult(CodeGenFunction &CGF, .objc_retainAutoreleasedReturnValue) { doRetainAutorelease = false; - // Look for an inline asm immediately preceding the call and kill it, too. - llvm::Instruction *prev = call->getPrevNode(); - if (llvm::CallInst *asmCall = dyn_cast_or_null<llvm::CallInst>(prev)) - if (asmCall->getCalledValue() - == CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker) - insnsToKill.push_back(prev); + // If we emitted an assembly marker for this call (and the + // ARCEntrypoints field should have been set if so), go looking + // for that call. If we can't find it, we can't do this + // optimization. But it should always be the immediately previous + // instruction, unless we needed bitcasts around the call. + if (CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker) { + llvm::Instruction *prev = call->getPrevNode(); + assert(prev); + if (isa<llvm::BitCastInst>(prev)) { + prev = prev->getPrevNode(); + assert(prev); + } + assert(isa<llvm::CallInst>(prev)); + assert(cast<llvm::CallInst>(prev)->getCalledValue() == + CGF.CGM.getARCEntrypoints().retainAutoreleasedReturnValueMarker); + insnsToKill.push_back(prev); + } } else { return 0; } @@ -1755,7 +1801,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, QualType type) { if (const ObjCIndirectCopyRestoreExpr *CRE = dyn_cast<ObjCIndirectCopyRestoreExpr>(E)) { - assert(getContext().getLangOpts().ObjCAutoRefCount); + assert(getLangOpts().ObjCAutoRefCount); assert(getContext().hasSameType(E->getType(), type)); return emitWritebackArg(*this, args, CRE); } @@ -1943,6 +1989,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, unsigned TypeAlign = getContext().getTypeAlignInChars(I->Ty).getQuantity(); + + // Insert a padding argument to ensure proper alignment. + if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) { + Args.push_back(llvm::UndefValue::get(PaddingType)); + ++IRArgNo; + } + switch (ArgInfo.getKind()) { case ABIArgInfo::Indirect: { if (RV.isScalar() || RV.isComplex()) { @@ -1969,7 +2022,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // we cannot force it to be sufficiently aligned. llvm::Value *Addr = RV.getAggregateAddr(); unsigned Align = ArgInfo.getIndirectAlign(); - const llvm::TargetData *TD = &CGM.getTargetData(); + const llvm::DataLayout *TD = &CGM.getDataLayout(); if ((!ArgInfo.getIndirectByVal() && I->NeedsCopy) || (ArgInfo.getIndirectByVal() && TypeAlign < Align && llvm::getOrEnforceKnownAlignment(Addr, Align, TD) < Align)) { @@ -1998,12 +2051,6 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, case ABIArgInfo::Extend: case ABIArgInfo::Direct: { - // Insert a padding argument to ensure proper alignment. - if (llvm::Type *PaddingType = ArgInfo.getPaddingType()) { - Args.push_back(llvm::UndefValue::get(PaddingType)); - ++IRArgNo; - } - if (!isa<llvm::StructType>(ArgInfo.getCoerceToType()) && ArgInfo.getCoerceToType() == ConvertType(info_it->type) && ArgInfo.getDirectOffset() == 0) { @@ -2049,8 +2096,25 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // and the optimizer generally likes scalar values better than FCAs. if (llvm::StructType *STy = dyn_cast<llvm::StructType>(ArgInfo.getCoerceToType())) { - SrcPtr = Builder.CreateBitCast(SrcPtr, - llvm::PointerType::getUnqual(STy)); + llvm::Type *SrcTy = + cast<llvm::PointerType>(SrcPtr->getType())->getElementType(); + uint64_t SrcSize = CGM.getDataLayout().getTypeAllocSize(SrcTy); + uint64_t DstSize = CGM.getDataLayout().getTypeAllocSize(STy); + + // If the source type is smaller than the destination type of the + // coerce-to logic, copy the source value into a temp alloca the size + // of the destination type to allow loading all of it. The bits past + // the source value are left undef. + if (SrcSize < DstSize) { + llvm::AllocaInst *TempAlloca + = CreateTempAlloca(STy, SrcPtr->getName() + ".coerce"); + Builder.CreateMemCpy(TempAlloca, SrcPtr, SrcSize, 0); + SrcPtr = TempAlloca; + } else { + SrcPtr = Builder.CreateBitCast(SrcPtr, + llvm::PointerType::getUnqual(STy)); + } + for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { llvm::Value *EltPtr = Builder.CreateConstGEP2_32(SrcPtr, 0, i); llvm::LoadInst *LI = Builder.CreateLoad(EltPtr); @@ -2113,10 +2177,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, unsigned CallingConv; CodeGen::AttributeListType AttributeList; CGM.ConstructAttributeList(CallInfo, TargetDecl, AttributeList, CallingConv); - llvm::AttrListPtr Attrs = llvm::AttrListPtr::get(AttributeList); + llvm::AttrListPtr Attrs = llvm::AttrListPtr::get(getLLVMContext(), + AttributeList); llvm::BasicBlock *InvokeDest = 0; - if (!(Attrs.getFnAttributes() & llvm::Attribute::NoUnwind)) + if (!Attrs.getFnAttributes().hasAttribute(llvm::Attributes::NoUnwind)) InvokeDest = getInvokeDest(); llvm::CallSite CS; diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index e37fa3ab72b7..b2225e48e361 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -542,12 +542,6 @@ namespace { }; } -static bool hasTrivialCopyOrMoveConstructor(const CXXRecordDecl *Record, - bool Moving) { - return Moving ? Record->hasTrivialMoveConstructor() : - Record->hasTrivialCopyConstructor(); -} - static void EmitMemberInitializer(CodeGenFunction &CGF, const CXXRecordDecl *ClassDecl, CXXCtorInitializer *MemberInit, @@ -588,12 +582,11 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, if (Array && Constructor->isImplicitlyDefined() && Constructor->isCopyOrMoveConstructor()) { QualType BaseElementTy = CGF.getContext().getBaseElementType(Array); - const CXXRecordDecl *Record = BaseElementTy->getAsCXXRecordDecl(); + CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(MemberInit->getInit()); if (BaseElementTy.isPODType(CGF.getContext()) || - (Record && hasTrivialCopyOrMoveConstructor(Record, - Constructor->isMoveConstructor()))) { - // Find the source pointer. We knows it's the last argument because - // we know we're in a copy constructor. + (CE && CE->getConstructor()->isTrivial())) { + // Find the source pointer. We know it's the last argument because + // we know we're in an implicit copy constructor. unsigned SrcArgIndex = Args.size() - 1; llvm::Value *SrcPtr = CGF.Builder.CreateLoad(CGF.GetAddrOfLocalVar(Args[SrcArgIndex])); @@ -952,8 +945,8 @@ void CodeGenFunction::EmitDestructorBody(FunctionArgList &Args) { } // -fapple-kext must inline any call to this dtor into // the caller's body. - if (getContext().getLangOpts().AppleKext) - CurFn->addFnAttr(llvm::Attribute::AlwaysInline); + if (getLangOpts().AppleKext) + CurFn->addFnAttr(llvm::Attributes::AlwaysInline); break; } @@ -1238,7 +1231,7 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, CGDebugInfo *DI = getDebugInfo(); if (DI && - CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo) { + CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo) { // If debug info for this class has not been emitted then this is the // right time to do so. const CXXRecordDecl *Parent = D->getParent(); @@ -1268,7 +1261,9 @@ CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(D, Type), ForVirtualBase); llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, Type); - EmitCXXMemberCall(D, Callee, ReturnValueSlot(), This, VTT, ArgBeg, ArgEnd); + // FIXME: Provide a source location here. + EmitCXXMemberCall(D, SourceLocation(), Callee, ReturnValueSlot(), This, + VTT, ArgBeg, ArgEnd); } void @@ -1413,14 +1408,16 @@ void CodeGenFunction::EmitCXXDestructorCall(const CXXDestructorDecl *DD, llvm::Value *VTT = GetVTTParameter(*this, GlobalDecl(DD, Type), ForVirtualBase); llvm::Value *Callee = 0; - if (getContext().getLangOpts().AppleKext) + if (getLangOpts().AppleKext) Callee = BuildAppleKextVirtualDestructorCall(DD, Type, DD->getParent()); if (!Callee) Callee = CGM.GetAddrOfCXXDestructor(DD, Type); - EmitCXXMemberCall(DD, Callee, ReturnValueSlot(), This, VTT, 0, 0); + // FIXME: Provide a source location here. + EmitCXXMemberCall(DD, SourceLocation(), Callee, ReturnValueSlot(), This, + VTT, 0, 0); } namespace { diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index fd1c7a339807..80fa09be7473 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -15,6 +15,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "CGBlocks.h" +#include "CGObjCRuntime.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" @@ -34,7 +35,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Dwarf.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" using namespace clang; using namespace clang::CodeGen; @@ -157,7 +158,7 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { OS << OID->getName(); } else if (const ObjCCategoryImplDecl *OCD = dyn_cast<const ObjCCategoryImplDecl>(DC)){ - OS << ((NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' << + OS << ((const NamedDecl *)OCD)->getIdentifier()->getNameStart() << '(' << OCD->getIdentifier()->getNameStart() << ')'; } OS << ' ' << OMD->getSelector().getAsString() << ']'; @@ -254,9 +255,13 @@ unsigned CGDebugInfo::getLineNumber(SourceLocation Loc) { return PLoc.isValid()? PLoc.getLine() : 0; } -/// getColumnNumber - Get column number for the location. If location is -/// invalid then use current location. +/// getColumnNumber - Get column number for the location. unsigned CGDebugInfo::getColumnNumber(SourceLocation Loc) { + // We may not want column information at all. + if (!CGM.getCodeGenOpts().DebugColumnInfo) + return 0; + + // If the location is invalid then use the current column. if (Loc.isInvalid() && CurLoc.isInvalid()) return 0; SourceManager &SM = CGM.getContext().getSourceManager(); @@ -347,44 +352,60 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) { llvm_unreachable("Unexpected builtin type"); case BuiltinType::NullPtr: return DBuilder. - createNullPtrType(BT->getName(CGM.getContext().getLangOpts())); + createNullPtrType(BT->getName(CGM.getLangOpts())); case BuiltinType::Void: return llvm::DIType(); case BuiltinType::ObjCClass: - return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, - "objc_class", TheCU, - getOrCreateMainFile(), 0); + if (ClassTy.Verify()) + return ClassTy; + ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, + "objc_class", TheCU, + getOrCreateMainFile(), 0); + return ClassTy; case BuiltinType::ObjCId: { // typedef struct objc_class *Class; // typedef struct objc_object { // Class isa; // } *id; - // TODO: Cache these two types to avoid duplicates. - llvm::DIType OCTy = - DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, - "objc_class", TheCU, getOrCreateMainFile(), 0); + if (ObjTy.Verify()) + return ObjTy; + + if (!ClassTy.Verify()) + ClassTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, + "objc_class", TheCU, + getOrCreateMainFile(), 0); + unsigned Size = CGM.getContext().getTypeSize(CGM.getContext().VoidPtrTy); - llvm::DIType ISATy = DBuilder.createPointerType(OCTy, Size); + llvm::DIType ISATy = DBuilder.createPointerType(ClassTy, Size); + + llvm::DIType FwdTy = DBuilder.createStructType(TheCU, "objc_object", + getOrCreateMainFile(), + 0, 0, 0, 0, + llvm::DIArray()); - SmallVector<llvm::Value *, 16> EltTys; + llvm::TrackingVH<llvm::MDNode> ObjNode(FwdTy); + SmallVector<llvm::Value *, 1> EltTys; llvm::DIType FieldTy = - DBuilder.createMemberType(getOrCreateMainFile(), "isa", + DBuilder.createMemberType(llvm::DIDescriptor(ObjNode), "isa", getOrCreateMainFile(), 0, Size, 0, 0, 0, ISATy); EltTys.push_back(FieldTy); llvm::DIArray Elements = DBuilder.getOrCreateArray(EltTys); - - return DBuilder.createStructType(TheCU, "objc_object", - getOrCreateMainFile(), - 0, 0, 0, 0, Elements); + + ObjNode->replaceOperandWith(10, Elements); + ObjTy = llvm::DIType(ObjNode); + return ObjTy; } case BuiltinType::ObjCSel: { - return + if (SelTy.Verify()) + return SelTy; + SelTy = DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_structure_type, "objc_selector", TheCU, getOrCreateMainFile(), 0); + return SelTy; } case BuiltinType::UChar: case BuiltinType::Char_U: Encoding = llvm::dwarf::DW_ATE_unsigned_char; break; @@ -417,7 +438,7 @@ llvm::DIType CGDebugInfo::CreateType(const BuiltinType *BT) { case BuiltinType::ULong: BTName = "long unsigned int"; break; case BuiltinType::ULongLong: BTName = "long long unsigned int"; break; default: - BTName = BT->getName(CGM.getContext().getLangOpts()); + BTName = BT->getName(CGM.getLangOpts()); break; } // Bit size, align and offset of the type. @@ -498,21 +519,17 @@ llvm::DIType CGDebugInfo::createRecordFwdDecl(const RecordDecl *RD, llvm::DIDescriptor Ctx) { llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation()); unsigned Line = getLineNumber(RD->getLocation()); - StringRef RDName = RD->getName(); + StringRef RDName = getClassName(RD); - // Get the tag. - const CXXRecordDecl *CXXDecl = dyn_cast<CXXRecordDecl>(RD); unsigned Tag = 0; - if (CXXDecl) { - RDName = getClassName(RD); - Tag = llvm::dwarf::DW_TAG_class_type; - } - else if (RD->isStruct()) + if (RD->isStruct() || RD->isInterface()) Tag = llvm::dwarf::DW_TAG_structure_type; else if (RD->isUnion()) Tag = llvm::dwarf::DW_TAG_union_type; - else - llvm_unreachable("Unknown RecordDecl type!"); + else { + assert(RD->isClass()); + Tag = llvm::dwarf::DW_TAG_class_type; + } // Create the type. return DBuilder.createForwardDecl(Tag, RDName, Ctx, DefUnit, Line); @@ -550,7 +567,7 @@ llvm::DIDescriptor CGDebugInfo::createContextChain(const Decl *Context) { /// then emit record's fwd if debug info size reduction is enabled. llvm::DIType CGDebugInfo::CreatePointeeType(QualType PointeeTy, llvm::DIFile Unit) { - if (CGM.getCodeGenOpts().DebugInfo != CodeGenOptions::LimitedDebugInfo) + if (CGM.getCodeGenOpts().getDebugInfo() != CodeGenOptions::LimitedDebugInfo) return getOrCreateType(PointeeTy, Unit); // Limit debug info for the pointee type. @@ -777,8 +794,6 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit, for (CXXRecordDecl::capture_const_iterator I = CXXDecl->captures_begin(), E = CXXDecl->captures_end(); I != E; ++I, ++Field, ++fieldno) { const LambdaExpr::Capture C = *I; - // TODO: Need to handle 'this' in some way by probably renaming the - // this of the lambda class and having a field member of 'this'. if (C.capturesVariable()) { VarDecl *V = C.getCapturedVar(); llvm::DIFile VUnit = getOrCreateFile(C.getLocation()); @@ -793,10 +808,24 @@ CollectRecordFields(const RecordDecl *record, llvm::DIFile tunit, Field->getAccess(), layout.getFieldOffset(fieldno), VUnit, RecordTy); elements.push_back(fieldType); + } else { + // TODO: Need to handle 'this' in some way by probably renaming the + // this of the lambda class and having a field member of 'this' or + // by using AT_object_pointer for the function and having that be + // used as 'this' for semantic references. + assert(C.capturesThis() && "Field that isn't captured and isn't this?"); + FieldDecl *f = *Field; + llvm::DIFile VUnit = getOrCreateFile(f->getLocation()); + QualType type = f->getType(); + llvm::DIType fieldType + = createFieldType("this", type, 0, f->getLocation(), f->getAccess(), + layout.getFieldOffset(fieldNo), VUnit, RecordTy); + + elements.push_back(fieldType); } } } else { - bool IsMsStruct = record->hasAttr<MsStructAttr>(); + bool IsMsStruct = record->isMsStruct(CGM.getContext()); const FieldDecl *LastFD = 0; for (RecordDecl::field_iterator I = record->field_begin(), E = record->field_end(); @@ -875,12 +904,12 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, // TODO: This and the artificial type below are misleading, the // types aren't artificial the argument is, but the current // metadata doesn't represent that. - ThisPtrType = DBuilder.createArtificialType(ThisPtrType); + ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); Elts.push_back(ThisPtrType); } else { llvm::DIType ThisPtrType = getOrCreateType(ThisPtr, Unit); TypeCache[ThisPtr.getAsOpaquePtr()] = ThisPtrType; - ThisPtrType = DBuilder.createArtificialType(ThisPtrType); + ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); Elts.push_back(ThisPtrType); } } @@ -995,12 +1024,8 @@ CollectCXXMemberFunctions(const CXXRecordDecl *RD, llvm::DIFile Unit, if (D->isImplicit() && !D->isUsed()) continue; - if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { - // Only emit debug information for user provided functions, we're - // unlikely to want info for artificial functions. - if (Method->isUserProvided()) - EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy)); - } + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) + EltTys.push_back(CreateCXXMemberFunction(Method, Unit, RecordTy)); else if (FunctionTemplateDecl *FTD = dyn_cast<FunctionTemplateDecl>(D)) for (FunctionTemplateDecl::spec_iterator SI = FTD->spec_begin(), SE = FTD->spec_end(); SI != SE; ++SI) @@ -1182,7 +1207,7 @@ CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile Unit, /// getOrCreateRecordType - Emit record type's standalone debug info. llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy, SourceLocation Loc) { - assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); llvm::DIType T = getOrCreateType(RTy, getOrCreateFile(Loc)); return T; } @@ -1191,7 +1216,7 @@ llvm::DIType CGDebugInfo::getOrCreateRecordType(QualType RTy, /// debug info. llvm::DIType CGDebugInfo::getOrCreateInterfaceType(QualType D, SourceLocation Loc) { - assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); llvm::DIType T = getOrCreateType(D, getOrCreateFile(Loc)); DBuilder.retainType(T); return T; @@ -1388,12 +1413,21 @@ llvm::DIType CGDebugInfo::CreateType(const ObjCInterfaceType *Ty, FieldAlign = CGM.getContext().getTypeAlign(FType); } - // We can't know the offset of our ivar in the structure if we're using - // the non-fragile abi and the debugger should ignore the value anyways. - // Call it the FieldNo+1 due to how debuggers use the information, - // e.g. negating the value when it needs a lookup in the dynamic table. - uint64_t FieldOffset = CGM.getLangOpts().ObjCRuntime.isNonFragile() - ? FieldNo+1 : RL.getFieldOffset(FieldNo); + uint64_t FieldOffset; + if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { + // We don't know the runtime offset of an ivar if we're using the + // non-fragile ABI. For bitfields, use the bit offset into the first + // byte of storage of the bitfield. For other fields, use zero. + if (Field->isBitField()) { + FieldOffset = CGM.getObjCRuntime().ComputeBitfieldBitOffset( + CGM, ID, Field); + FieldOffset %= CGM.getContext().getCharWidth(); + } else { + FieldOffset = 0; + } + } else { + FieldOffset = RL.getFieldOffset(FieldNo); + } unsigned Flags = 0; if (Field->getAccessControl() == ObjCIvarDecl::Protected) @@ -1570,9 +1604,29 @@ llvm::DIType CGDebugInfo::CreateType(const AtomicType *Ty, /// CreateEnumType - get enumeration type. llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) { - SmallVector<llvm::Value *, 16> Enumerators; + uint64_t Size = 0; + uint64_t Align = 0; + if (!ED->getTypeForDecl()->isIncompleteType()) { + Size = CGM.getContext().getTypeSize(ED->getTypeForDecl()); + Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl()); + } + + // If this is just a forward declaration, construct an appropriately + // marked node and just return it. + if (!ED->getDefinition()) { + llvm::DIDescriptor EDContext; + EDContext = getContextDescriptor(cast<Decl>(ED->getDeclContext())); + llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation()); + unsigned Line = getLineNumber(ED->getLocation()); + StringRef EDName = ED->getName(); + return DBuilder.createForwardDecl(llvm::dwarf::DW_TAG_enumeration_type, + EDName, EDContext, DefUnit, Line, 0, + Size, Align); + } // Create DIEnumerator elements for each enumerator. + SmallVector<llvm::Value *, 16> Enumerators; + ED = ED->getDefinition(); for (EnumDecl::enumerator_iterator Enum = ED->enumerator_begin(), EnumEnd = ED->enumerator_end(); Enum != EnumEnd; ++Enum) { @@ -1586,21 +1640,14 @@ llvm::DIType CGDebugInfo::CreateEnumType(const EnumDecl *ED) { llvm::DIFile DefUnit = getOrCreateFile(ED->getLocation()); unsigned Line = getLineNumber(ED->getLocation()); - uint64_t Size = 0; - uint64_t Align = 0; - if (!ED->getTypeForDecl()->isIncompleteType()) { - Size = CGM.getContext().getTypeSize(ED->getTypeForDecl()); - Align = CGM.getContext().getTypeAlign(ED->getTypeForDecl()); - } llvm::DIDescriptor EnumContext = getContextDescriptor(cast<Decl>(ED->getDeclContext())); llvm::DIType ClassTy = ED->isScopedUsingClassTag() ? getOrCreateType(ED->getIntegerType(), DefUnit) : llvm::DIType(); - unsigned Flags = !ED->isCompleteDefinition() ? llvm::DIDescriptor::FlagFwdDecl : 0; llvm::DIType DbgTy = DBuilder.createEnumerationType(EnumContext, ED->getName(), DefUnit, Line, Size, Align, EltArray, - ClassTy, Flags); + ClassTy); return DbgTy; } @@ -1838,10 +1885,10 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) { // Get overall information about the record type for the debug info. llvm::DIFile DefUnit = getOrCreateFile(RD->getLocation()); unsigned Line = getLineNumber(RD->getLocation()); - StringRef RDName = RD->getName(); + StringRef RDName = getClassName(RD); llvm::DIDescriptor RDContext; - if (CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo) + if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo) RDContext = createContextChain(cast<Decl>(RD->getDeclContext())); else RDContext = getContextDescriptor(cast<Decl>(RD->getDeclContext())); @@ -1859,9 +1906,7 @@ llvm::DIType CGDebugInfo::CreateLimitedType(const RecordType *Ty) { if (RD->isUnion()) RealDecl = DBuilder.createUnionType(RDContext, RDName, DefUnit, Line, Size, Align, 0, llvm::DIArray()); - else if (CXXDecl) { - RDName = getClassName(RD); - + else if (RD->isClass()) { // FIXME: This could be a struct type giving a default visibility different // than C++ class type, but needs llvm metadata changes first. RealDecl = DBuilder.createClassType(RDContext, RDName, DefUnit, Line, @@ -1969,7 +2014,7 @@ llvm::DISubprogram CGDebugInfo::getFunctionDeclaration(const Decl *D) { // getOrCreateFunctionType - Construct DIType. If it is a c++ method, include // implicit parameter "this". -llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D, +llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl *D, QualType FnType, llvm::DIFile F) { @@ -1982,9 +2027,11 @@ llvm::DIType CGDebugInfo::getOrCreateFunctionType(const Decl * D, // First element is always return type. For 'void' functions it is NULL. Elts.push_back(getOrCreateType(OMethod->getResultType(), F)); // "self" pointer is always first argument. - Elts.push_back(getOrCreateType(OMethod->getSelfDecl()->getType(), F)); - // "cmd" pointer is always second argument. - Elts.push_back(getOrCreateType(OMethod->getCmdDecl()->getType(), F)); + llvm::DIType SelfTy = getOrCreateType(OMethod->getSelfDecl()->getType(), F); + Elts.push_back(DBuilder.createObjectPointerType(SelfTy)); + // "_cmd" pointer is always second argument. + llvm::DIType CmdTy = getOrCreateType(OMethod->getCmdDecl()->getType(), F); + Elts.push_back(DBuilder.createArtificialType(CmdTy)); // Get rest of the arguments. for (ObjCMethodDecl::param_const_iterator PI = OMethod->param_begin(), PE = OMethod->param_end(); PI != PE; ++PI) @@ -2007,14 +2054,22 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, FnBeginRegionCount.push_back(LexicalBlockStack.size()); const Decl *D = GD.getDecl(); + // Function may lack declaration in source code if it is created by Clang + // CodeGen (examples: _GLOBAL__I_a, __cxx_global_array_dtor, thunk). + bool HasDecl = (D != 0); // Use the location of the declaration. - SourceLocation Loc = D->getLocation(); - + SourceLocation Loc; + if (HasDecl) + Loc = D->getLocation(); + unsigned Flags = 0; llvm::DIFile Unit = getOrCreateFile(Loc); llvm::DIDescriptor FDContext(Unit); llvm::DIArray TParamsArray; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (!HasDecl) { + // Use llvm function name. + Name = Fn->getName(); + } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // If there is a DISubprogram for this function available then use it. llvm::DenseMap<const FunctionDecl *, llvm::WeakVH>::iterator FI = SPCache.find(FD->getCanonicalDecl()); @@ -2035,10 +2090,10 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, Flags |= llvm::DIDescriptor::FlagPrototyped; } if (LinkageName == Name || - CGM.getCodeGenOpts().DebugInfo <= CodeGenOptions::DebugLineTablesOnly) + CGM.getCodeGenOpts().getDebugInfo() <= CodeGenOptions::DebugLineTablesOnly) LinkageName = StringRef(); - if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) { + if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { if (const NamespaceDecl *NSDecl = dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext())) FDContext = getOrCreateNameSpace(NSDecl); @@ -2061,12 +2116,13 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, Name = Name.substr(1); unsigned LineNo = getLineNumber(Loc); - if (D->isImplicit()) + if (!HasDecl || D->isImplicit()) Flags |= llvm::DIDescriptor::FlagArtificial; llvm::DIType DIFnType; llvm::DISubprogram SPDecl; - if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) { + if (HasDecl && + CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { DIFnType = getOrCreateFunctionType(D, FnType, Unit); SPDecl = getFunctionDeclaration(D); } else { @@ -2089,7 +2145,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, QualType FnType, // Push function on region stack. llvm::MDNode *SPN = SP; LexicalBlockStack.push_back(SPN); - RegionMap[D] = llvm::WeakVH(SP); + if (HasDecl) + RegionMap[D] = llvm::WeakVH(SP); } /// EmitLocation - Emit metadata to indicate a change in line/column @@ -2242,7 +2299,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, llvm::Value *Storage, unsigned ArgNo, CGBuilderTy &Builder) { - assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); @@ -2253,7 +2310,7 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, else Ty = getOrCreateType(VD->getType(), Unit); - // If there is not any debug info for type then do not emit debug info + // If there is no debug info for this type then do not emit debug info // for this variable. if (!Ty) return; @@ -2279,8 +2336,16 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, unsigned Flags = 0; if (VD->isImplicit()) Flags |= llvm::DIDescriptor::FlagArtificial; + // If this is the first argument and it is implicit then + // give it an object pointer flag. + // FIXME: There has to be a better way to do this, but for static + // functions there won't be an implicit param at arg1 and + // otherwise it is 'self' or 'this'. + if (isa<ImplicitParamDecl>(VD) && ArgNo == 1) + Flags |= llvm::DIDescriptor::FlagObjectPointer; + llvm::MDNode *Scope = LexicalBlockStack.back(); - + StringRef Name = VD->getName(); if (!Name.empty()) { if (VD->hasAttr<BlocksAttr>()) { @@ -2376,14 +2441,15 @@ void CGDebugInfo::EmitDeclare(const VarDecl *VD, unsigned Tag, void CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder) { - assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); EmitDeclare(VD, llvm::dwarf::DW_TAG_auto_variable, Storage, 0, Builder); } -void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( - const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder, - const CGBlockInfo &blockInfo) { - assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo); +void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable(const VarDecl *VD, + llvm::Value *Storage, + CGBuilderTy &Builder, + const CGBlockInfo &blockInfo) { + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); if (Builder.GetInsertBlock() == 0) @@ -2399,11 +2465,16 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( else Ty = getOrCreateType(VD->getType(), Unit); + // Self is passed along as an implicit non-arg variable in a + // block. Mark it as the object pointer. + if (isa<ImplicitParamDecl>(VD) && VD->getName() == "self") + Ty = DBuilder.createObjectPointerType(Ty); + // Get location information. unsigned Line = getLineNumber(VD->getLocation()); unsigned Column = getColumnNumber(VD->getLocation()); - const llvm::TargetData &target = CGM.getTargetData(); + const llvm::DataLayout &target = CGM.getDataLayout(); CharUnits offset = CharUnits::fromQuantity( target.getStructLayout(blockInfo.StructureType) @@ -2418,7 +2489,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); // offset of __forwarding field offset = CGM.getContext() - .toCharUnitsFromBits(target.getPointerSizeInBits()); + .toCharUnitsFromBits(target.getPointerSizeInBits(0)); addr.push_back(llvm::ConstantInt::get(Int64Ty, offset.getQuantity())); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpDeref)); addr.push_back(llvm::ConstantInt::get(Int64Ty, llvm::DIBuilder::OpPlus)); @@ -2444,7 +2515,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, unsigned ArgNo, CGBuilderTy &Builder) { - assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); EmitDeclare(VD, llvm::dwarf::DW_TAG_arg_variable, AI, ArgNo, Builder); } @@ -2461,7 +2532,7 @@ namespace { void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, llvm::Value *addr, CGBuilderTy &Builder) { - assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); ASTContext &C = CGM.getContext(); const BlockDecl *blockDecl = block.getBlockDecl(); @@ -2475,7 +2546,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, getContextDescriptor(cast<Decl>(blockDecl->getDeclContext())); const llvm::StructLayout *blockLayout = - CGM.getTargetData().getStructLayout(block.StructureType); + CGM.getDataLayout().getStructLayout(block.StructureType); SmallVector<llvm::Value*, 16> fields; fields.push_back(createFieldType("__isa", C.VoidPtrTy, 0, loc, AS_public, @@ -2606,7 +2677,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, /// EmitGlobalVariable - Emit information about a global variable. void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, const VarDecl *D) { - assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); // Create global variable debug descriptor. llvm::DIFile Unit = getOrCreateFile(D->getLocation()); unsigned LineNo = getLineNumber(D->getLocation()); @@ -2640,7 +2711,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, /// EmitGlobalVariable - Emit information about an objective-c interface. void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, ObjCInterfaceDecl *ID) { - assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); // Create global variable debug descriptor. llvm::DIFile Unit = getOrCreateFile(ID->getLocation()); unsigned LineNo = getLineNumber(ID->getLocation()); @@ -2666,7 +2737,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, /// EmitGlobalVariable - Emit global variable's debug info. void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, llvm::Constant *Init) { - assert(CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo); // Create the descriptor for the variable. llvm::DIFile Unit = getOrCreateFile(VD->getLocation()); StringRef Name = VD->getName(); diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index 44cc49ade123..2e88a7376a6c 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -50,6 +50,9 @@ class CGDebugInfo { llvm::DICompileUnit TheCU; SourceLocation CurLoc, PrevLoc; llvm::DIType VTablePtrType; + llvm::DIType ClassTy; + llvm::DIType ObjTy; + llvm::DIType SelTy; /// TypeCache - Cache of previously constructed Types. llvm::DenseMap<void *, llvm::WeakVH> TypeCache; diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index be6638e0e57b..887058753e14 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -24,7 +24,7 @@ #include "clang/Frontend/CodeGenOptions.h" #include "llvm/GlobalVariable.h" #include "llvm/Intrinsics.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include "llvm/Type.h" using namespace clang; using namespace CodeGen; @@ -121,7 +121,7 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) { // uniqued. We can't do this in C, though, because there's no // standard way to agree on which variables are the same (i.e. // there's no mangling). - if (getContext().getLangOpts().CPlusPlus) + if (getLangOpts().CPlusPlus) if (llvm::GlobalValue::isWeakForLinker(CurFn->getLinkage())) Linkage = CurFn->getLinkage(); @@ -141,7 +141,7 @@ void CodeGenFunction::EmitVarDecl(const VarDecl &D) { static std::string GetStaticDeclName(CodeGenFunction &CGF, const VarDecl &D, const char *Separator) { CodeGenModule &CGM = CGF.CGM; - if (CGF.getContext().getLangOpts().CPlusPlus) { + if (CGF.getLangOpts().CPlusPlus) { StringRef Name = CGM.getMangledName(&D); return Name.str(); } @@ -184,12 +184,14 @@ CodeGenFunction::CreateStaticVarDecl(const VarDecl &D, Name = GetStaticDeclName(*this, D, Separator); llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(Ty); + unsigned AddrSpace = + CGM.GetGlobalVarAddressSpace(&D, CGM.getContext().getTargetAddressSpace(Ty)); llvm::GlobalVariable *GV = new llvm::GlobalVariable(CGM.getModule(), LTy, Ty.isConstant(getContext()), Linkage, CGM.EmitNullConstant(D.getType()), Name, 0, llvm::GlobalVariable::NotThreadLocal, - CGM.getContext().getTargetAddressSpace(Ty)); + AddrSpace); GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); if (Linkage != llvm::GlobalValue::InternalLinkage) GV->setVisibility(CurFn->getVisibility()); @@ -220,7 +222,7 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, // If constant emission failed, then this should be a C++ static // initializer. if (!Init) { - if (!getContext().getLangOpts().CPlusPlus) + if (!getLangOpts().CPlusPlus) CGM.ErrorUnsupported(D.getInit(), "constant l-value expression"); else if (Builder.GetInsertBlock()) { // Since we have a static initializer, this global variable can't @@ -331,7 +333,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, // Emit global variable debug descriptor for static vars. CGDebugInfo *DI = getDebugInfo(); if (DI && - CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) { + CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) { DI->setLocation(D.getLocation()); DI->EmitGlobalVariable(var, &D); } @@ -704,9 +706,8 @@ static bool canEmitInitWithFewStoresAfterMemset(llvm::Constant *Init, /// stores that would be required. static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc, bool isVolatile, CGBuilderTy &Builder) { - // Zero doesn't require a store. - if (Init->isNullValue() || isa<llvm::UndefValue>(Init)) - return; + assert(!Init->isNullValue() && !isa<llvm::UndefValue>(Init) && + "called emitStoresForInitAfterMemset for zero or undef value."); if (isa<llvm::ConstantInt>(Init) || isa<llvm::ConstantFP>(Init) || isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) || @@ -719,10 +720,11 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc, dyn_cast<llvm::ConstantDataSequential>(Init)) { for (unsigned i = 0, e = CDS->getNumElements(); i != e; ++i) { llvm::Constant *Elt = CDS->getElementAsConstant(i); - - // Get a pointer to the element and emit it. - emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i), - isVolatile, Builder); + + // If necessary, get a pointer to the element and emit it. + if (!Elt->isNullValue() && !isa<llvm::UndefValue>(Elt)) + emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i), + isVolatile, Builder); } return; } @@ -732,9 +734,11 @@ static void emitStoresForInitAfterMemset(llvm::Constant *Init, llvm::Value *Loc, for (unsigned i = 0, e = Init->getNumOperands(); i != e; ++i) { llvm::Constant *Elt = cast<llvm::Constant>(Init->getOperand(i)); - // Get a pointer to the element and emit it. - emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i), - isVolatile, Builder); + + // If necessary, get a pointer to the element and emit it. + if (!Elt->isNullValue() && !isa<llvm::UndefValue>(Elt)) + emitStoresForInitAfterMemset(Elt, Builder.CreateConstGEP2_32(Loc, 0, i), + isVolatile, Builder); } } @@ -791,7 +795,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { llvm::Value *DeclPtr; if (Ty->isConstantSizeType()) { if (!Target.useGlobalsForAutomaticVariables()) { - bool NRVO = getContext().getLangOpts().ElideConstructors && + bool NRVO = getLangOpts().ElideConstructors && D.isNRVOVariable(); // If this value is a POD array or struct with a statically @@ -910,7 +914,8 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // Emit debug info for local var declaration. if (HaveInsertPoint()) if (CGDebugInfo *DI = getDebugInfo()) { - if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) { + if (CGM.getCodeGenOpts().getDebugInfo() + >= CodeGenOptions::LimitedDebugInfo) { DI->setLocation(D.getLocation()); if (Target.useGlobalsForAutomaticVariables()) { DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr), @@ -1056,10 +1061,11 @@ void CodeGenFunction::EmitAutoVarInit(const AutoVarEmission &emission) { // If the initializer is all or mostly zeros, codegen with memset then do // a few stores afterward. if (shouldUseMemSetPlusStoresToInitialize(constant, - CGM.getTargetData().getTypeAllocSize(constant->getType()))) { + CGM.getDataLayout().getTypeAllocSize(constant->getType()))) { Builder.CreateMemSet(Loc, llvm::ConstantInt::get(Int8Ty, 0), SizeVal, alignment.getQuantity(), isVolatile); - if (!constant->isNullValue()) { + // Zero and undef don't require a stores. + if (!constant->isNullValue() && !isa<llvm::UndefValue>(constant)) { Loc = Builder.CreateBitCast(Loc, constant->getType()->getPointerTo()); emitStoresForInitAfterMemset(constant, Loc, isVolatile, Builder); } @@ -1493,8 +1499,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg, LocalDeclMap[&D] = Arg; if (CGDebugInfo *DI = getDebugInfo()) { - if (CGM.getCodeGenOpts().DebugInfo >= - CodeGenOptions::LimitedDebugInfo) { + if (CGM.getCodeGenOpts().getDebugInfo() + >= CodeGenOptions::LimitedDebugInfo) { DI->setLocation(D.getLocation()); DI->EmitDeclareOfBlockLiteralArgVariable(*BlockInfo, Arg, Builder); } @@ -1576,7 +1582,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, llvm::Value *Arg, // Emit debug info for param declaration. if (CGDebugInfo *DI = getDebugInfo()) { - if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) { + if (CGM.getCodeGenOpts().getDebugInfo() + >= CodeGenOptions::LimitedDebugInfo) { DI->EmitDeclareOfArgVariable(&D, DeclPtr, ArgNo, Builder); } } diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 492b95ad155b..65be3c19fb88 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -16,6 +16,7 @@ #include "CGCXXABI.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/Intrinsics.h" +#include "llvm/ADT/StringExtras.h" using namespace clang; using namespace CodeGen; @@ -163,6 +164,9 @@ static llvm::Constant *createAtExitStub(CodeGenModule &CGM, CodeGenFunction CGF(CGM); + // Initialize debug info if needed. + CGF.maybeInitializeDebugInfo(); + CGF.StartFunction(GlobalDecl(), CGM.getContext().VoidTy, fn, CGM.getTypes().arrangeNullaryFunction(), FunctionArgList(), SourceLocation()); @@ -218,7 +222,7 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, llvm::Function *Fn = llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, Name, &CGM.getModule()); - if (!CGM.getContext().getLangOpts().AppleKext) { + if (!CGM.getLangOpts().AppleKext) { // Set the section if needed. if (const char *Section = CGM.getContext().getTargetInfo().getStaticInitSectionSpecifier()) @@ -228,8 +232,8 @@ CreateGlobalInitOrDestructFunction(CodeGenModule &CGM, if (!CGM.getLangOpts().Exceptions) Fn->setDoesNotThrow(); - if (CGM.getLangOpts().AddressSanitizer) - Fn->addFnAttr(llvm::Attribute::AddressSafety); + if (CGM.getLangOpts().SanitizeAddress) + Fn->addFnAttr(llvm::Attributes::AddressSafety); return Fn; } @@ -252,8 +256,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size()); PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn)); DelayedCXXInitPosition.erase(D); - } - else { + } else { llvm::DenseMap<const Decl *, unsigned>::iterator I = DelayedCXXInitPosition.find(D); if (I == DelayedCXXInitPosition.end()) { @@ -276,28 +279,50 @@ CodeGenModule::EmitCXXGlobalInitFunc() { llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, false); - // Create our global initialization function. - llvm::Function *Fn = - CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a"); + // Create our global initialization function. if (!PrioritizedCXXGlobalInits.empty()) { SmallVector<llvm::Constant*, 8> LocalCXXGlobalInits; llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(), - PrioritizedCXXGlobalInits.end()); - for (unsigned i = 0; i < PrioritizedCXXGlobalInits.size(); i++) { - llvm::Function *Fn = PrioritizedCXXGlobalInits[i].second; - LocalCXXGlobalInits.push_back(Fn); - } - LocalCXXGlobalInits.append(CXXGlobalInits.begin(), CXXGlobalInits.end()); - CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, + PrioritizedCXXGlobalInits.end()); + // Iterate over "chunks" of ctors with same priority and emit each chunk + // into separate function. Note - everything is sorted first by priority, + // second - by lex order, so we emit ctor functions in proper order. + for (SmallVectorImpl<GlobalInitData >::iterator + I = PrioritizedCXXGlobalInits.begin(), + E = PrioritizedCXXGlobalInits.end(); I != E; ) { + SmallVectorImpl<GlobalInitData >::iterator + PrioE = std::upper_bound(I + 1, E, *I, GlobalInitPriorityCmp()); + + LocalCXXGlobalInits.clear(); + unsigned Priority = I->first.priority; + // Compute the function suffix from priority. Prepend with zeroes to make + // sure the function names are also ordered as priorities. + std::string PrioritySuffix = llvm::utostr(Priority); + // Priority is always <= 65535 (enforced by sema).. + PrioritySuffix = std::string(6-PrioritySuffix.size(), '0')+PrioritySuffix; + llvm::Function *Fn = + CreateGlobalInitOrDestructFunction(*this, FTy, + "_GLOBAL__I_" + PrioritySuffix); + + for (; I < PrioE; ++I) + LocalCXXGlobalInits.push_back(I->second); + + CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, &LocalCXXGlobalInits[0], LocalCXXGlobalInits.size()); + AddGlobalCtor(Fn, Priority); + } } - else - CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, - &CXXGlobalInits[0], - CXXGlobalInits.size()); + + llvm::Function *Fn = + CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a"); + + CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, + &CXXGlobalInits[0], + CXXGlobalInits.size()); AddGlobalCtor(Fn); + CXXGlobalInits.clear(); PrioritizedCXXGlobalInits.clear(); } @@ -321,8 +346,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, const VarDecl *D, llvm::GlobalVariable *Addr, bool PerformInit) { - if (CGM.getModuleDebugInfo() && !D->hasAttr<NoDebugAttr>()) - DebugInfo = CGM.getModuleDebugInfo(); + // Check if we need to emit debug info for variable initializer. + if (!D->hasAttr<NoDebugAttr>()) + maybeInitializeDebugInfo(); StartFunction(GlobalDecl(D), getContext().VoidTy, Fn, getTypes().arrangeNullaryFunction(), @@ -344,6 +370,9 @@ void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, llvm::Constant **Decls, unsigned NumDecls) { + // Initialize debug info if needed. + maybeInitializeDebugInfo(); + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, getTypes().arrangeNullaryFunction(), FunctionArgList(), SourceLocation()); @@ -369,6 +398,9 @@ void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, void CodeGenFunction::GenerateCXXGlobalDtorsFunc(llvm::Function *Fn, const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> > &DtorsAndObjects) { + // Initialize debug info if needed. + maybeInitializeDebugInfo(); + StartFunction(GlobalDecl(), getContext().VoidTy, Fn, getTypes().arrangeNullaryFunction(), FunctionArgList(), SourceLocation()); @@ -405,6 +437,9 @@ CodeGenFunction::generateDestroyHelper(llvm::Constant *addr, llvm::Function *fn = CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor"); + // Initialize debug info if needed. + maybeInitializeDebugInfo(); + StartFunction(GlobalDecl(), getContext().VoidTy, fn, FI, args, SourceLocation()); diff --git a/lib/CodeGen/CGException.cpp b/lib/CodeGen/CGException.cpp index ba9c2967cd3d..86dee5a4ab98 100644 --- a/lib/CodeGen/CGException.cpp +++ b/lib/CodeGen/CGException.cpp @@ -307,14 +307,15 @@ static bool PersonalityHasOnlyCXXUses(llvm::Constant *Fn) { /// aggressive about only using the ObjC++ personality in a function /// when it really needs it. void CodeGenModule::SimplifyPersonality() { - // For now, this is really a Darwin-specific operation. - if (!Context.getTargetInfo().getTriple().isOSDarwin()) - return; - // If we're not in ObjC++ -fexceptions, there's nothing to do. if (!LangOpts.CPlusPlus || !LangOpts.ObjC1 || !LangOpts.Exceptions) return; + // Both the problem this endeavors to fix and the way the logic + // above works is specific to the NeXT runtime. + if (!LangOpts.ObjCRuntime.isNeXTFamily()) + return; + const EHPersonality &ObjCXX = EHPersonality::get(LangOpts); const EHPersonality &CXX = getCXXPersonality(LangOpts); if (&ObjCXX == &CXX) @@ -534,7 +535,7 @@ static void emitFilterDispatchBlock(CodeGenFunction &CGF, llvm::Value *zero = CGF.Builder.getInt32(0); llvm::Value *failsFilter = CGF.Builder.CreateICmpSLT(selector, zero, "ehspec.fails"); - CGF.Builder.CreateCondBr(failsFilter, unexpectedBB, CGF.getEHResumeBlock()); + CGF.Builder.CreateCondBr(failsFilter, unexpectedBB, CGF.getEHResumeBlock(false)); CGF.EmitBlock(unexpectedBB); } @@ -614,7 +615,7 @@ CodeGenFunction::getEHDispatchBlock(EHScopeStack::stable_iterator si) { // The dispatch block for the end of the scope chain is a block that // just resumes unwinding. if (si == EHStack.stable_end()) - return getEHResumeBlock(); + return getEHResumeBlock(true); // Otherwise, we should look at the actual scope. EHScope &scope = *EHStack.find(si); @@ -1546,7 +1547,7 @@ llvm::BasicBlock *CodeGenFunction::getTerminateHandler() { return TerminateHandler; } -llvm::BasicBlock *CodeGenFunction::getEHResumeBlock() { +llvm::BasicBlock *CodeGenFunction::getEHResumeBlock(bool isCleanup) { if (EHResumeBlock) return EHResumeBlock; CGBuilderTy::InsertPoint SavedIP = Builder.saveIP(); @@ -1560,7 +1561,7 @@ llvm::BasicBlock *CodeGenFunction::getEHResumeBlock() { // This can always be a call because we necessarily didn't find // anything on the EH stack which needs our help. const char *RethrowName = Personality.CatchallRethrowFn; - if (RethrowName != 0) { + if (RethrowName != 0 && !isCleanup) { Builder.CreateCall(getCatchallRethrowFn(*this, RethrowName), getExceptionFromSlot()) ->setDoesNotReturn(); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 1fe4c18badc6..63cc5b515da8 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -26,7 +26,8 @@ #include "llvm/Intrinsics.h" #include "llvm/LLVMContext.h" #include "llvm/MDBuilder.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" +#include "llvm/ADT/Hashing.h" using namespace clang; using namespace CodeGen; @@ -156,50 +157,6 @@ void CodeGenFunction::EmitAnyExprToMem(const Expr *E, } } -namespace { -/// \brief An adjustment to be made to the temporary created when emitting a -/// reference binding, which accesses a particular subobject of that temporary. - struct SubobjectAdjustment { - enum { - DerivedToBaseAdjustment, - FieldAdjustment, - MemberPointerAdjustment - } Kind; - - union { - struct { - const CastExpr *BasePath; - const CXXRecordDecl *DerivedClass; - } DerivedToBase; - - FieldDecl *Field; - - struct { - const MemberPointerType *MPT; - llvm::Value *Ptr; - } Ptr; - }; - - SubobjectAdjustment(const CastExpr *BasePath, - const CXXRecordDecl *DerivedClass) - : Kind(DerivedToBaseAdjustment) { - DerivedToBase.BasePath = BasePath; - DerivedToBase.DerivedClass = DerivedClass; - } - - SubobjectAdjustment(FieldDecl *Field) - : Kind(FieldAdjustment) { - this->Field = Field; - } - - SubobjectAdjustment(const MemberPointerType *MPT, llvm::Value *Ptr) - : Kind(MemberPointerAdjustment) { - this->Ptr.MPT = MPT; - this->Ptr.Ptr = Ptr; - } - }; -} - static llvm::Value * CreateReferenceTemporary(CodeGenFunction &CGF, QualType Type, const NamedDecl *InitializedDecl) { @@ -232,32 +189,18 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, const CXXDestructorDecl *&ReferenceTemporaryDtor, QualType &ObjCARCReferenceLifetimeType, const NamedDecl *InitializedDecl) { - // Look through single-element init lists that claim to be lvalues. They're - // just syntactic wrappers in this case. - if (const InitListExpr *ILE = dyn_cast<InitListExpr>(E)) { - if (ILE->getNumInits() == 1 && ILE->isGLValue()) - E = ILE->getInit(0); - } - - // Look through expressions for materialized temporaries (for now). - if (const MaterializeTemporaryExpr *M - = dyn_cast<MaterializeTemporaryExpr>(E)) { - // Objective-C++ ARC: - // If we are binding a reference to a temporary that has ownership, we - // need to perform retain/release operations on the temporary. - if (CGF.getContext().getLangOpts().ObjCAutoRefCount && - E->getType()->isObjCLifetimeType() && - (E->getType().getObjCLifetime() == Qualifiers::OCL_Strong || - E->getType().getObjCLifetime() == Qualifiers::OCL_Weak || - E->getType().getObjCLifetime() == Qualifiers::OCL_Autoreleasing)) - ObjCARCReferenceLifetimeType = E->getType(); - - E = M->GetTemporaryExpr(); - } + const MaterializeTemporaryExpr *M = NULL; + E = E->findMaterializedTemporary(M); + // Objective-C++ ARC: + // If we are binding a reference to a temporary that has ownership, we + // need to perform retain/release operations on the temporary. + if (M && CGF.getLangOpts().ObjCAutoRefCount && + M->getType()->isObjCLifetimeType() && + (M->getType().getObjCLifetime() == Qualifiers::OCL_Strong || + M->getType().getObjCLifetime() == Qualifiers::OCL_Weak || + M->getType().getObjCLifetime() == Qualifiers::OCL_Autoreleasing)) + ObjCARCReferenceLifetimeType = M->getType(); - if (const CXXDefaultArgExpr *DAE = dyn_cast<CXXDefaultArgExpr>(E)) - E = DAE->getExpr(); - if (const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(E)) { CGF.enterFullExpression(EWC); CodeGenFunction::RunCleanupsScope Scope(CGF); @@ -335,54 +278,13 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, return ReferenceTemporary; } - - SmallVector<SubobjectAdjustment, 2> Adjustments; - while (true) { - E = E->IgnoreParens(); - - if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { - if ((CE->getCastKind() == CK_DerivedToBase || - CE->getCastKind() == CK_UncheckedDerivedToBase) && - E->getType()->isRecordType()) { - E = CE->getSubExpr(); - CXXRecordDecl *Derived - = cast<CXXRecordDecl>(E->getType()->getAs<RecordType>()->getDecl()); - Adjustments.push_back(SubobjectAdjustment(CE, Derived)); - continue; - } - - if (CE->getCastKind() == CK_NoOp) { - E = CE->getSubExpr(); - continue; - } - } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { - if (!ME->isArrow() && ME->getBase()->isRValue()) { - assert(ME->getBase()->getType()->isRecordType()); - if (FieldDecl *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) { - E = ME->getBase(); - Adjustments.push_back(SubobjectAdjustment(Field)); - continue; - } - } - } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { - if (BO->isPtrMemOp()) { - assert(BO->getLHS()->isRValue()); - E = BO->getLHS(); - const MemberPointerType *MPT = - BO->getRHS()->getType()->getAs<MemberPointerType>(); - llvm::Value *Ptr = CGF.EmitScalarExpr(BO->getRHS()); - Adjustments.push_back(SubobjectAdjustment(MPT, Ptr)); - } - } - if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E)) - if (opaque->getType()->isRecordType()) - return CGF.EmitOpaqueValueLValue(opaque).getAddress(); + SmallVector<SubobjectAdjustment, 2> Adjustments; + E = E->skipRValueSubobjectAdjustments(Adjustments); + if (const OpaqueValueExpr *opaque = dyn_cast<OpaqueValueExpr>(E)) + if (opaque->getType()->isRecordType()) + return CGF.EmitOpaqueValueLValue(opaque).getAddress(); - // Nothing changed. - break; - } - // Create a reference temporary if necessary. AggValueSlot AggSlot = AggValueSlot::ignored(); if (CGF.hasAggregateLLVMType(E->getType()) && @@ -446,8 +348,9 @@ EmitExprForReferenceBinding(CodeGenFunction &CGF, const Expr *E, } case SubobjectAdjustment::MemberPointerAdjustment: { + llvm::Value *Ptr = CGF.EmitScalarExpr(Adjustment.Ptr.RHS); Object = CGF.CGM.getCXXABI().EmitMemberDataPointerAddress( - CGF, Object, Adjustment.Ptr.Ptr, Adjustment.Ptr.MPT); + CGF, Object, Ptr, Adjustment.Ptr.MPT); break; } } @@ -486,6 +389,15 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E, ReferenceTemporaryDtor, ObjCARCReferenceLifetimeType, InitializedDecl); + if (SanitizePerformTypeCheck && !E->getType()->isFunctionType()) { + // C++11 [dcl.ref]p5 (as amended by core issue 453): + // If a glvalue to which a reference is directly bound designates neither + // an existing object or function of an appropriate type nor a region of + // storage of suitable size and alignment to contain an object of the + // reference's type, the behavior is undefined. + QualType Ty = E->getType(); + EmitTypeCheck(TCK_ReferenceBinding, E->getExprLoc(), Value, Ty); + } if (!ReferenceTemporaryDtor && ObjCARCReferenceLifetimeType.isNull()) return RValue::get(Value); @@ -549,22 +461,133 @@ unsigned CodeGenFunction::getAccessedFieldNo(unsigned Idx, ->getZExtValue(); } -void CodeGenFunction::EmitCheck(llvm::Value *Address, unsigned Size) { - if (!CatchUndefined) +/// Emit the hash_16_bytes function from include/llvm/ADT/Hashing.h. +static llvm::Value *emitHash16Bytes(CGBuilderTy &Builder, llvm::Value *Low, + llvm::Value *High) { + llvm::Value *KMul = Builder.getInt64(0x9ddfea08eb382d69ULL); + llvm::Value *K47 = Builder.getInt64(47); + llvm::Value *A0 = Builder.CreateMul(Builder.CreateXor(Low, High), KMul); + llvm::Value *A1 = Builder.CreateXor(Builder.CreateLShr(A0, K47), A0); + llvm::Value *B0 = Builder.CreateMul(Builder.CreateXor(High, A1), KMul); + llvm::Value *B1 = Builder.CreateXor(Builder.CreateLShr(B0, K47), B0); + return Builder.CreateMul(B1, KMul); +} + +void CodeGenFunction::EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, + llvm::Value *Address, + QualType Ty, CharUnits Alignment) { + if (!SanitizePerformTypeCheck) return; - // This needs to be to the standard address space. - Address = Builder.CreateBitCast(Address, Int8PtrTy); + // Don't check pointers outside the default address space. The null check + // isn't correct, the object-size check isn't supported by LLVM, and we can't + // communicate the addresses to the runtime handler for the vptr check. + if (Address->getType()->getPointerAddressSpace()) + return; - llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, IntPtrTy); + llvm::Value *Cond = 0; - llvm::Value *Min = Builder.getFalse(); - llvm::Value *C = Builder.CreateCall2(F, Address, Min); - llvm::BasicBlock *Cont = createBasicBlock(); - Builder.CreateCondBr(Builder.CreateICmpUGE(C, - llvm::ConstantInt::get(IntPtrTy, Size)), - Cont, getTrapBB()); - EmitBlock(Cont); + if (getLangOpts().SanitizeNull) { + // The glvalue must not be an empty glvalue. + Cond = Builder.CreateICmpNE( + Address, llvm::Constant::getNullValue(Address->getType())); + } + + if (getLangOpts().SanitizeObjectSize && !Ty->isIncompleteType()) { + uint64_t Size = getContext().getTypeSizeInChars(Ty).getQuantity(); + + // The glvalue must refer to a large enough storage region. + // FIXME: If Address Sanitizer is enabled, insert dynamic instrumentation + // to check this. + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::objectsize, IntPtrTy); + llvm::Value *Min = Builder.getFalse(); + llvm::Value *CastAddr = Builder.CreateBitCast(Address, Int8PtrTy); + llvm::Value *LargeEnough = + Builder.CreateICmpUGE(Builder.CreateCall2(F, CastAddr, Min), + llvm::ConstantInt::get(IntPtrTy, Size)); + Cond = Cond ? Builder.CreateAnd(Cond, LargeEnough) : LargeEnough; + } + + uint64_t AlignVal = 0; + + if (getLangOpts().SanitizeAlignment) { + AlignVal = Alignment.getQuantity(); + if (!Ty->isIncompleteType() && !AlignVal) + AlignVal = getContext().getTypeAlignInChars(Ty).getQuantity(); + + // The glvalue must be suitably aligned. + if (AlignVal) { + llvm::Value *Align = + Builder.CreateAnd(Builder.CreatePtrToInt(Address, IntPtrTy), + llvm::ConstantInt::get(IntPtrTy, AlignVal - 1)); + llvm::Value *Aligned = + Builder.CreateICmpEQ(Align, llvm::ConstantInt::get(IntPtrTy, 0)); + Cond = Cond ? Builder.CreateAnd(Cond, Aligned) : Aligned; + } + } + + if (Cond) { + llvm::Constant *StaticData[] = { + EmitCheckSourceLocation(Loc), + EmitCheckTypeDescriptor(Ty), + llvm::ConstantInt::get(SizeTy, AlignVal), + llvm::ConstantInt::get(Int8Ty, TCK) + }; + EmitCheck(Cond, "type_mismatch", StaticData, Address); + } + + // If possible, check that the vptr indicates that there is a subobject of + // type Ty at offset zero within this object. + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + if (getLangOpts().SanitizeVptr && TCK != TCK_ConstructorCall && + RD && RD->hasDefinition() && RD->isDynamicClass()) { + // Compute a hash of the mangled name of the type. + // + // FIXME: This is not guaranteed to be deterministic! Move to a + // fingerprinting mechanism once LLVM provides one. For the time + // being the implementation happens to be deterministic. + llvm::SmallString<64> MangledName; + llvm::raw_svector_ostream Out(MangledName); + CGM.getCXXABI().getMangleContext().mangleCXXRTTI(Ty.getUnqualifiedType(), + Out); + llvm::hash_code TypeHash = hash_value(Out.str()); + + // Load the vptr, and compute hash_16_bytes(TypeHash, vptr). + llvm::Value *Low = llvm::ConstantInt::get(Int64Ty, TypeHash); + llvm::Type *VPtrTy = llvm::PointerType::get(IntPtrTy, 0); + llvm::Value *VPtrAddr = Builder.CreateBitCast(Address, VPtrTy); + llvm::Value *VPtrVal = Builder.CreateLoad(VPtrAddr); + llvm::Value *High = Builder.CreateZExt(VPtrVal, Int64Ty); + + llvm::Value *Hash = emitHash16Bytes(Builder, Low, High); + Hash = Builder.CreateTrunc(Hash, IntPtrTy); + + // Look the hash up in our cache. + const int CacheSize = 128; + llvm::Type *HashTable = llvm::ArrayType::get(IntPtrTy, CacheSize); + llvm::Value *Cache = CGM.CreateRuntimeVariable(HashTable, + "__ubsan_vptr_type_cache"); + llvm::Value *Slot = Builder.CreateAnd(Hash, + llvm::ConstantInt::get(IntPtrTy, + CacheSize-1)); + llvm::Value *Indices[] = { Builder.getInt32(0), Slot }; + llvm::Value *CacheVal = + Builder.CreateLoad(Builder.CreateInBoundsGEP(Cache, Indices)); + + // If the hash isn't in the cache, call a runtime handler to perform the + // hard work of checking whether the vptr is for an object of the right + // type. This will either fill in the cache and return, or produce a + // diagnostic. + llvm::Constant *StaticData[] = { + EmitCheckSourceLocation(Loc), + EmitCheckTypeDescriptor(Ty), + CGM.GetAddrOfRTTIDescriptor(Ty.getUnqualifiedType()), + llvm::ConstantInt::get(Int8Ty, TCK) + }; + llvm::Value *DynamicData[] = { Address, Hash }; + EmitCheck(Builder.CreateICmpEQ(CacheVal, Hash), + "dynamic_type_cache_miss", StaticData, DynamicData, true); + } } @@ -641,11 +664,11 @@ LValue CodeGenFunction::EmitUnsupportedLValue(const Expr *E, return MakeAddrLValue(llvm::UndefValue::get(Ty), E->getType()); } -LValue CodeGenFunction::EmitCheckedLValue(const Expr *E) { +LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) { LValue LV = EmitLValue(E); if (!isa<DeclRefExpr>(E) && !LV.isBitField() && LV.isSimple()) - EmitCheck(LV.getAddress(), - getContext().getTypeSizeInChars(E->getType()).getQuantity()); + EmitTypeCheck(TCK, E->getExprLoc(), LV.getAddress(), + E->getType(), LV.getAlignment()); return LV; } @@ -672,7 +695,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { llvm_unreachable("cannot emit a property reference directly"); case Expr::ObjCSelectorExprClass: - return EmitObjCSelectorLValue(cast<ObjCSelectorExpr>(E)); + return EmitObjCSelectorLValue(cast<ObjCSelectorExpr>(E)); case Expr::ObjCIsaExprClass: return EmitObjCIsaExpr(cast<ObjCIsaExpr>(E)); case Expr::BinaryOperatorClass: @@ -709,6 +732,8 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { return EmitCXXConstructLValue(cast<CXXConstructExpr>(E)); case Expr::CXXBindTemporaryExprClass: return EmitCXXBindTemporaryLValue(cast<CXXBindTemporaryExpr>(E)); + case Expr::CXXUuidofExprClass: + return EmitCXXUuidofLValue(cast<CXXUuidofExpr>(E)); case Expr::LambdaExprClass: return EmitLambdaLValue(cast<LambdaExpr>(E)); @@ -1124,7 +1149,7 @@ RValue CodeGenFunction::EmitLoadOfBitfieldLValue(LValue LV) { // Get the output type. llvm::Type *ResLTy = ConvertType(LV.getType()); - unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy); + unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy); // Compute the result as an OR of all of the individual component accesses. llvm::Value *Res = 0; @@ -1322,7 +1347,7 @@ void CodeGenFunction::EmitStoreThroughBitfieldLValue(RValue Src, LValue Dst, // Get the output type. llvm::Type *ResLTy = ConvertTypeForMem(Dst.getType()); - unsigned ResSizeInBits = CGM.getTargetData().getTypeSizeInBits(ResLTy); + unsigned ResSizeInBits = CGM.getDataLayout().getTypeSizeInBits(ResLTy); // Get the source value, truncated to the width of the bit-field. llvm::Value *SrcVal = Src.getScalarVal(); @@ -1645,6 +1670,21 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { CharUnits Alignment = getContext().getDeclAlign(ND); QualType T = E->getType(); + // A DeclRefExpr for a reference initialized by a constant expression can + // appear without being odr-used. Directly emit the constant initializer. + if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { + const Expr *Init = VD->getAnyInitializer(VD); + if (Init && !isa<ParmVarDecl>(VD) && VD->getType()->isReferenceType() && + VD->isUsableInConstantExpressions(getContext()) && + VD->checkInitIsICE()) { + llvm::Constant *Val = + CGM.EmitConstantValue(*VD->evaluateValue(), VD->getType(), this); + assert(Val && "failed to emit reference constant expression"); + // FIXME: Eventually we will want to emit vector element references. + return MakeAddrLValue(Val, T, Alignment); + } + } + // FIXME: We should be able to assert this for FunctionDecls as well! // FIXME: We should be able to assert this for all DeclRefExprs, not just // those with a valid source location. @@ -1655,7 +1695,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { if (ND->hasAttr<WeakRefAttr>()) { const ValueDecl *VD = cast<ValueDecl>(ND); llvm::Constant *Aliasee = CGM.GetWeakRefReference(VD); - return MakeAddrLValue(Aliasee, E->getType(), Alignment); + return MakeAddrLValue(Aliasee, T, Alignment); } if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { @@ -1683,9 +1723,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { } assert(isa<BlockDecl>(CurCodeDecl) && E->refersToEnclosingLocal()); - CharUnits alignment = getContext().getDeclAlign(VD); return MakeAddrLValue(GetAddrOfBlockDecl(VD, isBlockVariable), - E->getType(), alignment); + T, Alignment); } assert(V && "DeclRefExpr not entered in LocalDeclMap?"); @@ -1736,8 +1775,8 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { // of a pointer to object; as in void foo (__weak id *param); *param = 0; // But, we continue to generate __strong write barrier on indirect write // into a pointer to object. - if (getContext().getLangOpts().ObjC1 && - getContext().getLangOpts().getGC() != LangOptions::NonGC && + if (getLangOpts().ObjC1 && + getLangOpts().getGC() != LangOptions::NonGC && LV.isObjCWeak()) LV.setNonGC(!E->isOBJCGCCandidate(getContext())); return LV; @@ -1815,8 +1854,9 @@ GetAddrOfConstantWideString(StringRef Str, static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source, SmallString<32>& Target) { Target.resize(CharByteWidth * (Source.size() + 1)); - char* ResultPtr = &Target[0]; - bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr); + char *ResultPtr = &Target[0]; + const UTF8 *ErrorPtr; + bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr, ErrorPtr); (void)success; assert(success); Target.resize(ResultPtr - &Target[0]); @@ -1888,33 +1928,167 @@ LValue CodeGenFunction::EmitPredefinedLValue(const PredefinedExpr *E) { } } -llvm::BasicBlock *CodeGenFunction::getTrapBB() { - const CodeGenOptions &GCO = CGM.getCodeGenOpts(); +/// Emit a type description suitable for use by a runtime sanitizer library. The +/// format of a type descriptor is +/// +/// \code +/// { i16 TypeKind, i16 TypeInfo } +/// \endcode +/// +/// followed by an array of i8 containing the type name. TypeKind is 0 for an +/// integer, 1 for a floating point value, and -1 for anything else. +llvm::Constant *CodeGenFunction::EmitCheckTypeDescriptor(QualType T) { + // FIXME: Only emit each type's descriptor once. + uint16_t TypeKind = -1; + uint16_t TypeInfo = 0; + + if (T->isIntegerType()) { + TypeKind = 0; + TypeInfo = (llvm::Log2_32(getContext().getTypeSize(T)) << 1) | + T->isSignedIntegerType(); + } else if (T->isFloatingType()) { + TypeKind = 1; + TypeInfo = getContext().getTypeSize(T); + } + + // Format the type name as if for a diagnostic, including quotes and + // optionally an 'aka'. + llvm::SmallString<32> Buffer; + CGM.getDiags().ConvertArgToString(DiagnosticsEngine::ak_qualtype, + (intptr_t)T.getAsOpaquePtr(), + 0, 0, 0, 0, 0, 0, Buffer, + ArrayRef<intptr_t>()); + + llvm::Constant *Components[] = { + Builder.getInt16(TypeKind), Builder.getInt16(TypeInfo), + llvm::ConstantDataArray::getString(getLLVMContext(), Buffer) + }; + llvm::Constant *Descriptor = llvm::ConstantStruct::getAnon(Components); + + llvm::GlobalVariable *GV = + new llvm::GlobalVariable(CGM.getModule(), Descriptor->getType(), + /*isConstant=*/true, + llvm::GlobalVariable::PrivateLinkage, + Descriptor); + GV->setUnnamedAddr(true); + return GV; +} - // If we are not optimzing, don't collapse all calls to trap in the function - // to the same call, that way, in the debugger they can see which operation - // did in fact fail. If we are optimizing, we collapse all calls to trap down - // to just one per function to save on codesize. - if (GCO.OptimizationLevel && TrapBB) - return TrapBB; +llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) { + llvm::Type *TargetTy = IntPtrTy; + + // Integers which fit in intptr_t are zero-extended and passed directly. + if (V->getType()->isIntegerTy() && + V->getType()->getIntegerBitWidth() <= TargetTy->getIntegerBitWidth()) + return Builder.CreateZExt(V, TargetTy); + + // Pointers are passed directly, everything else is passed by address. + if (!V->getType()->isPointerTy()) { + llvm::Value *Ptr = Builder.CreateAlloca(V->getType()); + Builder.CreateStore(V, Ptr); + V = Ptr; + } + return Builder.CreatePtrToInt(V, TargetTy); +} + +/// \brief Emit a representation of a SourceLocation for passing to a handler +/// in a sanitizer runtime library. The format for this data is: +/// \code +/// struct SourceLocation { +/// const char *Filename; +/// int32_t Line, Column; +/// }; +/// \endcode +/// For an invalid SourceLocation, the Filename pointer is null. +llvm::Constant *CodeGenFunction::EmitCheckSourceLocation(SourceLocation Loc) { + PresumedLoc PLoc = getContext().getSourceManager().getPresumedLoc(Loc); + + llvm::Constant *Data[] = { + // FIXME: Only emit each file name once. + PLoc.isValid() ? cast<llvm::Constant>( + Builder.CreateGlobalStringPtr(PLoc.getFilename())) + : llvm::Constant::getNullValue(Int8PtrTy), + Builder.getInt32(PLoc.getLine()), + Builder.getInt32(PLoc.getColumn()) + }; - llvm::BasicBlock *Cont = 0; - if (HaveInsertPoint()) { - Cont = createBasicBlock("cont"); - EmitBranch(Cont); + return llvm::ConstantStruct::getAnon(Data); +} + +void CodeGenFunction::EmitCheck(llvm::Value *Checked, StringRef CheckName, + llvm::ArrayRef<llvm::Constant *> StaticArgs, + llvm::ArrayRef<llvm::Value *> DynamicArgs, + bool Recoverable) { + llvm::BasicBlock *Cont = createBasicBlock("cont"); + + llvm::BasicBlock *Handler = createBasicBlock("handler." + CheckName); + Builder.CreateCondBr(Checked, Cont, Handler); + EmitBlock(Handler); + + llvm::Constant *Info = llvm::ConstantStruct::getAnon(StaticArgs); + llvm::GlobalValue *InfoPtr = + new llvm::GlobalVariable(CGM.getModule(), Info->getType(), true, + llvm::GlobalVariable::PrivateLinkage, Info); + InfoPtr->setUnnamedAddr(true); + + llvm::SmallVector<llvm::Value *, 4> Args; + llvm::SmallVector<llvm::Type *, 4> ArgTypes; + Args.reserve(DynamicArgs.size() + 1); + ArgTypes.reserve(DynamicArgs.size() + 1); + + // Handler functions take an i8* pointing to the (handler-specific) static + // information block, followed by a sequence of intptr_t arguments + // representing operand values. + Args.push_back(Builder.CreateBitCast(InfoPtr, Int8PtrTy)); + ArgTypes.push_back(Int8PtrTy); + for (size_t i = 0, n = DynamicArgs.size(); i != n; ++i) { + Args.push_back(EmitCheckValue(DynamicArgs[i])); + ArgTypes.push_back(IntPtrTy); + } + + llvm::FunctionType *FnType = + llvm::FunctionType::get(CGM.VoidTy, ArgTypes, false); + llvm::AttrBuilder B; + if (!Recoverable) { + B.addAttribute(llvm::Attributes::NoReturn) + .addAttribute(llvm::Attributes::NoUnwind); + } + B.addAttribute(llvm::Attributes::UWTable); + llvm::Value *Fn = CGM.CreateRuntimeFunction(FnType, + ("__ubsan_handle_" + CheckName).str(), + llvm::Attributes::get(getLLVMContext(), + B)); + llvm::CallInst *HandlerCall = Builder.CreateCall(Fn, Args); + if (Recoverable) { + Builder.CreateBr(Cont); + } else { + HandlerCall->setDoesNotReturn(); + HandlerCall->setDoesNotThrow(); + Builder.CreateUnreachable(); } - TrapBB = createBasicBlock("trap"); - EmitBlock(TrapBB); - llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap); - llvm::CallInst *TrapCall = Builder.CreateCall(F); - TrapCall->setDoesNotReturn(); - TrapCall->setDoesNotThrow(); - Builder.CreateUnreachable(); + EmitBlock(Cont); +} - if (Cont) - EmitBlock(Cont); - return TrapBB; +void CodeGenFunction::EmitTrapvCheck(llvm::Value *Checked) { + llvm::BasicBlock *Cont = createBasicBlock("cont"); + + // If we're optimizing, collapse all calls to trap down to just one per + // function to save on code size. + if (!CGM.getCodeGenOpts().OptimizationLevel || !TrapBB) { + TrapBB = createBasicBlock("trap"); + Builder.CreateCondBr(Checked, Cont, TrapBB); + EmitBlock(TrapBB); + llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::trap); + llvm::CallInst *TrapCall = Builder.CreateCall(F); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + Builder.CreateUnreachable(); + } else { + Builder.CreateCondBr(Checked, Cont, TrapBB); + } + + EmitBlock(Cont); } /// isSimpleArrayDecayOperand - If the specified expr is a simple decay from an @@ -2007,14 +2181,14 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { // Propagate the alignment from the array itself to the result. ArrayAlignment = ArrayLV.getAlignment(); - if (getContext().getLangOpts().isSignedOverflowDefined()) + if (getLangOpts().isSignedOverflowDefined()) Address = Builder.CreateGEP(ArrayPtr, Args, "arrayidx"); else Address = Builder.CreateInBoundsGEP(ArrayPtr, Args, "arrayidx"); } else { // The base must be a pointer, which is not an aggregate. Emit it. llvm::Value *Base = EmitScalarExpr(E->getBase()); - if (getContext().getLangOpts().isSignedOverflowDefined()) + if (getLangOpts().isSignedOverflowDefined()) Address = Builder.CreateGEP(Base, Idx, "arrayidx"); else Address = Builder.CreateInBoundsGEP(Base, Idx, "arrayidx"); @@ -2037,8 +2211,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E) { LV.getQuals().setAddressSpace(E->getBase()->getType().getAddressSpace()); - if (getContext().getLangOpts().ObjC1 && - getContext().getLangOpts().getGC() != LangOptions::NonGC) { + if (getLangOpts().ObjC1 && + getLangOpts().getGC() != LangOptions::NonGC) { LV.setNonGC(!E->isOBJCGCCandidate(getContext())); setObjCGCLValueClass(getContext(), E, LV); } @@ -2114,11 +2288,13 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar. LValue BaseLV; - if (E->isArrow()) - BaseLV = MakeNaturalAlignAddrLValue(EmitScalarExpr(BaseExpr), - BaseExpr->getType()->getPointeeType()); - else - BaseLV = EmitLValue(BaseExpr); + if (E->isArrow()) { + llvm::Value *Ptr = EmitScalarExpr(BaseExpr); + QualType PtrTy = BaseExpr->getType()->getPointeeType(); + EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Ptr, PtrTy); + BaseLV = MakeNaturalAlignAddrLValue(Ptr, PtrTy); + } else + BaseLV = EmitCheckedLValue(BaseExpr, TCK_MemberAccess); NamedDecl *ND = E->getMemberDecl(); if (FieldDecl *Field = dyn_cast<FieldDecl>(ND)) { @@ -2355,7 +2531,10 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!"); - + + case CK_BuiltinFnToFnPtr: + llvm_unreachable("builtin functions are handled elsewhere"); + // These two casts are currently treated as no-ops, although they could // potentially be real operations depending on the target's ABI. case CK_NonAtomicToAtomic: @@ -2546,7 +2725,7 @@ RValue CodeGenFunction::EmitCallExpr(const CallExpr *E, if (const CXXPseudoDestructorExpr *PseudoDtor = dyn_cast<CXXPseudoDestructorExpr>(E->getCallee()->IgnoreParens())) { QualType DestroyedType = PseudoDtor->getDestroyedType(); - if (getContext().getLangOpts().ObjCAutoRefCount && + if (getLangOpts().ObjCAutoRefCount && DestroyedType->isObjCLifetimeType() && (DestroyedType.getObjCLifetime() == Qualifiers::OCL_Strong || DestroyedType.getObjCLifetime() == Qualifiers::OCL_Weak)) { @@ -2635,7 +2814,7 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { } RValue RV = EmitAnyExpr(E->getRHS()); - LValue LV = EmitLValue(E->getLHS()); + LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); EmitStoreThroughLValue(RV, LV); return LV; } @@ -2677,6 +2856,14 @@ CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) { return MakeAddrLValue(EmitCXXTypeidExpr(E), E->getType()); } +llvm::Value *CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) { + return CGM.GetAddrOfUuidDescriptor(E); +} + +LValue CodeGenFunction::EmitCXXUuidofLValue(const CXXUuidofExpr *E) { + return MakeAddrLValue(EmitCXXUuidofExpr(E), E->getType()); +} + LValue CodeGenFunction::EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E) { AggValueSlot Slot = CreateAggTemp(E->getType(), "temp.lvalue"); @@ -2977,11 +3164,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { uint64_t Size = sizeChars.getQuantity(); CharUnits alignChars = getContext().getTypeAlignInChars(AtomicTy); unsigned Align = alignChars.getQuantity(); - unsigned MaxInlineWidth = - getContext().getTargetInfo().getMaxAtomicInlineWidth(); - bool UseLibcall = (Size != Align || Size > MaxInlineWidth); - - + unsigned MaxInlineWidthInBits = + getContext().getTargetInfo().getMaxAtomicInlineWidth(); + bool UseLibcall = (Size != Align || + getContext().toBits(sizeChars) > MaxInlineWidthInBits); llvm::Value *Ptr, *Order, *OrderFail = 0, *Val1 = 0, *Val2 = 0; Ptr = EmitScalarExpr(E->getPtr()); @@ -3177,6 +3363,13 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { return ConvertTempToRValue(*this, E->getType(), Dest); } + bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store || + E->getOp() == AtomicExpr::AO__atomic_store || + E->getOp() == AtomicExpr::AO__atomic_store_n; + bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load || + E->getOp() == AtomicExpr::AO__atomic_load || + E->getOp() == AtomicExpr::AO__atomic_load_n; + llvm::Type *IPtrTy = llvm::IntegerType::get(getLLVMContext(), Size * 8)->getPointerTo(); llvm::Value *OrigDest = Dest; @@ -3194,14 +3387,20 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { break; case 1: // memory_order_consume case 2: // memory_order_acquire + if (IsStore) + break; // Avoid crashing on code with undefined behavior EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, llvm::Acquire); break; case 3: // memory_order_release + if (IsLoad) + break; // Avoid crashing on code with undefined behavior EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, llvm::Release); break; case 4: // memory_order_acq_rel + if (IsLoad || IsStore) + break; // Avoid crashing on code with undefined behavior EmitAtomicOp(*this, E, Dest, Ptr, Val1, Val2, Size, Align, llvm::AcquireRelease); break; @@ -3221,13 +3420,6 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E, llvm::Value *Dest) { // Long case, when Order isn't obviously constant. - bool IsStore = E->getOp() == AtomicExpr::AO__c11_atomic_store || - E->getOp() == AtomicExpr::AO__atomic_store || - E->getOp() == AtomicExpr::AO__atomic_store_n; - bool IsLoad = E->getOp() == AtomicExpr::AO__c11_atomic_load || - E->getOp() == AtomicExpr::AO__atomic_load || - E->getOp() == AtomicExpr::AO__atomic_load_n; - // Create all the relevant BB's llvm::BasicBlock *MonotonicBB = 0, *AcquireBB = 0, *ReleaseBB = 0, *AcqRelBB = 0, *SeqCstBB = 0; diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 61f7362ecaef..718e8f999ce7 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -549,8 +549,10 @@ AggExprEmitter::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { void AggExprEmitter::VisitCastExpr(CastExpr *E) { switch (E->getCastKind()) { case CK_Dynamic: { + // FIXME: Can this actually happen? We have no test coverage for it. assert(isa<CXXDynamicCastExpr>(E) && "CK_Dynamic without a dynamic_cast?"); - LValue LV = CGF.EmitCheckedLValue(E->getSubExpr()); + LValue LV = CGF.EmitCheckedLValue(E->getSubExpr(), + CodeGenFunction::TCK_Load); // FIXME: Do we also need to handle property references here? if (LV.isSimple()) CGF.EmitDynamicCast(LV.getAddress(), cast<CXXDynamicCastExpr>(E)); @@ -645,6 +647,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: case CK_CopyAndAutoreleaseBlockObject: + case CK_BuiltinFnToFnPtr: llvm_unreachable("cast kind invalid for aggregate types"); } } @@ -771,7 +774,7 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { Visit(E->getRHS()); // Now emit the LHS and copy into it. - LValue LHS = CGF.EmitLValue(E->getLHS()); + LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); EmitCopy(E->getLHS()->getType(), AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed, @@ -1205,7 +1208,7 @@ static void CheckAggExprForMemSetUse(AggValueSlot &Slot, const Expr *E, if (Slot.isZeroed() || Slot.isVolatile() || Slot.getAddr() == 0) return; // C++ objects with a user-declared constructor don't need zero'ing. - if (CGF.getContext().getLangOpts().CPlusPlus) + if (CGF.getLangOpts().CPlusPlus) if (const RecordType *RT = CGF.getContext() .getBaseElementType(E->getType())->getAs<RecordType>()) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); @@ -1271,10 +1274,11 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) { void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr, QualType Ty, bool isVolatile, - CharUnits alignment) { + CharUnits alignment, + bool isAssignment) { assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex"); - if (getContext().getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus) { if (const RecordType *RT = Ty->getAs<RecordType>()) { CXXRecordDecl *Record = cast<CXXRecordDecl>(RT->getDecl()); assert((Record->hasTrivialCopyConstructor() || @@ -1300,9 +1304,13 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, // implementation handles this case safely. If there is a libc that does not // safely handle this, we can add a target hook. - // Get size and alignment info for this aggregate. - std::pair<CharUnits, CharUnits> TypeInfo = - getContext().getTypeInfoInChars(Ty); + // Get data size and alignment info for this aggregate. If this is an + // assignment don't copy the tail padding. Otherwise copying it is fine. + std::pair<CharUnits, CharUnits> TypeInfo; + if (isAssignment) + TypeInfo = getContext().getTypeInfoDataSizeInChars(Ty); + else + TypeInfo = getContext().getTypeInfoInChars(Ty); if (alignment.isZero()) alignment = TypeInfo.second; @@ -1359,11 +1367,17 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, } } } + + // Determine the metadata to describe the position of any padding in this + // memcpy, as well as the TBAA tags for the members of the struct, in case + // the optimizer wishes to expand it in to scalar memory operations. + llvm::MDNode *TBAAStructTag = CGM.getTBAAStructInfo(Ty); Builder.CreateMemCpy(DestPtr, SrcPtr, llvm::ConstantInt::get(IntPtrTy, TypeInfo.first.getQuantity()), - alignment.getQuantity(), isVolatile); + alignment.getQuantity(), isVolatile, + /*TBAATag=*/0, TBAAStructTag); } void CodeGenFunction::MaybeEmitStdInitializerListCleanup(llvm::Value *loc, diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 31ea1b5448a7..7f640f6e6433 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -24,6 +24,7 @@ using namespace clang; using namespace CodeGen; RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, + SourceLocation CallLoc, llvm::Value *Callee, ReturnValueSlot ReturnValue, llvm::Value *This, @@ -33,6 +34,13 @@ RValue CodeGenFunction::EmitCXXMemberCall(const CXXMethodDecl *MD, assert(MD->isInstance() && "Trying to emit a member call expr on a static method!"); + // C++11 [class.mfct.non-static]p2: + // If a non-static member function of a class X is called for an object that + // is not of type X, or of a type derived from X, the behavior is undefined. + EmitTypeCheck(isa<CXXConstructorDecl>(MD) ? TCK_ConstructorCall + : TCK_MemberCall, + CallLoc, This, getContext().getRecordType(MD->getParent())); + CallArgList Args; // Push the this ptr. @@ -168,8 +176,9 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); CGDebugInfo *DI = getDebugInfo(); - if (DI && CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo - && !isa<CallExpr>(ME->getBase())) { + if (DI && + CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::LimitedDebugInfo && + !isa<CallExpr>(ME->getBase())) { QualType PQTy = ME->getBase()->IgnoreParenImpCasts()->getType(); if (const PointerType * PTy = dyn_cast<PointerType>(PQTy)) { DI->getOrCreateRecordType(PTy->getPointeeType(), @@ -235,7 +244,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, // We don't like to generate the trivial copy/move assignment operator // when it isn't necessary; just produce the proper effect here. llvm::Value *RHS = EmitLValue(*CE->arg_begin()).getAddress(); - EmitAggregateCopy(This, RHS, CE->getType()); + EmitAggregateAssign(This, RHS, CE->getType()); return RValue::get(This); } @@ -251,16 +260,16 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, } // Compute the function type we're calling. + const CXXMethodDecl *CalleeDecl = DevirtualizedMethod ? DevirtualizedMethod : MD; const CGFunctionInfo *FInfo = 0; - if (isa<CXXDestructorDecl>(MD)) - FInfo = &CGM.getTypes().arrangeCXXDestructor(cast<CXXDestructorDecl>(MD), + if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(CalleeDecl)) + FInfo = &CGM.getTypes().arrangeCXXDestructor(Dtor, Dtor_Complete); - else if (isa<CXXConstructorDecl>(MD)) - FInfo = &CGM.getTypes().arrangeCXXConstructorDeclaration( - cast<CXXConstructorDecl>(MD), - Ctor_Complete); + else if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(CalleeDecl)) + FInfo = &CGM.getTypes().arrangeCXXConstructorDeclaration(Ctor, + Ctor_Complete); else - FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(MD); + FInfo = &CGM.getTypes().arrangeCXXMethodDeclaration(CalleeDecl); llvm::Type *Ty = CGM.getTypes().GetFunctionType(*FInfo); @@ -277,7 +286,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, if (UseVirtualCall) { Callee = BuildVirtualCall(Dtor, Dtor_Complete, This, Ty); } else { - if (getContext().getLangOpts().AppleKext && + if (getLangOpts().AppleKext && MD->isVirtual() && ME->hasQualifier()) Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty); @@ -295,7 +304,7 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, } else if (UseVirtualCall) { Callee = BuildVirtualCall(MD, This, Ty); } else { - if (getContext().getLangOpts().AppleKext && + if (getLangOpts().AppleKext && MD->isVirtual() && ME->hasQualifier()) Callee = BuildAppleKextVirtualCall(MD, ME->getQualifier(), Ty); @@ -306,8 +315,8 @@ RValue CodeGenFunction::EmitCXXMemberCallExpr(const CXXMemberCallExpr *CE, } } - return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0, - CE->arg_begin(), CE->arg_end()); + return EmitCXXMemberCall(MD, CE->getExprLoc(), Callee, ReturnValue, This, + /*VTT=*/0, CE->arg_begin(), CE->arg_end()); } RValue @@ -337,6 +346,9 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, else This = EmitLValue(BaseExpr).getAddress(); + EmitTypeCheck(TCK_MemberCall, E->getExprLoc(), This, + QualType(MPT->getClass(), 0)); + // Ask the ABI to load the callee. Note that This is modified. llvm::Value *Callee = CGM.getCXXABI().EmitLoadOfMemberFunctionPointer(*this, This, MemFnPtr, MPT); @@ -370,13 +382,13 @@ CodeGenFunction::EmitCXXOperatorMemberCallExpr(const CXXOperatorCallExpr *E, MD->isTrivial()) { llvm::Value *Src = EmitLValue(E->getArg(1)).getAddress(); QualType Ty = E->getType(); - EmitAggregateCopy(This, Src, Ty); + EmitAggregateAssign(This, Src, Ty); return RValue::get(This); } llvm::Value *Callee = EmitCXXOperatorMemberCallee(E, MD, This); - return EmitCXXMemberCall(MD, Callee, ReturnValue, This, /*VTT=*/0, - E->arg_begin() + 1, E->arg_end()); + return EmitCXXMemberCall(MD, E->getExprLoc(), Callee, ReturnValue, This, + /*VTT=*/0, E->arg_begin() + 1, E->arg_end()); } RValue CodeGenFunction::EmitCUDAKernelCallExpr(const CUDAKernelCallExpr *E, @@ -457,7 +469,7 @@ CodeGenFunction::EmitCXXConstructExpr(const CXXConstructExpr *E, // Elide the constructor if we're constructing from a temporary. // The temporary check is required because Sema sets this on NRVO // returns. - if (getContext().getLangOpts().ElideConstructors && E->isElidable()) { + if (getLangOpts().ElideConstructors && E->isElidable()) { assert(getContext().hasSameUnqualifiedType(E->getType(), E->getArg(0)->getType())); if (E->getArg(0)->isTemporaryObject(getContext(), CD->getParent())) { @@ -878,7 +890,7 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E, if (constNum->getZExtValue() <= initializerElements) { // If there was a cleanup, deactivate it. if (cleanupDominator) - DeactivateCleanupBlock(cleanup, cleanupDominator);; + DeactivateCleanupBlock(cleanup, cleanupDominator); return; } } else { @@ -949,7 +961,6 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, if (E->isArray()) { if (const CXXConstructExpr *CCE = dyn_cast_or_null<CXXConstructExpr>(Init)){ CXXConstructorDecl *Ctor = CCE->getConstructor(); - bool RequiresZeroInitialization = false; if (Ctor->isTrivial()) { // If new expression did not specify value-initialization, then there // is no initialization. @@ -962,13 +973,11 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E, EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie); return; } - - RequiresZeroInitialization = true; } CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr, CCE->arg_begin(), CCE->arg_end(), - RequiresZeroInitialization); + CCE->requiresZeroInitialization()); return; } else if (Init && isa<ImplicitValueInitExpr>(Init) && CGF.CGM.getTypes().isZeroInitializable(ElementType)) { @@ -1230,8 +1239,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { llvm::BasicBlock *contBB = 0; llvm::Value *allocation = RV.getScalarVal(); - unsigned AS = - cast<llvm::PointerType>(allocation->getType())->getAddressSpace(); + unsigned AS = allocation->getType()->getPointerAddressSpace(); // The null-check means that the initializer is conditionally // evaluated. @@ -1377,8 +1385,14 @@ static void EmitObjectDelete(CodeGenFunction &CGF, if (UseGlobalDelete) { // If we're supposed to call the global delete, make sure we do so // even if the destructor throws. + + // Derive the complete-object pointer, which is what we need + // to pass to the deallocation function. + llvm::Value *completePtr = + CGF.CGM.getCXXABI().adjustToCompleteObject(CGF, Ptr, ElementType); + CGF.EHStack.pushCleanup<CallObjectDelete>(NormalAndEHCleanup, - Ptr, OperatorDelete, + completePtr, OperatorDelete, ElementType); } @@ -1390,8 +1404,9 @@ static void EmitObjectDelete(CodeGenFunction &CGF, = CGF.BuildVirtualCall(Dtor, UseGlobalDelete? Dtor_Complete : Dtor_Deleting, Ptr, Ty); - CGF.EmitCXXMemberCall(Dtor, Callee, ReturnValueSlot(), Ptr, /*VTT=*/0, - 0, 0); + // FIXME: Provide a source location here. + CGF.EmitCXXMemberCall(Dtor, SourceLocation(), Callee, ReturnValueSlot(), + Ptr, /*VTT=*/0, 0, 0); if (UseGlobalDelete) { CGF.PopCleanupBlock(); diff --git a/lib/CodeGen/CGExprComplex.cpp b/lib/CodeGen/CGExprComplex.cpp index 0233745afa91..66b6f8629a52 100644 --- a/lib/CodeGen/CGExprComplex.cpp +++ b/lib/CodeGen/CGExprComplex.cpp @@ -427,6 +427,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastExpr::CastKind CK, Expr *Op, case CK_ARCReclaimReturnedObject: case CK_ARCExtendBlockObject: case CK_CopyAndAutoreleaseBlockObject: + case CK_BuiltinFnToFnPtr: llvm_unreachable("invalid cast kind for complex value"); case CK_FloatingRealToComplex: @@ -640,7 +641,7 @@ EmitCompoundAssign(const CompoundAssignOperator *E, LValue LV = EmitCompoundAssignLValue(E, Func, Val); // The result of an assignment in C is the assigned r-value. - if (!CGF.getContext().getLangOpts().CPlusPlus) + if (!CGF.getLangOpts().CPlusPlus) return Val; // If the lvalue is non-volatile, return the computed value of the assignment. @@ -675,7 +676,7 @@ ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) { LValue LV = EmitBinAssignLValue(E, Val); // The result of an assignment in C is the assigned r-value. - if (!CGF.getContext().getLangOpts().CPlusPlus) + if (!CGF.getLangOpts().CPlusPlus) return Val; // If the lvalue is non-volatile, return the computed value of the assignment. diff --git a/lib/CodeGen/CGExprConstant.cpp b/lib/CodeGen/CGExprConstant.cpp index a17a43639ad7..206f74a30258 100644 --- a/lib/CodeGen/CGExprConstant.cpp +++ b/lib/CodeGen/CGExprConstant.cpp @@ -24,7 +24,7 @@ #include "llvm/Constants.h" #include "llvm/Function.h" #include "llvm/GlobalVariable.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" using namespace clang; using namespace CodeGen; @@ -79,12 +79,12 @@ private: CharUnits getAlignment(const llvm::Constant *C) const { if (Packed) return CharUnits::One(); return CharUnits::fromQuantity( - CGM.getTargetData().getABITypeAlignment(C->getType())); + CGM.getDataLayout().getABITypeAlignment(C->getType())); } CharUnits getSizeInChars(const llvm::Constant *C) const { return CharUnits::fromQuantity( - CGM.getTargetData().getTypeAllocSize(C->getType())); + CGM.getDataLayout().getTypeAllocSize(C->getType())); } }; @@ -204,7 +204,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, if (!FitsCompletelyInPreviousByte) { unsigned NewFieldWidth = FieldSize - BitsInPreviousByte; - if (CGM.getTargetData().isBigEndian()) { + if (CGM.getDataLayout().isBigEndian()) { Tmp = Tmp.lshr(NewFieldWidth); Tmp = Tmp.trunc(BitsInPreviousByte); @@ -220,7 +220,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, } Tmp = Tmp.zext(CharWidth); - if (CGM.getTargetData().isBigEndian()) { + if (CGM.getDataLayout().isBigEndian()) { if (FitsCompletelyInPreviousByte) Tmp = Tmp.shl(BitsInPreviousByte - FieldValue.getBitWidth()); } else { @@ -269,7 +269,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, while (FieldValue.getBitWidth() > CharWidth) { llvm::APInt Tmp; - if (CGM.getTargetData().isBigEndian()) { + if (CGM.getDataLayout().isBigEndian()) { // We want the high bits. Tmp = FieldValue.lshr(FieldValue.getBitWidth() - CharWidth).trunc(CharWidth); @@ -292,7 +292,7 @@ void ConstStructBuilder::AppendBitField(const FieldDecl *Field, "Should not have more than a byte left!"); if (FieldValue.getBitWidth() < CharWidth) { - if (CGM.getTargetData().isBigEndian()) { + if (CGM.getDataLayout().isBigEndian()) { unsigned BitWidth = FieldValue.getBitWidth(); FieldValue = FieldValue.zext(CharWidth) << (CharWidth - BitWidth); @@ -337,7 +337,7 @@ void ConstStructBuilder::ConvertStructToPacked() { llvm::Constant *C = Elements[i]; CharUnits ElementAlign = CharUnits::fromQuantity( - CGM.getTargetData().getABITypeAlignment(C->getType())); + CGM.getDataLayout().getABITypeAlignment(C->getType())); CharUnits AlignedElementOffsetInChars = ElementOffsetInChars.RoundUpToAlignment(ElementAlign); @@ -379,7 +379,7 @@ bool ConstStructBuilder::Build(InitListExpr *ILE) { unsigned FieldNo = 0; unsigned ElementNo = 0; const FieldDecl *LastFD = 0; - bool IsMsStruct = RD->hasAttr<MsStructAttr>(); + bool IsMsStruct = RD->isMsStruct(CGM.getContext()); for (RecordDecl::field_iterator Field = RD->field_begin(), FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { @@ -478,7 +478,7 @@ void ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, unsigned FieldNo = 0; const FieldDecl *LastFD = 0; - bool IsMsStruct = RD->hasAttr<MsStructAttr>(); + bool IsMsStruct = RD->isMsStruct(CGM.getContext()); uint64_t OffsetBits = CGM.getContext().toBits(Offset); for (RecordDecl::field_iterator Field = RD->field_begin(), @@ -665,8 +665,8 @@ public: SmallVector<llvm::Type*, 2> Types; Elts.push_back(C); Types.push_back(C->getType()); - unsigned CurSize = CGM.getTargetData().getTypeAllocSize(C->getType()); - unsigned TotalSize = CGM.getTargetData().getTypeAllocSize(destType); + unsigned CurSize = CGM.getDataLayout().getTypeAllocSize(C->getType()); + unsigned TotalSize = CGM.getDataLayout().getTypeAllocSize(destType); assert(CurSize <= TotalSize && "Union size mismatch!"); if (unsigned NumPadBytes = TotalSize - CurSize) { @@ -691,6 +691,9 @@ public: case CK_Dependent: llvm_unreachable("saw dependent cast!"); + case CK_BuiltinFnToFnPtr: + llvm_unreachable("builtin functions are handled elsewhere"); + case CK_ReinterpretMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_BaseToDerivedMemberPointer: @@ -811,11 +814,7 @@ public: return llvm::ConstantArray::get(AType, Elts); } - llvm::Constant *EmitStructInitialization(InitListExpr *ILE) { - return ConstStructBuilder::BuildStruct(CGM, CGF, ILE); - } - - llvm::Constant *EmitUnionInitialization(InitListExpr *ILE) { + llvm::Constant *EmitRecordInitialization(InitListExpr *ILE) { return ConstStructBuilder::BuildStruct(CGM, CGF, ILE); } @@ -828,10 +827,7 @@ public: return EmitArrayInitialization(ILE); if (ILE->getType()->isRecordType()) - return EmitStructInitialization(ILE); - - if (ILE->getType()->isUnionType()) - return EmitUnionInitialization(ILE); + return EmitRecordInitialization(ILE); return 0; } @@ -999,6 +995,9 @@ public: T = Typeid->getExprOperand()->getType(); return CGM.GetAddrOfRTTIDescriptor(T); } + case Expr::CXXUuidofExprClass: { + return CGM.GetAddrOfUuidDescriptor(cast<CXXUuidofExpr>(E)); + } } return 0; diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 1cccafe0d787..b429b1d6e47e 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -28,7 +28,7 @@ #include "llvm/Intrinsics.h" #include "llvm/Module.h" #include "llvm/Support/CFG.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include <cstdarg> using namespace clang; @@ -45,6 +45,7 @@ struct BinOpInfo { Value *RHS; QualType Ty; // Computation Type. BinaryOperator::Opcode Opcode; // Opcode of BinOp to perform + bool FPContractable; const Expr *E; // Entire expr, for error unsupported. May not be binop. }; @@ -80,7 +81,11 @@ public: llvm::Type *ConvertType(QualType T) { return CGF.ConvertType(T); } LValue EmitLValue(const Expr *E) { return CGF.EmitLValue(E); } - LValue EmitCheckedLValue(const Expr *E) { return CGF.EmitCheckedLValue(E); } + LValue EmitCheckedLValue(const Expr *E, CodeGenFunction::TypeCheckKind TCK) { + return CGF.EmitCheckedLValue(E, TCK); + } + + void EmitBinOpCheck(Value *Check, const BinOpInfo &Info); Value *EmitLoadOfLValue(LValue LV) { return CGF.EmitLoadOfLValue(LV).getScalarVal(); @@ -90,13 +95,19 @@ public: /// value l-value, this method emits the address of the l-value, then loads /// and returns the result. Value *EmitLoadOfLValue(const Expr *E) { - return EmitLoadOfLValue(EmitCheckedLValue(E)); + return EmitLoadOfLValue(EmitCheckedLValue(E, CodeGenFunction::TCK_Load)); } /// EmitConversionToBool - Convert the specified expression value to a /// boolean (i1) truth value. This is equivalent to "Val != 0". Value *EmitConversionToBool(Value *Src, QualType DstTy); + /// \brief Emit a check that a conversion to or from a floating-point type + /// does not overflow. + void EmitFloatConversionCheck(Value *OrigSrc, QualType OrigSrcType, + Value *Src, QualType SrcType, + QualType DstType, llvm::Type *DstTy); + /// EmitScalarConversion - Emit a conversion from the specified type to the /// specified destination type, both of which are LLVM scalar types. Value *EmitScalarConversion(Value *Src, QualType SrcTy, QualType DstTy); @@ -391,34 +402,26 @@ public: // Binary Operators. Value *EmitMul(const BinOpInfo &Ops) { if (Ops.Ty->isSignedIntegerOrEnumerationType()) { - switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) { - case LangOptions::SOB_Undefined: - return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); + switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); + case LangOptions::SOB_Undefined: + if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow) + return Builder.CreateNSWMul(Ops.LHS, Ops.RHS, "mul"); + // Fall through. case LangOptions::SOB_Trapping: return EmitOverflowCheckedBinOp(Ops); } } - + if (Ops.LHS->getType()->isFPOrFPVectorTy()) return Builder.CreateFMul(Ops.LHS, Ops.RHS, "mul"); return Builder.CreateMul(Ops.LHS, Ops.RHS, "mul"); } - bool isTrapvOverflowBehavior() { - return CGF.getContext().getLangOpts().getSignedOverflowBehavior() - == LangOptions::SOB_Trapping; - } /// Create a binary op that checks for overflow. /// Currently only supports +, - and *. Value *EmitOverflowCheckedBinOp(const BinOpInfo &Ops); - // Emit the overflow BB when -ftrapv option is activated. - void EmitOverflowBB(llvm::BasicBlock *overflowBB) { - Builder.SetInsertPoint(overflowBB); - llvm::Function *Trap = CGF.CGM.getIntrinsic(llvm::Intrinsic::trap); - Builder.CreateCall(Trap); - Builder.CreateUnreachable(); - } + // Check for undefined division and modulus behaviors. void EmitUndefinedBehaviorIntegerDivAndRemCheck(const BinOpInfo &Ops, llvm::Value *Zero,bool isDiv); @@ -537,6 +540,110 @@ Value *ScalarExprEmitter::EmitConversionToBool(Value *Src, QualType SrcType) { return EmitPointerToBoolConversion(Src); } +void ScalarExprEmitter::EmitFloatConversionCheck(Value *OrigSrc, + QualType OrigSrcType, + Value *Src, QualType SrcType, + QualType DstType, + llvm::Type *DstTy) { + using llvm::APFloat; + using llvm::APSInt; + + llvm::Type *SrcTy = Src->getType(); + + llvm::Value *Check = 0; + if (llvm::IntegerType *IntTy = dyn_cast<llvm::IntegerType>(SrcTy)) { + // Integer to floating-point. This can fail for unsigned short -> __half + // or unsigned __int128 -> float. + assert(DstType->isFloatingType()); + bool SrcIsUnsigned = OrigSrcType->isUnsignedIntegerOrEnumerationType(); + + APFloat LargestFloat = + APFloat::getLargest(CGF.getContext().getFloatTypeSemantics(DstType)); + APSInt LargestInt(IntTy->getBitWidth(), SrcIsUnsigned); + + bool IsExact; + if (LargestFloat.convertToInteger(LargestInt, APFloat::rmTowardZero, + &IsExact) != APFloat::opOK) + // The range of representable values of this floating point type includes + // all values of this integer type. Don't need an overflow check. + return; + + llvm::Value *Max = llvm::ConstantInt::get(VMContext, LargestInt); + if (SrcIsUnsigned) + Check = Builder.CreateICmpULE(Src, Max); + else { + llvm::Value *Min = llvm::ConstantInt::get(VMContext, -LargestInt); + llvm::Value *GE = Builder.CreateICmpSGE(Src, Min); + llvm::Value *LE = Builder.CreateICmpSLE(Src, Max); + Check = Builder.CreateAnd(GE, LE); + } + } else { + // Floating-point to integer or floating-point to floating-point. This has + // undefined behavior if the source is +-Inf, NaN, or doesn't fit into the + // destination type. + const llvm::fltSemantics &SrcSema = + CGF.getContext().getFloatTypeSemantics(OrigSrcType); + APFloat MaxSrc(SrcSema, APFloat::uninitialized); + APFloat MinSrc(SrcSema, APFloat::uninitialized); + + if (isa<llvm::IntegerType>(DstTy)) { + unsigned Width = CGF.getContext().getIntWidth(DstType); + bool Unsigned = DstType->isUnsignedIntegerOrEnumerationType(); + + APSInt Min = APSInt::getMinValue(Width, Unsigned); + if (MinSrc.convertFromAPInt(Min, !Unsigned, APFloat::rmTowardZero) & + APFloat::opOverflow) + // Don't need an overflow check for lower bound. Just check for + // -Inf/NaN. + MinSrc = APFloat::getLargest(SrcSema, true); + + APSInt Max = APSInt::getMaxValue(Width, Unsigned); + if (MaxSrc.convertFromAPInt(Max, !Unsigned, APFloat::rmTowardZero) & + APFloat::opOverflow) + // Don't need an overflow check for upper bound. Just check for + // +Inf/NaN. + MaxSrc = APFloat::getLargest(SrcSema, false); + } else { + const llvm::fltSemantics &DstSema = + CGF.getContext().getFloatTypeSemantics(DstType); + bool IsInexact; + + MinSrc = APFloat::getLargest(DstSema, true); + if (MinSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) & + APFloat::opOverflow) + MinSrc = APFloat::getLargest(SrcSema, true); + + MaxSrc = APFloat::getLargest(DstSema, false); + if (MaxSrc.convert(SrcSema, APFloat::rmTowardZero, &IsInexact) & + APFloat::opOverflow) + MaxSrc = APFloat::getLargest(SrcSema, false); + } + + // If we're converting from __half, convert the range to float to match + // the type of src. + if (OrigSrcType->isHalfType()) { + const llvm::fltSemantics &Sema = + CGF.getContext().getFloatTypeSemantics(SrcType); + bool IsInexact; + MinSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact); + MaxSrc.convert(Sema, APFloat::rmTowardZero, &IsInexact); + } + + llvm::Value *GE = + Builder.CreateFCmpOGE(Src, llvm::ConstantFP::get(VMContext, MinSrc)); + llvm::Value *LE = + Builder.CreateFCmpOLE(Src, llvm::ConstantFP::get(VMContext, MaxSrc)); + Check = Builder.CreateAnd(GE, LE); + } + + // FIXME: Provide a SourceLocation. + llvm::Constant *StaticArgs[] = { + CGF.EmitCheckTypeDescriptor(OrigSrcType), + CGF.EmitCheckTypeDescriptor(DstType) + }; + CGF.EmitCheck(Check, "float_cast_overflow", StaticArgs, OrigSrc); +} + /// EmitScalarConversion - Emit a conversion from the specified type to the /// specified destination type, both of which are LLVM scalar types. Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, @@ -547,6 +654,8 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, if (DstType->isVoidType()) return 0; + llvm::Value *OrigSrc = Src; + QualType OrigSrcType = SrcType; llvm::Type *SrcTy = Src->getType(); // Floating casts might be a bit special: if we're doing casts to / from half @@ -620,6 +729,12 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType, Value *Res = NULL; llvm::Type *ResTy = DstTy; + // An overflowing conversion has undefined behavior if either the source type + // or the destination type is a floating-point type. + if (CGF.getLangOpts().SanitizeFloatCastOverflow && + (OrigSrcType->isFloatingType() || DstType->isFloatingType())) + EmitFloatConversionCheck(OrigSrc, OrigSrcType, Src, SrcType, DstType, DstTy); + // Cast to half via float if (DstType->isHalfType()) DstTy = CGF.FloatTy; @@ -686,6 +801,54 @@ Value *ScalarExprEmitter::EmitNullValue(QualType Ty) { return llvm::Constant::getNullValue(ConvertType(Ty)); } +/// \brief Emit a sanitization check for the given "binary" operation (which +/// might actually be a unary increment which has been lowered to a binary +/// operation). The check passes if \p Check, which is an \c i1, is \c true. +void ScalarExprEmitter::EmitBinOpCheck(Value *Check, const BinOpInfo &Info) { + StringRef CheckName; + llvm::SmallVector<llvm::Constant *, 4> StaticData; + llvm::SmallVector<llvm::Value *, 2> DynamicData; + + BinaryOperatorKind Opcode = Info.Opcode; + if (BinaryOperator::isCompoundAssignmentOp(Opcode)) + Opcode = BinaryOperator::getOpForCompoundAssignment(Opcode); + + StaticData.push_back(CGF.EmitCheckSourceLocation(Info.E->getExprLoc())); + const UnaryOperator *UO = dyn_cast<UnaryOperator>(Info.E); + if (UO && UO->getOpcode() == UO_Minus) { + CheckName = "negate_overflow"; + StaticData.push_back(CGF.EmitCheckTypeDescriptor(UO->getType())); + DynamicData.push_back(Info.RHS); + } else { + if (BinaryOperator::isShiftOp(Opcode)) { + // Shift LHS negative or too large, or RHS out of bounds. + CheckName = "shift_out_of_bounds"; + const BinaryOperator *BO = cast<BinaryOperator>(Info.E); + StaticData.push_back( + CGF.EmitCheckTypeDescriptor(BO->getLHS()->getType())); + StaticData.push_back( + CGF.EmitCheckTypeDescriptor(BO->getRHS()->getType())); + } else if (Opcode == BO_Div || Opcode == BO_Rem) { + // Divide or modulo by zero, or signed overflow (eg INT_MAX / -1). + CheckName = "divrem_overflow"; + StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.E->getType())); + } else { + // Signed arithmetic overflow (+, -, *). + switch (Opcode) { + case BO_Add: CheckName = "add_overflow"; break; + case BO_Sub: CheckName = "sub_overflow"; break; + case BO_Mul: CheckName = "mul_overflow"; break; + default: llvm_unreachable("unexpected opcode for bin op check"); + } + StaticData.push_back(CGF.EmitCheckTypeDescriptor(Info.E->getType())); + } + DynamicData.push_back(Info.LHS); + DynamicData.push_back(Info.RHS); + } + + CGF.EmitCheck(Check, CheckName, StaticData, DynamicData); +} + //===----------------------------------------------------------------------===// // Visitor Methods //===----------------------------------------------------------------------===// @@ -802,7 +965,8 @@ Value *ScalarExprEmitter::VisitMemberExpr(MemberExpr *E) { // debug info size. CGDebugInfo *DI = CGF.getDebugInfo(); if (DI && - CGF.CGM.getCodeGenOpts().DebugInfo == CodeGenOptions::LimitedDebugInfo) { + CGF.CGM.getCodeGenOpts().getDebugInfo() + == CodeGenOptions::LimitedDebugInfo) { QualType PQTy = E->getBase()->IgnoreParenImpCasts()->getType(); if (const PointerType * PTy = dyn_cast<PointerType>(PQTy)) if (FieldDecl *M = dyn_cast<FieldDecl>(E->getMemberDecl())) @@ -1032,7 +1196,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { // are in the same order as in the CastKind enum. switch (Kind) { case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!"); - + case CK_BuiltinFnToFnPtr: + llvm_unreachable("builtin functions are handled elsewhere"); + case CK_LValueBitCast: case CK_ObjCObjectLValueCast: { Value *V = EmitLValue(E).getAddress(); @@ -1055,19 +1221,18 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { return Visit(const_cast<Expr*>(E)); case CK_BaseToDerived: { - const CXXRecordDecl *DerivedClassDecl = - DestTy->getCXXRecordDeclForPointerType(); - - return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl, + const CXXRecordDecl *DerivedClassDecl = DestTy->getPointeeCXXRecordDecl(); + assert(DerivedClassDecl && "BaseToDerived arg isn't a C++ object pointer!"); + + return CGF.GetAddressOfDerivedClass(Visit(E), DerivedClassDecl, CE->path_begin(), CE->path_end(), ShouldNullCheckClassCastValue(CE)); } case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { - const RecordType *DerivedClassTy = - E->getType()->getAs<PointerType>()->getPointeeType()->getAs<RecordType>(); - CXXRecordDecl *DerivedClassDecl = - cast<CXXRecordDecl>(DerivedClassTy->getDecl()); + const CXXRecordDecl *DerivedClassDecl = + E->getType()->getPointeeCXXRecordDecl(); + assert(DerivedClassDecl && "DerivedToBase arg isn't a C++ object pointer!"); return CGF.GetAddressOfBaseClass(Visit(E), DerivedClassDecl, CE->path_begin(), CE->path_end(), @@ -1248,17 +1413,20 @@ llvm::Value *ScalarExprEmitter:: EmitAddConsiderOverflowBehavior(const UnaryOperator *E, llvm::Value *InVal, llvm::Value *NextVal, bool IsInc) { - switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) { - case LangOptions::SOB_Undefined: - return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec"); + switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: return Builder.CreateAdd(InVal, NextVal, IsInc ? "inc" : "dec"); + case LangOptions::SOB_Undefined: + if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow) + return Builder.CreateNSWAdd(InVal, NextVal, IsInc ? "inc" : "dec"); + // Fall through. case LangOptions::SOB_Trapping: BinOpInfo BinOp; BinOp.LHS = InVal; BinOp.RHS = NextVal; BinOp.Ty = E->getType(); BinOp.Opcode = BO_Add; + BinOp.FPContractable = false; BinOp.E = E; return EmitOverflowCheckedBinOp(BinOp); } @@ -1300,7 +1468,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, // Most common case by far: integer increment. } else if (type->isIntegerType()) { - llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount); + llvm::Value *amt = llvm::ConstantInt::get(value->getType(), amount, true); // Note that signed integer inc/dec with width less than int can't // overflow because of promotion rules; we're just eliding a few steps here. @@ -1320,7 +1488,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, = CGF.getContext().getAsVariableArrayType(type)) { llvm::Value *numElts = CGF.getVLASize(vla).first; if (!isInc) numElts = Builder.CreateNSWNeg(numElts, "vla.negsize"); - if (CGF.getContext().getLangOpts().isSignedOverflowDefined()) + if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, numElts, "vla.inc"); else value = Builder.CreateInBoundsGEP(value, numElts, "vla.inc"); @@ -1330,7 +1498,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, llvm::Value *amt = Builder.getInt32(amount); value = CGF.EmitCastToVoidPtr(value); - if (CGF.getContext().getLangOpts().isSignedOverflowDefined()) + if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, amt, "incdec.funcptr"); else value = Builder.CreateInBoundsGEP(value, amt, "incdec.funcptr"); @@ -1339,7 +1507,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, // For everything else, we can just do a simple increment. } else { llvm::Value *amt = Builder.getInt32(amount); - if (CGF.getContext().getLangOpts().isSignedOverflowDefined()) + if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, amt, "incdec.ptr"); else value = Builder.CreateInBoundsGEP(value, amt, "incdec.ptr"); @@ -1400,7 +1568,7 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, llvm::Value *sizeValue = llvm::ConstantInt::get(CGF.SizeTy, size.getQuantity()); - if (CGF.getContext().getLangOpts().isSignedOverflowDefined()) + if (CGF.getLangOpts().isSignedOverflowDefined()) value = Builder.CreateGEP(value, sizeValue, "incdec.objptr"); else value = Builder.CreateInBoundsGEP(value, sizeValue, "incdec.objptr"); @@ -1444,6 +1612,7 @@ Value *ScalarExprEmitter::VisitUnaryMinus(const UnaryOperator *E) { BinOp.LHS = llvm::Constant::getNullValue(BinOp.RHS->getType()); BinOp.Ty = E->getType(); BinOp.Opcode = BO_Sub; + BinOp.FPContractable = false; BinOp.E = E; return EmitSub(BinOp); } @@ -1652,6 +1821,7 @@ BinOpInfo ScalarExprEmitter::EmitBinOps(const BinaryOperator *E) { Result.RHS = Visit(E->getRHS()); Result.Ty = E->getType(); Result.Opcode = E->getOpcode(); + Result.FPContractable = E->isFPContractable(); Result.E = E; return Result; } @@ -1678,9 +1848,10 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue( OpInfo.RHS = Visit(E->getRHS()); OpInfo.Ty = E->getComputationResultType(); OpInfo.Opcode = E->getOpcode(); + OpInfo.FPContractable = false; OpInfo.E = E; // Load/convert the LHS. - LValue LHSLV = EmitCheckedLValue(E->getLHS()); + LValue LHSLV = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); OpInfo.LHS = EmitLoadOfLValue(LHSLV); llvm::PHINode *atomicPHI = 0; @@ -1740,7 +1911,7 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, return 0; // The result of an assignment in C is the assigned r-value. - if (!CGF.getContext().getLangOpts().CPlusPlus) + if (!CGF.getLangOpts().CPlusPlus) return RHS; // If the lvalue is non-volatile, return the computed value of the assignment. @@ -1752,56 +1923,44 @@ Value *ScalarExprEmitter::EmitCompoundAssign(const CompoundAssignOperator *E, } void ScalarExprEmitter::EmitUndefinedBehaviorIntegerDivAndRemCheck( - const BinOpInfo &Ops, - llvm::Value *Zero, bool isDiv) { - llvm::Function::iterator insertPt = Builder.GetInsertBlock(); - llvm::BasicBlock *contBB = - CGF.createBasicBlock(isDiv ? "div.cont" : "rem.cont", CGF.CurFn, - llvm::next(insertPt)); - llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", CGF.CurFn); + const BinOpInfo &Ops, llvm::Value *Zero, bool isDiv) { + llvm::Value *Cond = 0; + + if (CGF.getLangOpts().SanitizeDivideByZero) + Cond = Builder.CreateICmpNE(Ops.RHS, Zero); - llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType()); + if (CGF.getLangOpts().SanitizeSignedIntegerOverflow && + Ops.Ty->hasSignedIntegerRepresentation()) { + llvm::IntegerType *Ty = cast<llvm::IntegerType>(Zero->getType()); - if (Ops.Ty->hasSignedIntegerRepresentation()) { llvm::Value *IntMin = Builder.getInt(llvm::APInt::getSignedMinValue(Ty->getBitWidth())); llvm::Value *NegOne = llvm::ConstantInt::get(Ty, -1ULL); - llvm::Value *Cond1 = Builder.CreateICmpEQ(Ops.RHS, Zero); - llvm::Value *LHSCmp = Builder.CreateICmpEQ(Ops.LHS, IntMin); - llvm::Value *RHSCmp = Builder.CreateICmpEQ(Ops.RHS, NegOne); - llvm::Value *Cond2 = Builder.CreateAnd(LHSCmp, RHSCmp, "and"); - Builder.CreateCondBr(Builder.CreateOr(Cond1, Cond2, "or"), - overflowBB, contBB); - } else { - CGF.Builder.CreateCondBr(Builder.CreateICmpEQ(Ops.RHS, Zero), - overflowBB, contBB); + llvm::Value *LHSCmp = Builder.CreateICmpNE(Ops.LHS, IntMin); + llvm::Value *RHSCmp = Builder.CreateICmpNE(Ops.RHS, NegOne); + llvm::Value *Overflow = Builder.CreateOr(LHSCmp, RHSCmp, "or"); + Cond = Cond ? Builder.CreateAnd(Cond, Overflow, "and") : Overflow; } - EmitOverflowBB(overflowBB); - Builder.SetInsertPoint(contBB); + + if (Cond) + EmitBinOpCheck(Cond, Ops); } Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { - if (isTrapvOverflowBehavior()) { + if (CGF.getLangOpts().SanitizeDivideByZero || + CGF.getLangOpts().SanitizeSignedIntegerOverflow) { llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); if (Ops.Ty->isIntegerType()) EmitUndefinedBehaviorIntegerDivAndRemCheck(Ops, Zero, true); - else if (Ops.Ty->isRealFloatingType()) { - llvm::Function::iterator insertPt = Builder.GetInsertBlock(); - llvm::BasicBlock *DivCont = CGF.createBasicBlock("div.cont", CGF.CurFn, - llvm::next(insertPt)); - llvm::BasicBlock *overflowBB = CGF.createBasicBlock("overflow", - CGF.CurFn); - CGF.Builder.CreateCondBr(Builder.CreateFCmpOEQ(Ops.RHS, Zero), - overflowBB, DivCont); - EmitOverflowBB(overflowBB); - Builder.SetInsertPoint(DivCont); - } + else if (CGF.getLangOpts().SanitizeDivideByZero && + Ops.Ty->isRealFloatingType()) + EmitBinOpCheck(Builder.CreateFCmpUNE(Ops.RHS, Zero), Ops); } if (Ops.LHS->getType()->isFPOrFPVectorTy()) { llvm::Value *Val = Builder.CreateFDiv(Ops.LHS, Ops.RHS, "div"); - if (CGF.getContext().getLangOpts().OpenCL) { + if (CGF.getLangOpts().OpenCL) { // OpenCL 1.1 7.4: minimum accuracy of single precision / is 2.5ulp llvm::Type *ValTy = Val->getType(); if (ValTy->isFloatTy() || @@ -1819,7 +1978,7 @@ Value *ScalarExprEmitter::EmitDiv(const BinOpInfo &Ops) { Value *ScalarExprEmitter::EmitRem(const BinOpInfo &Ops) { // Rem in C can't be a floating point type: C99 6.5.5p2. - if (isTrapvOverflowBehavior()) { + if (CGF.getLangOpts().SanitizeDivideByZero) { llvm::Value *Zero = llvm::Constant::getNullValue(ConvertType(Ops.Ty)); if (Ops.Ty->isIntegerType()) @@ -1866,6 +2025,19 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { Value *result = Builder.CreateExtractValue(resultAndOverflow, 0); Value *overflow = Builder.CreateExtractValue(resultAndOverflow, 1); + // Handle overflow with llvm.trap if no custom handler has been specified. + const std::string *handlerName = + &CGF.getLangOpts().OverflowHandler; + if (handlerName->empty()) { + // If the signed-integer-overflow sanitizer is enabled, emit a call to its + // runtime. Otherwise, this is a -ftrapv check, so just emit a trap. + if (CGF.getLangOpts().SanitizeSignedIntegerOverflow) + EmitBinOpCheck(Builder.CreateNot(overflow), Ops); + else + CGF.EmitTrapvCheck(Builder.CreateNot(overflow)); + return result; + } + // Branch in case of overflow. llvm::BasicBlock *initialBB = Builder.GetInsertBlock(); llvm::Function::iterator insertPt = initialBB; @@ -1875,15 +2047,6 @@ Value *ScalarExprEmitter::EmitOverflowCheckedBinOp(const BinOpInfo &Ops) { Builder.CreateCondBr(overflow, overflowBB, continueBB); - // Handle overflow with llvm.trap. - const std::string *handlerName = - &CGF.getContext().getLangOpts().OverflowHandler; - if (handlerName->empty()) { - EmitOverflowBB(overflowBB); - Builder.SetInsertPoint(continueBB); - return result; - } - // If an overflow handler is set, then we want to call it and then use its // result, if it returns. Builder.SetInsertPoint(overflowBB); @@ -2001,24 +2164,106 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, return CGF.Builder.CreateInBoundsGEP(pointer, index, "add.ptr"); } +// Construct an fmuladd intrinsic to represent a fused mul-add of MulOp and +// Addend. Use negMul and negAdd to negate the first operand of the Mul or +// the add operand respectively. This allows fmuladd to represent a*b-c, or +// c-a*b. Patterns in LLVM should catch the negated forms and translate them to +// efficient operations. +static Value* buildFMulAdd(llvm::BinaryOperator *MulOp, Value *Addend, + const CodeGenFunction &CGF, CGBuilderTy &Builder, + bool negMul, bool negAdd) { + assert(!(negMul && negAdd) && "Only one of negMul and negAdd should be set."); + + Value *MulOp0 = MulOp->getOperand(0); + Value *MulOp1 = MulOp->getOperand(1); + if (negMul) { + MulOp0 = + Builder.CreateFSub( + llvm::ConstantFP::getZeroValueForNegation(MulOp0->getType()), MulOp0, + "neg"); + } else if (negAdd) { + Addend = + Builder.CreateFSub( + llvm::ConstantFP::getZeroValueForNegation(Addend->getType()), Addend, + "neg"); + } + + Value *FMulAdd = + Builder.CreateCall3( + CGF.CGM.getIntrinsic(llvm::Intrinsic::fmuladd, Addend->getType()), + MulOp0, MulOp1, Addend); + MulOp->eraseFromParent(); + + return FMulAdd; +} + +// Check whether it would be legal to emit an fmuladd intrinsic call to +// represent op and if so, build the fmuladd. +// +// Checks that (a) the operation is fusable, and (b) -ffp-contract=on. +// Does NOT check the type of the operation - it's assumed that this function +// will be called from contexts where it's known that the type is contractable. +static Value* tryEmitFMulAdd(const BinOpInfo &op, + const CodeGenFunction &CGF, CGBuilderTy &Builder, + bool isSub=false) { + + assert((op.Opcode == BO_Add || op.Opcode == BO_AddAssign || + op.Opcode == BO_Sub || op.Opcode == BO_SubAssign) && + "Only fadd/fsub can be the root of an fmuladd."); + + // Check whether this op is marked as fusable. + if (!op.FPContractable) + return 0; + + // Check whether -ffp-contract=on. (If -ffp-contract=off/fast, fusing is + // either disabled, or handled entirely by the LLVM backend). + if (CGF.getLangOpts().getFPContractMode() != LangOptions::FPC_On) + return 0; + + // We have a potentially fusable op. Look for a mul on one of the operands. + if (llvm::BinaryOperator* LHSBinOp = dyn_cast<llvm::BinaryOperator>(op.LHS)) { + if (LHSBinOp->getOpcode() == llvm::Instruction::FMul) { + assert(LHSBinOp->getNumUses() == 0 && + "Operations with multiple uses shouldn't be contracted."); + return buildFMulAdd(LHSBinOp, op.RHS, CGF, Builder, false, isSub); + } + } else if (llvm::BinaryOperator* RHSBinOp = + dyn_cast<llvm::BinaryOperator>(op.RHS)) { + if (RHSBinOp->getOpcode() == llvm::Instruction::FMul) { + assert(RHSBinOp->getNumUses() == 0 && + "Operations with multiple uses shouldn't be contracted."); + return buildFMulAdd(RHSBinOp, op.LHS, CGF, Builder, isSub, false); + } + } + + return 0; +} + Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) { if (op.LHS->getType()->isPointerTy() || op.RHS->getType()->isPointerTy()) return emitPointerArithmetic(CGF, op, /*subtraction*/ false); if (op.Ty->isSignedIntegerOrEnumerationType()) { - switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) { - case LangOptions::SOB_Undefined: - return Builder.CreateNSWAdd(op.LHS, op.RHS, "add"); + switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: return Builder.CreateAdd(op.LHS, op.RHS, "add"); + case LangOptions::SOB_Undefined: + if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow) + return Builder.CreateNSWAdd(op.LHS, op.RHS, "add"); + // Fall through. case LangOptions::SOB_Trapping: return EmitOverflowCheckedBinOp(op); } } - if (op.LHS->getType()->isFPOrFPVectorTy()) + if (op.LHS->getType()->isFPOrFPVectorTy()) { + // Try to form an fmuladd. + if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder)) + return FMulAdd; + return Builder.CreateFAdd(op.LHS, op.RHS, "add"); + } return Builder.CreateAdd(op.LHS, op.RHS, "add"); } @@ -2027,18 +2272,24 @@ Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) { // The LHS is always a pointer if either side is. if (!op.LHS->getType()->isPointerTy()) { if (op.Ty->isSignedIntegerOrEnumerationType()) { - switch (CGF.getContext().getLangOpts().getSignedOverflowBehavior()) { - case LangOptions::SOB_Undefined: - return Builder.CreateNSWSub(op.LHS, op.RHS, "sub"); + switch (CGF.getLangOpts().getSignedOverflowBehavior()) { case LangOptions::SOB_Defined: return Builder.CreateSub(op.LHS, op.RHS, "sub"); + case LangOptions::SOB_Undefined: + if (!CGF.getLangOpts().SanitizeSignedIntegerOverflow) + return Builder.CreateNSWSub(op.LHS, op.RHS, "sub"); + // Fall through. case LangOptions::SOB_Trapping: return EmitOverflowCheckedBinOp(op); } } - if (op.LHS->getType()->isFPOrFPVectorTy()) + if (op.LHS->getType()->isFPOrFPVectorTy()) { + // Try to form an fmuladd. + if (Value *FMulAdd = tryEmitFMulAdd(op, CGF, Builder, true)) + return FMulAdd; return Builder.CreateFSub(op.LHS, op.RHS, "sub"); + } return Builder.CreateSub(op.LHS, op.RHS, "sub"); } @@ -2108,14 +2359,34 @@ Value *ScalarExprEmitter::EmitShl(const BinOpInfo &Ops) { if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); - if (CGF.CatchUndefined - && isa<llvm::IntegerType>(Ops.LHS->getType())) { + if (CGF.getLangOpts().SanitizeShift && + isa<llvm::IntegerType>(Ops.LHS->getType())) { unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth(); - llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); - CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS, - llvm::ConstantInt::get(RHS->getType(), Width)), - Cont, CGF.getTrapBB()); - CGF.EmitBlock(Cont); + llvm::Value *WidthMinusOne = + llvm::ConstantInt::get(RHS->getType(), Width - 1); + // FIXME: Emit the branching explicitly rather than emitting the check + // twice. + EmitBinOpCheck(Builder.CreateICmpULE(RHS, WidthMinusOne), Ops); + + if (Ops.Ty->hasSignedIntegerRepresentation()) { + // Check whether we are shifting any non-zero bits off the top of the + // integer. + llvm::Value *BitsShiftedOff = + Builder.CreateLShr(Ops.LHS, + Builder.CreateSub(WidthMinusOne, RHS, "shl.zeros", + /*NUW*/true, /*NSW*/true), + "shl.check"); + if (CGF.getLangOpts().CPlusPlus) { + // In C99, we are not permitted to shift a 1 bit into the sign bit. + // Under C++11's rules, shifting a 1 bit into the sign bit is + // OK, but shifting a 1 bit out of it is not. (C89 and C++03 don't + // define signed left shifts, so we use the C99 and C++11 rules there). + llvm::Value *One = llvm::ConstantInt::get(BitsShiftedOff->getType(), 1); + BitsShiftedOff = Builder.CreateLShr(BitsShiftedOff, One); + } + llvm::Value *Zero = llvm::ConstantInt::get(BitsShiftedOff->getType(), 0); + EmitBinOpCheck(Builder.CreateICmpEQ(BitsShiftedOff, Zero), Ops); + } } return Builder.CreateShl(Ops.LHS, RHS, "shl"); @@ -2128,14 +2399,11 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { if (Ops.LHS->getType() != RHS->getType()) RHS = Builder.CreateIntCast(RHS, Ops.LHS->getType(), false, "sh_prom"); - if (CGF.CatchUndefined - && isa<llvm::IntegerType>(Ops.LHS->getType())) { + if (CGF.getLangOpts().SanitizeShift && + isa<llvm::IntegerType>(Ops.LHS->getType())) { unsigned Width = cast<llvm::IntegerType>(Ops.LHS->getType())->getBitWidth(); - llvm::BasicBlock *Cont = CGF.createBasicBlock("cont"); - CGF.Builder.CreateCondBr(Builder.CreateICmpULT(RHS, - llvm::ConstantInt::get(RHS->getType(), Width)), - Cont, CGF.getTrapBB()); - CGF.EmitBlock(Cont); + llvm::Value *WidthVal = llvm::ConstantInt::get(RHS->getType(), Width); + EmitBinOpCheck(Builder.CreateICmpULT(RHS, WidthVal), Ops); } if (Ops.Ty->hasUnsignedIntegerRepresentation()) @@ -2326,7 +2594,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { case Qualifiers::OCL_Weak: RHS = Visit(E->getRHS()); - LHS = EmitCheckedLValue(E->getLHS()); + LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore); break; @@ -2336,7 +2604,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { // __block variables need to have the rhs evaluated first, plus // this should improve codegen just a little. RHS = Visit(E->getRHS()); - LHS = EmitCheckedLValue(E->getLHS()); + LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); // Store the value into the LHS. Bit-fields are handled specially // because the result is altered by the store, i.e., [C99 6.5.16p1] @@ -2353,7 +2621,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { return 0; // The result of an assignment in C is the assigned r-value. - if (!CGF.getContext().getLangOpts().CPlusPlus) + if (!CGF.getLangOpts().CPlusPlus) return RHS; // If the lvalue is non-volatile, return the computed value of the assignment. @@ -2567,7 +2835,7 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { // OpenCL: If the condition is a vector, we can treat this condition like // the select function. - if (CGF.getContext().getLangOpts().OpenCL + if (CGF.getLangOpts().OpenCL && condExpr->getType()->isVectorType()) { llvm::Value *CondV = CGF.EmitScalarExpr(condExpr); llvm::Value *LHS = Visit(lhsExpr); diff --git a/lib/CodeGen/CGObjC.cpp b/lib/CodeGen/CGObjC.cpp index 4ac172d1cbb5..c90e4eca8476 100644 --- a/lib/CodeGen/CGObjC.cpp +++ b/lib/CodeGen/CGObjC.cpp @@ -21,7 +21,7 @@ #include "clang/AST/StmtObjC.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include "llvm/InlineAsm.h" using namespace clang; using namespace CodeGen; @@ -440,8 +440,8 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD, SourceLocation StartLoc) { FunctionArgList args; // Check if we should generate debug info for this method. - if (CGM.getModuleDebugInfo() && !OMD->hasAttr<NoDebugAttr>()) - DebugInfo = CGM.getModuleDebugInfo(); + if (!OMD->hasAttr<NoDebugAttr>()) + maybeInitializeDebugInfo(); llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD); @@ -613,7 +613,16 @@ PropertyImplStrategy::PropertyImplStrategy(CodeGenModule &CGM, // which translates to objc_storeStrong. This isn't required, but // it's slightly nicer. } else if (CGM.getLangOpts().ObjCAutoRefCount && !IsAtomic) { - Kind = Expression; + // Using standard expression emission for the setter is only + // acceptable if the ivar is __strong, which won't be true if + // the property is annotated with __attribute__((NSObject)). + // TODO: falling all the way back to objc_setProperty here is + // just laziness, though; we could still use objc_storeStrong + // if we hacked it right. + if (ivarType.getObjCLifetime() == Qualifiers::OCL_Strong) + Kind = Expression; + else + Kind = SetPropertyAndExpressionGet; return; // Otherwise, we need to at least use setProperty. However, if @@ -801,6 +810,10 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, PropertyImplStrategy strategy(CGM, propImpl); switch (strategy.getKind()) { case PropertyImplStrategy::Native: { + // We don't need to do anything for a zero-size struct. + if (strategy.getIvarSize().isZero()) + return; + LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0); // Currently, all atomic accesses have to be through integer @@ -1032,12 +1045,7 @@ static bool hasTrivialSetExpr(const ObjCPropertyImplDecl *PID) { static bool UseOptimizedSetter(CodeGenModule &CGM) { if (CGM.getLangOpts().getGC() != LangOptions::NonGC) return false; - const TargetInfo &Target = CGM.getContext().getTargetInfo(); - - if (Target.getPlatformName() != "macosx") - return false; - - return Target.getPlatformMinVersion() >= VersionTuple(10, 8); + return CGM.getLangOpts().ObjCRuntime.hasOptimizedSetter(); } void @@ -1064,6 +1072,10 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, PropertyImplStrategy strategy(CGM, propImpl); switch (strategy.getKind()) { case PropertyImplStrategy::Native: { + // We don't need to do anything for a zero-size struct. + if (strategy.getIvarSize().isZero()) + return; + llvm::Value *argAddr = LocalDeclMap[*setterMethod->param_begin()]; LValue ivarLValue = @@ -1097,7 +1109,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, llvm::Value *setOptimizedPropertyFn = 0; llvm::Value *setPropertyFn = 0; if (UseOptimizedSetter(CGM)) { - // 10.8 code and GC is off + // 10.8 and iOS 6.0 code and GC is off setOptimizedPropertyFn = CGM.getObjCRuntime() .GetOptimizedPropertySetFunction(strategy.isAtomic(), @@ -1209,7 +1221,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, BinaryOperator assign(&ivarRef, finalArg, BO_Assign, ivarRef.getType(), VK_RValue, OK_Ordinary, - SourceLocation()); + SourceLocation(), false); EmitStmt(&assign); } @@ -1697,11 +1709,11 @@ static llvm::Constant *createARCRuntimeFunction(CodeGenModule &CGM, // references to the runtime support library. We don't really // permit this to fail, but we need a particular relocation style. if (llvm::Function *f = dyn_cast<llvm::Function>(fn)) { - if (!CGM.getLangOpts().ObjCRuntime.hasARC()) + if (!CGM.getLangOpts().ObjCRuntime.hasNativeARC()) f->setLinkage(llvm::Function::ExternalWeakLinkage); // set nonlazybind attribute for these APIs for performance. if (fnName == "objc_retain" || fnName == "objc_release") - f->addFnAttr(llvm::Attribute::NonLazyBind); + f->addFnAttr(llvm::Attributes::NonLazyBind); } return fn; @@ -1945,6 +1957,28 @@ void CodeGenFunction::EmitARCRelease(llvm::Value *value, bool precise) { } } +/// Destroy a __strong variable. +/// +/// At -O0, emit a call to store 'null' into the address; +/// instrumenting tools prefer this because the address is exposed, +/// but it's relatively cumbersome to optimize. +/// +/// At -O1 and above, just load and call objc_release. +/// +/// call void \@objc_storeStrong(i8** %addr, i8* null) +void CodeGenFunction::EmitARCDestroyStrong(llvm::Value *addr, bool precise) { + if (CGM.getCodeGenOpts().OptimizationLevel == 0) { + llvm::PointerType *addrTy = cast<llvm::PointerType>(addr->getType()); + llvm::Value *null = llvm::ConstantPointerNull::get( + cast<llvm::PointerType>(addrTy->getElementType())); + EmitARCStoreStrongCall(addr, null, /*ignored*/ true); + return; + } + + llvm::Value *value = Builder.CreateLoad(addr); + EmitARCRelease(value, precise); +} + /// Store into a strong object. Always calls this: /// call void \@objc_storeStrong(i8** %addr, i8* %value) llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(llvm::Value *addr, @@ -2218,15 +2252,13 @@ void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) { void CodeGenFunction::destroyARCStrongPrecise(CodeGenFunction &CGF, llvm::Value *addr, QualType type) { - llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy"); - CGF.EmitARCRelease(ptr, /*precise*/ true); + CGF.EmitARCDestroyStrong(addr, /*precise*/ true); } void CodeGenFunction::destroyARCStrongImprecise(CodeGenFunction &CGF, llvm::Value *addr, QualType type) { - llvm::Value *ptr = CGF.Builder.CreateLoad(addr, "strongdestroy"); - CGF.EmitARCRelease(ptr, /*precise*/ false); + CGF.EmitARCDestroyStrong(addr, /*precise*/ false); } void CodeGenFunction::destroyARCWeak(CodeGenFunction &CGF, @@ -2730,7 +2762,7 @@ void CodeGenFunction::EmitObjCAutoreleasePoolStmt( // Keep track of the current cleanup stack depth. RunCleanupsScope Scope(*this); - if (CGM.getLangOpts().ObjCRuntime.hasARC()) { + if (CGM.getLangOpts().ObjCRuntime.hasNativeARC()) { llvm::Value *token = EmitObjCAutoreleasePoolPush(); EHStack.pushCleanup<CallObjCAutoreleasePoolObject>(NormalCleanup, token); } else { @@ -2826,9 +2858,8 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction( "__assign_helper_atomic_property_", &CGM.getModule()); - if (CGM.getModuleDebugInfo()) - DebugInfo = CGM.getModuleDebugInfo(); - + // Initialize debug info if needed. + maybeInitializeDebugInfo(); StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation()); @@ -2845,8 +2876,8 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction( Expr *Args[2] = { &DST, &SRC }; CallExpr *CalleeExp = cast<CallExpr>(PID->getSetterCXXAssignment()); CXXOperatorCallExpr TheCall(C, OO_Equal, CalleeExp->getCallee(), - Args, 2, DestTy->getPointeeType(), - VK_LValue, SourceLocation()); + Args, DestTy->getPointeeType(), + VK_LValue, SourceLocation(), false); EmitStmt(&TheCall); @@ -2912,9 +2943,8 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( llvm::Function::Create(LTy, llvm::GlobalValue::InternalLinkage, "__copy_helper_atomic_property_", &CGM.getModule()); - if (CGM.getModuleDebugInfo()) - DebugInfo = CGM.getModuleDebugInfo(); - + // Initialize debug info if needed. + maybeInitializeDebugInfo(); StartFunction(FD, C.VoidTy, Fn, FI, args, SourceLocation()); @@ -2940,7 +2970,7 @@ CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( CXXConstructExpr::Create(C, Ty, SourceLocation(), CXXConstExpr->getConstructor(), CXXConstExpr->isElidable(), - &ConstructorArgs[0], ConstructorArgs.size(), + ConstructorArgs, CXXConstExpr->hadMultipleCandidates(), CXXConstExpr->isListInitialization(), CXXConstExpr->requiresZeroInitialization(), diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp index 6d129d02a561..68d234dde6ea 100644 --- a/lib/CodeGen/CGObjCGNU.cpp +++ b/lib/CodeGen/CGObjCGNU.cpp @@ -33,7 +33,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/Compiler.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include <cstdarg> @@ -224,6 +224,25 @@ protected: llvm::ArrayType *ArrayTy = llvm::ArrayType::get(Ty, V.size()); return MakeGlobal(ArrayTy, V, Name, linkage); } + /// Returns a property name and encoding string. + llvm::Constant *MakePropertyEncodingString(const ObjCPropertyDecl *PD, + const Decl *Container) { + ObjCRuntime R = CGM.getLangOpts().ObjCRuntime; + if ((R.getKind() == ObjCRuntime::GNUstep) && + (R.getVersion() >= VersionTuple(1, 6))) { + std::string NameAndAttributes; + std::string TypeStr; + CGM.getContext().getObjCEncodingForPropertyDecl(PD, Container, TypeStr); + NameAndAttributes += '\0'; + NameAndAttributes += TypeStr.length() + 3; + NameAndAttributes += TypeStr; + NameAndAttributes += '\0'; + NameAndAttributes += PD->getNameAsString(); + return llvm::ConstantExpr::getGetElementPtr( + CGM.GetAddrOfConstantString(NameAndAttributes), Zeros); + } + return MakeConstantString(PD->getNameAsString()); + } /// Ensures that the value has the required type, by inserting a bitcast if /// required. This function lets us avoid inserting bitcasts that are /// redundant. @@ -514,7 +533,10 @@ public: const CGBlockInfo &blockInfo) { return NULLPtr; } - + virtual llvm::Constant *BuildRCBlockLayout(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + return NULLPtr; + } virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) { return 0; } @@ -578,6 +600,8 @@ class CGObjCGNUstep : public CGObjCGNU { /// Type of an slot structure pointer. This is returned by the various /// lookup functions. llvm::Type *SlotTy; + public: + virtual llvm::Constant *GetEHType(QualType T); protected: virtual llvm::Value *LookupIMP(CodeGenFunction &CGF, llvm::Value *&Receiver, @@ -653,11 +677,40 @@ class CGObjCGNUstep : public CGObjCGNU { } }; -/// The ObjFW runtime, which closely follows the GCC runtime's -/// compiler ABI. Support here is due to Jonathan Schleifer, the -/// ObjFW maintainer. -class CGObjCObjFW : public CGObjCGCC { - /// Emit class references unconditionally as direct symbol references. +/// Support for the ObjFW runtime. Support here is due to +/// Jonathan Schleifer <js@webkeks.org>, the ObjFW maintainer. +class CGObjCObjFW: public CGObjCGNU { +protected: + /// The GCC ABI message lookup function. Returns an IMP pointing to the + /// method implementation for this message. + LazyRuntimeFunction MsgLookupFn; + /// The GCC ABI superclass message lookup function. Takes a pointer to a + /// structure describing the receiver and the class, and a selector as + /// arguments. Returns the IMP for the corresponding method. + LazyRuntimeFunction MsgLookupSuperFn; + + virtual llvm::Value *LookupIMP(CodeGenFunction &CGF, + llvm::Value *&Receiver, + llvm::Value *cmd, + llvm::MDNode *node) { + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *args[] = { + EnforceType(Builder, Receiver, IdTy), + EnforceType(Builder, cmd, SelectorTy) }; + llvm::CallSite imp = CGF.EmitCallOrInvoke(MsgLookupFn, args); + imp->setMetadata(msgSendMDKind, node); + return imp.getInstruction(); + } + + virtual llvm::Value *LookupIMPSuper(CodeGenFunction &CGF, + llvm::Value *ObjCSuper, + llvm::Value *cmd) { + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *lookupArgs[] = {EnforceType(Builder, ObjCSuper, + PtrToObjCSuperTy), cmd}; + return Builder.CreateCall(MsgLookupSuperFn, lookupArgs); + } + virtual llvm::Value *GetClassNamed(CGBuilderTy &Builder, const std::string &Name, bool isWeak) { if (isWeak) @@ -678,7 +731,13 @@ class CGObjCObjFW : public CGObjCGCC { } public: - CGObjCObjFW(CodeGenModule &Mod): CGObjCGCC(Mod) {} + CGObjCObjFW(CodeGenModule &Mod): CGObjCGNU(Mod, 9, 3) { + // IMP objc_msg_lookup(id, SEL); + MsgLookupFn.init(&CGM, "objc_msg_lookup", IMPTy, IdTy, SelectorTy, NULL); + // IMP objc_msg_lookup_super(struct objc_super*, SEL); + MsgLookupSuperFn.init(&CGM, "objc_msg_lookup_super", IMPTy, + PtrToObjCSuperTy, SelectorTy, NULL); + } }; } // end anonymous namespace @@ -909,29 +968,30 @@ llvm::Value *CGObjCGNU::GetSelector(CGBuilderTy &Builder, const ObjCMethodDecl } llvm::Constant *CGObjCGNU::GetEHType(QualType T) { - if (!CGM.getLangOpts().CPlusPlus) { - if (T->isObjCIdType() - || T->isObjCQualifiedIdType()) { - // With the old ABI, there was only one kind of catchall, which broke - // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as - // a pointer indicating object catchalls, and NULL to indicate real - // catchalls - if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { - return MakeConstantString("@id"); - } else { - return 0; - } - } - - // All other types should be Objective-C interface pointer types. - const ObjCObjectPointerType *OPT = - T->getAs<ObjCObjectPointerType>(); - assert(OPT && "Invalid @catch type."); - const ObjCInterfaceDecl *IDecl = - OPT->getObjectType()->getInterface(); - assert(IDecl && "Invalid @catch type."); - return MakeConstantString(IDecl->getIdentifier()->getName()); + if (T->isObjCIdType() || T->isObjCQualifiedIdType()) { + // With the old ABI, there was only one kind of catchall, which broke + // foreign exceptions. With the new ABI, we use __objc_id_typeinfo as + // a pointer indicating object catchalls, and NULL to indicate real + // catchalls + if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { + return MakeConstantString("@id"); + } else { + return 0; + } } + + // All other types should be Objective-C interface pointer types. + const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>(); + assert(OPT && "Invalid @catch type."); + const ObjCInterfaceDecl *IDecl = OPT->getObjectType()->getInterface(); + assert(IDecl && "Invalid @catch type."); + return MakeConstantString(IDecl->getIdentifier()->getName()); +} + +llvm::Constant *CGObjCGNUstep::GetEHType(QualType T) { + if (!CGM.getLangOpts().CPlusPlus) + return CGObjCGNU::GetEHType(T); + // For Objective-C++, we want to provide the ability to catch both C++ and // Objective-C objects in the same function. @@ -1436,7 +1496,7 @@ llvm::Constant *CGObjCGNU::GenerateClassStructure( Elements.push_back(Zero); Elements.push_back(llvm::ConstantInt::get(LongTy, info)); if (isMeta) { - llvm::TargetData td(&TheModule); + llvm::DataLayout td(&TheModule); Elements.push_back( llvm::ConstantInt::get(LongTy, td.getTypeSizeInBits(ClassTy) / @@ -1595,13 +1655,13 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { std::string TypeStr; Context.getObjCEncodingForMethodDecl(*iter, TypeStr); if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) { - InstanceMethodNames.push_back( - MakeConstantString((*iter)->getSelector().getAsString())); - InstanceMethodTypes.push_back(MakeConstantString(TypeStr)); - } else { OptionalInstanceMethodNames.push_back( MakeConstantString((*iter)->getSelector().getAsString())); OptionalInstanceMethodTypes.push_back(MakeConstantString(TypeStr)); + } else { + InstanceMethodNames.push_back( + MakeConstantString((*iter)->getSelector().getAsString())); + InstanceMethodTypes.push_back(MakeConstantString(TypeStr)); } } // Collect information about class methods: @@ -1615,13 +1675,13 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { std::string TypeStr; Context.getObjCEncodingForMethodDecl((*iter),TypeStr); if ((*iter)->getImplementationControl() == ObjCMethodDecl::Optional) { - ClassMethodNames.push_back( - MakeConstantString((*iter)->getSelector().getAsString())); - ClassMethodTypes.push_back(MakeConstantString(TypeStr)); - } else { OptionalClassMethodNames.push_back( MakeConstantString((*iter)->getSelector().getAsString())); OptionalClassMethodTypes.push_back(MakeConstantString(TypeStr)); + } else { + ClassMethodNames.push_back( + MakeConstantString((*iter)->getSelector().getAsString())); + ClassMethodTypes.push_back(MakeConstantString(TypeStr)); } } @@ -1656,7 +1716,9 @@ void CGObjCGNU::GenerateProtocol(const ObjCProtocolDecl *PD) { std::vector<llvm::Constant*> Fields; ObjCPropertyDecl *property = *iter; - Fields.push_back(MakeConstantString(property->getNameAsString())); + + Fields.push_back(MakePropertyEncodingString(property, PD)); + Fields.push_back(llvm::ConstantInt::get(Int8Ty, property->getPropertyAttributes())); Fields.push_back(llvm::ConstantInt::get(Int8Ty, 0)); @@ -1909,7 +1971,7 @@ llvm::Constant *CGObjCGNU::GeneratePropertyList(const ObjCImplementationDecl *OI bool isSynthesized = (propertyImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); - Fields.push_back(MakeConstantString(property->getNameAsString())); + Fields.push_back(MakePropertyEncodingString(property, OID)); Fields.push_back(llvm::ConstantInt::get(Int8Ty, property->getPropertyAttributes())); Fields.push_back(llvm::ConstantInt::get(Int8Ty, isSynthesized)); @@ -2011,7 +2073,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { Context.getASTObjCInterfaceLayout(SuperClassDecl).getSize().getQuantity(); // For non-fragile ivars, set the instance size to 0 - {the size of just this // class}. The runtime will then set this to the correct value on load. - if (CGM.getContext().getLangOpts().ObjCRuntime.isNonFragile()) { + if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { instanceSize = 0 - (instanceSize - superInstanceSize); } @@ -2026,7 +2088,7 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { // Get the offset uint64_t BaseOffset = ComputeIvarBaseOffset(CGM, OID, IVD); uint64_t Offset = BaseOffset; - if (CGM.getContext().getLangOpts().ObjCRuntime.isNonFragile()) { + if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) { Offset = BaseOffset - superInstanceSize; } llvm::Constant *OffsetValue = llvm::ConstantInt::get(IntTy, Offset); @@ -2334,7 +2396,7 @@ llvm::Function *CGObjCGNU::ModuleInitFunction() { // Runtime version, used for ABI compatibility checking. Elements.push_back(llvm::ConstantInt::get(LongTy, RuntimeVersion)); // sizeof(ModuleTy) - llvm::TargetData td(&TheModule); + llvm::DataLayout td(&TheModule); Elements.push_back( llvm::ConstantInt::get(LongTy, td.getTypeSizeInBits(ModuleTy) / @@ -2488,7 +2550,7 @@ void CGObjCGNU::EmitTryStmt(CodeGenFunction &CGF, // Unlike the Apple non-fragile runtimes, which also uses // unwind-based zero cost exceptions, the GNU Objective C runtime's // EH support isn't a veneer over C++ EH. Instead, exception - // objects are created by __objc_exception_throw and destroyed by + // objects are created by objc_exception_throw and destroyed by // the personality function; this avoids the need for bracketing // catch handlers with calls to __blah_begin_catch/__blah_end_catch // (or even _Unwind_DeleteException), but probably doesn't @@ -2513,7 +2575,9 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF, ExceptionAsObject = CGF.ObjCEHValueStack.back(); } ExceptionAsObject = CGF.Builder.CreateBitCast(ExceptionAsObject, IdTy); - CGF.EmitCallOrInvoke(ExceptionThrowFn, ExceptionAsObject); + llvm::CallSite Throw = + CGF.EmitCallOrInvoke(ExceptionThrowFn, ExceptionAsObject); + Throw.setDoesNotReturn(); CGF.Builder.CreateUnreachable(); CGF.Builder.ClearInsertionPoint(); } diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index ef802a3ed0ca..2203f0182800 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -36,7 +36,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include <cstdio> using namespace clang; @@ -66,7 +66,8 @@ private: return CGM.CreateRuntimeFunction(llvm::FunctionType::get(ObjectPtrTy, params, true), "objc_msgSend", - llvm::Attribute::NonLazyBind); + llvm::Attributes::get(CGM.getLLVMContext(), + llvm::Attributes::NonLazyBind)); } /// void objc_msgSend_stret (id, SEL, ...) @@ -433,19 +434,19 @@ public: /// SyncEnterFn - LLVM object_sync_enter function. llvm::Constant *getSyncEnterFn() { - // void objc_sync_enter (id) + // int objc_sync_enter (id) llvm::Type *args[] = { ObjectPtrTy }; llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, args, false); + llvm::FunctionType::get(CGM.IntTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_sync_enter"); } /// SyncExitFn - LLVM object_sync_exit function. llvm::Constant *getSyncExitFn() { - // void objc_sync_exit (id) + // int objc_sync_exit (id) llvm::Type *args[] = { ObjectPtrTy }; llvm::FunctionType *FTy = - llvm::FunctionType::get(CGM.VoidTy, args, false); + llvm::FunctionType::get(CGM.IntTy, args, false); return CGM.CreateRuntimeFunction(FTy, "objc_sync_exit"); } @@ -583,7 +584,8 @@ public: return CGM.CreateRuntimeFunction(llvm::FunctionType::get(CGM.Int32Ty, params, false), "_setjmp", - llvm::Attribute::ReturnsTwice); + llvm::Attributes::get(CGM.getLLVMContext(), + llvm::Attributes::NonLazyBind)); } public: @@ -753,6 +755,74 @@ public: : skip(_skip), scan(_scan) {} }; + /// opcode for captured block variables layout 'instructions'. + /// In the following descriptions, 'I' is the value of the immediate field. + /// (field following the opcode). + /// + enum BLOCK_LAYOUT_OPCODE { + /// An operator which affects how the following layout should be + /// interpreted. + /// I == 0: Halt interpretation and treat everything else as + /// a non-pointer. Note that this instruction is equal + /// to '\0'. + /// I != 0: Currently unused. + BLOCK_LAYOUT_OPERATOR = 0, + + /// The next I+1 bytes do not contain a value of object pointer type. + /// Note that this can leave the stream unaligned, meaning that + /// subsequent word-size instructions do not begin at a multiple of + /// the pointer size. + BLOCK_LAYOUT_NON_OBJECT_BYTES = 1, + + /// The next I+1 words do not contain a value of object pointer type. + /// This is simply an optimized version of BLOCK_LAYOUT_BYTES for + /// when the required skip quantity is a multiple of the pointer size. + BLOCK_LAYOUT_NON_OBJECT_WORDS = 2, + + /// The next I+1 words are __strong pointers to Objective-C + /// objects or blocks. + BLOCK_LAYOUT_STRONG = 3, + + /// The next I+1 words are pointers to __block variables. + BLOCK_LAYOUT_BYREF = 4, + + /// The next I+1 words are __weak pointers to Objective-C + /// objects or blocks. + BLOCK_LAYOUT_WEAK = 5, + + /// The next I+1 words are __unsafe_unretained pointers to + /// Objective-C objects or blocks. + BLOCK_LAYOUT_UNRETAINED = 6 + + /// The next I+1 words are block or object pointers with some + /// as-yet-unspecified ownership semantics. If we add more + /// flavors of ownership semantics, values will be taken from + /// this range. + /// + /// This is included so that older tools can at least continue + /// processing the layout past such things. + //BLOCK_LAYOUT_OWNERSHIP_UNKNOWN = 7..10, + + /// All other opcodes are reserved. Halt interpretation and + /// treat everything else as opaque. + }; + + class RUN_SKIP { + public: + enum BLOCK_LAYOUT_OPCODE opcode; + CharUnits block_var_bytepos; + CharUnits block_var_size; + RUN_SKIP(enum BLOCK_LAYOUT_OPCODE Opcode = BLOCK_LAYOUT_OPERATOR, + CharUnits BytePos = CharUnits::Zero(), + CharUnits Size = CharUnits::Zero()) + : opcode(Opcode), block_var_bytepos(BytePos), block_var_size(Size) {} + + // Allow sorting based on byte pos. + bool operator<(const RUN_SKIP &b) const { + return block_var_bytepos < b.block_var_bytepos; + } + }; + protected: llvm::LLVMContext &VMContext; // FIXME! May not be needing this after all. @@ -761,6 +831,9 @@ protected: // gc ivar layout bitmap calculation helper caches. SmallVector<GC_IVAR, 16> SkipIvars; SmallVector<GC_IVAR, 16> IvarsInfo; + + // arc/mrr layout of captured block literal variables. + SmallVector<RUN_SKIP, 16> RunSkipBlockVars; /// LazySymbols - Symbols to generate a lazy reference for. See /// DefinedSymbols and FinishModule(). @@ -869,6 +942,24 @@ protected: ArrayRef<const FieldDecl*> RecFields, unsigned int BytePos, bool ForStrongLayout, bool &HasUnion); + + Qualifiers::ObjCLifetime getBlockCaptureLifetime(QualType QT); + + void UpdateRunSkipBlockVars(bool IsByref, + Qualifiers::ObjCLifetime LifeTime, + CharUnits FieldOffset, + CharUnits FieldSize); + + void BuildRCBlockVarRecordLayout(const RecordType *RT, + CharUnits BytePos, bool &HasUnion); + + void BuildRCRecordLayout(const llvm::StructLayout *RecLayout, + const RecordDecl *RD, + ArrayRef<const FieldDecl*> RecFields, + CharUnits BytePos, bool &HasUnion); + + uint64_t InlineLayoutInstruction(SmallVectorImpl<unsigned char> &Layout); + /// GetIvarLayoutName - Returns a unique constant for the given /// ivar layout bitmap. @@ -959,6 +1050,8 @@ public: virtual llvm::Constant *GetOrEmitProtocolRef(const ObjCProtocolDecl *PD)=0; virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM, const CGBlockInfo &blockInfo); + virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM, + const CGBlockInfo &blockInfo); }; @@ -1787,8 +1880,8 @@ static Qualifiers::GC GetGCAttrTypeForType(ASTContext &Ctx, QualType FQT) { llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, const CGBlockInfo &blockInfo) { + llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy); - if (CGM.getLangOpts().getGC() == LangOptions::NonGC && !CGM.getLangOpts().ObjCAutoRefCount) return nullPtr; @@ -1807,7 +1900,7 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, // Calculate the basic layout of the block structure. const llvm::StructLayout *layout = - CGM.getTargetData().getStructLayout(blockInfo.StructureType); + CGM.getDataLayout().getStructLayout(blockInfo.StructureType); // Ignore the optional 'this' capture: C++ objects are not assumed // to be GC'ed. @@ -1860,7 +1953,7 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, llvm::Constant *C = BuildIvarLayoutBitmap(BitMap); if (CGM.getLangOpts().ObjCGCBitmapPrint) { printf("\n block variable layout for block: "); - const unsigned char *s = (unsigned char*)BitMap.c_str(); + const unsigned char *s = (const unsigned char*)BitMap.c_str(); for (unsigned i = 0, e = BitMap.size(); i < e; i++) if (!(s[i] & 0xf0)) printf("0x0%x%s", s[i], s[i] != 0 ? ", " : ""); @@ -1872,6 +1965,476 @@ llvm::Constant *CGObjCCommonMac::BuildGCBlockLayout(CodeGenModule &CGM, return C; } +/// getBlockCaptureLifetime - This routine returns life time of the captured +/// block variable for the purpose of block layout meta-data generation. FQT is +/// the type of the variable captured in the block. +Qualifiers::ObjCLifetime CGObjCCommonMac::getBlockCaptureLifetime(QualType FQT) { + if (CGM.getLangOpts().ObjCAutoRefCount) + return FQT.getObjCLifetime(); + + // MRR. + if (FQT->isObjCObjectPointerType() || FQT->isBlockPointerType()) + return Qualifiers::OCL_ExplicitNone; + + return Qualifiers::OCL_None; +} + +void CGObjCCommonMac::UpdateRunSkipBlockVars(bool IsByref, + Qualifiers::ObjCLifetime LifeTime, + CharUnits FieldOffset, + CharUnits FieldSize) { + // __block variables are passed by their descriptor address. + if (IsByref) + RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_BYREF, FieldOffset, + FieldSize)); + else if (LifeTime == Qualifiers::OCL_Strong) + RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_STRONG, FieldOffset, + FieldSize)); + else if (LifeTime == Qualifiers::OCL_Weak) + RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_WEAK, FieldOffset, + FieldSize)); + else if (LifeTime == Qualifiers::OCL_ExplicitNone) + RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_UNRETAINED, FieldOffset, + FieldSize)); + else + RunSkipBlockVars.push_back(RUN_SKIP(BLOCK_LAYOUT_NON_OBJECT_BYTES, + FieldOffset, + FieldSize)); +} + +void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, + const RecordDecl *RD, + ArrayRef<const FieldDecl*> RecFields, + CharUnits BytePos, bool &HasUnion) { + bool IsUnion = (RD && RD->isUnion()); + CharUnits MaxUnionSize = CharUnits::Zero(); + const FieldDecl *MaxField = 0; + const FieldDecl *LastFieldBitfieldOrUnnamed = 0; + CharUnits MaxFieldOffset = CharUnits::Zero(); + CharUnits LastBitfieldOrUnnamedOffset = CharUnits::Zero(); + + if (RecFields.empty()) + return; + unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + + for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { + const FieldDecl *Field = RecFields[i]; + // Note that 'i' here is actually the field index inside RD of Field, + // although this dependency is hidden. + const ASTRecordLayout &RL = CGM.getContext().getASTRecordLayout(RD); + CharUnits FieldOffset = + CGM.getContext().toCharUnitsFromBits(RL.getFieldOffset(i)); + + // Skip over unnamed or bitfields + if (!Field->getIdentifier() || Field->isBitField()) { + LastFieldBitfieldOrUnnamed = Field; + LastBitfieldOrUnnamedOffset = FieldOffset; + continue; + } + + LastFieldBitfieldOrUnnamed = 0; + QualType FQT = Field->getType(); + if (FQT->isRecordType() || FQT->isUnionType()) { + if (FQT->isUnionType()) + HasUnion = true; + + BuildRCBlockVarRecordLayout(FQT->getAs<RecordType>(), + BytePos + FieldOffset, HasUnion); + continue; + } + + if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) { + const ConstantArrayType *CArray = + dyn_cast_or_null<ConstantArrayType>(Array); + uint64_t ElCount = CArray->getSize().getZExtValue(); + assert(CArray && "only array with known element size is supported"); + FQT = CArray->getElementType(); + while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) { + const ConstantArrayType *CArray = + dyn_cast_or_null<ConstantArrayType>(Array); + ElCount *= CArray->getSize().getZExtValue(); + FQT = CArray->getElementType(); + } + + assert(!FQT->isUnionType() && + "layout for array of unions not supported"); + if (FQT->isRecordType() && ElCount) { + int OldIndex = RunSkipBlockVars.size() - 1; + const RecordType *RT = FQT->getAs<RecordType>(); + BuildRCBlockVarRecordLayout(RT, BytePos + FieldOffset, + HasUnion); + + // Replicate layout information for each array element. Note that + // one element is already done. + uint64_t ElIx = 1; + for (int FirstIndex = RunSkipBlockVars.size() - 1 ;ElIx < ElCount; ElIx++) { + CharUnits Size = CGM.getContext().getTypeSizeInChars(RT); + for (int i = OldIndex+1; i <= FirstIndex; ++i) + RunSkipBlockVars.push_back( + RUN_SKIP(RunSkipBlockVars[i].opcode, + RunSkipBlockVars[i].block_var_bytepos + Size*ElIx, + RunSkipBlockVars[i].block_var_size)); + } + continue; + } + } + CharUnits FieldSize = CGM.getContext().getTypeSizeInChars(Field->getType()); + if (IsUnion) { + CharUnits UnionIvarSize = FieldSize; + if (UnionIvarSize > MaxUnionSize) { + MaxUnionSize = UnionIvarSize; + MaxField = Field; + MaxFieldOffset = FieldOffset; + } + } else { + UpdateRunSkipBlockVars(false, + getBlockCaptureLifetime(FQT), + BytePos + FieldOffset, + FieldSize); + } + } + + if (LastFieldBitfieldOrUnnamed) { + if (LastFieldBitfieldOrUnnamed->isBitField()) { + // Last field was a bitfield. Must update the info. + uint64_t BitFieldSize + = LastFieldBitfieldOrUnnamed->getBitWidthValue(CGM.getContext()); + unsigned UnsSize = (BitFieldSize / ByteSizeInBits) + + ((BitFieldSize % ByteSizeInBits) != 0); + CharUnits Size = CharUnits::fromQuantity(UnsSize); + Size += LastBitfieldOrUnnamedOffset; + UpdateRunSkipBlockVars(false, + getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()), + BytePos + LastBitfieldOrUnnamedOffset, + Size); + } else { + assert(!LastFieldBitfieldOrUnnamed->getIdentifier() &&"Expected unnamed"); + // Last field was unnamed. Must update skip info. + CharUnits FieldSize + = CGM.getContext().getTypeSizeInChars(LastFieldBitfieldOrUnnamed->getType()); + UpdateRunSkipBlockVars(false, + getBlockCaptureLifetime(LastFieldBitfieldOrUnnamed->getType()), + BytePos + LastBitfieldOrUnnamedOffset, + FieldSize); + } + } + + if (MaxField) + UpdateRunSkipBlockVars(false, + getBlockCaptureLifetime(MaxField->getType()), + BytePos + MaxFieldOffset, + MaxUnionSize); +} + +void CGObjCCommonMac::BuildRCBlockVarRecordLayout(const RecordType *RT, + CharUnits BytePos, + bool &HasUnion) { + const RecordDecl *RD = RT->getDecl(); + SmallVector<const FieldDecl*, 16> Fields; + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i) + Fields.push_back(*i); + llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0)); + const llvm::StructLayout *RecLayout = + CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty)); + + BuildRCRecordLayout(RecLayout, RD, Fields, BytePos, HasUnion); +} + +/// InlineLayoutInstruction - This routine produce an inline instruction for the +/// block variable layout if it can. If not, it returns 0. Rules are as follow: +/// If ((uintptr_t) layout) < (1 << 12), the layout is inline. In the 64bit world, +/// an inline layout of value 0x0000000000000xyz is interpreted as follows: +/// x captured object pointers of BLOCK_LAYOUT_STRONG. Followed by +/// y captured object of BLOCK_LAYOUT_BYREF. Followed by +/// z captured object of BLOCK_LAYOUT_WEAK. If any of the above is missing, zero +/// replaces it. For example, 0x00000x00 means x BLOCK_LAYOUT_STRONG and no +/// BLOCK_LAYOUT_BYREF and no BLOCK_LAYOUT_WEAK objects are captured. +uint64_t CGObjCCommonMac::InlineLayoutInstruction( + SmallVectorImpl<unsigned char> &Layout) { + uint64_t Result = 0; + if (Layout.size() <= 3) { + unsigned size = Layout.size(); + unsigned strong_word_count = 0, byref_word_count=0, weak_word_count=0; + unsigned char inst; + enum BLOCK_LAYOUT_OPCODE opcode ; + switch (size) { + case 3: + inst = Layout[0]; + opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4); + if (opcode == BLOCK_LAYOUT_STRONG) + strong_word_count = (inst & 0xF)+1; + else + return 0; + inst = Layout[1]; + opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4); + if (opcode == BLOCK_LAYOUT_BYREF) + byref_word_count = (inst & 0xF)+1; + else + return 0; + inst = Layout[2]; + opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4); + if (opcode == BLOCK_LAYOUT_WEAK) + weak_word_count = (inst & 0xF)+1; + else + return 0; + break; + + case 2: + inst = Layout[0]; + opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4); + if (opcode == BLOCK_LAYOUT_STRONG) { + strong_word_count = (inst & 0xF)+1; + inst = Layout[1]; + opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4); + if (opcode == BLOCK_LAYOUT_BYREF) + byref_word_count = (inst & 0xF)+1; + else if (opcode == BLOCK_LAYOUT_WEAK) + weak_word_count = (inst & 0xF)+1; + else + return 0; + } + else if (opcode == BLOCK_LAYOUT_BYREF) { + byref_word_count = (inst & 0xF)+1; + inst = Layout[1]; + opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4); + if (opcode == BLOCK_LAYOUT_WEAK) + weak_word_count = (inst & 0xF)+1; + else + return 0; + } + else + return 0; + break; + + case 1: + inst = Layout[0]; + opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4); + if (opcode == BLOCK_LAYOUT_STRONG) + strong_word_count = (inst & 0xF)+1; + else if (opcode == BLOCK_LAYOUT_BYREF) + byref_word_count = (inst & 0xF)+1; + else if (opcode == BLOCK_LAYOUT_WEAK) + weak_word_count = (inst & 0xF)+1; + else + return 0; + break; + + default: + return 0; + } + + // Cannot inline when any of the word counts is 15. Because this is one less + // than the actual work count (so 15 means 16 actual word counts), + // and we can only display 0 thru 15 word counts. + if (strong_word_count == 16 || byref_word_count == 16 || weak_word_count == 16) + return 0; + + unsigned count = + (strong_word_count != 0) + (byref_word_count != 0) + (weak_word_count != 0); + + if (size == count) { + if (strong_word_count) + Result = strong_word_count; + Result <<= 4; + if (byref_word_count) + Result += byref_word_count; + Result <<= 4; + if (weak_word_count) + Result += weak_word_count; + } + } + return Result; +} + +llvm::Constant *CGObjCCommonMac::BuildRCBlockLayout(CodeGenModule &CGM, + const CGBlockInfo &blockInfo) { + assert(CGM.getLangOpts().getGC() == LangOptions::NonGC); + + llvm::Constant *nullPtr = llvm::Constant::getNullValue(CGM.Int8PtrTy); + + RunSkipBlockVars.clear(); + bool hasUnion = false; + + unsigned WordSizeInBits = CGM.getContext().getTargetInfo().getPointerWidth(0); + unsigned ByteSizeInBits = CGM.getContext().getTargetInfo().getCharWidth(); + unsigned WordSizeInBytes = WordSizeInBits/ByteSizeInBits; + + const BlockDecl *blockDecl = blockInfo.getBlockDecl(); + + // Calculate the basic layout of the block structure. + const llvm::StructLayout *layout = + CGM.getDataLayout().getStructLayout(blockInfo.StructureType); + + // Ignore the optional 'this' capture: C++ objects are not assumed + // to be GC'ed. + + // Walk the captured variables. + for (BlockDecl::capture_const_iterator ci = blockDecl->capture_begin(), + ce = blockDecl->capture_end(); ci != ce; ++ci) { + const VarDecl *variable = ci->getVariable(); + QualType type = variable->getType(); + + const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); + + // Ignore constant captures. + if (capture.isConstant()) continue; + + CharUnits fieldOffset = + CharUnits::fromQuantity(layout->getElementOffset(capture.getIndex())); + + assert(!type->isArrayType() && "array variable should not be caught"); + if (const RecordType *record = type->getAs<RecordType>()) { + BuildRCBlockVarRecordLayout(record, fieldOffset, hasUnion); + continue; + } + CharUnits fieldSize; + if (ci->isByRef()) + fieldSize = CharUnits::fromQuantity(WordSizeInBytes); + else + fieldSize = CGM.getContext().getTypeSizeInChars(type); + UpdateRunSkipBlockVars(ci->isByRef(), getBlockCaptureLifetime(type), + fieldOffset, fieldSize); + } + + if (RunSkipBlockVars.empty()) + return nullPtr; + + // Sort on byte position; captures might not be allocated in order, + // and unions can do funny things. + llvm::array_pod_sort(RunSkipBlockVars.begin(), RunSkipBlockVars.end()); + SmallVector<unsigned char, 16> Layout; + + unsigned size = RunSkipBlockVars.size(); + for (unsigned i = 0; i < size; i++) { + enum BLOCK_LAYOUT_OPCODE opcode = RunSkipBlockVars[i].opcode; + CharUnits start_byte_pos = RunSkipBlockVars[i].block_var_bytepos; + CharUnits end_byte_pos = start_byte_pos; + unsigned j = i+1; + while (j < size) { + if (opcode == RunSkipBlockVars[j].opcode) { + end_byte_pos = RunSkipBlockVars[j++].block_var_bytepos; + i++; + } + else + break; + } + CharUnits size_in_bytes = + end_byte_pos - start_byte_pos + RunSkipBlockVars[j-1].block_var_size; + if (j < size) { + CharUnits gap = + RunSkipBlockVars[j].block_var_bytepos - + RunSkipBlockVars[j-1].block_var_bytepos - RunSkipBlockVars[j-1].block_var_size; + size_in_bytes += gap; + } + CharUnits residue_in_bytes = CharUnits::Zero(); + if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES) { + residue_in_bytes = size_in_bytes % WordSizeInBytes; + size_in_bytes -= residue_in_bytes; + opcode = BLOCK_LAYOUT_NON_OBJECT_WORDS; + } + + unsigned size_in_words = size_in_bytes.getQuantity() / WordSizeInBytes; + while (size_in_words >= 16) { + // Note that value in imm. is one less that the actual + // value. So, 0xf means 16 words follow! + unsigned char inst = (opcode << 4) | 0xf; + Layout.push_back(inst); + size_in_words -= 16; + } + if (size_in_words > 0) { + // Note that value in imm. is one less that the actual + // value. So, we subtract 1 away! + unsigned char inst = (opcode << 4) | (size_in_words-1); + Layout.push_back(inst); + } + if (residue_in_bytes > CharUnits::Zero()) { + unsigned char inst = + (BLOCK_LAYOUT_NON_OBJECT_BYTES << 4) | (residue_in_bytes.getQuantity()-1); + Layout.push_back(inst); + } + } + + int e = Layout.size()-1; + while (e >= 0) { + unsigned char inst = Layout[e--]; + enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4); + if (opcode == BLOCK_LAYOUT_NON_OBJECT_BYTES || opcode == BLOCK_LAYOUT_NON_OBJECT_WORDS) + Layout.pop_back(); + else + break; + } + + uint64_t Result = InlineLayoutInstruction(Layout); + if (Result != 0) { + // Block variable layout instruction has been inlined. + if (CGM.getLangOpts().ObjCGCBitmapPrint) { + printf("\n Inline instruction for block variable layout: "); + printf("0x0%llx\n", (unsigned long long)Result); + } + if (WordSizeInBytes == 8) { + const llvm::APInt Instruction(64, Result); + return llvm::Constant::getIntegerValue(CGM.Int64Ty, Instruction); + } + else { + const llvm::APInt Instruction(32, Result); + return llvm::Constant::getIntegerValue(CGM.Int32Ty, Instruction); + } + } + + unsigned char inst = (BLOCK_LAYOUT_OPERATOR << 4) | 0; + Layout.push_back(inst); + std::string BitMap; + for (unsigned i = 0, e = Layout.size(); i != e; i++) + BitMap += Layout[i]; + + if (CGM.getLangOpts().ObjCGCBitmapPrint) { + printf("\n block variable layout: "); + for (unsigned i = 0, e = BitMap.size(); i != e; i++) { + unsigned char inst = BitMap[i]; + enum BLOCK_LAYOUT_OPCODE opcode = (enum BLOCK_LAYOUT_OPCODE) (inst >> 4); + unsigned delta = 1; + switch (opcode) { + case BLOCK_LAYOUT_OPERATOR: + printf("BL_OPERATOR:"); + delta = 0; + break; + case BLOCK_LAYOUT_NON_OBJECT_BYTES: + printf("BL_NON_OBJECT_BYTES:"); + break; + case BLOCK_LAYOUT_NON_OBJECT_WORDS: + printf("BL_NON_OBJECT_WORD:"); + break; + case BLOCK_LAYOUT_STRONG: + printf("BL_STRONG:"); + break; + case BLOCK_LAYOUT_BYREF: + printf("BL_BYREF:"); + break; + case BLOCK_LAYOUT_WEAK: + printf("BL_WEAK:"); + break; + case BLOCK_LAYOUT_UNRETAINED: + printf("BL_UNRETAINED:"); + break; + } + // Actual value of word count is one more that what is in the imm. + // field of the instruction + printf("%d", (inst & 0xf) + delta); + if (i < e-1) + printf(", "); + else + printf("\n"); + } + } + + llvm::GlobalVariable * Entry = + CreateMetadataVar("\01L_OBJC_CLASS_NAME_", + llvm::ConstantDataArray::getString(VMContext, BitMap,false), + "__TEXT,__objc_classname,cstring_literals", 1, true); + return getConstantGEP(VMContext, Entry, 0, 0); +} + llvm::Value *CGObjCMac::GenerateProtocolRef(CGBuilderTy &Builder, const ObjCProtocolDecl *PD) { // FIXME: I don't understand why gcc generates this, or where it is @@ -2040,7 +2603,7 @@ CGObjCMac::EmitProtocolExtension(const ObjCProtocolDecl *PD, ArrayRef<llvm::Constant*> OptClassMethods, ArrayRef<llvm::Constant*> MethodTypesExt) { uint64_t Size = - CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy); + CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolExtensionTy); llvm::Constant *Values[] = { llvm::ConstantInt::get(ObjCTypes.IntTy, Size), EmitMethodDescList("\01L_OBJC_PROTOCOL_INSTANCE_METHODS_OPT_" @@ -2180,7 +2743,7 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name, return llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); unsigned PropertySize = - CGM.getTargetData().getTypeAllocSize(ObjCTypes.PropertyTy); + CGM.getDataLayout().getTypeAllocSize(ObjCTypes.PropertyTy); llvm::Constant *Values[3]; Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, PropertySize); Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Properties.size()); @@ -2269,7 +2832,7 @@ CGObjCMac::EmitMethodDescList(Twine Name, const char *Section, }; */ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { - unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.CategoryTy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.CategoryTy); // FIXME: This is poor design, the OCD should have a pointer to the category // decl. Additionally, note that Category can be null for the @implementation @@ -2338,15 +2901,37 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { MethodDefinitions.clear(); } -// FIXME: Get from somewhere? -enum ClassFlags { - eClassFlags_Factory = 0x00001, - eClassFlags_Meta = 0x00002, - // <rdr://5142207> - eClassFlags_HasCXXStructors = 0x02000, - eClassFlags_Hidden = 0x20000, - eClassFlags_ABI2_Hidden = 0x00010, - eClassFlags_ABI2_HasCXXStructors = 0x00004 // <rdr://4923634> +enum FragileClassFlags { + FragileABI_Class_Factory = 0x00001, + FragileABI_Class_Meta = 0x00002, + FragileABI_Class_HasCXXStructors = 0x02000, + FragileABI_Class_Hidden = 0x20000 +}; + +enum NonFragileClassFlags { + /// Is a meta-class. + NonFragileABI_Class_Meta = 0x00001, + + /// Is a root class. + NonFragileABI_Class_Root = 0x00002, + + /// Has a C++ constructor and destructor. + NonFragileABI_Class_HasCXXStructors = 0x00004, + + /// Has hidden visibility. + NonFragileABI_Class_Hidden = 0x00010, + + /// Has the exception attribute. + NonFragileABI_Class_Exception = 0x00020, + + /// (Obsolete) ARC-specific: this class has a .release_ivars method + NonFragileABI_Class_HasIvarReleaser = 0x00040, + + /// Class implementation was compiled under ARC. + NonFragileABI_Class_CompiledByARC = 0x00080, + + /// Class has non-trivial destructors, but zero-initialization is okay. + NonFragileABI_Class_HasCXXDestructorOnly = 0x00100 }; /* @@ -2379,15 +2964,15 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { EmitProtocolList("\01L_OBJC_CLASS_PROTOCOLS_" + ID->getName(), Interface->all_referenced_protocol_begin(), Interface->all_referenced_protocol_end()); - unsigned Flags = eClassFlags_Factory; - if (ID->hasCXXStructors()) - Flags |= eClassFlags_HasCXXStructors; + unsigned Flags = FragileABI_Class_Factory; + if (ID->hasNonZeroConstructors() || ID->hasDestructors()) + Flags |= FragileABI_Class_HasCXXStructors; unsigned Size = CGM.getContext().getASTObjCImplementationLayout(ID).getSize().getQuantity(); // FIXME: Set CXX-structors flag. if (ID->getClassInterface()->getVisibility() == HiddenVisibility) - Flags |= eClassFlags_Hidden; + Flags |= FragileABI_Class_Hidden; llvm::SmallVector<llvm::Constant*, 16> InstanceMethods, ClassMethods; for (ObjCImplementationDecl::instmeth_iterator @@ -2470,11 +3055,11 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { llvm::Constant *CGObjCMac::EmitMetaClass(const ObjCImplementationDecl *ID, llvm::Constant *Protocols, ArrayRef<llvm::Constant*> Methods) { - unsigned Flags = eClassFlags_Meta; - unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassTy); + unsigned Flags = FragileABI_Class_Meta; + unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassTy); if (ID->getClassInterface()->getVisibility() == HiddenVisibility) - Flags |= eClassFlags_Hidden; + Flags |= FragileABI_Class_Hidden; llvm::Constant *Values[12]; // The isa for the metaclass is the root of the hierarchy. @@ -2588,7 +3173,7 @@ llvm::Value *CGObjCMac::EmitSuperClassRef(const ObjCInterfaceDecl *ID) { llvm::Constant * CGObjCMac::EmitClassExtension(const ObjCImplementationDecl *ID) { uint64_t Size = - CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassExtensionTy); + CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassExtensionTy); llvm::Constant *Values[3]; Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); @@ -3481,7 +4066,7 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { - unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); @@ -3502,7 +4087,7 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, bool threadlocal) { llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { - unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); @@ -3528,7 +4113,7 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, assert(ivarOffset && "EmitObjCIvarAssign - ivarOffset is NULL"); llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { - unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); @@ -3548,7 +4133,7 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { - unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4) ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) : CGF.Builder.CreateBitCast(src, ObjCTypes.LongLongTy); @@ -3679,7 +4264,7 @@ void CGObjCCommonMac::EmitImageInfo() { static const int ModuleVersion = 7; void CGObjCMac::EmitModuleInfo() { - uint64_t Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.ModuleTy); + uint64_t Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ModuleTy); llvm::Constant *Values[] = { llvm::ConstantInt::get(ObjCTypes.LongTy, ModuleVersion), @@ -3824,7 +4409,7 @@ void CGObjCCommonMac::BuildAggrIvarRecordLayout(const RecordType *RT, Fields.push_back(*i); llvm::Type *Ty = CGM.getTypes().ConvertType(QualType(RT, 0)); const llvm::StructLayout *RecLayout = - CGM.getTargetData().getStructLayout(cast<llvm::StructType>(Ty)); + CGM.getDataLayout().getStructLayout(cast<llvm::StructType>(Ty)); BuildAggrIvarLayout(0, RecLayout, RD, Fields, BytePos, ForStrongLayout, HasUnion); @@ -3951,7 +4536,7 @@ void CGObjCCommonMac::BuildAggrIvarLayout(const ObjCImplementationDecl *OI, if (IsUnion) { // FIXME: Why the asymmetry? We divide by word size in bits on other // side. - uint64_t UnionIvarSize = FieldSize; + uint64_t UnionIvarSize = FieldSize / ByteSizeInBits; if (UnionIvarSize > MaxSkippedUnionIvarSize) { MaxSkippedUnionIvarSize = UnionIvarSize; MaxSkippedField = Field; @@ -4005,7 +4590,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayoutBitmap(std::string &BitMap) { // Build the string of skip/scan nibbles SmallVector<SKIP_SCAN, 32> SkipScanIvars; unsigned int WordSize = - CGM.getTypes().getTargetData().getTypeAllocSize(PtrTy); + CGM.getTypes().getDataLayout().getTypeAllocSize(PtrTy); if (IvarsInfo[0].ivar_bytepos == 0) { WordsToSkip = 0; WordsToScan = IvarsInfo[0].ivar_size; @@ -4187,7 +4772,7 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( printf("\n%s ivar layout for class '%s': ", ForStrongLayout ? "strong" : "weak", OMD->getClassInterface()->getName().data()); - const unsigned char *s = (unsigned char*)BitMap.c_str(); + const unsigned char *s = (const unsigned char*)BitMap.c_str(); for (unsigned i = 0, e = BitMap.size(); i < e; i++) if (!(s[i] & 0xf0)) printf("0x0%x%s", s[i], s[i] != 0 ? ", " : ""); @@ -4835,7 +5420,7 @@ AddModuleClassList(ArrayRef<llvm::GlobalValue*> Container, llvm::GlobalValue::InternalLinkage, Init, SymbolName); - GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType())); + GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType())); GV->setSection(SectionName); CGM.AddUsedGlobal(GV); } @@ -4941,19 +5526,6 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) { return VTableDispatchMethods.count(Sel); } -// Metadata flags -enum MetaDataDlags { - CLS = 0x0, - CLS_META = 0x1, - CLS_ROOT = 0x2, - OBJC2_CLS_HIDDEN = 0x10, - CLS_EXCEPTION = 0x20, - - /// (Obsolete) ARC-specific: this class has a .release_ivars method - CLS_HAS_IVAR_RELEASER = 0x40, - /// class was compiled with -fobjc-arr - CLS_COMPILED_BY_ARC = 0x80 // (1<<7) -}; /// BuildClassRoTInitializer - generate meta-data for: /// struct _class_ro_t { /// uint32_t const flags; @@ -4978,19 +5550,20 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( llvm::Constant *Values[10]; // 11 for 64bit targets! if (CGM.getLangOpts().ObjCAutoRefCount) - flags |= CLS_COMPILED_BY_ARC; + flags |= NonFragileABI_Class_CompiledByARC; Values[ 0] = llvm::ConstantInt::get(ObjCTypes.IntTy, flags); Values[ 1] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceStart); Values[ 2] = llvm::ConstantInt::get(ObjCTypes.IntTy, InstanceSize); // FIXME. For 64bit targets add 0 here. - Values[ 3] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes) + Values[ 3] = (flags & NonFragileABI_Class_Meta) + ? GetIvarLayoutName(0, ObjCTypes) : BuildIvarLayout(ID, true); Values[ 4] = GetClassName(ID->getIdentifier()); // const struct _method_list_t * const baseMethods; std::vector<llvm::Constant*> Methods; std::string MethodListName("\01l_OBJC_$_"); - if (flags & CLS_META) { + if (flags & NonFragileABI_Class_Meta) { MethodListName += "CLASS_METHODS_" + ID->getNameAsString(); for (ObjCImplementationDecl::classmeth_iterator i = ID->classmeth_begin(), e = ID->classmeth_end(); i != e; ++i) { @@ -5030,28 +5603,27 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( OID->all_referenced_protocol_begin(), OID->all_referenced_protocol_end()); - if (flags & CLS_META) + if (flags & NonFragileABI_Class_Meta) { Values[ 7] = llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy); - else - Values[ 7] = EmitIvarList(ID); - Values[ 8] = (flags & CLS_META) ? GetIvarLayoutName(0, ObjCTypes) - : BuildIvarLayout(ID, false); - if (flags & CLS_META) + Values[ 8] = GetIvarLayoutName(0, ObjCTypes); Values[ 9] = llvm::Constant::getNullValue(ObjCTypes.PropertyListPtrTy); - else + } else { + Values[ 7] = EmitIvarList(ID); + Values[ 8] = BuildIvarLayout(ID, false); Values[ 9] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + ID->getName(), ID, ID->getClassInterface(), ObjCTypes); + } llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassRonfABITy, Values); llvm::GlobalVariable *CLASS_RO_GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassRonfABITy, false, llvm::GlobalValue::InternalLinkage, Init, - (flags & CLS_META) ? + (flags & NonFragileABI_Class_Meta) ? std::string("\01l_OBJC_METACLASS_RO_$_")+ClassName : std::string("\01l_OBJC_CLASS_RO_$_")+ClassName); CLASS_RO_GV->setAlignment( - CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassRonfABITy)); + CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassRonfABITy)); CLASS_RO_GV->setSection("__DATA, __objc_const"); return CLASS_RO_GV; @@ -5088,7 +5660,7 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassMetaData( GV->setInitializer(Init); GV->setSection("__DATA, __objc_data"); GV->setAlignment( - CGM.getTargetData().getABITypeAlignment(ObjCTypes.ClassnfABITy)); + CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ClassnfABITy)); if (HiddenVisibility) GV->setVisibility(llvm::GlobalValue::HiddenVisibility); return GV; @@ -5138,23 +5710,31 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { "CGObjCNonFragileABIMac::GenerateClass - class is 0"); // FIXME: Is this correct (that meta class size is never computed)? uint32_t InstanceStart = - CGM.getTargetData().getTypeAllocSize(ObjCTypes.ClassnfABITy); + CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ClassnfABITy); uint32_t InstanceSize = InstanceStart; - uint32_t flags = CLS_META; + uint32_t flags = NonFragileABI_Class_Meta; std::string ObjCMetaClassName(getMetaclassSymbolPrefix()); std::string ObjCClassName(getClassSymbolPrefix()); llvm::GlobalVariable *SuperClassGV, *IsAGV; + // Build the flags for the metaclass. bool classIsHidden = ID->getClassInterface()->getVisibility() == HiddenVisibility; if (classIsHidden) - flags |= OBJC2_CLS_HIDDEN; - if (ID->hasCXXStructors()) - flags |= eClassFlags_ABI2_HasCXXStructors; + flags |= NonFragileABI_Class_Hidden; + + // FIXME: why is this flag set on the metaclass? + // ObjC metaclasses have no fields and don't really get constructed. + if (ID->hasNonZeroConstructors() || ID->hasDestructors()) { + flags |= NonFragileABI_Class_HasCXXStructors; + if (!ID->hasNonZeroConstructors()) + flags |= NonFragileABI_Class_HasCXXDestructorOnly; + } + if (!ID->getClassInterface()->getSuperClass()) { // class is root - flags |= CLS_ROOT; + flags |= NonFragileABI_Class_Root; SuperClassGV = GetClassGlobal(ObjCClassName + ClassName); IsAGV = GetClassGlobal(ObjCMetaClassName + ClassName); } else { @@ -5183,17 +5763,28 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { DefinedMetaClasses.push_back(MetaTClass); // Metadata for the class - flags = CLS; + flags = 0; if (classIsHidden) - flags |= OBJC2_CLS_HIDDEN; - if (ID->hasCXXStructors()) - flags |= eClassFlags_ABI2_HasCXXStructors; + flags |= NonFragileABI_Class_Hidden; + + if (ID->hasNonZeroConstructors() || ID->hasDestructors()) { + flags |= NonFragileABI_Class_HasCXXStructors; + + // Set a flag to enable a runtime optimization when a class has + // fields that require destruction but which don't require + // anything except zero-initialization during construction. This + // is most notably true of __strong and __weak types, but you can + // also imagine there being C++ types with non-trivial default + // constructors that merely set all fields to null. + if (!ID->hasNonZeroConstructors()) + flags |= NonFragileABI_Class_HasCXXDestructorOnly; + } if (hasObjCExceptionAttribute(CGM.getContext(), ID->getClassInterface())) - flags |= CLS_EXCEPTION; + flags |= NonFragileABI_Class_Exception; if (!ID->getClassInterface()->getSuperClass()) { - flags |= CLS_ROOT; + flags |= NonFragileABI_Class_Root; SuperClassGV = 0; } else { // Has a root. Current class is not a root. @@ -5220,7 +5811,7 @@ void CGObjCNonFragileABIMac::GenerateClass(const ObjCImplementationDecl *ID) { DefinedNonLazyClasses.push_back(ClassMD); // Force the definition of the EHType if necessary. - if (flags & CLS_EXCEPTION) + if (flags & NonFragileABI_Class_Exception) GetInterfaceEHType(ID->getClassInterface(), true); // Make sure method definition entries are all clear for next implementation. MethodDefinitions.clear(); @@ -5344,7 +5935,7 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { Init, ExtCatName); GCATV->setAlignment( - CGM.getTargetData().getABITypeAlignment(ObjCTypes.CategorynfABITy)); + CGM.getDataLayout().getABITypeAlignment(ObjCTypes.CategorynfABITy)); GCATV->setSection("__DATA, __objc_const"); CGM.AddUsedGlobal(GCATV); DefinedCategories.push_back(GCATV); @@ -5391,7 +5982,7 @@ CGObjCNonFragileABIMac::EmitMethodList(Twine Name, llvm::Constant *Values[3]; // sizeof(struct _objc_method) - unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.MethodTy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.MethodTy); Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); // method_count Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Methods.size()); @@ -5403,7 +5994,7 @@ CGObjCNonFragileABIMac::EmitMethodList(Twine Name, llvm::GlobalVariable *GV = new llvm::GlobalVariable(CGM.getModule(), Init->getType(), false, llvm::GlobalValue::InternalLinkage, Init, Name); - GV->setAlignment(CGM.getTargetData().getABITypeAlignment(Init->getType())); + GV->setAlignment(CGM.getDataLayout().getABITypeAlignment(Init->getType())); GV->setSection(Section); CGM.AddUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.MethodListnfABIPtrTy); @@ -5437,7 +6028,7 @@ CGObjCNonFragileABIMac::EmitIvarOffsetVar(const ObjCInterfaceDecl *ID, IvarOffsetGV->setInitializer(llvm::ConstantInt::get(ObjCTypes.LongTy, Offset)); IvarOffsetGV->setAlignment( - CGM.getTargetData().getABITypeAlignment(ObjCTypes.LongTy)); + CGM.getDataLayout().getABITypeAlignment(ObjCTypes.LongTy)); // FIXME: This matches gcc, but shouldn't the visibility be set on the use as // well (i.e., in ObjCIvarOffsetVariable). @@ -5490,7 +6081,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( Ivar[2] = GetMethodVarType(IVD); llvm::Type *FieldTy = CGM.getTypes().ConvertTypeForMem(IVD->getType()); - unsigned Size = CGM.getTargetData().getTypeAllocSize(FieldTy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(FieldTy); unsigned Align = CGM.getContext().getPreferredTypeAlign( IVD->getType().getTypePtr()) >> 3; Align = llvm::Log2_32(Align); @@ -5508,7 +6099,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( return llvm::Constant::getNullValue(ObjCTypes.IvarListnfABIPtrTy); llvm::Constant *Values[3]; - unsigned Size = CGM.getTargetData().getTypeAllocSize(ObjCTypes.IvarnfABITy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(ObjCTypes.IvarnfABITy); Values[0] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); Values[1] = llvm::ConstantInt::get(ObjCTypes.IntTy, Ivars.size()); llvm::ArrayType *AT = llvm::ArrayType::get(ObjCTypes.IvarnfABITy, @@ -5522,7 +6113,7 @@ llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( Init, Prefix + OID->getName()); GV->setAlignment( - CGM.getTargetData().getABITypeAlignment(Init->getType())); + CGM.getDataLayout().getABITypeAlignment(Init->getType())); GV->setSection("__DATA, __objc_const"); CGM.AddUsedGlobal(GV); @@ -5644,7 +6235,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( Values[7] = EmitPropertyList("\01l_OBJC_$_PROP_LIST_" + PD->getName(), 0, PD, ObjCTypes); uint32_t Size = - CGM.getTargetData().getTypeAllocSize(ObjCTypes.ProtocolnfABITy); + CGM.getDataLayout().getTypeAllocSize(ObjCTypes.ProtocolnfABITy); Values[8] = llvm::ConstantInt::get(ObjCTypes.IntTy, Size); Values[9] = llvm::Constant::getNullValue(ObjCTypes.IntTy); Values[10] = EmitProtocolMethodTypes("\01l_OBJC_$_PROTOCOL_METHOD_TYPES_" @@ -5663,7 +6254,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( false, llvm::GlobalValue::WeakAnyLinkage, Init, "\01l_OBJC_PROTOCOL_$_" + PD->getName()); Entry->setAlignment( - CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABITy)); + CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABITy)); Entry->setSection("__DATA,__datacoal_nt,coalesced"); Protocols[PD->getIdentifier()] = Entry; @@ -5678,7 +6269,7 @@ llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( false, llvm::GlobalValue::WeakAnyLinkage, Entry, "\01l_OBJC_LABEL_PROTOCOL_$_" + PD->getName()); PTGV->setAlignment( - CGM.getTargetData().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); + CGM.getDataLayout().getABITypeAlignment(ObjCTypes.ProtocolnfABIPtrTy)); PTGV->setSection("__DATA, __objc_protolist, coalesced, no_dead_strip"); PTGV->setVisibility(llvm::GlobalValue::HiddenVisibility); CGM.AddUsedGlobal(PTGV); @@ -5732,7 +6323,7 @@ CGObjCNonFragileABIMac::EmitProtocolList(Twine Name, Init, Name); GV->setSection("__DATA, __objc_const"); GV->setAlignment( - CGM.getTargetData().getABITypeAlignment(Init->getType())); + CGM.getDataLayout().getABITypeAlignment(Init->getType())); CGM.AddUsedGlobal(GV); return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ProtocolListnfABIPtrTy); @@ -5970,7 +6561,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitClassRefFromId(CGBuilderTy &Builder, ClassGV, "\01L_OBJC_CLASSLIST_REFERENCES_$_"); Entry->setAlignment( - CGM.getTargetData().getABITypeAlignment( + CGM.getDataLayout().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_classrefs, regular, no_dead_strip"); CGM.AddUsedGlobal(Entry); @@ -6004,7 +6595,7 @@ CGObjCNonFragileABIMac::EmitSuperClassRef(CGBuilderTy &Builder, ClassGV, "\01L_OBJC_CLASSLIST_SUP_REFS_$_"); Entry->setAlignment( - CGM.getTargetData().getABITypeAlignment( + CGM.getDataLayout().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); CGM.AddUsedGlobal(Entry); @@ -6030,7 +6621,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitMetaClassRef(CGBuilderTy &Builder, MetaClassGV, "\01L_OBJC_CLASSLIST_SUP_REFS_$_"); Entry->setAlignment( - CGM.getTargetData().getABITypeAlignment( + CGM.getDataLayout().getABITypeAlignment( ObjCTypes.ClassnfABIPtrTy)); Entry->setSection("__DATA, __objc_superrefs, regular, no_dead_strip"); @@ -6079,16 +6670,9 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, // If this is a class message the metaclass is passed as the target. llvm::Value *Target; - if (IsClassMessage) { - if (isCategoryImpl) { - // Message sent to "super' in a class method defined in - // a category implementation. - Target = EmitClassRef(CGF.Builder, Class); - Target = CGF.Builder.CreateStructGEP(Target, 0); - Target = CGF.Builder.CreateLoad(Target); - } else + if (IsClassMessage) Target = EmitMetaClassRef(CGF.Builder, Class); - } else + else Target = EmitSuperClassRef(CGF.Builder, Class); // FIXME: We shouldn't need to do this cast, rectify the ASTContext and @@ -6143,7 +6727,7 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *ivarOffset) { llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { - unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy)); @@ -6164,7 +6748,7 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign( llvm::Value *src, llvm::Value *dst) { llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { - unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy)); @@ -6211,7 +6795,7 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, llvm::Value *src, llvm::Value *dst) { llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { - unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy)); @@ -6232,7 +6816,7 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, bool threadlocal) { llvm::Type * SrcTy = src->getType(); if (!isa<llvm::PointerType>(SrcTy)) { - unsigned Size = CGM.getTargetData().getTypeAllocSize(SrcTy); + unsigned Size = CGM.getDataLayout().getTypeAllocSize(SrcTy); assert(Size <= 8 && "does not support size > 8"); src = (Size == 4 ? CGF.Builder.CreateBitCast(src, ObjCTypes.IntTy) : CGF.Builder.CreateBitCast(src, ObjCTypes.LongTy)); @@ -6364,7 +6948,7 @@ CGObjCNonFragileABIMac::GetInterfaceEHType(const ObjCInterfaceDecl *ID, if (CGM.getLangOpts().getVisibilityMode() == HiddenVisibility) Entry->setVisibility(llvm::GlobalValue::HiddenVisibility); - Entry->setAlignment(CGM.getTargetData().getABITypeAlignment( + Entry->setAlignment(CGM.getDataLayout().getABITypeAlignment( ObjCTypes.EHTypeTy)); if (ForDefinition) { diff --git a/lib/CodeGen/CGObjCRuntime.cpp b/lib/CodeGen/CGObjCRuntime.cpp index 9aa68376bcd0..6932dd709d16 100644 --- a/lib/CodeGen/CGObjCRuntime.cpp +++ b/lib/CodeGen/CGObjCRuntime.cpp @@ -78,6 +78,13 @@ uint64_t CGObjCRuntime::ComputeIvarBaseOffset(CodeGen::CodeGenModule &CGM, CGM.getContext().getCharWidth(); } +unsigned CGObjCRuntime::ComputeBitfieldBitOffset( + CodeGen::CodeGenModule &CGM, + const ObjCInterfaceDecl *ID, + const ObjCIvarDecl *Ivar) { + return LookupFieldBitOffset(CGM, ID, ID->getImplementation(), Ivar); +} + LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, const ObjCInterfaceDecl *OID, llvm::Value *BaseValue, diff --git a/lib/CodeGen/CGObjCRuntime.h b/lib/CodeGen/CGObjCRuntime.h index 219a3e4df0d4..3e77875e6baf 100644 --- a/lib/CodeGen/CGObjCRuntime.h +++ b/lib/CodeGen/CGObjCRuntime.h @@ -261,6 +261,8 @@ public: llvm::Value *Size) = 0; virtual llvm::Constant *BuildGCBlockLayout(CodeGen::CodeGenModule &CGM, const CodeGen::CGBlockInfo &blockInfo) = 0; + virtual llvm::Constant *BuildRCBlockLayout(CodeGen::CodeGenModule &CGM, + const CodeGen::CGBlockInfo &blockInfo) = 0; virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name) = 0; struct MessageSendInfo { @@ -275,6 +277,12 @@ public: MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method, QualType resultType, CallArgList &callArgs); + + // FIXME: This probably shouldn't be here, but the code to compute + // it is here. + unsigned ComputeBitfieldBitOffset(CodeGen::CodeGenModule &CGM, + const ObjCInterfaceDecl *ID, + const ObjCIvarDecl *Ivar); }; /// Creates an instance of an Objective-C runtime class. diff --git a/lib/CodeGen/CGRTTI.cpp b/lib/CodeGen/CGRTTI.cpp index d1b370a1f728..7c83d39f8bce 100644 --- a/lib/CodeGen/CGRTTI.cpp +++ b/lib/CodeGen/CGRTTI.cpp @@ -105,7 +105,6 @@ public: /// BuildTypeInfo - Build the RTTI type info struct for the given type. /// /// \param Force - true to force the creation of this RTTI value - /// \param ForEH - true if this is for exception handling llvm::Constant *BuildTypeInfo(QualType Ty, bool Force = false); }; } @@ -779,28 +778,24 @@ static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *Base, cast<CXXRecordDecl>(Base->getType()->getAs<RecordType>()->getDecl()); if (Base->isVirtual()) { - if (Bases.VirtualBases.count(BaseDecl)) { + // Mark the virtual base as seen. + if (!Bases.VirtualBases.insert(BaseDecl)) { // If this virtual base has been seen before, then the class is diamond // shaped. Flags |= RTTIBuilder::VMI_DiamondShaped; } else { if (Bases.NonVirtualBases.count(BaseDecl)) Flags |= RTTIBuilder::VMI_NonDiamondRepeat; - - // Mark the virtual base as seen. - Bases.VirtualBases.insert(BaseDecl); } } else { - if (Bases.NonVirtualBases.count(BaseDecl)) { + // Mark the non-virtual base as seen. + if (!Bases.NonVirtualBases.insert(BaseDecl)) { // If this non-virtual base has been seen before, then the class has non- // diamond shaped repeated inheritance. Flags |= RTTIBuilder::VMI_NonDiamondRepeat; } else { if (Bases.VirtualBases.count(BaseDecl)) Flags |= RTTIBuilder::VMI_NonDiamondRepeat; - - // Mark the non-virtual base as seen. - Bases.NonVirtualBases.insert(BaseDecl); } } @@ -891,7 +886,7 @@ void RTTIBuilder::BuildVMIClassTypeInfo(const CXXRecordDecl *RD) { Offset = Layout.getBaseClassOffset(BaseDecl); }; - OffsetFlags = Offset.getQuantity() << 8; + OffsetFlags = uint64_t(Offset.getQuantity()) << 8; // The low-order byte of __offset_flags contains flags, as given by the // masks from the enumeration __offset_flags_masks. @@ -982,7 +977,7 @@ llvm::Constant *CodeGenModule::GetAddrOfRTTIDescriptor(QualType Ty, // Return a bogus pointer if RTTI is disabled, unless it's for EH. // FIXME: should we even be calling this method if RTTI is disabled // and it's not for EH? - if (!ForEH && !getContext().getLangOpts().RTTI) + if (!ForEH && !getLangOpts().RTTI) return llvm::Constant::getNullValue(Int8PtrTy); if (ForEH && Ty->isObjCObjectPointerType() && diff --git a/lib/CodeGen/CGRecordLayout.h b/lib/CodeGen/CGRecordLayout.h index 94c822f49f17..3db5e0483bab 100644 --- a/lib/CodeGen/CGRecordLayout.h +++ b/lib/CodeGen/CGRecordLayout.h @@ -166,8 +166,8 @@ public: class CGRecordLayout { friend class CodeGenTypes; - CGRecordLayout(const CGRecordLayout&); // DO NOT IMPLEMENT - void operator=(const CGRecordLayout&); // DO NOT IMPLEMENT + CGRecordLayout(const CGRecordLayout &) LLVM_DELETED_FUNCTION; + void operator=(const CGRecordLayout &) LLVM_DELETED_FUNCTION; private: /// The LLVM type corresponding to this record layout; used when diff --git a/lib/CodeGen/CGRecordLayoutBuilder.cpp b/lib/CodeGen/CGRecordLayoutBuilder.cpp index d642ef8533c5..26ef3efe73e6 100644 --- a/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -25,7 +25,7 @@ #include "llvm/Type.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" using namespace clang; using namespace CodeGen; @@ -206,7 +206,7 @@ void CGRecordLayoutBuilder::Layout(const RecordDecl *D) { Alignment = Types.getContext().getASTRecordLayout(D).getAlignment(); Packed = D->hasAttr<PackedAttr>(); - IsMsStruct = D->hasAttr<MsStructAttr>(); + IsMsStruct = D->isMsStruct(Types.getContext()); if (D->isUnion()) { LayoutUnion(D); @@ -239,7 +239,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, llvm::Type *Ty = Types.ConvertTypeForMem(FD->getType()); CharUnits TypeSizeInBytes = - CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(Ty)); + CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(Ty)); uint64_t TypeSizeInBits = Types.getContext().toBits(TypeSizeInBytes); bool IsSigned = FD->getType()->isSignedIntegerOrEnumerationType(); @@ -259,7 +259,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, // in big-endian machines the first fields are in higher bit positions, // so revert the offset. The byte offsets are reversed(back) later. - if (Types.getTargetData().isBigEndian()) { + if (Types.getDataLayout().isBigEndian()) { FieldOffset = ((ContainingTypeSizeInBits)-FieldOffset-FieldSize); } @@ -334,7 +334,7 @@ CGBitFieldInfo CGBitFieldInfo::MakeInfo(CodeGenTypes &Types, // on big-endian machines we reverted the bit offset because first fields are // in higher bits. But this also reverts the bytes, so fix this here by reverting // the byte offset on big-endian machines. - if (Types.getTargetData().isBigEndian()) { + if (Types.getDataLayout().isBigEndian()) { AI.FieldByteOffset = Types.getContext().toCharUnitsFromBits( ContainingTypeSizeInBits - AccessStart - AccessWidth); } else { @@ -553,9 +553,9 @@ void CGRecordLayoutBuilder::LayoutUnion(const RecordDecl *D) { hasOnlyZeroSizedBitFields = false; CharUnits fieldAlign = CharUnits::fromQuantity( - Types.getTargetData().getABITypeAlignment(fieldType)); + Types.getDataLayout().getABITypeAlignment(fieldType)); CharUnits fieldSize = CharUnits::fromQuantity( - Types.getTargetData().getTypeAllocSize(fieldType)); + Types.getDataLayout().getTypeAllocSize(fieldType)); if (fieldAlign < unionAlign) continue; @@ -884,7 +884,7 @@ void CGRecordLayoutBuilder::AppendTailPadding(CharUnits RecordSize) { void CGRecordLayoutBuilder::AppendField(CharUnits fieldOffset, llvm::Type *fieldType) { CharUnits fieldSize = - CharUnits::fromQuantity(Types.getTargetData().getTypeAllocSize(fieldType)); + CharUnits::fromQuantity(Types.getDataLayout().getTypeAllocSize(fieldType)); FieldTypes.push_back(fieldType); @@ -957,7 +957,7 @@ CharUnits CGRecordLayoutBuilder::getTypeAlignment(llvm::Type *Ty) const { if (Packed) return CharUnits::One(); - return CharUnits::fromQuantity(Types.getTargetData().getABITypeAlignment(Ty)); + return CharUnits::fromQuantity(Types.getDataLayout().getABITypeAlignment(Ty)); } CharUnits CGRecordLayoutBuilder::getAlignmentAsLLVMStruct() const { @@ -1036,7 +1036,7 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, const ASTRecordLayout &Layout = getContext().getASTRecordLayout(D); uint64_t TypeSizeInBits = getContext().toBits(Layout.getSize()); - assert(TypeSizeInBits == getTargetData().getTypeAllocSizeInBits(Ty) && + assert(TypeSizeInBits == getDataLayout().getTypeAllocSizeInBits(Ty) && "Type size mismatch!"); if (BaseTy) { @@ -1049,19 +1049,19 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, getContext().toBits(AlignedNonVirtualTypeSize); assert(AlignedNonVirtualTypeSizeInBits == - getTargetData().getTypeAllocSizeInBits(BaseTy) && + getDataLayout().getTypeAllocSizeInBits(BaseTy) && "Type size mismatch!"); } // Verify that the LLVM and AST field offsets agree. llvm::StructType *ST = dyn_cast<llvm::StructType>(RL->getLLVMType()); - const llvm::StructLayout *SL = getTargetData().getStructLayout(ST); + const llvm::StructLayout *SL = getDataLayout().getStructLayout(ST); const ASTRecordLayout &AST_RL = getContext().getASTRecordLayout(D); RecordDecl::field_iterator it = D->field_begin(); const FieldDecl *LastFD = 0; - bool IsMsStruct = D->hasAttr<MsStructAttr>(); + bool IsMsStruct = D->isMsStruct(getContext()); for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) { const FieldDecl *FD = *it; diff --git a/lib/CodeGen/CGStmt.cpp b/lib/CodeGen/CGStmt.cpp index d78908dee876..3548dbac6fc1 100644 --- a/lib/CodeGen/CGStmt.cpp +++ b/lib/CodeGen/CGStmt.cpp @@ -21,7 +21,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/InlineAsm.h" #include "llvm/Intrinsics.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" using namespace clang; using namespace CodeGen; @@ -132,8 +132,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break; case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break; - case Stmt::AsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break; - case Stmt::MSAsmStmtClass: EmitMSAsmStmt(cast<MSAsmStmt>(*S)); break; + case Stmt::GCCAsmStmtClass: // Intentional fall-through. + case Stmt::MSAsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break; case Stmt::ObjCAtTryStmtClass: EmitObjCAtTryStmt(cast<ObjCAtTryStmt>(*S)); @@ -237,6 +237,10 @@ void CodeGenFunction::SimplifyForwardingBlocks(llvm::BasicBlock *BB) { if (!BI || !BI->isUnconditional()) return; + // Can only simplify empty blocks. + if (BI != BB->begin()) + return; + BB->replaceAllUsesWith(BI->getSuccessor(0)); BI->eraseFromParent(); BB->eraseFromParent(); @@ -743,6 +747,17 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { // Emit the result value, even if unused, to evalute the side effects. const Expr *RV = S.getRetValue(); + // Treat block literals in a return expression as if they appeared + // in their own scope. This permits a small, easily-implemented + // exception to our over-conservative rules about not jumping to + // statements following block literals with non-trivial cleanups. + RunCleanupsScope cleanupScope(*this); + if (const ExprWithCleanups *cleanups = + dyn_cast_or_null<ExprWithCleanups>(RV)) { + enterFullExpression(cleanups); + RV = cleanups->getSubExpr(); + } + // FIXME: Clean this up by using an LValue for ReturnTemp, // EmitStoreThroughLValue, and EmitAnyExpr. if (S.getNRVOCandidate() && S.getNRVOCandidate()->isNRVOVariable() && @@ -779,6 +794,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) { AggValueSlot::IsNotAliased)); } + cleanupScope.ForceCleanup(); EmitBranchThroughCleanup(ReturnBlock); } @@ -899,7 +915,8 @@ void CodeGenFunction::EmitCaseStmt(const CaseStmt &S) { // If the body of the case is just a 'break', and if there was no fallthrough, // try to not emit an empty block. - if ((CGM.getCodeGenOpts().OptimizationLevel > 0) && isa<BreakStmt>(S.getSubStmt())) { + if ((CGM.getCodeGenOpts().OptimizationLevel > 0) && + isa<BreakStmt>(S.getSubStmt())) { JumpDest Block = BreakContinueStack.back().BreakBlock; // Only do this optimization if there are no cleanups that need emitting. @@ -1263,6 +1280,10 @@ SimplifyConstraint(const char *Constraint, const TargetInfo &Target, case '=': // Will see this and the following in mult-alt constraints. case '+': break; + case '#': // Ignore the rest of the constraint alternative. + while (Constraint[1] && Constraint[1] != ',') + Constraint++; + break; case ',': Result += "|"; break; @@ -1323,8 +1344,7 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr, } llvm::Value* -CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S, - const TargetInfo::ConstraintInfo &Info, +CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info, LValue InputValue, QualType InputType, std::string &ConstraintStr) { llvm::Value *Arg; @@ -1333,7 +1353,7 @@ CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S, Arg = EmitLoadOfLValue(InputValue).getScalarVal(); } else { llvm::Type *Ty = ConvertType(InputType); - uint64_t Size = CGM.getTargetData().getTypeSizeInBits(Ty); + uint64_t Size = CGM.getDataLayout().getTypeSizeInBits(Ty); if (Size <= 64 && llvm::isPowerOf2_64(Size)) { Ty = llvm::IntegerType::get(getLLVMContext(), Size); Ty = llvm::PointerType::getUnqual(Ty); @@ -1353,7 +1373,7 @@ CodeGenFunction::EmitAsmInputLValue(const AsmStmt &S, return Arg; } -llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S, +llvm::Value* CodeGenFunction::EmitAsmInput( const TargetInfo::ConstraintInfo &Info, const Expr *InputExpr, std::string &ConstraintStr) { @@ -1363,7 +1383,7 @@ llvm::Value* CodeGenFunction::EmitAsmInput(const AsmStmt &S, InputExpr = InputExpr->IgnoreParenNoopCasts(getContext()); LValue Dest = EmitLValue(InputExpr); - return EmitAsmInputLValue(S, Info, Dest, InputExpr->getType(), ConstraintStr); + return EmitAsmInputLValue(Info, Dest, InputExpr->getType(), ConstraintStr); } /// getAsmSrcLocInfo - Return the !srcloc metadata node to attach to an inline @@ -1396,23 +1416,8 @@ static llvm::MDNode *getAsmSrcLocInfo(const StringLiteral *Str, } void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { - // Analyze the asm string to decompose it into its pieces. We know that Sema - // has already done this, so it is guaranteed to be successful. - SmallVector<AsmStmt::AsmStringPiece, 4> Pieces; - unsigned DiagOffs; - S.AnalyzeAsmString(Pieces, getContext(), DiagOffs); - - // Assemble the pieces into the final asm string. - std::string AsmString; - for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { - if (Pieces[i].isString()) - AsmString += Pieces[i].getString(); - else if (Pieces[i].getModifier() == '\0') - AsmString += '$' + llvm::utostr(Pieces[i].getOperandNo()); - else - AsmString += "${" + llvm::utostr(Pieces[i].getOperandNo()) + ':' + - Pieces[i].getModifier() + '}'; - } + // Assemble the final asm string. + std::string AsmString = S.generateAsmString(getContext()); // Get all the output and input constraints together. SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; @@ -1511,7 +1516,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { InOutConstraints += ','; const Expr *InputExpr = S.getOutputExpr(i); - llvm::Value *Arg = EmitAsmInputLValue(S, Info, Dest, InputExpr->getType(), + llvm::Value *Arg = EmitAsmInputLValue(Info, Dest, InputExpr->getType(), InOutConstraints); if (llvm::Type* AdjTy = @@ -1549,7 +1554,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { *InputExpr->IgnoreParenNoopCasts(getContext()), Target, CGM, S); - llvm::Value *Arg = EmitAsmInput(S, Info, InputExpr, Constraints); + llvm::Value *Arg = EmitAsmInput(Info, InputExpr, Constraints); // If this input argument is tied to a larger output result, extend the // input to be the same size as the output. The LLVM backend wants to see @@ -1596,7 +1601,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Clobbers for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) { - StringRef Clobber = S.getClobber(i)->getString(); + StringRef Clobber = S.getClobber(i); if (Clobber != "memory" && Clobber != "cc") Clobber = Target.getNormalizedGCCRegisterName(Clobber); @@ -1628,15 +1633,22 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { llvm::FunctionType *FTy = llvm::FunctionType::get(ResultType, ArgTypes, false); + bool HasSideEffect = S.isVolatile() || S.getNumOutputs() == 0; + llvm::InlineAsm::AsmDialect AsmDialect = isa<MSAsmStmt>(&S) ? + llvm::InlineAsm::AD_Intel : llvm::InlineAsm::AD_ATT; llvm::InlineAsm *IA = - llvm::InlineAsm::get(FTy, AsmString, Constraints, - S.isVolatile() || S.getNumOutputs() == 0); + llvm::InlineAsm::get(FTy, AsmString, Constraints, HasSideEffect, + /* IsAlignStack */ false, AsmDialect); llvm::CallInst *Result = Builder.CreateCall(IA, Args); - Result->addAttribute(~0, llvm::Attribute::NoUnwind); + Result->addAttribute(llvm::AttrListPtr::FunctionIndex, + llvm::Attributes::get(getLLVMContext(), + llvm::Attributes::NoUnwind)); // Slap the source location of the inline asm into a !srcloc metadata on the - // call. - Result->setMetadata("srcloc", getAsmSrcLocInfo(S.getAsmString(), *this)); + // call. FIXME: Handle metadata for MS-style inline asms. + if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S)) + Result->setMetadata("srcloc", getAsmSrcLocInfo(gccAsmStmt->getAsmString(), + *this)); // Extract all of the register value results from the asm. std::vector<llvm::Value*> RegResults; @@ -1662,12 +1674,12 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { if (TruncTy->isFloatingPointTy()) Tmp = Builder.CreateFPTrunc(Tmp, TruncTy); else if (TruncTy->isPointerTy() && Tmp->getType()->isIntegerTy()) { - uint64_t ResSize = CGM.getTargetData().getTypeSizeInBits(TruncTy); + uint64_t ResSize = CGM.getDataLayout().getTypeSizeInBits(TruncTy); Tmp = Builder.CreateTrunc(Tmp, llvm::IntegerType::get(getLLVMContext(), (unsigned)ResSize)); Tmp = Builder.CreateIntToPtr(Tmp, TruncTy); } else if (Tmp->getType()->isPointerTy() && TruncTy->isIntegerTy()) { - uint64_t TmpSize =CGM.getTargetData().getTypeSizeInBits(Tmp->getType()); + uint64_t TmpSize =CGM.getDataLayout().getTypeSizeInBits(Tmp->getType()); Tmp = Builder.CreatePtrToInt(Tmp, llvm::IntegerType::get(getLLVMContext(), (unsigned)TmpSize)); Tmp = Builder.CreateTrunc(Tmp, TruncTy); @@ -1681,47 +1693,3 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { EmitStoreThroughLValue(RValue::get(Tmp), ResultRegDests[i]); } } - -void CodeGenFunction::EmitMSAsmStmt(const MSAsmStmt &S) { - // MS-style inline assembly is not fully supported, so sema emits a warning. - if (!CGM.getCodeGenOpts().EmitMicrosoftInlineAsm) - return; - - assert (S.isSimple() && "CodeGen can only handle simple MSAsmStmts."); - - std::vector<llvm::Value*> Args; - std::vector<llvm::Type *> ArgTypes; - std::string Constraints; - - // Clobbers - for (unsigned i = 0, e = S.getNumClobbers(); i != e; ++i) { - StringRef Clobber = S.getClobber(i); - - if (Clobber != "memory" && Clobber != "cc") - Clobber = Target.getNormalizedGCCRegisterName(Clobber); - - if (i != 0) - Constraints += ','; - - Constraints += "~{"; - Constraints += Clobber; - Constraints += '}'; - } - - // Add machine specific clobbers - std::string MachineClobbers = Target.getClobbers(); - if (!MachineClobbers.empty()) { - if (!Constraints.empty()) - Constraints += ','; - Constraints += MachineClobbers; - } - - llvm::FunctionType *FTy = - llvm::FunctionType::get(VoidTy, ArgTypes, false); - - llvm::InlineAsm *IA = - llvm::InlineAsm::get(FTy, *S.getAsmString(), Constraints, true); - llvm::CallInst *Result = Builder.CreateCall(IA, Args); - Result->addAttribute(~0, llvm::Attribute::NoUnwind); - Result->addAttribute(~0, llvm::Attribute::IANSDialect); -} diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index cdaa26a2bad6..5b37fe4b9634 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -79,15 +79,16 @@ llvm::Constant *CodeGenModule::GetAddrOfThunk(GlobalDecl GD, static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF, llvm::Value *Ptr, int64_t NonVirtualAdjustment, - int64_t VirtualAdjustment) { + int64_t VirtualAdjustment, + bool IsReturnAdjustment) { if (!NonVirtualAdjustment && !VirtualAdjustment) return Ptr; llvm::Type *Int8PtrTy = CGF.Int8PtrTy; llvm::Value *V = CGF.Builder.CreateBitCast(Ptr, Int8PtrTy); - if (NonVirtualAdjustment) { - // Do the non-virtual adjustment. + if (NonVirtualAdjustment && !IsReturnAdjustment) { + // Perform the non-virtual adjustment for a base-to-derived cast. V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment); } @@ -95,7 +96,7 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF, llvm::Type *PtrDiffTy = CGF.ConvertType(CGF.getContext().getPointerDiffType()); - // Do the virtual adjustment. + // Perform the virtual adjustment. llvm::Value *VTablePtrPtr = CGF.Builder.CreateBitCast(V, Int8PtrTy->getPointerTo()); @@ -113,6 +114,11 @@ static llvm::Value *PerformTypeAdjustment(CodeGenFunction &CGF, V = CGF.Builder.CreateInBoundsGEP(V, Offset); } + if (NonVirtualAdjustment && IsReturnAdjustment) { + // Perform the non-virtual adjustment for a derived-to-base cast. + V = CGF.Builder.CreateConstInBoundsGEP1_64(V, NonVirtualAdjustment); + } + // Cast back to the original type. return CGF.Builder.CreateBitCast(V, Ptr->getType()); } @@ -150,8 +156,7 @@ static void setThunkVisibility(CodeGenModule &CGM, const CXXMethodDecl *MD, case TSK_ExplicitSpecialization: case TSK_ImplicitInstantiation: - if (!CGM.getCodeGenOpts().HiddenWeakTemplateVTables) - return; + return; break; } @@ -199,7 +204,8 @@ static RValue PerformReturnAdjustment(CodeGenFunction &CGF, ReturnValue = PerformTypeAdjustment(CGF, ReturnValue, Thunk.Return.NonVirtual, - Thunk.Return.VBaseOffsetOffset); + Thunk.Return.VBaseOffsetOffset, + /*IsReturnAdjustment*/true); if (NullCheckValue) { CGF.Builder.CreateBr(AdjustEnd); @@ -248,7 +254,9 @@ void CodeGenFunction::GenerateVarArgsThunk( llvm::Function *BaseFn = cast<llvm::Function>(Callee); // Clone to thunk. - llvm::Function *NewFn = llvm::CloneFunction(BaseFn); + llvm::ValueToValueMapTy VMap; + llvm::Function *NewFn = llvm::CloneFunction(BaseFn, VMap, + /*ModuleLevelChanges=*/false); CGM.getModule().getFunctionList().push_back(NewFn); Fn->replaceAllUsesWith(NewFn); NewFn->takeName(Fn); @@ -281,7 +289,8 @@ void CodeGenFunction::GenerateVarArgsThunk( llvm::Value *AdjustedThisPtr = PerformTypeAdjustment(*this, ThisPtr, Thunk.This.NonVirtual, - Thunk.This.VCallOffsetOffset); + Thunk.This.VCallOffsetOffset, + /*IsReturnAdjustment*/false); ThisStore->setOperand(0, AdjustedThisPtr); if (!Thunk.Return.isEmpty()) { @@ -324,7 +333,10 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, FunctionArgs.push_back(Param); } - + + // Initialize debug info if needed. + maybeInitializeDebugInfo(); + StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs, SourceLocation()); @@ -335,7 +347,8 @@ void CodeGenFunction::GenerateThunk(llvm::Function *Fn, llvm::Value *AdjustedThisPtr = PerformTypeAdjustment(*this, LoadCXXThis(), Thunk.This.NonVirtual, - Thunk.This.VCallOffsetOffset); + Thunk.This.VCallOffsetOffset, + /*IsReturnAdjustment*/false); CallArgList CallArgs; @@ -455,6 +468,8 @@ void CodeGenVTables::EmitThunk(GlobalDecl GD, const ThunkInfo &Thunk, return; } + CGM.SetLLVMFunctionAttributesForDefinition(GD.getDecl(), ThunkFn); + if (ThunkFn->isVarArg()) { // Varargs thunks are special; we can't just generate a call because // we can't copy the varargs. Our implementation is rather @@ -524,7 +539,7 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, unsigned NextVTableThunkIndex = 0; - llvm::Constant* PureVirtualFn = 0; + llvm::Constant *PureVirtualFn = 0, *DeletedVirtualFn = 0; for (unsigned I = 0; I != NumComponents; ++I) { VTableComponent Component = Components[I]; @@ -573,14 +588,25 @@ CodeGenVTables::CreateVTableInitializer(const CXXRecordDecl *RD, if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) { // We have a pure virtual member function. if (!PureVirtualFn) { - llvm::FunctionType *Ty =
- llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false);
- StringRef PureCallName = CGM.getCXXABI().GetPureVirtualCallName();
- PureVirtualFn = CGM.CreateRuntimeFunction(Ty, PureCallName);
- PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn,
+ llvm::FunctionType *Ty = + llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); + StringRef PureCallName = CGM.getCXXABI().GetPureVirtualCallName(); + PureVirtualFn = CGM.CreateRuntimeFunction(Ty, PureCallName); + PureVirtualFn = llvm::ConstantExpr::getBitCast(PureVirtualFn, CGM.Int8PtrTy); } Init = PureVirtualFn; + } else if (cast<CXXMethodDecl>(GD.getDecl())->isDeleted()) { + if (!DeletedVirtualFn) { + llvm::FunctionType *Ty = + llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); + StringRef DeletedCallName = + CGM.getCXXABI().GetDeletedVirtualCallName(); + DeletedVirtualFn = CGM.CreateRuntimeFunction(Ty, DeletedCallName); + DeletedVirtualFn = llvm::ConstantExpr::getBitCast(DeletedVirtualFn, + CGM.Int8PtrTy); + } + Init = DeletedVirtualFn; } else { // Check if we should use a thunk. if (NextVTableThunkIndex < NumVTableThunks && diff --git a/lib/CodeGen/CodeGenAction.cpp b/lib/CodeGen/CodeGenAction.cpp index dd32167b8477..9d6d183d97d9 100644 --- a/lib/CodeGen/CodeGenAction.cpp +++ b/lib/CodeGen/CodeGenAction.cpp @@ -65,9 +65,11 @@ namespace clang { TargetOpts(targetopts), LangOpts(langopts), AsmOutStream(OS), + Context(), LLVMIRGeneration("LLVM IR Generation Time"), Gen(CreateLLVMCodeGen(Diags, infile, compopts, C)), - LinkModule(LinkModule) { + LinkModule(LinkModule) + { llvm::TimePassesIsEnabled = TimePasses; } @@ -379,7 +381,7 @@ void CodeGenAction::ExecuteAction() { // FIXME: This is stupid, IRReader shouldn't take ownership. llvm::MemoryBuffer *MainFileCopy = llvm::MemoryBuffer::getMemBufferCopy(MainFile->getBuffer(), - getCurrentFile().c_str()); + getCurrentFile()); llvm::SMDiagnostic Err; TheModule.reset(ParseIR(MainFileCopy, Err, *VMContext)); diff --git a/lib/CodeGen/CodeGenFunction.cpp b/lib/CodeGen/CodeGenFunction.cpp index 1d02861ed786..18f1623d242e 100644 --- a/lib/CodeGen/CodeGenFunction.cpp +++ b/lib/CodeGen/CodeGenFunction.cpp @@ -24,7 +24,7 @@ #include "clang/Frontend/CodeGenOptions.h" #include "llvm/Intrinsics.h" #include "llvm/MDBuilder.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" using namespace clang; using namespace CodeGen; @@ -32,6 +32,10 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) : CodeGenTypeCache(cgm), CGM(cgm), Target(CGM.getContext().getTargetInfo()), Builder(cgm.getModule().getContext()), + SanitizePerformTypeCheck(CGM.getLangOpts().SanitizeNull | + CGM.getLangOpts().SanitizeAlignment | + CGM.getLangOpts().SanitizeObjectSize | + CGM.getLangOpts().SanitizeVptr), AutoreleaseResult(false), BlockInfo(0), BlockPointer(0), LambdaThisCaptureField(0), NormalCleanupDest(0), NextCleanupDestIndex(1), FirstBlockInfo(0), EHResumeBlock(0), ExceptionSlot(0), EHSelectorSlot(0), @@ -40,8 +44,6 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) CXXABIThisDecl(0), CXXABIThisValue(0), CXXThisValue(0), CXXVTTDecl(0), CXXVTTValue(0), OutermostConditional(0), TerminateLandingPad(0), TerminateHandler(0), TrapBB(0) { - - CatchUndefined = getContext().getLangOpts().CatchUndefined; if (!suppressNewContext) CGM.getCXXABI().getMangleContext().startNewFunction(); } @@ -348,11 +350,11 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, for (FunctionDecl::redecl_iterator RI = FD->redecls_begin(), RE = FD->redecls_end(); RI != RE; ++RI) if (RI->isInlineSpecified()) { - Fn->addFnAttr(llvm::Attribute::InlineHint); + Fn->addFnAttr(llvm::Attributes::InlineHint); break; } - if (getContext().getLangOpts().OpenCL) { + if (getLangOpts().OpenCL) { // Add metadata for a kernel function. if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) EmitOpenCLKernelMetadata(FD, Fn); @@ -485,7 +487,7 @@ static void TryMarkNoThrow(llvm::Function *F) { } else if (isa<llvm::ResumeInst>(&*BI)) { return; } - F->setDoesNotThrow(true); + F->setDoesNotThrow(); } void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, @@ -493,8 +495,8 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl()); // Check if we should generate debug info for this function. - if (CGM.getModuleDebugInfo() && !FD->hasAttr<NoDebugAttr>()) - DebugInfo = CGM.getModuleDebugInfo(); + if (!FD->hasAttr<NoDebugAttr>()) + maybeInitializeDebugInfo(); FunctionArgList Args; QualType ResTy = FD->getResultType(); @@ -517,7 +519,7 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, EmitDestructorBody(Args); else if (isa<CXXConstructorDecl>(FD)) EmitConstructorBody(Args); - else if (getContext().getLangOpts().CUDA && + else if (getLangOpts().CUDA && !CGM.getCodeGenOpts().CUDAIsDevice && FD->hasAttr<CUDAGlobalAttr>()) CGM.getCUDARuntime().EmitDeviceStubBody(*this, Args); @@ -535,6 +537,24 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn, else EmitFunctionBody(Args); + // C++11 [stmt.return]p2: + // Flowing off the end of a function [...] results in undefined behavior in + // a value-returning function. + // C11 6.9.1p12: + // If the '}' that terminates a function is reached, and the value of the + // function call is used by the caller, the behavior is undefined. + if (getLangOpts().CPlusPlus && !FD->hasImplicitReturnZero() && + !FD->getResultType()->isVoidType() && Builder.GetInsertBlock()) { + if (getLangOpts().SanitizeReturn) + EmitCheck(Builder.getFalse(), "missing_return", + EmitCheckSourceLocation(FD->getLocation()), + llvm::ArrayRef<llvm::Value*>()); + else if (CGM.getCodeGenOpts().OptimizationLevel == 0) + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::trap)); + Builder.CreateUnreachable(); + Builder.ClearInsertionPoint(); + } + // Emit the standard function epilogue. FinishFunction(BodyRange.getEnd()); @@ -806,7 +826,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType, void CodeGenFunction::EmitNullInitialization(llvm::Value *DestPtr, QualType Ty) { // Ignore empty classes in C++. - if (getContext().getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus) { if (const RecordType *RT = Ty->getAs<RecordType>()) { if (cast<CXXRecordDecl>(RT->getDecl())->isEmpty()) return; @@ -983,8 +1003,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType, arrayType = getContext().getAsArrayType(eltType); } - unsigned AddressSpace = - cast<llvm::PointerType>(addr->getType())->getAddressSpace(); + unsigned AddressSpace = addr->getType()->getPointerAddressSpace(); llvm::Type *BaseType = ConvertType(eltType)->getPointerTo(AddressSpace); addr = Builder.CreateBitCast(addr, BaseType, "array.begin"); } else { @@ -1027,6 +1046,7 @@ CodeGenFunction::getVLASize(const VariableArrayType *type) { numElements = vlaSize; } else { // It's undefined behavior if this wraps around, so mark it that way. + // FIXME: Teach -fcatch-undefined-behavior to trap this. numElements = Builder.CreateNUWMul(numElements, vlaSize); } } while ((type = getContext().getAsVariableArrayType(elementType))); @@ -1104,10 +1124,26 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { // e.g. with a typedef and a pointer to it. llvm::Value *&entry = VLASizeMap[size]; if (!entry) { + llvm::Value *Size = EmitScalarExpr(size); + + // C11 6.7.6.2p5: + // If the size is an expression that is not an integer constant + // expression [...] each time it is evaluated it shall have a value + // greater than zero. + if (getLangOpts().SanitizeVLABound && + size->getType()->isSignedIntegerType()) { + llvm::Value *Zero = llvm::Constant::getNullValue(Size->getType()); + llvm::Constant *StaticArgs[] = { + EmitCheckSourceLocation(size->getLocStart()), + EmitCheckTypeDescriptor(size->getType()) + }; + EmitCheck(Builder.CreateICmpSGT(Size, Zero), + "vla_bound_not_positive", StaticArgs, Size); + } + // Always zexting here would be wrong if it weren't // undefined behavior to have a negative bound. - entry = Builder.CreateIntCast(EmitScalarExpr(size), SizeTy, - /*signed*/ false); + entry = Builder.CreateIntCast(Size, SizeTy, /*signed*/ false); } } type = vat->getElementType(); @@ -1156,7 +1192,7 @@ void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E, llvm::Constant *Init) { assert (Init && "Invalid DeclRefExpr initializer!"); if (CGDebugInfo *Dbg = getDebugInfo()) - if (CGM.getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) + if (CGM.getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) Dbg->EmitGlobalVariable(E->getDecl(), Init); } diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index ed3e43beb0f8..f2ab226ab530 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -222,8 +222,7 @@ public: /// immediately-enclosing context of the cleanup scope. For /// EH cleanups, this is run in a terminate context. /// - // \param IsForEHCleanup true if this is for an EH cleanup, false - /// if for a normal cleanup. + // \param flags cleanup kind. virtual void Emit(CodeGenFunction &CGF, Flags flags) = 0; }; @@ -533,8 +532,8 @@ public: /// CodeGenFunction - This class organizes the per-function state that is used /// while generating LLVM code. class CodeGenFunction : public CodeGenTypeCache { - CodeGenFunction(const CodeGenFunction&); // DO NOT IMPLEMENT - void operator=(const CodeGenFunction&); // DO NOT IMPLEMENT + CodeGenFunction(const CodeGenFunction &) LLVM_DELETED_FUNCTION; + void operator=(const CodeGenFunction &) LLVM_DELETED_FUNCTION; friend class CGCXXABI; public: @@ -595,8 +594,9 @@ public: /// potentially higher performance penalties. unsigned char BoundsChecking; - /// CatchUndefined - Emit run-time checks to catch undefined behaviors. - bool CatchUndefined; + /// \brief Whether any type-checking sanitizers are enabled. If \c false, + /// calls to EmitTypeCheck can be skipped. + bool SanitizePerformTypeCheck; /// In ARC, whether we should autorelease the return value. bool AutoreleaseResult; @@ -795,8 +795,8 @@ public: bool OldDidCallStackSave; bool PerformCleanup; - RunCleanupsScope(const RunCleanupsScope &); // DO NOT IMPLEMENT - RunCleanupsScope &operator=(const RunCleanupsScope &); // DO NOT IMPLEMENT + RunCleanupsScope(const RunCleanupsScope &) LLVM_DELETED_FUNCTION; + void operator=(const RunCleanupsScope &) LLVM_DELETED_FUNCTION; protected: CodeGenFunction& CGF; @@ -839,8 +839,8 @@ public: SourceRange Range; bool PopDebugStack; - LexicalScope(const LexicalScope &); // DO NOT IMPLEMENT THESE - LexicalScope &operator=(const LexicalScope &); + LexicalScope(const LexicalScope &) LLVM_DELETED_FUNCTION; + void operator=(const LexicalScope &) LLVM_DELETED_FUNCTION; public: /// \brief Enter a new cleanup scope. @@ -908,7 +908,7 @@ public: /// themselves). void popCatchScope(); - llvm::BasicBlock *getEHResumeBlock(); + llvm::BasicBlock *getEHResumeBlock(bool isCleanup); llvm::BasicBlock *getEHDispatchBlock(EHScopeStack::stable_iterator scope); /// An object to manage conditionally-evaluated expressions. @@ -1213,6 +1213,14 @@ public: CodeGenTypes &getTypes() const { return CGM.getTypes(); } ASTContext &getContext() const { return CGM.getContext(); } + /// Returns true if DebugInfo is actually initialized. + bool maybeInitializeDebugInfo() { + if (CGM.getModuleDebugInfo()) { + DebugInfo = CGM.getModuleDebugInfo(); + return true; + } + return false; + } CGDebugInfo *getDebugInfo() { if (DisableDebugInfo) return NULL; @@ -1504,7 +1512,7 @@ public: static bool hasAggregateLLVMType(QualType T); /// createBasicBlock - Create an LLVM basic block. - llvm::BasicBlock *createBasicBlock(StringRef name = "", + llvm::BasicBlock *createBasicBlock(const Twine &name = "", llvm::Function *parent = 0, llvm::BasicBlock *before = 0) { #ifdef NDEBUG @@ -1631,7 +1639,7 @@ public: /// aggregate expression, the aggloc/agglocvolatile arguments indicate where /// the result should be returned. /// - /// \param IgnoreResult - True if the resulting value isn't used. + /// \param ignoreResult True if the resulting value isn't used. RValue EmitAnyExpr(const Expr *E, AggValueSlot aggSlot = AggValueSlot::ignored(), bool ignoreResult = false); @@ -1654,13 +1662,26 @@ public: void EmitExprAsInit(const Expr *init, const ValueDecl *D, LValue lvalue, bool capturedByInit); + /// EmitAggregateCopy - Emit an aggrate assignment. + /// + /// The difference to EmitAggregateCopy is that tail padding is not copied. + /// This is required for correctness when assigning non-POD structures in C++. + void EmitAggregateAssign(llvm::Value *DestPtr, llvm::Value *SrcPtr, + QualType EltTy, bool isVolatile=false, + CharUnits Alignment = CharUnits::Zero()) { + EmitAggregateCopy(DestPtr, SrcPtr, EltTy, isVolatile, Alignment, true); + } + /// EmitAggregateCopy - Emit an aggrate copy. /// /// \param isVolatile - True iff either the source or the destination is /// volatile. + /// \param isAssignment - If false, allow padding to be copied. This often + /// yields more efficient. void EmitAggregateCopy(llvm::Value *DestPtr, llvm::Value *SrcPtr, QualType EltTy, bool isVolatile=false, - CharUnits Alignment = CharUnits::Zero()); + CharUnits Alignment = CharUnits::Zero(), + bool isAssignment = false); /// StartBlock - Start new block named N. If insert block is a dummy block /// then reuse it. @@ -1829,12 +1850,37 @@ public: llvm::Value* EmitCXXTypeidExpr(const CXXTypeidExpr *E); llvm::Value *EmitDynamicCast(llvm::Value *V, const CXXDynamicCastExpr *DCE); + llvm::Value* EmitCXXUuidofExpr(const CXXUuidofExpr *E); void MaybeEmitStdInitializerListCleanup(llvm::Value *loc, const Expr *init); void EmitStdInitializerListCleanup(llvm::Value *loc, const InitListExpr *init); - void EmitCheck(llvm::Value *, unsigned Size); + /// \brief Situations in which we might emit a check for the suitability of a + /// pointer or glvalue. + enum TypeCheckKind { + /// Checking the operand of a load. Must be suitably sized and aligned. + TCK_Load, + /// Checking the destination of a store. Must be suitably sized and aligned. + TCK_Store, + /// Checking the bound value in a reference binding. Must be suitably sized + /// and aligned, but is not required to refer to an object (until the + /// reference is used), per core issue 453. + TCK_ReferenceBinding, + /// Checking the object expression in a non-static data member access. Must + /// be an object within its lifetime. + TCK_MemberAccess, + /// Checking the 'this' pointer for a call to a non-static member function. + /// Must be an object within its lifetime. + TCK_MemberCall, + /// Checking the 'this' pointer for a constructor call. + TCK_ConstructorCall + }; + + /// \brief Emit a check that \p V is the address of storage of the + /// appropriate size and alignment for an object of type \p Type. + void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, llvm::Value *V, + QualType Type, CharUnits Alignment = CharUnits::Zero()); llvm::Value *EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre); @@ -1981,7 +2027,6 @@ public: void EmitCaseStmt(const CaseStmt &S); void EmitCaseStmtRange(const CaseStmt &S); void EmitAsmStmt(const AsmStmt &S); - void EmitMSAsmStmt(const MSAsmStmt &S); void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S); void EmitObjCAtTryStmt(const ObjCAtTryStmt &S); @@ -2033,11 +2078,10 @@ public: /// LValue EmitLValue(const Expr *E); - /// EmitCheckedLValue - Same as EmitLValue but additionally we generate - /// checking code to guard against undefined behavior. This is only - /// suitable when we know that the address will be used to access the - /// object. - LValue EmitCheckedLValue(const Expr *E); + /// \brief Same as EmitLValue but additionally we generate checking code to + /// guard against undefined behavior. This is only suitable when we know + /// that the address will be used to access the object. + LValue EmitCheckedLValue(const Expr *E, TypeCheckKind TCK); /// EmitToMemory - Change a scalar value from its value /// representation to its in-memory representation. @@ -2178,6 +2222,7 @@ public: LValue EmitCXXBindTemporaryLValue(const CXXBindTemporaryExpr *E); LValue EmitLambdaLValue(const LambdaExpr *E); LValue EmitCXXTypeidLValue(const CXXTypeidExpr *E); + LValue EmitCXXUuidofLValue(const CXXUuidofExpr *E); LValue EmitObjCMessageExprLValue(const ObjCMessageExpr *E); LValue EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E); @@ -2230,6 +2275,7 @@ public: const CXXRecordDecl *RD); RValue EmitCXXMemberCall(const CXXMethodDecl *MD, + SourceLocation CallLoc, llvm::Value *Callee, ReturnValueSlot ReturnValue, llvm::Value *This, @@ -2310,6 +2356,7 @@ public: llvm::Value *EmitARCRetain(QualType type, llvm::Value *value); llvm::Value *EmitARCRetainNonBlock(llvm::Value *value); llvm::Value *EmitARCRetainBlock(llvm::Value *value, bool mandatory); + void EmitARCDestroyStrong(llvm::Value *addr, bool precise); void EmitARCRelease(llvm::Value *value, bool precise); llvm::Value *EmitARCAutorelease(llvm::Value *value); llvm::Value *EmitARCAutoreleaseReturnValue(llvm::Value *value); @@ -2516,9 +2563,29 @@ public: void EmitBranchOnBoolExpr(const Expr *Cond, llvm::BasicBlock *TrueBlock, llvm::BasicBlock *FalseBlock); - /// getTrapBB - Create a basic block that will call the trap intrinsic. We'll - /// generate a branch around the created basic block as necessary. - llvm::BasicBlock *getTrapBB(); + /// \brief Emit a description of a type in a format suitable for passing to + /// a runtime sanitizer handler. + llvm::Constant *EmitCheckTypeDescriptor(QualType T); + + /// \brief Convert a value into a format suitable for passing to a runtime + /// sanitizer handler. + llvm::Value *EmitCheckValue(llvm::Value *V); + + /// \brief Emit a description of a source location in a format suitable for + /// passing to a runtime sanitizer handler. + llvm::Constant *EmitCheckSourceLocation(SourceLocation Loc); + + /// \brief Create a basic block that will call a handler function in a + /// sanitizer runtime with the provided arguments, and create a conditional + /// branch to it. + void EmitCheck(llvm::Value *Checked, StringRef CheckName, + llvm::ArrayRef<llvm::Constant *> StaticArgs, + llvm::ArrayRef<llvm::Value *> DynamicArgs, + bool Recoverable = false); + + /// \brief Create a basic block that will call the trap intrinsic, and emit a + /// conditional branch to it, for the -ftrapv checks. + void EmitTrapvCheck(llvm::Value *Checked); /// EmitCallArg - Emit a single call argument. void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType); @@ -2553,12 +2620,10 @@ private: SmallVector<llvm::Value*, 16> &Args, llvm::FunctionType *IRFuncTy); - llvm::Value* EmitAsmInput(const AsmStmt &S, - const TargetInfo::ConstraintInfo &Info, + llvm::Value* EmitAsmInput(const TargetInfo::ConstraintInfo &Info, const Expr *InputExpr, std::string &ConstraintStr); - llvm::Value* EmitAsmInputLValue(const AsmStmt &S, - const TargetInfo::ConstraintInfo &Info, + llvm::Value* EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info, LValue InputValue, QualType InputType, std::string &ConstraintStr); @@ -2624,15 +2689,9 @@ private: void AddObjCARCExceptionMetadata(llvm::Instruction *Inst); - /// GetPointeeAlignment - Given an expression with a pointer type, find the - /// alignment of the type referenced by the pointer. Skip over implicit - /// casts. - unsigned GetPointeeAlignment(const Expr *Addr); - - /// GetPointeeAlignmentValue - Given an expression with a pointer type, find - /// the alignment of the type referenced by the pointer. Skip over implicit - /// casts. Return the alignment as an llvm::Value. - llvm::Value *GetPointeeAlignmentValue(const Expr *Addr); + /// GetPointeeAlignment - Given an expression with a pointer type, emit the + /// value and compute our best estimate of the alignment of the pointee. + std::pair<llvm::Value*, unsigned> EmitPointerWithAlignment(const Expr *Addr); }; /// Helper class with most of the code for saving a value for a diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 3ae3c521300b..17972e29b65a 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -42,7 +42,7 @@ #include "llvm/ADT/APSInt.h" #include "llvm/ADT/Triple.h" #include "llvm/Target/Mangler.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include "llvm/Support/CallSite.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -62,10 +62,10 @@ static CGCXXABI &createCXXABI(CodeGenModule &CGM) { CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, - llvm::Module &M, const llvm::TargetData &TD, + llvm::Module &M, const llvm::DataLayout &TD, DiagnosticsEngine &diags) : Context(C), LangOpts(C.getLangOpts()), CodeGenOpts(CGO), TheModule(M), - TheTargetData(TD), TheTargetCodeGenInfo(0), Diags(diags), + TheDataLayout(TD), TheTargetCodeGenInfo(0), Diags(diags), ABI(createCXXABI(*this)), Types(*this), TBAA(0), @@ -103,14 +103,14 @@ CodeGenModule::CodeGenModule(ASTContext &C, const CodeGenOptions &CGO, createCUDARuntime(); // Enable TBAA unless it's suppressed. ThreadSanitizer needs TBAA even at O0. - if (LangOpts.ThreadSanitizer || + if (LangOpts.SanitizeThread || (!CodeGenOpts.RelaxedAliasing && CodeGenOpts.OptimizationLevel > 0)) TBAA = new CodeGenTBAA(Context, VMContext, CodeGenOpts, getLangOpts(), ABI.getMangleContext()); // If debug info or coverage generation is enabled, create the CGDebugInfo // object. - if (CodeGenOpts.DebugInfo != CodeGenOptions::NoDebugInfo || + if (CodeGenOpts.getDebugInfo() != CodeGenOptions::NoDebugInfo || CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes) DebugInfo = new CGDebugInfo(*this); @@ -202,6 +202,12 @@ llvm::MDNode *CodeGenModule::getTBAAInfoForVTablePtr() { return TBAA->getTBAAInfoForVTablePtr(); } +llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) { + if (!TBAA) + return 0; + return TBAA->getTBAAStructInfo(QTy); +} + void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst, llvm::MDNode *TBAAInfo) { Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo); @@ -287,7 +293,7 @@ void CodeGenModule::setTLSMode(llvm::GlobalVariable *GV, assert(D.isThreadSpecified() && "setting TLS mode on non-TLS var!"); llvm::GlobalVariable::ThreadLocalMode TLM; - TLM = GetLLVMTLSModel(CodeGenOpts.DefaultTLSModel); + TLM = GetLLVMTLSModel(CodeGenOpts.getDefaultTLSModel()); // Override the TLS model if it is explicitly specified. if (D.hasAttr<TLSModelAttr>()) { @@ -347,9 +353,7 @@ void CodeGenModule::setTypeVisibility(llvm::GlobalValue *GV, // to deal with mixed-visibility symbols. case TSK_ExplicitSpecialization: case TSK_ImplicitInstantiation: - if (!CodeGenOpts.HiddenWeakTemplateVTables) - return; - break; + return; } // If there's a key function, there may be translation units @@ -529,7 +533,7 @@ void CodeGenModule::SetLLVMFunctionAttributes(const Decl *D, unsigned CallingConv; AttributeListType AttributeList; ConstructAttributeList(Info, D, AttributeList, CallingConv); - F->setAttributes(llvm::AttrListPtr::get(AttributeList)); + F->setAttributes(llvm::AttrListPtr::get(getLLVMContext(), AttributeList)); F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv)); } @@ -559,39 +563,46 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, F->setHasUWTable(); if (!hasUnwindExceptions(LangOpts)) - F->addFnAttr(llvm::Attribute::NoUnwind); + F->addFnAttr(llvm::Attributes::NoUnwind); if (D->hasAttr<NakedAttr>()) { // Naked implies noinline: we should not be inlining such functions. - F->addFnAttr(llvm::Attribute::Naked); - F->addFnAttr(llvm::Attribute::NoInline); + F->addFnAttr(llvm::Attributes::Naked); + F->addFnAttr(llvm::Attributes::NoInline); } if (D->hasAttr<NoInlineAttr>()) - F->addFnAttr(llvm::Attribute::NoInline); + F->addFnAttr(llvm::Attributes::NoInline); // (noinline wins over always_inline, and we can't specify both in IR) if ((D->hasAttr<AlwaysInlineAttr>() || D->hasAttr<ForceInlineAttr>()) && - !F->hasFnAttr(llvm::Attribute::NoInline)) - F->addFnAttr(llvm::Attribute::AlwaysInline); + !F->getFnAttributes().hasAttribute(llvm::Attributes::NoInline)) + F->addFnAttr(llvm::Attributes::AlwaysInline); // FIXME: Communicate hot and cold attributes to LLVM more directly. if (D->hasAttr<ColdAttr>()) - F->addFnAttr(llvm::Attribute::OptimizeForSize); + F->addFnAttr(llvm::Attributes::OptimizeForSize); + + if (D->hasAttr<MinSizeAttr>()) + F->addFnAttr(llvm::Attributes::MinSize); if (isa<CXXConstructorDecl>(D) || isa<CXXDestructorDecl>(D)) F->setUnnamedAddr(true); + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) + if (MD->isVirtual()) + F->setUnnamedAddr(true); + if (LangOpts.getStackProtector() == LangOptions::SSPOn) - F->addFnAttr(llvm::Attribute::StackProtect); + F->addFnAttr(llvm::Attributes::StackProtect); else if (LangOpts.getStackProtector() == LangOptions::SSPReq) - F->addFnAttr(llvm::Attribute::StackProtectReq); + F->addFnAttr(llvm::Attributes::StackProtectReq); - if (LangOpts.AddressSanitizer) { + if (LangOpts.SanitizeAddress) { // When AddressSanitizer is enabled, set AddressSafety attribute // unless __attribute__((no_address_safety_analysis)) is used. if (!D->hasAttr<NoAddressSafetyAnalysisAttr>()) - F->addFnAttr(llvm::Attribute::AddressSafety); + F->addFnAttr(llvm::Attributes::AddressSafety); } unsigned alignment = D->getMaxAlignment() / Context.getCharWidth(); @@ -636,7 +647,8 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, if (unsigned IID = F->getIntrinsicID()) { // If this is an intrinsic function, set the function's attributes // to the intrinsic's attributes. - F->setAttributes(llvm::Intrinsic::getAttributes((llvm::Intrinsic::ID)IID)); + F->setAttributes(llvm::Intrinsic::getAttributes(getLLVMContext(), + (llvm::Intrinsic::ID)IID)); return; } @@ -822,6 +834,49 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { return !getContext().DeclMustBeEmitted(Global); } +llvm::Constant *CodeGenModule::GetAddrOfUuidDescriptor( + const CXXUuidofExpr* E) { + // Sema has verified that IIDSource has a __declspec(uuid()), and that its + // well-formed. + StringRef Uuid; + if (E->isTypeOperand()) + Uuid = CXXUuidofExpr::GetUuidAttrOfType(E->getTypeOperand())->getGuid(); + else { + // Special case: __uuidof(0) means an all-zero GUID. + Expr *Op = E->getExprOperand(); + if (!Op->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) + Uuid = CXXUuidofExpr::GetUuidAttrOfType(Op->getType())->getGuid(); + else + Uuid = "00000000-0000-0000-0000-000000000000"; + } + std::string Name = "__uuid_" + Uuid.str(); + + // Look for an existing global. + if (llvm::GlobalVariable *GV = getModule().getNamedGlobal(Name)) + return GV; + + llvm::Constant *Init = EmitUuidofInitializer(Uuid, E->getType()); + assert(Init && "failed to initialize as constant"); + + // GUIDs are assumed to be 16 bytes, spread over 4-2-2-8 bytes. However, the + // first field is declared as "long", which for many targets is 8 bytes. + // Those architectures are not supported. (With the MS abi, long is always 4 + // bytes.) + llvm::Type *GuidType = getTypes().ConvertType(E->getType()); + if (Init->getType() != GuidType) { + DiagnosticsEngine &Diags = getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "__uuidof codegen is not supported on this architecture"); + Diags.Report(E->getExprLoc(), DiagID) << E->getSourceRange(); + Init = llvm::UndefValue::get(GuidType); + } + + llvm::GlobalVariable *GV = new llvm::GlobalVariable(getModule(), GuidType, + /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, Init, Name); + GV->setUnnamedAddr(true); + return GV; +} + llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { const AliasAttr *AA = VD->getAttr<AliasAttr>(); assert(AA && "No alias?"); @@ -830,19 +885,23 @@ llvm::Constant *CodeGenModule::GetWeakRefReference(const ValueDecl *VD) { // See if there is already something with the target's name in the module. llvm::GlobalValue *Entry = GetGlobalValue(AA->getAliasee()); + if (Entry) { + unsigned AS = getContext().getTargetAddressSpace(VD->getType()); + return llvm::ConstantExpr::getBitCast(Entry, DeclTy->getPointerTo(AS)); + } llvm::Constant *Aliasee; if (isa<llvm::FunctionType>(DeclTy)) - Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl(), + Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, + GlobalDecl(cast<FunctionDecl>(VD)), /*ForVTable=*/false); else Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), llvm::PointerType::getUnqual(DeclTy), 0); - if (!Entry) { - llvm::GlobalValue* F = cast<llvm::GlobalValue>(Aliasee); - F->setLinkage(llvm::Function::ExternalWeakLinkage); - WeakRefReferences.insert(F); - } + + llvm::GlobalValue* F = cast<llvm::GlobalValue>(Aliasee); + F->setLinkage(llvm::Function::ExternalWeakLinkage); + WeakRefReferences.insert(F); return Aliasee; } @@ -1051,12 +1110,10 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName, // Lookup the entry, lazily creating it if necessary. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { - if (WeakRefReferences.count(Entry)) { + if (WeakRefReferences.erase(Entry)) { const FunctionDecl *FD = cast_or_null<FunctionDecl>(D.getDecl()); if (FD && !FD->hasAttr<WeakAttr>()) Entry->setLinkage(llvm::Function::ExternalLinkage); - - WeakRefReferences.erase(Entry); } if (Entry->getType()->getElementType() == Ty) @@ -1085,8 +1142,8 @@ CodeGenModule::GetOrCreateLLVMFunction(StringRef MangledName, assert(F->getName() == MangledName && "name was uniqued!"); if (D.getDecl()) SetFunctionAttributes(D, F, IsIncompleteFunction); - if (ExtraAttrs != llvm::Attribute::None) - F->addFnAttr(ExtraAttrs); + if (ExtraAttrs.hasAttributes()) + F->addAttribute(llvm::AttrListPtr::FunctionIndex, ExtraAttrs); // This is the first use or definition of a mangled name. If there is a // deferred decl with this name, remember that we need to emit it at the end @@ -1197,11 +1254,9 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, // Lookup the entry, lazily creating it if necessary. llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { - if (WeakRefReferences.count(Entry)) { + if (WeakRefReferences.erase(Entry)) { if (D && !D->hasAttr<WeakAttr>()) Entry->setLinkage(llvm::Function::ExternalLinkage); - - WeakRefReferences.erase(Entry); } if (UnnamedAddr) @@ -1279,7 +1334,7 @@ CodeGenModule::CreateOrReplaceCXXRuntimeVariable(StringRef Name, // Because C++ name mangling, the only way we can end up with an already // existing global with the same name is if it has been declared extern "C". - assert(GV->isDeclaration() && "Declaration has wrong type!"); + assert(GV->isDeclaration() && "Declaration has wrong type!"); OldGV = GV; } @@ -1424,7 +1479,7 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { return Context.toCharUnitsFromBits( - TheTargetData.getTypeStoreSizeInBits(Ty)); + TheDataLayout.getTypeStoreSizeInBits(Ty)); } llvm::Constant * @@ -1473,10 +1528,10 @@ CodeGenModule::MaybeEmitGlobalStdInitializerListInitializer(const VarDecl *D, // Now clone the InitListExpr to initialize the array instead. // Incredible hack: we want to use the existing InitListExpr here, so we need // to tell it that it no longer initializes a std::initializer_list. - Expr *arrayInit = new (ctx) InitListExpr(ctx, init->getLBraceLoc(), - const_cast<InitListExpr*>(init)->getInits(), - init->getNumInits(), - init->getRBraceLoc()); + ArrayRef<Expr*> Inits(const_cast<InitListExpr*>(init)->getInits(), + init->getNumInits()); + Expr *arrayInit = new (ctx) InitListExpr(ctx, init->getLBraceLoc(), Inits, + init->getRBraceLoc()); arrayInit->setType(arrayType); if (!cleanups.empty()) @@ -1682,9 +1737,21 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { if (NeedsGlobalCtor || NeedsGlobalDtor) EmitCXXGlobalVarDeclInitFunc(D, GV, NeedsGlobalCtor); + // If we are compiling with ASan, add metadata indicating dynamically + // initialized globals. + if (LangOpts.SanitizeAddress && NeedsGlobalCtor) { + llvm::Module &M = getModule(); + + llvm::NamedMDNode *DynamicInitializers = + M.getOrInsertNamedMetadata("llvm.asan.dynamically_initialized_globals"); + llvm::Value *GlobalToAdd[] = { GV }; + llvm::MDNode *ThisGlobal = llvm::MDNode::get(VMContext, GlobalToAdd); + DynamicInitializers->addOperand(ThisGlobal); + } + // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) - if (getCodeGenOpts().DebugInfo >= CodeGenOptions::LimitedDebugInfo) + if (getCodeGenOpts().getDebugInfo() >= CodeGenOptions::LimitedDebugInfo) DI->EmitGlobalVariable(GV, D); } @@ -1758,8 +1825,10 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, llvm::Attributes RAttrs = AttrList.getRetAttributes(); // Add the return attributes. - if (RAttrs) - AttrVec.push_back(llvm::AttributeWithIndex::get(0, RAttrs)); + if (RAttrs.hasAttributes()) + AttrVec.push_back(llvm:: + AttributeWithIndex::get(llvm::AttrListPtr::ReturnIndex, + RAttrs)); // If the function was passed too few arguments, don't transform. If extra // arguments were passed, we silently drop them. If any of the types @@ -1775,14 +1844,18 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, } // Add any parameter attributes. - if (llvm::Attributes PAttrs = AttrList.getParamAttributes(ArgNo + 1)) + llvm::Attributes PAttrs = AttrList.getParamAttributes(ArgNo + 1); + if (PAttrs.hasAttributes()) AttrVec.push_back(llvm::AttributeWithIndex::get(ArgNo + 1, PAttrs)); } if (DontTransform) continue; - if (llvm::Attributes FnAttrs = AttrList.getFnAttributes()) - AttrVec.push_back(llvm::AttributeWithIndex::get(~0, FnAttrs)); + llvm::Attributes FnAttrs = AttrList.getFnAttributes(); + if (FnAttrs.hasAttributes()) + AttrVec.push_back(llvm:: + AttributeWithIndex::get(llvm::AttrListPtr::FunctionIndex, + FnAttrs)); // Okay, we can transform this. Create the new call instruction and copy // over the required information. @@ -1791,7 +1864,7 @@ static void ReplaceUsesOfNonProtoTypeWithRealFunction(llvm::GlobalValue *Old, ArgList.clear(); if (!NewCall->getType()->isVoidTy()) NewCall->takeName(CI); - NewCall->setAttributes(llvm::AttrListPtr::get(AttrVec)); + NewCall->setAttributes(llvm::AttrListPtr::get(OldFn->getContext(), AttrVec)); NewCall->setCallingConv(CI->getCallingConv()); // Finally, remove the old call, replacing any uses with the new one. @@ -1911,7 +1984,7 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { // if a deferred decl. llvm::Constant *Aliasee; if (isa<llvm::FunctionType>(DeclTy)) - Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GlobalDecl(), + Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GD, /*ForVTable=*/false); else Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), @@ -1987,7 +2060,7 @@ GetConstantCFStringEntry(llvm::StringMap<llvm::Constant*> &Map, IsUTF16 = true; SmallVector<UTF16, 128> ToBuf(NumBytes + 1); // +1 for ending nulls. - const UTF8 *FromPtr = (UTF8 *)String.data(); + const UTF8 *FromPtr = (const UTF8 *)String.data(); UTF16 *ToPtr = &ToBuf[0]; (void)ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, @@ -2019,7 +2092,7 @@ CodeGenModule::GetAddrOfConstantCFString(const StringLiteral *Literal) { bool isUTF16 = false; llvm::StringMapEntry<llvm::Constant*> &Entry = GetConstantCFStringEntry(CFConstantStringMap, Literal, - getTargetData().isLittleEndian(), + getDataLayout().isLittleEndian(), isUTF16, StringLength); if (llvm::Constant *C = Entry.getValue()) @@ -2429,7 +2502,7 @@ void CodeGenModule::EmitObjCPropertyImplementations(const ObjCPropertyDecl *PD = PID->getPropertyDecl(); // Determine which methods need to be implemented, some may have - // been overridden. Note that ::isSynthesized is not the method + // been overridden. Note that ::isPropertyAccessor is not the method // we want, that just indicates if the decl came from a // property. What we want to know is if the method is defined in // this implementation. @@ -2465,11 +2538,11 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), cxxSelector, getContext().VoidTy, 0, D, /*isInstance=*/true, /*isVariadic=*/false, - /*isSynthesized=*/true, /*isImplicitlyDeclared=*/true, + /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(DTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); - D->setHasCXXStructors(true); + D->setHasDestructors(true); } // If the implementation doesn't have any ivar initializers, we don't need @@ -2487,13 +2560,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { getContext().getObjCIdType(), 0, D, /*isInstance=*/true, /*isVariadic=*/false, - /*isSynthesized=*/true, + /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(CTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); - D->setHasCXXStructors(true); + D->setHasNonZeroConstructors(true); } /// EmitNamespace - Emit all declarations in a namespace. @@ -2512,8 +2585,17 @@ void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) { } for (RecordDecl::decl_iterator I = LSD->decls_begin(), E = LSD->decls_end(); - I != E; ++I) + I != E; ++I) { + // Meta-data for ObjC class includes references to implemented methods. + // Generate class's method definitions first. + if (ObjCImplDecl *OID = dyn_cast<ObjCImplDecl>(*I)) { + for (ObjCContainerDecl::method_iterator M = OID->meth_begin(), + MEnd = OID->meth_end(); + M != MEnd; ++M) + EmitTopLevelDecl(*M); + } EmitTopLevelDecl(*I); + } } /// EmitTopLevelDecl - Emit code for a single top level declaration. @@ -2737,3 +2819,32 @@ void CodeGenModule::EmitCoverageFile() { } } } + +llvm::Constant *CodeGenModule::EmitUuidofInitializer(StringRef Uuid, + QualType GuidType) { + // Sema has checked that all uuid strings are of the form + // "12345678-1234-1234-1234-1234567890ab". + assert(Uuid.size() == 36); + const char *Uuidstr = Uuid.data(); + for (int i = 0; i < 36; ++i) { + if (i == 8 || i == 13 || i == 18 || i == 23) assert(Uuidstr[i] == '-'); + else assert(isxdigit(Uuidstr[i])); + } + + llvm::APInt Field0(32, StringRef(Uuidstr , 8), 16); + llvm::APInt Field1(16, StringRef(Uuidstr + 9, 4), 16); + llvm::APInt Field2(16, StringRef(Uuidstr + 14, 4), 16); + static const int Field3ValueOffsets[] = { 19, 21, 24, 26, 28, 30, 32, 34 }; + + APValue InitStruct(APValue::UninitStruct(), /*NumBases=*/0, /*NumFields=*/4); + InitStruct.getStructField(0) = APValue(llvm::APSInt(Field0)); + InitStruct.getStructField(1) = APValue(llvm::APSInt(Field1)); + InitStruct.getStructField(2) = APValue(llvm::APSInt(Field2)); + APValue& Arr = InitStruct.getStructField(3); + Arr = APValue(APValue::UninitArray(), 8, 8); + for (int t = 0; t < 8; ++t) + Arr.getArrayInitializedElt(t) = APValue(llvm::APSInt( + llvm::APInt(8, StringRef(Uuidstr + Field3ValueOffsets[t], 2), 16))); + + return EmitConstantValue(InitStruct, GuidType); +} diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index d6ff50d5ad79..1167c87ce13b 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -35,7 +35,7 @@ namespace llvm { class ConstantInt; class Function; class GlobalValue; - class TargetData; + class DataLayout; class FunctionType; class LLVMContext; } @@ -210,8 +210,8 @@ struct ARCEntrypoints { /// CodeGenModule - This class organizes the cross-function state that is used /// while generating LLVM code. class CodeGenModule : public CodeGenTypeCache { - CodeGenModule(const CodeGenModule&); // DO NOT IMPLEMENT - void operator=(const CodeGenModule&); // DO NOT IMPLEMENT + CodeGenModule(const CodeGenModule &) LLVM_DELETED_FUNCTION; + void operator=(const CodeGenModule &) LLVM_DELETED_FUNCTION; typedef std::vector<std::pair<llvm::Constant*, int> > CtorList; @@ -219,7 +219,7 @@ class CodeGenModule : public CodeGenTypeCache { const LangOptions &LangOpts; const CodeGenOptions &CodeGenOpts; llvm::Module &TheModule; - const llvm::TargetData &TheTargetData; + const llvm::DataLayout &TheDataLayout; mutable const TargetCodeGenInfo *TheTargetCodeGenInfo; DiagnosticsEngine &Diags; CGCXXABI &ABI; @@ -296,11 +296,18 @@ class CodeGenModule : public CodeGenTypeCache { /// order. llvm::DenseMap<const Decl*, unsigned> DelayedCXXInitPosition; + typedef std::pair<OrderGlobalInits, llvm::Function*> GlobalInitData; + + struct GlobalInitPriorityCmp { + bool operator()(const GlobalInitData &LHS, + const GlobalInitData &RHS) const { + return LHS.first.priority < RHS.first.priority; + } + }; + /// - Global variables with initializers whose order of initialization /// is set by init_priority attribute. - - SmallVector<std::pair<OrderGlobalInits, llvm::Function*>, 8> - PrioritizedCXXGlobalInits; + SmallVector<GlobalInitData, 8> PrioritizedCXXGlobalInits; /// CXXGlobalDtors - Global destructor functions and arguments that need to /// run on termination. @@ -357,7 +364,7 @@ class CodeGenModule : public CodeGenTypeCache { /// @} public: CodeGenModule(ASTContext &C, const CodeGenOptions &CodeGenOpts, - llvm::Module &M, const llvm::TargetData &TD, + llvm::Module &M, const llvm::DataLayout &TD, DiagnosticsEngine &Diags); ~CodeGenModule(); @@ -451,7 +458,7 @@ public: CodeGenVTables &getVTables() { return VTables; } VTableContext &getVTableContext() { return VTables.getVTableContext(); } DiagnosticsEngine &getDiags() const { return Diags; } - const llvm::TargetData &getTargetData() const { return TheTargetData; } + const llvm::DataLayout &getDataLayout() const { return TheDataLayout; } const TargetInfo &getTarget() const { return Context.getTargetInfo(); } llvm::LLVMContext &getLLVMContext() { return VMContext; } const TargetCodeGenInfo &getTargetCodeGenInfo(); @@ -461,6 +468,7 @@ public: llvm::MDNode *getTBAAInfo(QualType QTy); llvm::MDNode *getTBAAInfoForVTablePtr(); + llvm::MDNode *getTBAAStructInfo(QualType QTy); bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor); @@ -548,6 +556,9 @@ public: /// for the given type. llvm::Constant *GetAddrOfRTTIDescriptor(QualType Ty, bool ForEH = false); + /// GetAddrOfUuidDescriptor - Get the address of a uuid descriptor . + llvm::Constant *GetAddrOfUuidDescriptor(const CXXUuidofExpr* E); + /// GetAddrOfThunk - Get the address of the thunk for the given global decl. llvm::Constant *GetAddrOfThunk(GlobalDecl GD, const ThunkInfo &Thunk); @@ -701,7 +712,7 @@ public: llvm::Constant *CreateRuntimeFunction(llvm::FunctionType *Ty, StringRef Name, llvm::Attributes ExtraAttrs = - llvm::Attribute::None); + llvm::Attributes()); /// CreateRuntimeVariable - Create a new runtime global variable with the /// specified type and name. llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty, @@ -880,7 +891,7 @@ private: GlobalDecl D, bool ForVTable, llvm::Attributes ExtraAttrs = - llvm::Attribute::None); + llvm::Attributes()); llvm::Constant *GetOrCreateLLVMGlobal(StringRef MangledName, llvm::PointerType *PTy, const VarDecl *D, @@ -984,6 +995,9 @@ private: /// to emit the .gcno and .gcda files in a way that persists in .bc files. void EmitCoverageFile(); + /// Emits the initializer for a uuidof string. + llvm::Constant *EmitUuidofInitializer(StringRef uuidstr, QualType IIDType); + /// MayDeferGeneration - Determine if the given decl can be emitted /// lazily; this is only relevant for definitions. The given decl /// must be either a function or var decl. diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp index bab60afbb7f2..d9004a02ae25 100644 --- a/lib/CodeGen/CodeGenTBAA.cpp +++ b/lib/CodeGen/CodeGenTBAA.cpp @@ -17,6 +17,7 @@ #include "CodeGenTBAA.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" #include "clang/AST/Mangle.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/LLVMContext.h" @@ -167,3 +168,59 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() { return MDHelper.createTBAANode("vtable pointer", getRoot()); } + +bool +CodeGenTBAA::CollectFields(uint64_t BaseOffset, + QualType QTy, + SmallVectorImpl<llvm::MDBuilder::TBAAStructField> & + Fields, + bool MayAlias) { + /* Things not handled yet include: C++ base classes, bitfields, */ + + if (const RecordType *TTy = QTy->getAs<RecordType>()) { + const RecordDecl *RD = TTy->getDecl()->getDefinition(); + if (RD->hasFlexibleArrayMember()) + return false; + + // TODO: Handle C++ base classes. + if (const CXXRecordDecl *Decl = dyn_cast<CXXRecordDecl>(RD)) + if (Decl->bases_begin() != Decl->bases_end()) + return false; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + unsigned idx = 0; + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i, ++idx) { + uint64_t Offset = BaseOffset + + Layout.getFieldOffset(idx) / Context.getCharWidth(); + QualType FieldQTy = i->getType(); + if (!CollectFields(Offset, FieldQTy, Fields, + MayAlias || TypeHasMayAlias(FieldQTy))) + return false; + } + return true; + } + + /* Otherwise, treat whatever it is as a field. */ + uint64_t Offset = BaseOffset; + uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity(); + llvm::MDNode *TBAAInfo = MayAlias ? getChar() : getTBAAInfo(QTy); + Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAAInfo)); + return true; +} + +llvm::MDNode * +CodeGenTBAA::getTBAAStructInfo(QualType QTy) { + const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); + + if (llvm::MDNode *N = StructMetadataCache[Ty]) + return N; + + SmallVector<llvm::MDBuilder::TBAAStructField, 4> Fields; + if (CollectFields(0, QTy, Fields, TypeHasMayAlias(QTy))) + return MDHelper.createTBAAStructNode(Fields); + + // For now, handle any other kind of type conservatively. + return StructMetadataCache[Ty] = NULL; +} diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h index c17a5cf03c60..eedb996f3eef 100644 --- a/lib/CodeGen/CodeGenTBAA.h +++ b/lib/CodeGen/CodeGenTBAA.h @@ -49,6 +49,10 @@ class CodeGenTBAA { /// MetadataCache - This maps clang::Types to llvm::MDNodes describing them. llvm::DenseMap<const Type *, llvm::MDNode *> MetadataCache; + /// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing + /// them for struct assignments. + llvm::DenseMap<const Type *, llvm::MDNode *> StructMetadataCache; + llvm::MDNode *Root; llvm::MDNode *Char; @@ -60,6 +64,13 @@ class CodeGenTBAA { /// considered to be equivalent to it. llvm::MDNode *getChar(); + /// CollectFields - Collect information about the fields of a type for + /// !tbaa.struct metadata formation. Return false for an unsupported type. + bool CollectFields(uint64_t BaseOffset, + QualType Ty, + SmallVectorImpl<llvm::MDBuilder::TBAAStructField> &Fields, + bool MayAlias); + public: CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext &VMContext, const CodeGenOptions &CGO, @@ -74,6 +85,10 @@ public: /// getTBAAInfoForVTablePtr - Get the TBAA MDNode to be used for a /// dereference of a vtable pointer. llvm::MDNode *getTBAAInfoForVTablePtr(); + + /// getTBAAStructInfo - Get the TBAAStruct MDNode to be used for a memcpy of + /// the given type. + llvm::MDNode *getTBAAStructInfo(QualType QTy); }; } // end namespace CodeGen diff --git a/lib/CodeGen/CodeGenTypes.cpp b/lib/CodeGen/CodeGenTypes.cpp index 9a78daefc71c..3c6c5c9a2e2f 100644 --- a/lib/CodeGen/CodeGenTypes.cpp +++ b/lib/CodeGen/CodeGenTypes.cpp @@ -23,13 +23,13 @@ #include "clang/AST/RecordLayout.h" #include "llvm/DerivedTypes.h" #include "llvm/Module.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" using namespace clang; using namespace CodeGen; CodeGenTypes::CodeGenTypes(CodeGenModule &CGM) : Context(CGM.getContext()), Target(Context.getTargetInfo()), - TheModule(CGM.getModule()), TheTargetData(CGM.getTargetData()), + TheModule(CGM.getModule()), TheDataLayout(CGM.getDataLayout()), TheABIInfo(CGM.getTargetCodeGenInfo().getABIInfo()), TheCXXABI(CGM.getCXXABI()), CodeGenOpts(CGM.getCodeGenOpts()), CGM(CGM) { diff --git a/lib/CodeGen/CodeGenTypes.h b/lib/CodeGen/CodeGenTypes.h index 3c29d2d74626..0519911a07ef 100644 --- a/lib/CodeGen/CodeGenTypes.h +++ b/lib/CodeGen/CodeGenTypes.h @@ -23,7 +23,7 @@ namespace llvm { class FunctionType; class Module; - class TargetData; + class DataLayout; class Type; class LLVMContext; class StructType; @@ -62,7 +62,7 @@ class CodeGenTypes { ASTContext &Context; const TargetInfo &Target; llvm::Module &TheModule; - const llvm::TargetData &TheTargetData; + const llvm::DataLayout &TheDataLayout; const ABIInfo &TheABIInfo; CGCXXABI &TheCXXABI; const CodeGenOptions &CodeGenOpts; @@ -108,7 +108,7 @@ public: CodeGenTypes(CodeGenModule &CGM); ~CodeGenTypes(); - const llvm::TargetData &getTargetData() const { return TheTargetData; } + const llvm::DataLayout &getDataLayout() const { return TheDataLayout; } const TargetInfo &getTarget() const { return Target; } ASTContext &getContext() const { return Context; } const ABIInfo &getABIInfo() const { return TheABIInfo; } diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 0b7ce36d5b94..245150c88d0a 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -23,11 +23,11 @@ #include "CGVTables.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" -#include <clang/AST/Mangle.h> -#include <clang/AST/Type.h> -#include <llvm/Intrinsics.h> -#include <llvm/Target/TargetData.h> -#include <llvm/Value.h> +#include "clang/AST/Mangle.h" +#include "clang/AST/Type.h" +#include "llvm/Intrinsics.h" +#include "llvm/DataLayout.h" +#include "llvm/Value.h" using namespace clang; using namespace CodeGen; @@ -92,6 +92,10 @@ public: llvm::Value *Addr, const MemberPointerType *MPT); + llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF, + llvm::Value *ptr, + QualType type); + void BuildConstructorSignature(const CXXConstructorDecl *Ctor, CXXCtorType T, CanQualType &ResTy, @@ -109,6 +113,7 @@ public: void EmitInstanceFunctionProlog(CodeGenFunction &CGF); StringRef GetPureVirtualCallName() { return "__cxa_pure_virtual"; } + StringRef GetDeletedVirtualCallName() { return "__cxa_deleted_virtual"; } CharUnits getArrayCookieSizeImpl(QualType elementType); llvm::Value *InitializeArrayCookie(CodeGenFunction &CGF, @@ -299,7 +304,7 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, CGBuilderTy &Builder = CGF.Builder; - unsigned AS = cast<llvm::PointerType>(Base->getType())->getAddressSpace(); + unsigned AS = Base->getType()->getPointerAddressSpace(); // Cast to char*. Base = Builder.CreateBitCast(Base, Builder.getInt8Ty()->getPointerTo(AS)); @@ -677,6 +682,25 @@ bool ItaniumCXXABI::isZeroInitializable(const MemberPointerType *MPT) { return MPT->getPointeeType()->isFunctionType(); } +/// The Itanium ABI always places an offset to the complete object +/// at entry -2 in the vtable. +llvm::Value *ItaniumCXXABI::adjustToCompleteObject(CodeGenFunction &CGF, + llvm::Value *ptr, + QualType type) { + // Grab the vtable pointer as an intptr_t*. + llvm::Value *vtable = CGF.GetVTablePtr(ptr, CGF.IntPtrTy->getPointerTo()); + + // Track back to entry -2 and pull out the offset there. + llvm::Value *offsetPtr = + CGF.Builder.CreateConstInBoundsGEP1_64(vtable, -2, "complete-offset.ptr"); + llvm::LoadInst *offset = CGF.Builder.CreateLoad(offsetPtr); + offset->setAlignment(CGF.PointerAlignInBytes); + + // Apply the offset. + ptr = CGF.Builder.CreateBitCast(ptr, CGF.Int8PtrTy); + return CGF.Builder.CreateInBoundsGEP(ptr, offset); +} + /// The generic ABI passes 'this', plus a VTT if it's initializing a /// base subobject. void ItaniumCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, @@ -810,7 +834,7 @@ llvm::Value *ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, QualType ElementType) { assert(requiresArrayCookie(expr)); - unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace(); + unsigned AS = NewPtr->getType()->getPointerAddressSpace(); ASTContext &Ctx = getContext(); QualType SizeTy = Ctx.getSizeType(); @@ -852,7 +876,7 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, CGF.Builder.CreateConstInBoundsGEP1_64(numElementsPtr, numElementsOffset.getQuantity()); - unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace(); + unsigned AS = allocPtr->getType()->getPointerAddressSpace(); numElementsPtr = CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS)); return CGF.Builder.CreateLoad(numElementsPtr); @@ -878,7 +902,7 @@ llvm::Value *ARMCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, // NewPtr is a char*. - unsigned AS = cast<llvm::PointerType>(NewPtr->getType())->getAddressSpace(); + unsigned AS = NewPtr->getType()->getPointerAddressSpace(); ASTContext &Ctx = getContext(); CharUnits SizeSize = Ctx.getTypeSizeInChars(Ctx.getSizeType()); @@ -913,7 +937,7 @@ llvm::Value *ARMCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *numElementsPtr = CGF.Builder.CreateConstInBoundsGEP1_64(allocPtr, CGF.SizeSizeInBytes); - unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace(); + unsigned AS = allocPtr->getType()->getPointerAddressSpace(); numElementsPtr = CGF.Builder.CreateBitCast(numElementsPtr, CGF.SizeTy->getPointerTo(AS)); return CGF.Builder.CreateLoad(numElementsPtr); @@ -927,9 +951,9 @@ static llvm::Constant *getGuardAcquireFn(CodeGenModule &CGM, llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.getTypes().ConvertType(CGM.getContext().IntTy), GuardPtrTy, /*isVarArg=*/false); - return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire", - llvm::Attribute::NoUnwind); + llvm::Attributes::get(CGM.getLLVMContext(), + llvm::Attributes::NoUnwind)); } static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM, @@ -937,9 +961,9 @@ static llvm::Constant *getGuardReleaseFn(CodeGenModule &CGM, // void __cxa_guard_release(__guard *guard_object); llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false); - return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release", - llvm::Attribute::NoUnwind); + llvm::Attributes::get(CGM.getLLVMContext(), + llvm::Attributes::NoUnwind)); } static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM, @@ -947,9 +971,9 @@ static llvm::Constant *getGuardAbortFn(CodeGenModule &CGM, // void __cxa_guard_abort(__guard *guard_object); llvm::FunctionType *FTy = llvm::FunctionType::get(CGM.VoidTy, GuardPtrTy, /*isVarArg=*/false); - return CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort", - llvm::Attribute::NoUnwind); + llvm::Attributes::get(CGM.getLLVMContext(), + llvm::Attributes::NoUnwind)); } namespace { @@ -1149,7 +1173,7 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF, // In Apple kexts, we want to add a global destructor entry. // FIXME: shouldn't this be guarded by some variable? - if (CGM.getContext().getLangOpts().AppleKext) { + if (CGM.getLangOpts().AppleKext) { // Generate a global destructor entry. return CGM.AddCXXDtorEntry(dtor, addr); } diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index 6a2925bbd953..8d205c3d0f5d 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -29,14 +29,18 @@ public: MicrosoftCXXABI(CodeGenModule &CGM) : CGCXXABI(CGM) {} StringRef GetPureVirtualCallName() { return "_purecall"; } + // No known support for deleted functions in MSVC yet, so this choice is + // arbitrary. + StringRef GetDeletedVirtualCallName() { return "_purecall"; } + + llvm::Value *adjustToCompleteObject(CodeGenFunction &CGF, + llvm::Value *ptr, + QualType type); void BuildConstructorSignature(const CXXConstructorDecl *Ctor, CXXCtorType Type, CanQualType &ResTy, - SmallVectorImpl<CanQualType> &ArgTys) { - // 'this' is already in place - // TODO: 'for base' flag - } + SmallVectorImpl<CanQualType> &ArgTys); void BuildDestructorSignature(const CXXDestructorDecl *Ctor, CXXDtorType Type, @@ -48,15 +52,9 @@ public: void BuildInstanceFunctionParams(CodeGenFunction &CGF, QualType &ResTy, - FunctionArgList &Params) { - BuildThisParam(CGF, Params); - // TODO: 'for base' flag - } + FunctionArgList &Params); - void EmitInstanceFunctionProlog(CodeGenFunction &CGF) { - EmitThisParam(CGF); - // TODO: 'for base' flag - } + void EmitInstanceFunctionProlog(CodeGenFunction &CGF); void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, llvm::GlobalVariable *DeclPtr, @@ -99,10 +97,49 @@ public: llvm::Value *readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr, CharUnits cookieSize); + static bool needThisReturn(GlobalDecl GD); }; } +llvm::Value *MicrosoftCXXABI::adjustToCompleteObject(CodeGenFunction &CGF, + llvm::Value *ptr, + QualType type) { + // FIXME: implement + return ptr; +} + +bool MicrosoftCXXABI::needThisReturn(GlobalDecl GD) { + const CXXMethodDecl* MD = cast<CXXMethodDecl>(GD.getDecl()); + return isa<CXXConstructorDecl>(MD); +} + +void MicrosoftCXXABI::BuildConstructorSignature(const CXXConstructorDecl *Ctor, + CXXCtorType Type, + CanQualType &ResTy, + SmallVectorImpl<CanQualType> &ArgTys) { + // 'this' is already in place + // TODO: 'for base' flag + // Ctor returns this ptr + ResTy = ArgTys[0]; +} + +void MicrosoftCXXABI::BuildInstanceFunctionParams(CodeGenFunction &CGF, + QualType &ResTy, + FunctionArgList &Params) { + BuildThisParam(CGF, Params); + if (needThisReturn(CGF.CurGD)) { + ResTy = Params[0]->getType(); + } +} + +void MicrosoftCXXABI::EmitInstanceFunctionProlog(CodeGenFunction &CGF) { + EmitThisParam(CGF); + if (needThisReturn(CGF.CurGD)) { + CGF.Builder.CreateStore(getThisValue(CGF), CGF.ReturnValue); + } +} + bool MicrosoftCXXABI::requiresArrayCookie(const CXXDeleteExpr *expr, QualType elementType) { // Microsoft seems to completely ignore the possibility of a @@ -127,7 +164,7 @@ CharUnits MicrosoftCXXABI::getArrayCookieSizeImpl(QualType type) { llvm::Value *MicrosoftCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, llvm::Value *allocPtr, CharUnits cookieSize) { - unsigned AS = cast<llvm::PointerType>(allocPtr->getType())->getAddressSpace(); + unsigned AS = allocPtr->getType()->getPointerAddressSpace(); llvm::Value *numElementsPtr = CGF.Builder.CreateBitCast(allocPtr, CGF.SizeTy->getPointerTo(AS)); return CGF.Builder.CreateLoad(numElementsPtr); @@ -147,7 +184,7 @@ llvm::Value* MicrosoftCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, llvm::Value *cookiePtr = newPtr; // Write the number of elements into the appropriate slot. - unsigned AS = cast<llvm::PointerType>(newPtr->getType())->getAddressSpace(); + unsigned AS = newPtr->getType()->getPointerAddressSpace(); llvm::Value *numElementsPtr = CGF.Builder.CreateBitCast(cookiePtr, CGF.SizeTy->getPointerTo(AS)); CGF.Builder.CreateStore(numElements, numElementsPtr); diff --git a/lib/CodeGen/ModuleBuilder.cpp b/lib/CodeGen/ModuleBuilder.cpp index ea2389e66b5a..012555962f82 100644 --- a/lib/CodeGen/ModuleBuilder.cpp +++ b/lib/CodeGen/ModuleBuilder.cpp @@ -21,14 +21,14 @@ #include "clang/Basic/TargetInfo.h" #include "llvm/LLVMContext.h" #include "llvm/Module.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include "llvm/ADT/OwningPtr.h" using namespace clang; namespace { class CodeGeneratorImpl : public CodeGenerator { DiagnosticsEngine &Diags; - OwningPtr<const llvm::TargetData> TD; + OwningPtr<const llvm::DataLayout> TD; ASTContext *Ctx; const CodeGenOptions CodeGenOpts; // Intentionally copied in. protected: @@ -54,7 +54,7 @@ namespace { M->setTargetTriple(Ctx->getTargetInfo().getTriple().getTriple()); M->setDataLayout(Ctx->getTargetInfo().getTargetDescription()); - TD.reset(new llvm::TargetData(Ctx->getTargetInfo().getTargetDescription())); + TD.reset(new llvm::DataLayout(Ctx->getTargetInfo().getTargetDescription())); Builder.reset(new CodeGen::CodeGenModule(Context, CodeGenOpts, *M, *TD, Diags)); } diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 9c23ed9871da..ffff0d0a1bc4 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -18,7 +18,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/Type.h" -#include "llvm/Target/TargetData.h" +#include "llvm/DataLayout.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -51,8 +51,8 @@ llvm::LLVMContext &ABIInfo::getVMContext() const { return CGT.getLLVMContext(); } -const llvm::TargetData &ABIInfo::getTargetData() const { - return CGT.getTargetData(); +const llvm::DataLayout &ABIInfo::getDataLayout() const { + return CGT.getDataLayout(); } @@ -389,6 +389,90 @@ ABIArgInfo DefaultABIInfo::classifyReturnType(QualType RetTy) const { ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); } +//===----------------------------------------------------------------------===// +// le32/PNaCl bitcode ABI Implementation +//===----------------------------------------------------------------------===// + +class PNaClABIInfo : public ABIInfo { + public: + PNaClABIInfo(CodeGen::CodeGenTypes &CGT) : ABIInfo(CGT) {} + + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs) const; + + virtual void computeInfo(CGFunctionInfo &FI) const; + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; +}; + +class PNaClTargetCodeGenInfo : public TargetCodeGenInfo { + public: + PNaClTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT) + : TargetCodeGenInfo(new PNaClABIInfo(CGT)) {} +}; + +void PNaClABIInfo::computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + + unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() : 0; + + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) + it->info = classifyArgumentType(it->type, FreeRegs); + } + +llvm::Value *PNaClABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + return 0; +} + +ABIArgInfo PNaClABIInfo::classifyArgumentType(QualType Ty, + unsigned &FreeRegs) const { + if (isAggregateTypeForABI(Ty)) { + // Records with non trivial destructors/constructors should not be passed + // by value. + FreeRegs = 0; + if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) + return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + + return ABIArgInfo::getIndirect(0); + } + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + + ABIArgInfo BaseInfo = (Ty->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + + // Regparm regs hold 32 bits. + unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; + if (SizeInRegs == 0) return BaseInfo; + if (SizeInRegs > FreeRegs) { + FreeRegs = 0; + return BaseInfo; + } + FreeRegs -= SizeInRegs; + return BaseInfo.isDirect() ? + ABIArgInfo::getDirectInReg(BaseInfo.getCoerceToType()) : + ABIArgInfo::getExtendInReg(BaseInfo.getCoerceToType()); +} + +ABIArgInfo PNaClABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + + if (isAggregateTypeForABI(RetTy)) + return ABIArgInfo::getIndirect(0); + + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = RetTy->getAs<EnumType>()) + RetTy = EnumTy->getDecl()->getIntegerType(); + + return (RetTy->isPromotableIntegerType() ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); +} + /// UseX86_MMXType - Return true if this is an MMX type that should use the /// special x86_mmx type. bool UseX86_MMXType(llvm::Type *IRType) { @@ -435,7 +519,8 @@ class X86_32ABIInfo : public ABIInfo { /// getIndirectResult - Give a source type \arg Ty, return a suitable result /// such that the argument will be passed in memory. - ABIArgInfo getIndirectResult(QualType Ty, bool ByVal = true) const; + ABIArgInfo getIndirectResult(QualType Ty, bool ByVal, + unsigned &FreeRegs) const; /// \brief Return the alignment to use for the given type on the stack. unsigned getTypeStackAlignInBytes(QualType Ty, unsigned Align) const; @@ -443,9 +528,10 @@ class X86_32ABIInfo : public ABIInfo { Class classify(QualType Ty) const; ABIArgInfo classifyReturnType(QualType RetTy, unsigned callingConvention) const; - ABIArgInfo classifyArgumentTypeWithReg(QualType RetTy, - unsigned &FreeRegs) const; - ABIArgInfo classifyArgumentType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy, unsigned &FreeRegs, + bool IsFastCall) const; + bool shouldUseInReg(QualType Ty, unsigned &FreeRegs, + bool IsFastCall, bool &NeedsPadding) const; public: @@ -682,9 +768,15 @@ unsigned X86_32ABIInfo::getTypeStackAlignInBytes(QualType Ty, return MinABIStackAlignInBytes; } -ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal) const { - if (!ByVal) +ABIArgInfo X86_32ABIInfo::getIndirectResult(QualType Ty, bool ByVal, + unsigned &FreeRegs) const { + if (!ByVal) { + if (FreeRegs) { + --FreeRegs; // Non byval indirects just use one pointer. + return ABIArgInfo::getIndirectInReg(0, false); + } return ABIArgInfo::getIndirect(0, false); + } // Compute the byval alignment. unsigned TypeAlign = getContext().getTypeAlign(Ty) / 8; @@ -714,45 +806,51 @@ X86_32ABIInfo::Class X86_32ABIInfo::classify(QualType Ty) const { return Integer; } -ABIArgInfo -X86_32ABIInfo::classifyArgumentTypeWithReg(QualType Ty, - unsigned &FreeRegs) const { - // Common case first. - if (FreeRegs == 0) - return classifyArgumentType(Ty); - +bool X86_32ABIInfo::shouldUseInReg(QualType Ty, unsigned &FreeRegs, + bool IsFastCall, bool &NeedsPadding) const { + NeedsPadding = false; Class C = classify(Ty); if (C == Float) - return classifyArgumentType(Ty); + return false; + + unsigned Size = getContext().getTypeSize(Ty); + unsigned SizeInRegs = (Size + 31) / 32; - unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; if (SizeInRegs == 0) - return classifyArgumentType(Ty); + return false; if (SizeInRegs > FreeRegs) { FreeRegs = 0; - return classifyArgumentType(Ty); + return false; } - assert(SizeInRegs >= 1 && SizeInRegs <= 3); + FreeRegs -= SizeInRegs; - // If it is a simple scalar, keep the type so that we produce a cleaner IR. - ABIArgInfo Foo = classifyArgumentType(Ty); - if (Foo.isDirect() && !Foo.getDirectOffset() && !Foo.getPaddingType()) - return ABIArgInfo::getDirectInReg(Foo.getCoerceToType()); - if (Foo.isExtend()) - return ABIArgInfo::getExtendInReg(Foo.getCoerceToType()); + if (IsFastCall) { + if (Size > 32) + return false; + + if (Ty->isIntegralOrEnumerationType()) + return true; + + if (Ty->isPointerType()) + return true; + + if (Ty->isReferenceType()) + return true; + + if (FreeRegs) + NeedsPadding = true; - llvm::LLVMContext &LLVMContext = getVMContext(); - llvm::Type *Int32 = llvm::Type::getInt32Ty(LLVMContext); - SmallVector<llvm::Type*, 3> Elements; - for (unsigned I = 0; I < SizeInRegs; ++I) - Elements.push_back(Int32); - llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); - return ABIArgInfo::getDirectInReg(Result); + return false; + } + + return true; } -ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const { +ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, + unsigned &FreeRegs, + bool IsFastCall) const { // FIXME: Set alignment on indirect arguments. if (isAggregateTypeForABI(Ty)) { // Structures with flexible arrays are always indirect. @@ -760,25 +858,38 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const { // Structures with either a non-trivial destructor or a non-trivial // copy constructor are always indirect. if (hasNonTrivialDestructorOrCopyConstructor(RT)) - return getIndirectResult(Ty, /*ByVal=*/false); + return getIndirectResult(Ty, false, FreeRegs); if (RT->getDecl()->hasFlexibleArrayMember()) - return getIndirectResult(Ty); + return getIndirectResult(Ty, true, FreeRegs); } // Ignore empty structs/unions. if (isEmptyRecord(getContext(), Ty, true)) return ABIArgInfo::getIgnore(); + llvm::LLVMContext &LLVMContext = getVMContext(); + llvm::IntegerType *Int32 = llvm::Type::getInt32Ty(LLVMContext); + bool NeedsPadding; + if (shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding)) { + unsigned SizeInRegs = (getContext().getTypeSize(Ty) + 31) / 32; + SmallVector<llvm::Type*, 3> Elements; + for (unsigned I = 0; I < SizeInRegs; ++I) + Elements.push_back(Int32); + llvm::Type *Result = llvm::StructType::get(LLVMContext, Elements); + return ABIArgInfo::getDirectInReg(Result); + } + llvm::IntegerType *PaddingType = NeedsPadding ? Int32 : 0; + // Expand small (<= 128-bit) record types when we know that the stack layout // of those arguments will match the struct. This is important because the // LLVM backend isn't smart enough to remove byval, which inhibits many // optimizations. if (getContext().getTypeSize(Ty) <= 4*32 && canExpandIndirectArgument(Ty, getContext())) - return ABIArgInfo::getExpand(); + return ABIArgInfo::getExpandWithPadding(IsFastCall, PaddingType); - return getIndirectResult(Ty); + return getIndirectResult(Ty, true, FreeRegs); } if (const VectorType *VT = Ty->getAs<VectorType>()) { @@ -809,16 +920,32 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty) const { if (const EnumType *EnumTy = Ty->getAs<EnumType>()) Ty = EnumTy->getDecl()->getIntegerType(); - return (Ty->isPromotableIntegerType() ? - ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); + bool NeedsPadding; + bool InReg = shouldUseInReg(Ty, FreeRegs, IsFastCall, NeedsPadding); + + if (Ty->isPromotableIntegerType()) { + if (InReg) + return ABIArgInfo::getExtendInReg(); + return ABIArgInfo::getExtend(); + } + if (InReg) + return ABIArgInfo::getDirectInReg(); + return ABIArgInfo::getDirect(); } void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.getReturnInfo() = classifyReturnType(FI.getReturnType(), FI.getCallingConvention()); - unsigned FreeRegs = FI.getHasRegParm() ? FI.getRegParm() : - DefaultNumRegisterParameters; + unsigned CC = FI.getCallingConvention(); + bool IsFastCall = CC == llvm::CallingConv::X86_FastCall; + unsigned FreeRegs; + if (IsFastCall) + FreeRegs = 2; + else if (FI.getHasRegParm()) + FreeRegs = FI.getRegParm(); + else + FreeRegs = DefaultNumRegisterParameters; // If the return value is indirect, then the hidden argument is consuming one // integer register. @@ -832,7 +959,7 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const { for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); it != ie; ++it) - it->info = classifyArgumentTypeWithReg(it->type, FreeRegs); + it->info = classifyArgumentType(it->type, FreeRegs, IsFastCall); } llvm::Value *X86_32ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, @@ -884,7 +1011,10 @@ void X86_32TargetCodeGenInfo::SetTargetAttributes(const Decl *D, llvm::Function *Fn = cast<llvm::Function>(GV); // Now add the 'alignstack' attribute with a value of 16. - Fn->addFnAttr(llvm::Attribute::constructStackAlignmentFromInt(16)); + llvm::AttrBuilder B; + B.addStackAlignmentAttr(16); + Fn->addAttribute(llvm::AttrListPtr::FunctionIndex, + llvm::Attributes::get(CGM.getLLVMContext(), B)); } } } @@ -1030,10 +1160,15 @@ class X86_64ABIInfo : public ABIInfo { } bool HasAVX; + // Some ABIs (e.g. X32 ABI and Native Client OS) use 32 bit pointers on + // 64-bit hardware. + bool Has64BitPointers; public: X86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool hasavx) : - ABIInfo(CGT), HasAVX(hasavx) {} + ABIInfo(CGT), HasAVX(hasavx), + Has64BitPointers(CGT.getDataLayout().getPointerSize(0) == 8) { + } bool isPassedUsingAVXType(QualType type) const { unsigned neededInt, neededSSE; @@ -1070,7 +1205,7 @@ public: class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { public: X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX) - : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)) {} + : TargetCodeGenInfo(new X86_64ABIInfo(CGT, HasAVX)) {} const X86_64ABIInfo &getABIInfo() const { return static_cast<const X86_64ABIInfo&>(TargetCodeGenInfo::getABIInfo()); @@ -1243,7 +1378,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Hi = Integer; } else if (k >= BuiltinType::Bool && k <= BuiltinType::LongLong) { Current = Integer; - } else if (k == BuiltinType::Float || k == BuiltinType::Double) { + } else if ((k == BuiltinType::Float || k == BuiltinType::Double) || + (k == BuiltinType::LongDouble && + getContext().getTargetInfo().getTriple().getOS() == + llvm::Triple::NativeClient)) { Current = SSE; } else if (k == BuiltinType::LongDouble) { Lo = X87; @@ -1266,7 +1404,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, } if (Ty->isMemberPointerType()) { - if (Ty->isMemberFunctionPointerType()) + if (Ty->isMemberFunctionPointerType() && Has64BitPointers) Lo = Hi = Integer; else Current = Integer; @@ -1329,7 +1467,10 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Lo = Hi = Integer; } else if (ET == getContext().FloatTy) Current = SSE; - else if (ET == getContext().DoubleTy) + else if (ET == getContext().DoubleTy || + (ET == getContext().LongDoubleTy && + getContext().getTargetInfo().getTriple().getOS() == + llvm::Triple::NativeClient)) Lo = Hi = SSE; else if (ET == getContext().LongDoubleTy) Current = ComplexX87; @@ -1708,7 +1849,7 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit, /// float at offset 4. It is conservatively correct for this routine to return /// false. static bool ContainsFloatAtOffset(llvm::Type *IRType, unsigned IROffset, - const llvm::TargetData &TD) { + const llvm::DataLayout &TD) { // Base case if we find a float. if (IROffset == 0 && IRType->isFloatTy()) return true; @@ -1748,8 +1889,8 @@ GetSSETypeAtOffset(llvm::Type *IRType, unsigned IROffset, // We want to pass as <2 x float> if the LLVM IR type contains a float at // offset+0 and offset+4. Walk the LLVM IR type to find out if this is the // case. - if (ContainsFloatAtOffset(IRType, IROffset, getTargetData()) && - ContainsFloatAtOffset(IRType, IROffset+4, getTargetData())) + if (ContainsFloatAtOffset(IRType, IROffset, getDataLayout()) && + ContainsFloatAtOffset(IRType, IROffset+4, getDataLayout())) return llvm::VectorType::get(llvm::Type::getFloatTy(getVMContext()), 2); return llvm::Type::getDoubleTy(getVMContext()); @@ -1777,7 +1918,8 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset, // returning an 8-byte unit starting with it. See if we can safely use it. if (IROffset == 0) { // Pointers and int64's always fill the 8-byte unit. - if (isa<llvm::PointerType>(IRType) || IRType->isIntegerTy(64)) + if ((isa<llvm::PointerType>(IRType) && Has64BitPointers) || + IRType->isIntegerTy(64)) return IRType; // If we have a 1/2/4-byte integer, we can use it only if the rest of the @@ -1787,8 +1929,10 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset, // have to do this analysis on the source type because we can't depend on // unions being lowered a specific way etc. if (IRType->isIntegerTy(8) || IRType->isIntegerTy(16) || - IRType->isIntegerTy(32)) { - unsigned BitWidth = cast<llvm::IntegerType>(IRType)->getBitWidth(); + IRType->isIntegerTy(32) || + (isa<llvm::PointerType>(IRType) && !Has64BitPointers)) { + unsigned BitWidth = isa<llvm::PointerType>(IRType) ? 32 : + cast<llvm::IntegerType>(IRType)->getBitWidth(); if (BitsContainNoUserData(SourceTy, SourceOffset*8+BitWidth, SourceOffset*8+64, getContext())) @@ -1798,7 +1942,7 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset, if (llvm::StructType *STy = dyn_cast<llvm::StructType>(IRType)) { // If this is a struct, recurse into the field at the specified offset. - const llvm::StructLayout *SL = getTargetData().getStructLayout(STy); + const llvm::StructLayout *SL = getDataLayout().getStructLayout(STy); if (IROffset < SL->getSizeInBytes()) { unsigned FieldIdx = SL->getElementContainingOffset(IROffset); IROffset -= SL->getElementOffset(FieldIdx); @@ -1810,7 +1954,7 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset, if (llvm::ArrayType *ATy = dyn_cast<llvm::ArrayType>(IRType)) { llvm::Type *EltTy = ATy->getElementType(); - unsigned EltSize = getTargetData().getTypeAllocSize(EltTy); + unsigned EltSize = getDataLayout().getTypeAllocSize(EltTy); unsigned EltOffset = IROffset/EltSize*EltSize; return GetINTEGERTypeAtOffset(EltTy, IROffset-EltOffset, SourceTy, SourceOffset); @@ -1837,14 +1981,14 @@ GetINTEGERTypeAtOffset(llvm::Type *IRType, unsigned IROffset, /// return {i32*, float}. static llvm::Type * GetX86_64ByValArgumentPair(llvm::Type *Lo, llvm::Type *Hi, - const llvm::TargetData &TD) { + const llvm::DataLayout &TD) { // In order to correctly satisfy the ABI, we need to the high part to start // at offset 8. If the high and low parts we inferred are both 4-byte types // (e.g. i32 and i32) then the resultant struct type ({i32,i32}) won't have // the second element at offset 8. Check for this: unsigned LoSize = (unsigned)TD.getTypeAllocSize(Lo); unsigned HiAlign = TD.getABITypeAlignment(Hi); - unsigned HiStart = llvm::TargetData::RoundUpAlignment(LoSize, HiAlign); + unsigned HiStart = llvm::DataLayout::RoundUpAlignment(LoSize, HiAlign); assert(HiStart != 0 && HiStart <= 8 && "Invalid x86-64 argument pair!"); // To handle this, we have to increase the size of the low part so that the @@ -1996,7 +2140,7 @@ classifyReturnType(QualType RetTy) const { // known to pass in the high eightbyte of the result. We do this by forming a // first class struct aggregate with the high and low part: {low, high} if (HighPart) - ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getTargetData()); + ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout()); return ABIArgInfo::getDirect(ResType); } @@ -2122,7 +2266,7 @@ ABIArgInfo X86_64ABIInfo::classifyArgumentType( // known to pass in the high eightbyte of the result. We do this by forming a // first class struct aggregate with the high and low part: {low, high} if (HighPart) - ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getTargetData()); + ResType = GetX86_64ByValArgumentPair(ResType, HighPart, getDataLayout()); return ABIArgInfo::getDirect(ResType); } @@ -2435,6 +2579,43 @@ llvm::Value *WinX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, return AddrTyped; } +namespace { + +class NaClX86_64ABIInfo : public ABIInfo { + public: + NaClX86_64ABIInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX) + : ABIInfo(CGT), PInfo(CGT), NInfo(CGT, HasAVX) {} + virtual void computeInfo(CGFunctionInfo &FI) const; + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; + private: + PNaClABIInfo PInfo; // Used for generating calls with pnaclcall callingconv. + X86_64ABIInfo NInfo; // Used for everything else. +}; + +class NaClX86_64TargetCodeGenInfo : public TargetCodeGenInfo { + public: + NaClX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, bool HasAVX) + : TargetCodeGenInfo(new NaClX86_64ABIInfo(CGT, HasAVX)) {} +}; + +} + +void NaClX86_64ABIInfo::computeInfo(CGFunctionInfo &FI) const { + if (FI.getASTCallingConvention() == CC_PnaclCall) + PInfo.computeInfo(FI); + else + NInfo.computeInfo(FI); +} + +llvm::Value *NaClX86_64ABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + // Always use the native convention; calling pnacl-style varargs functions + // is unuspported. + return NInfo.EmitVAArg(VAListAddr, Ty, CGF); +} + + // PowerPC-32 namespace { @@ -2497,6 +2678,62 @@ PPC32TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, // PowerPC-64 namespace { +/// PPC64_SVR4_ABIInfo - The 64-bit PowerPC ELF (SVR4) ABI information. +class PPC64_SVR4_ABIInfo : public DefaultABIInfo { + +public: + PPC64_SVR4_ABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} + + bool isPromotableTypeForABI(QualType Ty) const; + + ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType Ty) const; + + // TODO: We can add more logic to computeInfo to improve performance. + // Example: For aggregate arguments that fit in a register, we could + // use getDirectInReg (as is done below for structs containing a single + // floating-point value) to avoid pushing them to memory on function + // entry. This would require changing the logic in PPCISelLowering + // when lowering the parameters in the caller and args in the callee. + virtual void computeInfo(CGFunctionInfo &FI) const { + FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); + it != ie; ++it) { + // We rely on the default argument classification for the most part. + // One exception: An aggregate containing a single floating-point + // item must be passed in a register if one is available. + const Type *T = isSingleElementStruct(it->type, getContext()); + if (T) { + const BuiltinType *BT = T->getAs<BuiltinType>(); + if (BT && BT->isFloatingPoint()) { + QualType QT(T, 0); + it->info = ABIArgInfo::getDirectInReg(CGT.ConvertType(QT)); + continue; + } + } + it->info = classifyArgumentType(it->type); + } + } + + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, + QualType Ty, + CodeGenFunction &CGF) const; +}; + +class PPC64_SVR4_TargetCodeGenInfo : public TargetCodeGenInfo { +public: + PPC64_SVR4_TargetCodeGenInfo(CodeGenTypes &CGT) + : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT)) {} + + int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const { + // This is recovered from gcc output. + return 1; // r1 is the dedicated stack pointer + } + + bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const; +}; + class PPC64TargetCodeGenInfo : public DefaultTargetCodeGenInfo { public: PPC64TargetCodeGenInfo(CodeGenTypes &CGT) : DefaultTargetCodeGenInfo(CGT) {} @@ -2512,9 +2749,94 @@ public: } +// Return true if the ABI requires Ty to be passed sign- or zero- +// extended to 64 bits. bool -PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, - llvm::Value *Address) const { +PPC64_SVR4_ABIInfo::isPromotableTypeForABI(QualType Ty) const { + // Treat an enum type as its underlying type. + if (const EnumType *EnumTy = Ty->getAs<EnumType>()) + Ty = EnumTy->getDecl()->getIntegerType(); + + // Promotable integer types are required to be promoted by the ABI. + if (Ty->isPromotableIntegerType()) + return true; + + // In addition to the usual promotable integer types, we also need to + // extend all 32-bit types, since the ABI requires promotion to 64 bits. + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) + switch (BT->getKind()) { + case BuiltinType::Int: + case BuiltinType::UInt: + return true; + default: + break; + } + + return false; +} + +ABIArgInfo +PPC64_SVR4_ABIInfo::classifyArgumentType(QualType Ty) const { + if (isAggregateTypeForABI(Ty)) { + // Records with non trivial destructors/constructors should not be passed + // by value. + if (isRecordWithNonTrivialDestructorOrCopyConstructor(Ty)) + return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + + return ABIArgInfo::getIndirect(0); + } + + return (isPromotableTypeForABI(Ty) ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); +} + +ABIArgInfo +PPC64_SVR4_ABIInfo::classifyReturnType(QualType RetTy) const { + if (RetTy->isVoidType()) + return ABIArgInfo::getIgnore(); + + if (isAggregateTypeForABI(RetTy)) + return ABIArgInfo::getIndirect(0); + + return (isPromotableTypeForABI(RetTy) ? + ABIArgInfo::getExtend() : ABIArgInfo::getDirect()); +} + +// Based on ARMABIInfo::EmitVAArg, adjusted for 64-bit machine. +llvm::Value *PPC64_SVR4_ABIInfo::EmitVAArg(llvm::Value *VAListAddr, + QualType Ty, + CodeGenFunction &CGF) const { + llvm::Type *BP = CGF.Int8PtrTy; + llvm::Type *BPP = CGF.Int8PtrPtrTy; + + CGBuilderTy &Builder = CGF.Builder; + llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap"); + llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); + + // Update the va_list pointer. + unsigned SizeInBytes = CGF.getContext().getTypeSize(Ty) / 8; + unsigned Offset = llvm::RoundUpToAlignment(SizeInBytes, 8); + llvm::Value *NextAddr = + Builder.CreateGEP(Addr, llvm::ConstantInt::get(CGF.Int64Ty, Offset), + "ap.next"); + Builder.CreateStore(NextAddr, VAListAddrAsBPP); + + // If the argument is smaller than 8 bytes, it is right-adjusted in + // its doubleword slot. Adjust the pointer to pick it up from the + // correct offset. + if (SizeInBytes < 8) { + llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int64Ty); + AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt64(8 - SizeInBytes)); + Addr = Builder.CreateIntToPtr(AddrAsInt, BP); + } + + llvm::Type *PTy = llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); + return Builder.CreateBitCast(Addr, PTy); +} + +static bool +PPC64_initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) { // This is calculated from the LLVM and GCC tables and verified // against gcc output. AFAIK all ABIs use the same encoding. @@ -2553,6 +2875,21 @@ PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, return false; } +bool +PPC64_SVR4_TargetCodeGenInfo::initDwarfEHRegSizeTable( + CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const { + + return PPC64_initDwarfEHRegSizeTable(CGF, Address); +} + +bool +PPC64TargetCodeGenInfo::initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, + llvm::Value *Address) const { + + return PPC64_initDwarfEHRegSizeTable(CGF, Address); +} + //===----------------------------------------------------------------------===// // ARM ABI Implementation //===----------------------------------------------------------------------===// @@ -2576,14 +2913,18 @@ public: bool isEABI() const { StringRef Env = getContext().getTargetInfo().getTriple().getEnvironmentName(); - return (Env == "gnueabi" || Env == "eabi" || Env == "androideabi"); + return (Env == "gnueabi" || Env == "eabi" || + Env == "android" || Env == "androideabi"); } private: ABIKind getABIKind() const { return Kind; } ABIArgInfo classifyReturnType(QualType RetTy) const; - ABIArgInfo classifyArgumentType(QualType RetTy) const; + ABIArgInfo classifyArgumentType(QualType RetTy, int *VFPRegs, + unsigned &AllocatedVFP, + bool &IsHA) const; + bool isIllegalVectorType(QualType Ty) const; virtual void computeInfo(CGFunctionInfo &FI) const; @@ -2626,10 +2967,33 @@ public: } void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { + // To correctly handle Homogeneous Aggregate, we need to keep track of the + // VFP registers allocated so far. + // C.1.vfp If the argument is a VFP CPRC and there are sufficient consecutive + // VFP registers of the appropriate type unallocated then the argument is + // allocated to the lowest-numbered sequence of such registers. + // C.2.vfp If the argument is a VFP CPRC then any VFP registers that are + // unallocated are marked as unavailable. + unsigned AllocatedVFP = 0; + int VFPRegs[16] = { 0 }; FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); for (CGFunctionInfo::arg_iterator it = FI.arg_begin(), ie = FI.arg_end(); - it != ie; ++it) - it->info = classifyArgumentType(it->type); + it != ie; ++it) { + unsigned PreAllocation = AllocatedVFP; + bool IsHA = false; + // 6.1.2.3 There is one VFP co-processor register class using registers + // s0-s15 (d0-d7) for passing arguments. + const unsigned NumVFPs = 16; + it->info = classifyArgumentType(it->type, VFPRegs, AllocatedVFP, IsHA); + // If we do not have enough VFP registers for the HA, any VFP registers + // that are unallocated are marked as unavailable. To achieve this, we add + // padding of (NumVFPs - PreAllocation) floats. + if (IsHA && AllocatedVFP > NumVFPs && PreAllocation < NumVFPs) { + llvm::Type *PaddingTy = llvm::ArrayType::get( + llvm::Type::getFloatTy(getVMContext()), NumVFPs - PreAllocation); + it->info = ABIArgInfo::getExpandWithPadding(false, PaddingTy); + } + } // Always honor user-specified calling convention. if (FI.getCallingConvention() != llvm::CallingConv::C) @@ -2637,7 +3001,9 @@ void ARMABIInfo::computeInfo(CGFunctionInfo &FI) const { // Calling convention as default by an ABI. llvm::CallingConv::ID DefaultCC; - if (isEABI()) + if (getContext().getTargetInfo().getTriple().getEnvironmentName()=="gnueabihf") + DefaultCC = llvm::CallingConv::ARM_AAPCS_VFP; + else if (isEABI()) DefaultCC = llvm::CallingConv::ARM_AAPCS; else DefaultCC = llvm::CallingConv::ARM_APCS; @@ -2729,7 +3095,88 @@ static bool isHomogeneousAggregate(QualType Ty, const Type *&Base, return (Members > 0 && Members <= 4); } -ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const { +/// markAllocatedVFPs - update VFPRegs according to the alignment and +/// number of VFP registers (unit is S register) requested. +static void markAllocatedVFPs(int *VFPRegs, unsigned &AllocatedVFP, + unsigned Alignment, + unsigned NumRequired) { + // Early Exit. + if (AllocatedVFP >= 16) + return; + // C.1.vfp If the argument is a VFP CPRC and there are sufficient consecutive + // VFP registers of the appropriate type unallocated then the argument is + // allocated to the lowest-numbered sequence of such registers. + for (unsigned I = 0; I < 16; I += Alignment) { + bool FoundSlot = true; + for (unsigned J = I, JEnd = I + NumRequired; J < JEnd; J++) + if (J >= 16 || VFPRegs[J]) { + FoundSlot = false; + break; + } + if (FoundSlot) { + for (unsigned J = I, JEnd = I + NumRequired; J < JEnd; J++) + VFPRegs[J] = 1; + AllocatedVFP += NumRequired; + return; + } + } + // C.2.vfp If the argument is a VFP CPRC then any VFP registers that are + // unallocated are marked as unavailable. + for (unsigned I = 0; I < 16; I++) + VFPRegs[I] = 1; + AllocatedVFP = 17; // We do not have enough VFP registers. +} + +ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty, int *VFPRegs, + unsigned &AllocatedVFP, + bool &IsHA) const { + // We update number of allocated VFPs according to + // 6.1.2.1 The following argument types are VFP CPRCs: + // A single-precision floating-point type (including promoted + // half-precision types); A double-precision floating-point type; + // A 64-bit or 128-bit containerized vector type; Homogeneous Aggregate + // with a Base Type of a single- or double-precision floating-point type, + // 64-bit containerized vectors or 128-bit containerized vectors with one + // to four Elements. + + // Handle illegal vector types here. + if (isIllegalVectorType(Ty)) { + uint64_t Size = getContext().getTypeSize(Ty); + if (Size <= 32) { + llvm::Type *ResType = + llvm::Type::getInt32Ty(getVMContext()); + return ABIArgInfo::getDirect(ResType); + } + if (Size == 64) { + llvm::Type *ResType = llvm::VectorType::get( + llvm::Type::getInt32Ty(getVMContext()), 2); + markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, 2); + return ABIArgInfo::getDirect(ResType); + } + if (Size == 128) { + llvm::Type *ResType = llvm::VectorType::get( + llvm::Type::getInt32Ty(getVMContext()), 4); + markAllocatedVFPs(VFPRegs, AllocatedVFP, 4, 4); + return ABIArgInfo::getDirect(ResType); + } + return ABIArgInfo::getIndirect(0, /*ByVal=*/false); + } + // Update VFPRegs for legal vector types. + if (const VectorType *VT = Ty->getAs<VectorType>()) { + uint64_t Size = getContext().getTypeSize(VT); + // Size of a legal vector should be power of 2 and above 64. + markAllocatedVFPs(VFPRegs, AllocatedVFP, Size >= 128 ? 4 : 2, Size / 32); + } + // Update VFPRegs for floating point types. + if (const BuiltinType *BT = Ty->getAs<BuiltinType>()) { + if (BT->getKind() == BuiltinType::Half || + BT->getKind() == BuiltinType::Float) + markAllocatedVFPs(VFPRegs, AllocatedVFP, 1, 1); + if (BT->getKind() == BuiltinType::Double || + BT->getKind() == BuiltinType::LongDouble) + markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, 2); + } + if (!isAggregateTypeForABI(Ty)) { // Treat an enum type as its underlying type. if (const EnumType *EnumTy = Ty->getAs<EnumType>()) @@ -2749,18 +3196,42 @@ ABIArgInfo ARMABIInfo::classifyArgumentType(QualType Ty) const { return ABIArgInfo::getIndirect(0, /*ByVal=*/false); if (getABIKind() == ARMABIInfo::AAPCS_VFP) { - // Homogeneous Aggregates need to be expanded. + // Homogeneous Aggregates need to be expanded when we can fit the aggregate + // into VFP registers. const Type *Base = 0; - if (isHomogeneousAggregate(Ty, Base, getContext())) { + uint64_t Members = 0; + if (isHomogeneousAggregate(Ty, Base, getContext(), &Members)) { assert(Base && "Base class should be set for homogeneous aggregate"); + // Base can be a floating-point or a vector. + if (Base->isVectorType()) { + // ElementSize is in number of floats. + unsigned ElementSize = getContext().getTypeSize(Base) == 64 ? 2 : 4; + markAllocatedVFPs(VFPRegs, AllocatedVFP, ElementSize, + Members * ElementSize); + } else if (Base->isSpecificBuiltinType(BuiltinType::Float)) + markAllocatedVFPs(VFPRegs, AllocatedVFP, 1, Members); + else { + assert(Base->isSpecificBuiltinType(BuiltinType::Double) || + Base->isSpecificBuiltinType(BuiltinType::LongDouble)); + markAllocatedVFPs(VFPRegs, AllocatedVFP, 2, Members * 2); + } + IsHA = true; return ABIArgInfo::getExpand(); } } // Support byval for ARM. - if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64) || - getContext().getTypeAlign(Ty) > 64) { - return ABIArgInfo::getIndirect(0, /*ByVal=*/true); + // The ABI alignment for APCS is 4-byte and for AAPCS at least 4-byte and at + // most 8-byte. We realign the indirect argument if type alignment is bigger + // than ABI alignment. + uint64_t ABIAlign = 4; + uint64_t TyAlign = getContext().getTypeAlign(Ty) / 8; + if (getABIKind() == ARMABIInfo::AAPCS_VFP || + getABIKind() == ARMABIInfo::AAPCS) + ABIAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8); + if (getContext().getTypeSizeInChars(Ty) > CharUnits::fromQuantity(64)) { + return ABIArgInfo::getIndirect(0, /*ByVal=*/true, + /*Realign=*/TyAlign > ABIAlign); } // Otherwise, pass by coercing to a structure of the appropriate size. @@ -2946,6 +3417,21 @@ ABIArgInfo ARMABIInfo::classifyReturnType(QualType RetTy) const { return ABIArgInfo::getIndirect(0); } +/// isIllegalVector - check whether Ty is an illegal vector type. +bool ARMABIInfo::isIllegalVectorType(QualType Ty) const { + if (const VectorType *VT = Ty->getAs<VectorType>()) { + // Check whether VT is legal. + unsigned NumElements = VT->getNumElements(); + uint64_t Size = getContext().getTypeSize(VT); + // NumElements should be power of 2. + if ((NumElements & (NumElements - 1)) != 0) + return true; + // Size should be greater than 32 bits. + return Size <= 32; + } + return false; +} + llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CodeGenFunction &CGF) const { llvm::Type *BP = CGF.Int8PtrTy; @@ -2954,30 +3440,104 @@ llvm::Value *ARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, CGBuilderTy &Builder = CGF.Builder; llvm::Value *VAListAddrAsBPP = Builder.CreateBitCast(VAListAddr, BPP, "ap"); llvm::Value *Addr = Builder.CreateLoad(VAListAddrAsBPP, "ap.cur"); - // Handle address alignment for type alignment > 32 bits + + uint64_t Size = CGF.getContext().getTypeSize(Ty) / 8; uint64_t TyAlign = CGF.getContext().getTypeAlign(Ty) / 8; + bool IsIndirect = false; + + // The ABI alignment for 64-bit or 128-bit vectors is 8 for AAPCS and 4 for + // APCS. For AAPCS, the ABI alignment is at least 4-byte and at most 8-byte. + if (getABIKind() == ARMABIInfo::AAPCS_VFP || + getABIKind() == ARMABIInfo::AAPCS) + TyAlign = std::min(std::max(TyAlign, (uint64_t)4), (uint64_t)8); + else + TyAlign = 4; + // Use indirect if size of the illegal vector is bigger than 16 bytes. + if (isIllegalVectorType(Ty) && Size > 16) { + IsIndirect = true; + Size = 4; + TyAlign = 4; + } + + // Handle address alignment for ABI alignment > 4 bytes. if (TyAlign > 4) { assert((TyAlign & (TyAlign - 1)) == 0 && "Alignment is not power of 2!"); llvm::Value *AddrAsInt = Builder.CreatePtrToInt(Addr, CGF.Int32Ty); AddrAsInt = Builder.CreateAdd(AddrAsInt, Builder.getInt32(TyAlign - 1)); AddrAsInt = Builder.CreateAnd(AddrAsInt, Builder.getInt32(~(TyAlign - 1))); - Addr = Builder.CreateIntToPtr(AddrAsInt, BP); + Addr = Builder.CreateIntToPtr(AddrAsInt, BP, "ap.align"); } - llvm::Type *PTy = - llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); - llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); uint64_t Offset = - llvm::RoundUpToAlignment(CGF.getContext().getTypeSize(Ty) / 8, 4); + llvm::RoundUpToAlignment(Size, 4); llvm::Value *NextAddr = Builder.CreateGEP(Addr, llvm::ConstantInt::get(CGF.Int32Ty, Offset), "ap.next"); Builder.CreateStore(NextAddr, VAListAddrAsBPP); + if (IsIndirect) + Addr = Builder.CreateLoad(Builder.CreateBitCast(Addr, BPP)); + else if (TyAlign < CGF.getContext().getTypeAlign(Ty) / 8) { + // We can't directly cast ap.cur to pointer to a vector type, since ap.cur + // may not be correctly aligned for the vector type. We create an aligned + // temporary space and copy the content over from ap.cur to the temporary + // space. This is necessary if the natural alignment of the type is greater + // than the ABI alignment. + llvm::Type *I8PtrTy = Builder.getInt8PtrTy(); + CharUnits CharSize = getContext().getTypeSizeInChars(Ty); + llvm::Value *AlignedTemp = CGF.CreateTempAlloca(CGF.ConvertType(Ty), + "var.align"); + llvm::Value *Dst = Builder.CreateBitCast(AlignedTemp, I8PtrTy); + llvm::Value *Src = Builder.CreateBitCast(Addr, I8PtrTy); + Builder.CreateMemCpy(Dst, Src, + llvm::ConstantInt::get(CGF.IntPtrTy, CharSize.getQuantity()), + TyAlign, false); + Addr = AlignedTemp; //The content is in aligned location. + } + llvm::Type *PTy = + llvm::PointerType::getUnqual(CGF.ConvertType(Ty)); + llvm::Value *AddrTyped = Builder.CreateBitCast(Addr, PTy); + return AddrTyped; } +namespace { + +class NaClARMABIInfo : public ABIInfo { + public: + NaClARMABIInfo(CodeGen::CodeGenTypes &CGT, ARMABIInfo::ABIKind Kind) + : ABIInfo(CGT), PInfo(CGT), NInfo(CGT, Kind) {} + virtual void computeInfo(CGFunctionInfo &FI) const; + virtual llvm::Value *EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const; + private: + PNaClABIInfo PInfo; // Used for generating calls with pnaclcall callingconv. + ARMABIInfo NInfo; // Used for everything else. +}; + +class NaClARMTargetCodeGenInfo : public TargetCodeGenInfo { + public: + NaClARMTargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, ARMABIInfo::ABIKind Kind) + : TargetCodeGenInfo(new NaClARMABIInfo(CGT, Kind)) {} +}; + +} + +void NaClARMABIInfo::computeInfo(CGFunctionInfo &FI) const { + if (FI.getASTCallingConvention() == CC_PnaclCall) + PInfo.computeInfo(FI); + else + static_cast<const ABIInfo&>(NInfo).computeInfo(FI); +} + +llvm::Value *NaClARMABIInfo::EmitVAArg(llvm::Value *VAListAddr, QualType Ty, + CodeGenFunction &CGF) const { + // Always use the native convention; calling pnacl-style varargs functions + // is unsupported. + return static_cast<const ABIInfo&>(NInfo).EmitVAArg(VAListAddr, Ty, CGF); +} + //===----------------------------------------------------------------------===// // NVPTX ABI Implementation //===----------------------------------------------------------------------===// @@ -3072,7 +3632,7 @@ SetTargetAttributes(const Decl *D, llvm::GlobalValue *GV, // OpenCL __kernel functions get a kernel calling convention F->setCallingConv(llvm::CallingConv::PTX_Kernel); // And kernel functions are not subject to inlining - F->addFnAttr(llvm::Attribute::NoInline); + F->addFnAttr(llvm::Attributes::NoInline); } } @@ -3188,7 +3748,7 @@ void MBlazeTargetCodeGenInfo::SetTargetAttributes(const Decl *D, F->setCallingConv(CC); // Step 2: Add attributes goodness. - F->addFnAttr(llvm::Attribute::NoInline); + F->addFnAttr(llvm::Attributes::NoInline); } // Step 3: Emit _interrupt_handler alias. @@ -3226,7 +3786,7 @@ void MSP430TargetCodeGenInfo::SetTargetAttributes(const Decl *D, F->setCallingConv(llvm::CallingConv::MSP430_INTR); // Step 2: Add attributes goodness. - F->addFnAttr(llvm::Attribute::NoInline); + F->addFnAttr(llvm::Attributes::NoInline); // Step 3: Emit ISR vector alias. unsigned Num = attr->getNumber() + 0xffe0; @@ -3583,7 +4143,7 @@ void TCETargetCodeGenInfo::SetTargetAttributes(const Decl *D, if (M.getLangOpts().OpenCL) { if (FD->hasAttr<OpenCLKernelAttr>()) { // OpenCL C Kernel functions are not subject to inlining - F->addFnAttr(llvm::Attribute::NoInline); + F->addFnAttr(llvm::Attributes::NoInline); if (FD->hasAttr<ReqdWorkGroupSizeAttr>()) { @@ -3767,6 +4327,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { default: return *(TheTargetCodeGenInfo = new DefaultTargetCodeGenInfo(Types)); + case llvm::Triple::le32: + return *(TheTargetCodeGenInfo = new PNaClTargetCodeGenInfo(Types)); case llvm::Triple::mips: case llvm::Triple::mipsel: return *(TheTargetCodeGenInfo = new MIPSTargetCodeGenInfo(Types, true)); @@ -3779,19 +4341,29 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::thumb: { ARMABIInfo::ABIKind Kind = ARMABIInfo::AAPCS; - if (strcmp(getContext().getTargetInfo().getABI(), "apcs-gnu") == 0) Kind = ARMABIInfo::APCS; - else if (CodeGenOpts.FloatABI == "hard") + else if (CodeGenOpts.FloatABI == "hard" || + (CodeGenOpts.FloatABI != "soft" && Triple.getEnvironment()==llvm::Triple::GNUEABIHF)) Kind = ARMABIInfo::AAPCS_VFP; - return *(TheTargetCodeGenInfo = new ARMTargetCodeGenInfo(Types, Kind)); + switch (Triple.getOS()) { + case llvm::Triple::NativeClient: + return *(TheTargetCodeGenInfo = + new NaClARMTargetCodeGenInfo(Types, Kind)); + default: + return *(TheTargetCodeGenInfo = + new ARMTargetCodeGenInfo(Types, Kind)); + } } case llvm::Triple::ppc: return *(TheTargetCodeGenInfo = new PPC32TargetCodeGenInfo(Types)); case llvm::Triple::ppc64: - return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types)); + if (Triple.isOSBinFormatELF()) + return *(TheTargetCodeGenInfo = new PPC64_SVR4_TargetCodeGenInfo(Types)); + else + return *(TheTargetCodeGenInfo = new PPC64TargetCodeGenInfo(Types)); case llvm::Triple::nvptx: case llvm::Triple::nvptx64: @@ -3848,6 +4420,8 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { case llvm::Triple::MinGW32: case llvm::Triple::Cygwin: return *(TheTargetCodeGenInfo = new WinX86_64TargetCodeGenInfo(Types)); + case llvm::Triple::NativeClient: + return *(TheTargetCodeGenInfo = new NaClX86_64TargetCodeGenInfo(Types, HasAVX)); default: return *(TheTargetCodeGenInfo = new X86_64TargetCodeGenInfo(Types, HasAVX)); diff --git a/lib/Driver/Arg.cpp b/lib/Driver/Arg.cpp index c0a2a506a6ba..93d70a9fefed 100644 --- a/lib/Driver/Arg.cpp +++ b/lib/Driver/Arg.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Arg.h" +#include "clang/Basic/LLVM.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Option.h" #include "llvm/ADT/SmallString.h" @@ -15,22 +16,23 @@ #include "llvm/Support/raw_ostream.h" using namespace clang::driver; +using clang::StringRef; -Arg::Arg(const Option *_Opt, unsigned _Index, const Arg *_BaseArg) - : Opt(_Opt), BaseArg(_BaseArg), Index(_Index), +Arg::Arg(const Option _Opt, StringRef S, unsigned _Index, const Arg *_BaseArg) + : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index), Claimed(false), OwnsValues(false) { } -Arg::Arg(const Option *_Opt, unsigned _Index, +Arg::Arg(const Option _Opt, StringRef S, unsigned _Index, const char *Value0, const Arg *_BaseArg) - : Opt(_Opt), BaseArg(_BaseArg), Index(_Index), + : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index), Claimed(false), OwnsValues(false) { Values.push_back(Value0); } -Arg::Arg(const Option *_Opt, unsigned _Index, +Arg::Arg(const Option _Opt, StringRef S, unsigned _Index, const char *Value0, const char *Value1, const Arg *_BaseArg) - : Opt(_Opt), BaseArg(_BaseArg), Index(_Index), + : Opt(_Opt), BaseArg(_BaseArg), Spelling(S), Index(_Index), Claimed(false), OwnsValues(false) { Values.push_back(Value0); Values.push_back(Value1); @@ -47,7 +49,7 @@ void Arg::dump() const { llvm::errs() << "<"; llvm::errs() << " Opt:"; - Opt->dump(); + Opt.dump(); llvm::errs() << " Index:" << Index; @@ -83,39 +85,39 @@ void Arg::renderAsInput(const ArgList &Args, ArgStringList &Output) const { } for (unsigned i = 0, e = getNumValues(); i != e; ++i) - Output.push_back(getValue(Args, i)); + Output.push_back(getValue(i)); } void Arg::render(const ArgList &Args, ArgStringList &Output) const { switch (getOption().getRenderStyle()) { case Option::RenderValuesStyle: for (unsigned i = 0, e = getNumValues(); i != e; ++i) - Output.push_back(getValue(Args, i)); + Output.push_back(getValue(i)); break; case Option::RenderCommaJoinedStyle: { SmallString<256> Res; llvm::raw_svector_ostream OS(Res); - OS << getOption().getName(); + OS << getSpelling(); for (unsigned i = 0, e = getNumValues(); i != e; ++i) { if (i) OS << ','; - OS << getValue(Args, i); + OS << getValue(i); } Output.push_back(Args.MakeArgString(OS.str())); break; } - + case Option::RenderJoinedStyle: Output.push_back(Args.GetOrMakeJoinedArgString( - getIndex(), getOption().getName(), getValue(Args, 0))); + getIndex(), getSpelling(), getValue(0))); for (unsigned i = 1, e = getNumValues(); i != e; ++i) - Output.push_back(getValue(Args, i)); + Output.push_back(getValue(i)); break; case Option::RenderSeparateStyle: - Output.push_back(getOption().getName().data()); + Output.push_back(Args.MakeArgString(getSpelling())); for (unsigned i = 0, e = getNumValues(); i != e; ++i) - Output.push_back(getValue(Args, i)); + Output.push_back(getValue(i)); break; } } diff --git a/lib/Driver/ArgList.cpp b/lib/Driver/ArgList.cpp index 7fd439e63082..b3a43df98041 100644 --- a/lib/Driver/ArgList.cpp +++ b/lib/Driver/ArgList.cpp @@ -211,7 +211,7 @@ bool ArgList::hasFlag(OptSpecifier Pos, OptSpecifier Neg, bool Default) const { StringRef ArgList::getLastArgValue(OptSpecifier Id, StringRef Default) const { if (Arg *A = getLastArg(Id)) - return A->getValue(*this); + return A->getValue(); return Default; } @@ -220,10 +220,10 @@ int ArgList::getLastArgIntValue(OptSpecifier Id, int Default, int Res = Default; if (Arg *A = getLastArg(Id)) { - if (StringRef(A->getValue(*this)).getAsInteger(10, Res)) { + if (StringRef(A->getValue()).getAsInteger(10, Res)) { if (Diags) Diags->Report(diag::err_drv_invalid_int_value) - << A->getAsString(*this) << A->getValue(*this); + << A->getAsString(*this) << A->getValue(); } } @@ -258,7 +258,7 @@ void ArgList::AddAllArgValues(ArgStringList &Output, OptSpecifier Id0, ie = filtered_end(); it != ie; ++it) { (*it)->claim(); for (unsigned i = 0, e = (*it)->getNumValues(); i != e; ++i) - Output.push_back((*it)->getValue(*this, i)); + Output.push_back((*it)->getValue(i)); } } @@ -271,10 +271,10 @@ void ArgList::AddAllArgsTranslated(ArgStringList &Output, OptSpecifier Id0, if (Joined) { Output.push_back(MakeArgString(StringRef(Translation) + - (*it)->getValue(*this, 0))); + (*it)->getValue(0))); } else { Output.push_back(Translation); - Output.push_back((*it)->getValue(*this, 0)); + Output.push_back((*it)->getValue(0)); } } } @@ -362,33 +362,40 @@ const char *DerivedArgList::MakeArgString(StringRef Str) const { return BaseArgs.MakeArgString(Str); } -Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option *Opt) const { - Arg *A = new Arg(Opt, BaseArgs.MakeIndex(Opt->getName()), BaseArg); +Arg *DerivedArgList::MakeFlagArg(const Arg *BaseArg, const Option Opt) const { + Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) + + Twine(Opt.getName())), + BaseArgs.MakeIndex(Opt.getName()), BaseArg); SynthesizedArgs.push_back(A); return A; } -Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option *Opt, +Arg *DerivedArgList::MakePositionalArg(const Arg *BaseArg, const Option Opt, StringRef Value) const { unsigned Index = BaseArgs.MakeIndex(Value); - Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index), BaseArg); + Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) + + Twine(Opt.getName())), + Index, BaseArgs.getArgString(Index), BaseArg); SynthesizedArgs.push_back(A); return A; } -Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option *Opt, +Arg *DerivedArgList::MakeSeparateArg(const Arg *BaseArg, const Option Opt, StringRef Value) const { - unsigned Index = BaseArgs.MakeIndex(Opt->getName(), Value); - Arg *A = new Arg(Opt, Index, BaseArgs.getArgString(Index + 1), BaseArg); + unsigned Index = BaseArgs.MakeIndex(Opt.getName(), Value); + Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) + + Twine(Opt.getName())), + Index, BaseArgs.getArgString(Index + 1), BaseArg); SynthesizedArgs.push_back(A); return A; } -Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option *Opt, +Arg *DerivedArgList::MakeJoinedArg(const Arg *BaseArg, const Option Opt, StringRef Value) const { - unsigned Index = BaseArgs.MakeIndex(Opt->getName().str() + Value.str()); - Arg *A = new Arg(Opt, Index, - BaseArgs.getArgString(Index) + Opt->getName().size(), + unsigned Index = BaseArgs.MakeIndex(Opt.getName().str() + Value.str()); + Arg *A = new Arg(Opt, ArgList::MakeArgString(Twine(Opt.getPrefix()) + + Twine(Opt.getName())), Index, + BaseArgs.getArgString(Index) + Opt.getName().size(), BaseArg); SynthesizedArgs.push_back(A); return A; diff --git a/lib/Driver/CC1AsOptions.cpp b/lib/Driver/CC1AsOptions.cpp index ea80f5a20eae..4f89b73a46d3 100644 --- a/lib/Driver/CC1AsOptions.cpp +++ b/lib/Driver/CC1AsOptions.cpp @@ -15,11 +15,19 @@ using namespace clang::driver; using namespace clang::driver::options; using namespace clang::driver::cc1asoptions; +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) +#include "clang/Driver/CC1AsOptions.inc" +#undef OPTION +#undef PREFIX + static const OptTable::Info CC1AsInfoTable[] = { -#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ +#define PREFIX(NAME, VALUE) +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) \ - { NAME, HELPTEXT, METAVAR, Option::KIND##Class, PARAM, FLAGS, \ - OPT_##GROUP, OPT_##ALIAS }, + { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \ + FLAGS, OPT_##GROUP, OPT_##ALIAS }, #include "clang/Driver/CC1AsOptions.inc" }; diff --git a/lib/Driver/Compilation.cpp b/lib/Driver/Compilation.cpp index c962fca0bf9a..124e50c32ea4 100644 --- a/lib/Driver/Compilation.cpp +++ b/lib/Driver/Compilation.cpp @@ -17,6 +17,7 @@ #include "clang/Driver/ToolChain.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Program.h" #include <sys/stat.h> @@ -101,6 +102,105 @@ void Compilation::PrintJob(raw_ostream &OS, const Job &J, } } +static bool skipArg(const char *Flag, bool &SkipNextArg) { + StringRef FlagRef(Flag); + + // Assume we're going to see -Flag <Arg>. + SkipNextArg = true; + + // These flags are all of the form -Flag <Arg> and are treated as two + // arguments. Therefore, we need to skip the flag and the next argument. + bool Res = llvm::StringSwitch<bool>(Flag) + .Cases("-I", "-MF", "-MT", "-MQ", true) + .Cases("-o", "-coverage-file", "-dependency-file", true) + .Cases("-fdebug-compilation-dir", "-fmodule-cache-path", "-idirafter", true) + .Cases("-include", "-include-pch", "-internal-isystem", true) + .Cases("-internal-externc-isystem", "-iprefix", "-iwithprefix", true) + .Cases("-iwithprefixbefore", "-isysroot", "-isystem", "-iquote", true) + .Cases("-resource-dir", "-serialize-diagnostic-file", true) + .Case("-dwarf-debug-flags", true) + .Default(false); + + // Match found. + if (Res) + return Res; + + // The remaining flags are treated as a single argument. + SkipNextArg = false; + + // These flags are all of the form -Flag and have no second argument. + Res = llvm::StringSwitch<bool>(Flag) + .Cases("-M", "-MM", "-MG", "-MP", "-MD", true) + .Case("-MMD", true) + .Default(false); + + // Match found. + if (Res) + return Res; + + // These flags are treated as a single argument (e.g., -F<Dir>). + if (FlagRef.startswith("-F") || FlagRef.startswith("-I")) + return true; + + return false; +} + +static bool quoteNextArg(const char *flag) { + return llvm::StringSwitch<bool>(flag) + .Case("-D", true) + .Default(false); +} + +void Compilation::PrintDiagnosticJob(raw_ostream &OS, const Job &J) const { + if (const Command *C = dyn_cast<Command>(&J)) { + OS << C->getExecutable(); + unsigned QuoteNextArg = 0; + for (ArgStringList::const_iterator it = C->getArguments().begin(), + ie = C->getArguments().end(); it != ie; ++it) { + + bool SkipNext; + if (skipArg(*it, SkipNext)) { + if (SkipNext) ++it; + continue; + } + + if (!QuoteNextArg) + QuoteNextArg = quoteNextArg(*it) ? 2 : 0; + + OS << ' '; + + if (QuoteNextArg == 1) + OS << '"'; + + if (!std::strpbrk(*it, " \"\\$")) { + OS << *it; + } else { + // Quote the argument and escape shell special characters; this isn't + // really complete but is good enough. + OS << '"'; + for (const char *s = *it; *s; ++s) { + if (*s == '"' || *s == '\\' || *s == '$') + OS << '\\'; + OS << *s; + } + OS << '"'; + } + + if (QuoteNextArg) { + if (QuoteNextArg == 1) + OS << '"'; + --QuoteNextArg; + } + } + OS << '\n'; + } else { + const JobList *Jobs = cast<JobList>(&J); + for (JobList::const_iterator + it = Jobs->begin(), ie = Jobs->end(); it != ie; ++it) + PrintDiagnosticJob(OS, **it); + } +} + bool Compilation::CleanupFileList(const ArgStringList &Files, bool IssueErrors) const { bool Success = true; diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 87d533dd2953..68471ec04c6a 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -52,25 +52,13 @@ Driver::Driver(StringRef ClangExecutable, ClangExecutable(ClangExecutable), SysRoot(DEFAULT_SYSROOT), UseStdLib(true), DefaultTargetTriple(DefaultTargetTriple), DefaultImageName(DefaultImageName), - DriverTitle("clang \"gcc-compatible\" driver"), + DriverTitle("clang LLVM compiler"), CCPrintOptionsFilename(0), CCPrintHeadersFilename(0), CCLogDiagnosticsFilename(0), CCCIsCXX(false), CCCIsCPP(false),CCCEcho(false), CCCPrintBindings(false), CCPrintOptions(false), CCPrintHeaders(false), CCLogDiagnostics(false), CCGenDiagnostics(false), CCCGenericGCCName(""), CheckInputsExist(true), - CCCUseClang(true), CCCUseClangCXX(true), CCCUseClangCPP(true), - ForcedClangUse(false), CCCUsePCH(true), SuppressMissingInputWarning(false) { - if (IsProduction) { - // In a "production" build, only use clang on architectures we expect to - // work. - // - // During development its more convenient to always have the driver use - // clang, but we don't want users to be confused when things don't work, or - // to file bugs for things we don't support. - CCCClangArchs.insert(llvm::Triple::x86); - CCCClangArchs.insert(llvm::Triple::x86_64); - CCCClangArchs.insert(llvm::Triple::arm); - } + CCCUsePCH(true), SuppressMissingInputWarning(false) { Name = llvm::sys::path::stem(ClangExecutable); Dir = llvm::sys::path::parent_path(ClangExecutable); @@ -109,7 +97,7 @@ InputArgList *Driver::ParseArgStrings(ArrayRef<const char *> ArgList) { for (ArgList::const_iterator it = Args->begin(), ie = Args->end(); it != ie; ++it) { Arg *A = *it; - if (A->getOption().isUnsupported()) { + if (A->getOption().hasFlag(options::Unsupported)) { Diag(clang::diag::err_drv_unsupported_opt) << A->getAsString(*Args); continue; } @@ -186,9 +174,9 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { // Add the remaining values as Xlinker arguments. for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) - if (StringRef(A->getValue(Args, i)) != "--no-demangle") + if (StringRef(A->getValue(i)) != "--no-demangle") DAL->AddSeparateArg(A, Opts->getOption(options::OPT_Xlinker), - A->getValue(Args, i)); + A->getValue(i)); continue; } @@ -197,22 +185,22 @@ DerivedArgList *Driver::TranslateInputArgs(const InputArgList &Args) const { // some build systems. We don't try to be complete here because we don't // care to encourage this usage model. if (A->getOption().matches(options::OPT_Wp_COMMA) && - A->getNumValues() == 2 && - (A->getValue(Args, 0) == StringRef("-MD") || - A->getValue(Args, 0) == StringRef("-MMD"))) { + (A->getValue(0) == StringRef("-MD") || + A->getValue(0) == StringRef("-MMD"))) { // Rewrite to -MD/-MMD along with -MF. - if (A->getValue(Args, 0) == StringRef("-MD")) + if (A->getValue(0) == StringRef("-MD")) DAL->AddFlagArg(A, Opts->getOption(options::OPT_MD)); else DAL->AddFlagArg(A, Opts->getOption(options::OPT_MMD)); - DAL->AddSeparateArg(A, Opts->getOption(options::OPT_MF), - A->getValue(Args, 1)); + if (A->getNumValues() == 2) + DAL->AddSeparateArg(A, Opts->getOption(options::OPT_MF), + A->getValue(1)); continue; } // Rewrite reserved library names. if (A->getOption().matches(options::OPT_l)) { - StringRef Value = A->getValue(Args); + StringRef Value = A->getValue(); // Rewrite unless -nostdlib is present. if (!HasNostdlib && Value == "stdc++") { @@ -285,48 +273,23 @@ Compilation *Driver::BuildCompilation(ArrayRef<const char *> ArgList) { CCCIsCXX = Args->hasArg(options::OPT_ccc_cxx) || CCCIsCXX; CCCEcho = Args->hasArg(options::OPT_ccc_echo); if (const Arg *A = Args->getLastArg(options::OPT_ccc_gcc_name)) - CCCGenericGCCName = A->getValue(*Args); - CCCUseClangCXX = Args->hasFlag(options::OPT_ccc_clang_cxx, - options::OPT_ccc_no_clang_cxx, - CCCUseClangCXX); + CCCGenericGCCName = A->getValue(); CCCUsePCH = Args->hasFlag(options::OPT_ccc_pch_is_pch, options::OPT_ccc_pch_is_pth); - CCCUseClang = !Args->hasArg(options::OPT_ccc_no_clang); - CCCUseClangCPP = !Args->hasArg(options::OPT_ccc_no_clang_cpp); - if (const Arg *A = Args->getLastArg(options::OPT_ccc_clang_archs)) { - StringRef Cur = A->getValue(*Args); - - CCCClangArchs.clear(); - while (!Cur.empty()) { - std::pair<StringRef, StringRef> Split = Cur.split(','); - - if (!Split.first.empty()) { - llvm::Triple::ArchType Arch = - llvm::Triple(Split.first, "", "").getArch(); - - if (Arch == llvm::Triple::UnknownArch) - Diag(clang::diag::err_drv_invalid_arch_name) << Split.first; - - CCCClangArchs.insert(Arch); - } - - Cur = Split.second; - } - } // FIXME: DefaultTargetTriple is used by the target-prefixed calls to as/ld // and getToolChain is const. if (const Arg *A = Args->getLastArg(options::OPT_target)) - DefaultTargetTriple = A->getValue(*Args); + DefaultTargetTriple = A->getValue(); if (const Arg *A = Args->getLastArg(options::OPT_ccc_install_dir)) - Dir = InstalledDir = A->getValue(*Args); + Dir = InstalledDir = A->getValue(); for (arg_iterator it = Args->filtered_begin(options::OPT_B), ie = Args->filtered_end(); it != ie; ++it) { const Arg *A = *it; A->claim(); - PrefixDirs.push_back(A->getValue(*Args, 0)); + PrefixDirs.push_back(A->getValue(0)); } if (const Arg *A = Args->getLastArg(options::OPT__sysroot_EQ)) - SysRoot = A->getValue(*Args); + SysRoot = A->getValue(); if (Args->hasArg(options::OPT_nostdlib)) UseStdLib = false; @@ -399,11 +362,11 @@ void Driver::generateCompilationDiagnostics(Compilation &C, std::string Cmd; llvm::raw_string_ostream OS(Cmd); if (FailingCommand) - C.PrintJob(OS, *FailingCommand, "\n", false); + C.PrintDiagnosticJob(OS, *FailingCommand); else // Crash triggered by FORCE_CLANG_DIAGNOSTICS_CRASH, which doesn't have an // associated FailingCommand, so just pass all jobs. - C.PrintJob(OS, C.getJobs(), "\n", false); + C.PrintDiagnosticJob(OS, C.getJobs()); OS.flush(); // Clear stale state and suppress tool output. @@ -418,7 +381,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C, bool IgnoreInput = false; // Ignore input from stdin or any inputs that cannot be preprocessed. - if (!strcmp(it->second->getValue(C.getArgs()), "-")) { + if (!strcmp(it->second->getValue(), "-")) { Diag(clang::diag::note_drv_command_failed_diag_msg) << "Error generating preprocessed source(s) - ignoring input from stdin" "."; @@ -442,7 +405,7 @@ void Driver::generateCompilationDiagnostics(Compilation &C, it != ie; ++it) { Arg *A = *it; if (A->getOption().matches(options::OPT_arch)) { - StringRef ArchName = A->getValue(C.getArgs()); + StringRef ArchName = A->getValue(); ArchNames.insert(ArchName); } } @@ -501,57 +464,6 @@ void Driver::generateCompilationDiagnostics(Compilation &C, Diag(clang::diag::note_drv_command_failed_diag_msg) << "Error generating run script: " + Script + " " + Err; } else { - // Strip away options not necessary to reproduce the crash. - // FIXME: This doesn't work with quotes (e.g., -D "foo bar"). - SmallVector<std::string, 16> Flag; - Flag.push_back("-D "); - Flag.push_back("-F"); - Flag.push_back("-I "); - Flag.push_back("-M "); - Flag.push_back("-MD "); - Flag.push_back("-MF "); - Flag.push_back("-MG "); - Flag.push_back("-MM "); - Flag.push_back("-MMD "); - Flag.push_back("-MP "); - Flag.push_back("-MQ "); - Flag.push_back("-MT "); - Flag.push_back("-o "); - Flag.push_back("-coverage-file "); - Flag.push_back("-dependency-file "); - Flag.push_back("-fdebug-compilation-dir "); - Flag.push_back("-fmodule-cache-path "); - Flag.push_back("-idirafter "); - Flag.push_back("-include "); - Flag.push_back("-include-pch "); - Flag.push_back("-internal-isystem "); - Flag.push_back("-internal-externc-isystem "); - Flag.push_back("-iprefix "); - Flag.push_back("-iwithprefix "); - Flag.push_back("-iwithprefixbefore "); - Flag.push_back("-isysroot "); - Flag.push_back("-isystem "); - Flag.push_back("-iquote "); - Flag.push_back("-resource-dir "); - Flag.push_back("-serialize-diagnostic-file "); - for (unsigned i = 0, e = Flag.size(); i < e; ++i) { - size_t I = 0, E = 0; - do { - I = Cmd.find(Flag[i], I); - if (I == std::string::npos) break; - - E = Cmd.find(" ", I + Flag[i].length()); - if (E == std::string::npos) break; - // The -D option is not removed. Instead, the argument is quoted. - if (Flag[i] != "-D ") { - Cmd.erase(I, E - I + 1); - } else { - Cmd.insert(I+3, "\""); - Cmd.insert(++E, "\""); - I = E; - } - } while(1); - } // Append the new filename with correct preprocessed suffix. size_t I, E; I = Cmd.find("-main-file-name "); @@ -639,12 +551,12 @@ void Driver::PrintOptions(const ArgList &Args) const { it != ie; ++it, ++i) { Arg *A = *it; llvm::errs() << "Option " << i << " - " - << "Name: \"" << A->getOption().getName() << "\", " + << "Name: \"" << A->getOption().getPrefixedName() << "\", " << "Values: {"; for (unsigned j = 0; j < A->getNumValues(); ++j) { if (j) llvm::errs() << ", "; - llvm::errs() << '"' << A->getValue(Args, j) << '"'; + llvm::errs() << '"' << A->getValue(j) << '"'; } llvm::errs() << "}\n"; } @@ -652,7 +564,9 @@ void Driver::PrintOptions(const ArgList &Args) const { void Driver::PrintHelp(bool ShowHidden) const { getOpts().PrintHelp(llvm::outs(), Name.c_str(), DriverTitle.c_str(), - ShowHidden); + /*Include*/0, + /*Exclude*/options::NoDriverOption | + (ShowHidden ? 0 : options::HelpHidden)); } void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { @@ -750,12 +664,12 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { // FIXME: The following handlers should use a callback mechanism, we don't // know what the client would like to do. if (Arg *A = C.getArgs().getLastArg(options::OPT_print_file_name_EQ)) { - llvm::outs() << GetFilePath(A->getValue(C.getArgs()), TC) << "\n"; + llvm::outs() << GetFilePath(A->getValue(), TC) << "\n"; return false; } if (Arg *A = C.getArgs().getLastArg(options::OPT_print_prog_name_EQ)) { - llvm::outs() << GetProgramPath(A->getValue(C.getArgs()), TC) << "\n"; + llvm::outs() << GetProgramPath(A->getValue(), TC) << "\n"; return false; } @@ -818,7 +732,7 @@ static unsigned PrintActions1(const Compilation &C, Action *A, os << Action::getClassName(A->getKind()) << ", "; if (InputAction *IA = dyn_cast<InputAction>(A)) { - os << "\"" << IA->getInputArg().getValue(C.getArgs()) << "\""; + os << "\"" << IA->getInputArg().getValue() << "\""; } else if (BindArchAction *BIA = dyn_cast<BindArchAction>(A)) { os << '"' << BIA->getArchName() << '"' << ", {" << PrintActions1(C, *BIA->begin(), Ids) << "}"; @@ -878,7 +792,7 @@ void Driver::BuildUniversalActions(const ToolChain &TC, // Validate the option here; we don't save the type here because its // particular spelling may participate in other driver choices. llvm::Triple::ArchType Arch = - llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args)); + tools::darwin::getArchTypeForDarwinArchName(A->getValue()); if (Arch == llvm::Triple::UnknownArch) { Diag(clang::diag::err_drv_invalid_arch_name) << A->getAsString(Args); @@ -886,15 +800,15 @@ void Driver::BuildUniversalActions(const ToolChain &TC, } A->claim(); - if (ArchNames.insert(A->getValue(Args))) - Archs.push_back(A->getValue(Args)); + if (ArchNames.insert(A->getValue())) + Archs.push_back(A->getValue()); } } // When there is no explicit arch for this platform, make sure we still bind // the architecture (to the default) so that -Xarch_ is handled correctly. if (!Archs.size()) - Archs.push_back(Args.MakeArgString(TC.getArchName())); + Archs.push_back(Args.MakeArgString(TC.getDefaultUniversalArchName())); // FIXME: We killed off some others but these aren't yet detected in a // functional manner. If we added information to jobs about which "auxiliary" @@ -981,8 +895,8 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args, it != ie; ++it) { Arg *A = *it; - if (isa<InputOption>(A->getOption())) { - const char *Value = A->getValue(Args); + if (A->getOption().getKind() == Option::InputClass) { + const char *Value = A->getValue(); types::ID Ty = types::TY_INVALID; // Infer the input type if necessary. @@ -1049,8 +963,8 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args, if (CheckInputsExist && memcmp(Value, "-", 2) != 0) { SmallString<64> Path(Value); if (Arg *WorkDir = Args.getLastArg(options::OPT_working_directory)) { - SmallString<64> Directory(WorkDir->getValue(Args)); - if (llvm::sys::path::is_absolute(Directory.str())) { + if (!llvm::sys::path::is_absolute(Path.str())) { + SmallString<64> Directory(WorkDir->getValue()); llvm::sys::path::append(Directory, Value); Path.assign(Directory); } @@ -1064,21 +978,21 @@ void Driver::BuildInputs(const ToolChain &TC, const DerivedArgList &Args, } else Inputs.push_back(std::make_pair(Ty, A)); - } else if (A->getOption().isLinkerInput()) { + } else if (A->getOption().hasFlag(options::LinkerInput)) { // Just treat as object type, we could make a special type for this if // necessary. Inputs.push_back(std::make_pair(types::TY_Object, A)); } else if (A->getOption().matches(options::OPT_x)) { InputTypeArg = A; - InputType = types::lookupTypeForTypeSpecifier(A->getValue(Args)); + InputType = types::lookupTypeForTypeSpecifier(A->getValue()); A->claim(); // Follow gcc behavior and treat as linker input for invalid -x // options. Its not clear why we shouldn't just revert to unknown; but // this isn't very important, we might as well be bug compatible. if (!InputType) { - Diag(clang::diag::err_drv_unknown_language) << A->getValue(Args); + Diag(clang::diag::err_drv_unknown_language) << A->getValue(); InputType = types::TY_Object; } } @@ -1301,7 +1215,7 @@ void Driver::BuildJobs(Compilation &C) const { const char *LinkingOutput = 0; if (isa<LipoJobAction>(A)) { if (FinalOutput) - LinkingOutput = FinalOutput->getValue(C.getArgs()); + LinkingOutput = FinalOutput->getValue(); else LinkingOutput = DefaultImageName.c_str(); } @@ -1331,13 +1245,13 @@ void Driver::BuildJobs(Compilation &C) const { // DiagnosticsEngine, so that extra values, position, and so on could be // printed. if (!A->isClaimed()) { - if (A->getOption().hasNoArgumentUnused()) + if (A->getOption().hasFlag(options::NoArgumentUnused)) continue; // Suppress the warning automatically if this is just a flag, and it is an // instance of an argument we already claimed. const Option &Opt = A->getOption(); - if (isa<FlagOption>(Opt)) { + if (Opt.getKind() == Option::FlagClass) { bool DuplicateClaimed = false; for (arg_iterator it = C.getArgs().filtered_begin(&Opt), @@ -1392,6 +1306,7 @@ static const Tool &SelectToolForJob(Compilation &C, const ToolChain *TC, !C.getArgs().hasArg(options::OPT_no_integrated_cpp) && !C.getArgs().hasArg(options::OPT_traditional_cpp) && !C.getArgs().hasArg(options::OPT_save_temps) && + !C.getArgs().hasArg(options::OPT_rewrite_objc) && ToolForJob->hasIntegratedCPP()) Inputs = &(*Inputs)[0]->getInputs(); @@ -1413,7 +1328,7 @@ void Driver::BuildJobsForAction(Compilation &C, const Arg &Input = IA->getInputArg(); Input.claim(); if (Input.getOption().matches(options::OPT_INPUT)) { - const char *Name = Input.getValue(C.getArgs()); + const char *Name = Input.getValue(); Result = InputInfo(Name, A->getType(), Name); } else Result = InputInfo(&Input, A->getType(), ""); @@ -1502,7 +1417,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, if (AtTopLevel && !isa<DsymutilJobAction>(JA) && !isa<VerifyJobAction>(JA)) { if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) - return C.addResultFile(FinalOutput->getValue(C.getArgs())); + return C.addResultFile(FinalOutput->getValue()); } // Default to writing to stdout? @@ -1580,7 +1495,7 @@ const char *Driver::GetNamedOutputPath(Compilation &C, std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { // Respect a limited subset of the '-Bprefix' functionality in GCC by - // attempting to use this prefix when lokup up program paths. + // attempting to use this prefix when looking for file paths. for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(), ie = PrefixDirs.end(); it != ie; ++it) { std::string Dir(*it); @@ -1619,26 +1534,26 @@ std::string Driver::GetFilePath(const char *Name, const ToolChain &TC) const { return Name; } -static bool isPathExecutable(llvm::sys::Path &P, bool WantFile) { - bool Exists; - return (WantFile ? !llvm::sys::fs::exists(P.str(), Exists) && Exists - : P.canExecute()); -} - -std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC, - bool WantFile) const { +std::string Driver::GetProgramPath(const char *Name, + const ToolChain &TC) const { // FIXME: Needs a better variable than DefaultTargetTriple std::string TargetSpecificExecutable(DefaultTargetTriple + "-" + Name); // Respect a limited subset of the '-Bprefix' functionality in GCC by - // attempting to use this prefix when lokup up program paths. + // attempting to use this prefix when looking for program paths. for (Driver::prefix_list::const_iterator it = PrefixDirs.begin(), ie = PrefixDirs.end(); it != ie; ++it) { - llvm::sys::Path P(*it); - P.appendComponent(TargetSpecificExecutable); - if (isPathExecutable(P, WantFile)) return P.str(); - P.eraseComponent(); - P.appendComponent(Name); - if (isPathExecutable(P, WantFile)) return P.str(); + bool IsDirectory; + if (!llvm::sys::fs::is_directory(*it, IsDirectory) && IsDirectory) { + llvm::sys::Path P(*it); + P.appendComponent(TargetSpecificExecutable); + if (P.canExecute()) return P.str(); + P.eraseComponent(); + P.appendComponent(Name); + if (P.canExecute()) return P.str(); + } else { + llvm::sys::Path P(*it + Name); + if (P.canExecute()) return P.str(); + } } const ToolChain::path_list &List = TC.getProgramPaths(); @@ -1646,10 +1561,10 @@ std::string Driver::GetProgramPath(const char *Name, const ToolChain &TC, it = List.begin(), ie = List.end(); it != ie; ++it) { llvm::sys::Path P(*it); P.appendComponent(TargetSpecificExecutable); - if (isPathExecutable(P, WantFile)) return P.str(); + if (P.canExecute()) return P.str(); P.eraseComponent(); P.appendComponent(Name); - if (isPathExecutable(P, WantFile)) return P.str(); + if (P.canExecute()) return P.str(); } // If all else failed, search the path. @@ -1701,7 +1616,7 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, StringRef DarwinArchName) { // FIXME: Already done in Compilation *Driver::BuildCompilation if (const Arg *A = Args.getLastArg(options::OPT_target)) - DefaultTargetTriple = A->getValue(Args); + DefaultTargetTriple = A->getValue(); llvm::Triple Target(llvm::Triple::normalize(DefaultTargetTriple)); @@ -1710,14 +1625,14 @@ static llvm::Triple computeTargetTriple(StringRef DefaultTargetTriple, // If an explict Darwin arch name is given, that trumps all. if (!DarwinArchName.empty()) { Target.setArch( - llvm::Triple::getArchTypeForDarwinArchName(DarwinArchName)); + tools::darwin::getArchTypeForDarwinArchName(DarwinArchName)); return Target; } // Handle the Darwin '-arch' flag. if (Arg *A = Args.getLastArg(options::OPT_arch)) { llvm::Triple::ArchType DarwinArch - = llvm::Triple::getArchTypeForDarwinArchName(A->getValue(Args)); + = tools::darwin::getArchTypeForDarwinArchName(A->getValue()); if (DarwinArch != llvm::Triple::UnknownArch) Target.setArch(DarwinArch); } @@ -1820,37 +1735,14 @@ bool Driver::ShouldUseClangCompiler(const Compilation &C, const JobAction &JA, const llvm::Triple &Triple) const { // Check if user requested no clang, or clang doesn't understand this type (we // only handle single inputs for now). - if (!CCCUseClang || JA.size() != 1 || + if (JA.size() != 1 || !types::isAcceptedByClang((*JA.begin())->getType())) return false; // Otherwise make sure this is an action clang understands. - if (isa<PreprocessJobAction>(JA)) { - if (!CCCUseClangCPP) { - Diag(clang::diag::warn_drv_not_using_clang_cpp); - return false; - } - } else if (!isa<PrecompileJobAction>(JA) && !isa<CompileJobAction>(JA)) - return false; - - // Use clang for C++? - if (!CCCUseClangCXX && types::isCXX((*JA.begin())->getType())) { - Diag(clang::diag::warn_drv_not_using_clang_cxx); + if (!isa<PreprocessJobAction>(JA) && !isa<PrecompileJobAction>(JA) && + !isa<CompileJobAction>(JA)) return false; - } - - // Always use clang for precompiling, AST generation, and rewriting, - // regardless of archs. - if (isa<PrecompileJobAction>(JA) || - types::isOnlyAcceptedByClang(JA.getType())) - return true; - - // Finally, don't use clang if this isn't one of the user specified archs to - // build. - if (!CCCClangArchs.empty() && !CCCClangArchs.count(Triple.getArch())) { - Diag(clang::diag::warn_drv_not_using_clang_arch) << Triple.getArchName(); - return false; - } return true; } diff --git a/lib/Driver/DriverOptions.cpp b/lib/Driver/DriverOptions.cpp index 715819d04b26..3925b8aa35c5 100644 --- a/lib/Driver/DriverOptions.cpp +++ b/lib/Driver/DriverOptions.cpp @@ -14,11 +14,19 @@ using namespace clang::driver; using namespace clang::driver::options; +#define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ + HELPTEXT, METAVAR) +#include "clang/Driver/Options.inc" +#undef OPTION +#undef PREFIX + static const OptTable::Info InfoTable[] = { -#define OPTION(NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ +#define PREFIX(NAME, VALUE) +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, FLAGS, PARAM, \ HELPTEXT, METAVAR) \ - { NAME, HELPTEXT, METAVAR, Option::KIND##Class, PARAM, FLAGS, \ - OPT_##GROUP, OPT_##ALIAS }, + { PREFIX, NAME, HELPTEXT, METAVAR, OPT_##ID, Option::KIND##Class, PARAM, \ + FLAGS, OPT_##GROUP, OPT_##ALIAS }, #include "clang/Driver/Options.inc" }; diff --git a/lib/Driver/OptTable.cpp b/lib/Driver/OptTable.cpp index a3e38b26f20f..6e7b6951fb83 100644 --- a/lib/Driver/OptTable.cpp +++ b/lib/Driver/OptTable.cpp @@ -11,6 +11,7 @@ #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Option.h" +#include "clang/Driver/Options.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" #include <algorithm> @@ -54,6 +55,13 @@ static inline bool operator<(const OptTable::Info &A, const OptTable::Info &B) { if (int N = StrCmpOptionName(A.Name, B.Name)) return N == -1; + for (const char * const *APre = A.Prefixes, + * const *BPre = B.Prefixes; + *APre != 0 && *BPre != 0; ++APre, ++BPre) { + if (int N = StrCmpOptionName(*APre, *BPre)) + return N == -1; + } + // Names are the same, check that classes are in order; exactly one // should be joined, and it should succeed the other. assert(((A.Kind == Option::JoinedClass) ^ (B.Kind == Option::JoinedClass)) && @@ -78,23 +86,24 @@ OptSpecifier::OptSpecifier(const Option *Opt) : ID(Opt->getID()) {} // OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos) - : OptionInfos(_OptionInfos), NumOptionInfos(_NumOptionInfos), - Options(new Option*[NumOptionInfos]), - TheInputOption(0), TheUnknownOption(0), FirstSearchableIndex(0) + : OptionInfos(_OptionInfos), + NumOptionInfos(_NumOptionInfos), + TheInputOptionID(0), + TheUnknownOptionID(0), + FirstSearchableIndex(0) { // Explicitly zero initialize the error to work around a bug in array // value-initialization on MinGW with gcc 4.3.5. - memset(Options, 0, sizeof(*Options) * NumOptionInfos); // Find start of normal options. for (unsigned i = 0, e = getNumOptions(); i != e; ++i) { unsigned Kind = getInfo(i + 1).Kind; if (Kind == Option::InputClass) { - assert(!TheInputOption && "Cannot have multiple input options!"); - TheInputOption = getOption(i + 1); + assert(!TheInputOptionID && "Cannot have multiple input options!"); + TheInputOptionID = getInfo(i + 1).ID; } else if (Kind == Option::UnknownClass) { - assert(!TheUnknownOption && "Cannot have multiple input options!"); - TheUnknownOption = getOption(i + 1); + assert(!TheUnknownOptionID && "Cannot have multiple unknown options!"); + TheUnknownOptionID = getInfo(i + 1).ID; } else if (Kind != Option::GroupClass) { FirstSearchableIndex = i; break; @@ -115,91 +124,80 @@ OptTable::OptTable(const Info *_OptionInfos, unsigned _NumOptionInfos) // Check that options are in order. for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) { if (!(getInfo(i) < getInfo(i + 1))) { - getOption(i)->dump(); - getOption(i + 1)->dump(); + getOption(i).dump(); + getOption(i + 1).dump(); llvm_unreachable("Options are not in order!"); } } #endif + + // Build prefixes. + for (unsigned i = FirstSearchableIndex+1, e = getNumOptions(); i != e; ++i) { + if (const char *const *P = getInfo(i).Prefixes) { + for (; *P != 0; ++P) { + PrefixesUnion.insert(*P); + } + } + } + + // Build prefix chars. + for (llvm::StringSet<>::const_iterator I = PrefixesUnion.begin(), + E = PrefixesUnion.end(); I != E; ++I) { + StringRef Prefix = I->getKey(); + for (StringRef::const_iterator C = Prefix.begin(), CE = Prefix.end(); + C != CE; ++C) + if (std::find(PrefixChars.begin(), PrefixChars.end(), *C) + == PrefixChars.end()) + PrefixChars.push_back(*C); + } } OptTable::~OptTable() { - for (unsigned i = 0, e = getNumOptions(); i != e; ++i) - delete Options[i]; - delete[] Options; } -Option *OptTable::CreateOption(unsigned id) const { - const Info &info = getInfo(id); - const OptionGroup *Group = - cast_or_null<OptionGroup>(getOption(info.GroupID)); - const Option *Alias = getOption(info.AliasID); - - Option *Opt = 0; - switch (info.Kind) { - case Option::InputClass: - Opt = new InputOption(id); break; - case Option::UnknownClass: - Opt = new UnknownOption(id); break; - case Option::GroupClass: - Opt = new OptionGroup(id, info.Name, Group); break; - case Option::FlagClass: - Opt = new FlagOption(id, info.Name, Group, Alias); break; - case Option::JoinedClass: - Opt = new JoinedOption(id, info.Name, Group, Alias); break; - case Option::SeparateClass: - Opt = new SeparateOption(id, info.Name, Group, Alias); break; - case Option::CommaJoinedClass: - Opt = new CommaJoinedOption(id, info.Name, Group, Alias); break; - case Option::MultiArgClass: - Opt = new MultiArgOption(id, info.Name, Group, Alias, info.Param); break; - case Option::JoinedOrSeparateClass: - Opt = new JoinedOrSeparateOption(id, info.Name, Group, Alias); break; - case Option::JoinedAndSeparateClass: - Opt = new JoinedAndSeparateOption(id, info.Name, Group, Alias); break; - } +const Option OptTable::getOption(OptSpecifier Opt) const { + unsigned id = Opt.getID(); + if (id == 0) + return Option(0, 0); + assert((unsigned) (id - 1) < getNumOptions() && "Invalid ID."); + return Option(&getInfo(id), this); +} - if (info.Flags & DriverOption) - Opt->setDriverOption(true); - if (info.Flags & LinkerInput) - Opt->setLinkerInput(true); - if (info.Flags & NoArgumentUnused) - Opt->setNoArgumentUnused(true); - if (info.Flags & NoForward) - Opt->setNoForward(true); - if (info.Flags & RenderAsInput) - Opt->setNoOptAsInput(true); - if (info.Flags & RenderJoined) { - assert((info.Kind == Option::JoinedOrSeparateClass || - info.Kind == Option::SeparateClass) && "Invalid option."); - Opt->setRenderStyle(Option::RenderJoinedStyle); - } - if (info.Flags & RenderSeparate) { - assert((info.Kind == Option::JoinedOrSeparateClass || - info.Kind == Option::JoinedClass) && "Invalid option."); - Opt->setRenderStyle(Option::RenderSeparateStyle); - } - if (info.Flags & Unsupported) - Opt->setUnsupported(true); - if (info.Flags & CC1Option) - Opt->setIsCC1Option(true); +static bool isInput(const llvm::StringSet<> &Prefixes, StringRef Arg) { + if (Arg == "-") + return true; + for (llvm::StringSet<>::const_iterator I = Prefixes.begin(), + E = Prefixes.end(); I != E; ++I) + if (Arg.startswith(I->getKey())) + return false; + return true; +} - return Opt; +/// \returns Matched size. 0 means no match. +static unsigned matchOption(const OptTable::Info *I, StringRef Str) { + for (const char * const *Pre = I->Prefixes; *Pre != 0; ++Pre) { + StringRef Prefix(*Pre); + if (Str.startswith(Prefix) && Str.substr(Prefix.size()).startswith(I->Name)) + return Prefix.size() + StringRef(I->Name).size(); + } + return 0; } Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const { unsigned Prev = Index; const char *Str = Args.getArgString(Index); - // Anything that doesn't start with '-' is an input, as is '-' itself. - if (Str[0] != '-' || Str[1] == '\0') - return new Arg(TheInputOption, Index++, Str); + // Anything that doesn't start with PrefixesUnion is an input, as is '-' + // itself. + if (isInput(PrefixesUnion, Str)) + return new Arg(getOption(TheInputOptionID), Str, Index++, Str); const Info *Start = OptionInfos + FirstSearchableIndex; const Info *End = OptionInfos + getNumOptions(); + StringRef Name = StringRef(Str).ltrim(PrefixChars); // Search for the first next option which could be a prefix. - Start = std::lower_bound(Start, End, Str); + Start = std::lower_bound(Start, End, Name.data()); // Options are stored in sorted order, with '\0' at the end of the // alphabet. Since the only options which can accept a string must @@ -210,15 +208,16 @@ Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const { // blanking on the simplest way to make it fast. We can solve this // problem when we move to TableGen. for (; Start != End; ++Start) { + unsigned ArgSize = 0; // Scan for first option which is a proper prefix. for (; Start != End; ++Start) - if (memcmp(Str, Start->Name, strlen(Start->Name)) == 0) + if ((ArgSize = matchOption(Start, Str))) break; if (Start == End) break; // See if this option matches. - if (Arg *A = getOption(Start - OptionInfos + 1)->accept(Args, Index)) + if (Arg *A = Option(Start, this).accept(Args, Index, ArgSize)) return A; // Otherwise, see if this argument was missing values. @@ -226,7 +225,7 @@ Arg *OptTable::ParseOneArg(const ArgList &Args, unsigned &Index) const { return 0; } - return new Arg(TheUnknownOption, Index++, Str); + return new Arg(getOption(TheUnknownOptionID), Str, Index++, Str); } InputArgList *OptTable::ParseArgs(const char* const *ArgBegin, @@ -266,10 +265,11 @@ InputArgList *OptTable::ParseArgs(const char* const *ArgBegin, } static std::string getOptionHelpName(const OptTable &Opts, OptSpecifier Id) { - std::string Name = Opts.getOptionName(Id); + const Option O = Opts.getOption(Id); + std::string Name = O.getPrefixedName(); // Add metavar, if used. - switch (Opts.getOptionKind(Id)) { + switch (O.getKind()) { case Option::GroupClass: case Option::InputClass: case Option::UnknownClass: llvm_unreachable("Invalid option with help text."); @@ -346,7 +346,8 @@ static const char *getOptionHelpGroup(const OptTable &Opts, OptSpecifier Id) { } void OptTable::PrintHelp(raw_ostream &OS, const char *Name, - const char *Title, bool ShowHidden) const { + const char *Title, unsigned short FlagsToInclude, + unsigned short FlagsToExclude) const { OS << "OVERVIEW: " << Title << "\n"; OS << '\n'; OS << "USAGE: " << Name << " [options] <inputs>\n"; @@ -365,7 +366,8 @@ void OptTable::PrintHelp(raw_ostream &OS, const char *Name, if (getOptionKind(Id) == Option::GroupClass) continue; - if (!ShowHidden && isOptionHelpHidden(Id)) + if ((FlagsToInclude && !(getInfo(Id).Flags & FlagsToInclude)) || + getInfo(Id).Flags & FlagsToExclude) continue; if (const char *Text = getOptionHelpText(Id)) { diff --git a/lib/Driver/Option.cpp b/lib/Driver/Option.cpp index 03360ea2d89a..9a34df59036a 100644 --- a/lib/Driver/Option.cpp +++ b/lib/Driver/Option.cpp @@ -13,46 +13,20 @@ #include "clang/Driver/ArgList.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/Twine.h" #include <cassert> #include <algorithm> using namespace clang::driver; -Option::Option(OptionClass _Kind, OptSpecifier _ID, const char *_Name, - const OptionGroup *_Group, const Option *_Alias) - : Kind(_Kind), ID(_ID.getID()), Name(_Name), Group(_Group), Alias(_Alias), - Unsupported(false), LinkerInput(false), NoOptAsInput(false), - DriverOption(false), NoArgumentUnused(false), NoForward(false) { +Option::Option(const OptTable::Info *info, const OptTable *owner) + : Info(info), Owner(owner) { // Multi-level aliases are not supported, and alias options cannot // have groups. This just simplifies option tracking, it is not an // inherent limitation. - assert((!Alias || (!Alias->Alias && !Group)) && + assert((!Info || !getAlias().isValid() || (!getAlias().getAlias().isValid() && + !getGroup().isValid())) && "Multi-level aliases and aliases with groups are unsupported."); - - // Initialize rendering options based on the class. - switch (Kind) { - case GroupClass: - case InputClass: - case UnknownClass: - RenderStyle = RenderValuesStyle; - break; - - case JoinedClass: - case JoinedAndSeparateClass: - RenderStyle = RenderJoinedStyle; - break; - - case CommaJoinedClass: - RenderStyle = RenderCommaJoinedStyle; - break; - - case FlagClass: - case SeparateClass: - case MultiArgClass: - case JoinedOrSeparateClass: - RenderStyle = RenderSeparateStyle; - break; - } } Option::~Option() { @@ -60,7 +34,7 @@ Option::~Option() { void Option::dump() const { llvm::errs() << "<"; - switch (Kind) { + switch (getKind()) { #define P(N) case N: llvm::errs() << #N; break P(GroupClass); P(InputClass); @@ -75,206 +49,153 @@ void Option::dump() const { #undef P } - llvm::errs() << " Name:\"" << Name << '"'; + llvm::errs() << " Prefixes:["; + for (const char * const *Pre = Info->Prefixes; *Pre != 0; ++Pre) { + llvm::errs() << '"' << *Pre << (*(Pre + 1) == 0 ? "\"" : "\", "); + } + llvm::errs() << ']'; - if (Group) { + llvm::errs() << " Name:\"" << getName() << '"'; + + const Option Group = getGroup(); + if (Group.isValid()) { llvm::errs() << " Group:"; - Group->dump(); + Group.dump(); } - if (Alias) { + const Option Alias = getAlias(); + if (Alias.isValid()) { llvm::errs() << " Alias:"; - Alias->dump(); + Alias.dump(); } - if (const MultiArgOption *MOA = dyn_cast<MultiArgOption>(this)) - llvm::errs() << " NumArgs:" << MOA->getNumArgs(); + if (getKind() == MultiArgClass) + llvm::errs() << " NumArgs:" << getNumArgs(); llvm::errs() << ">\n"; } bool Option::matches(OptSpecifier Opt) const { // Aliases are never considered in matching, look through them. - if (Alias) - return Alias->matches(Opt); + const Option Alias = getAlias(); + if (Alias.isValid()) + return Alias.matches(Opt); // Check exact match. - if (ID == Opt) + if (getID() == Opt.getID()) return true; - if (Group) - return Group->matches(Opt); + const Option Group = getGroup(); + if (Group.isValid()) + return Group.matches(Opt); return false; } -OptionGroup::OptionGroup(OptSpecifier ID, const char *Name, - const OptionGroup *Group) - : Option(Option::GroupClass, ID, Name, Group, 0) { -} - -Arg *OptionGroup::accept(const ArgList &Args, unsigned &Index) const { - llvm_unreachable("accept() should never be called on an OptionGroup"); -} - -InputOption::InputOption(OptSpecifier ID) - : Option(Option::InputClass, ID, "<input>", 0, 0) { -} - -Arg *InputOption::accept(const ArgList &Args, unsigned &Index) const { - llvm_unreachable("accept() should never be called on an InputOption"); -} - -UnknownOption::UnknownOption(OptSpecifier ID) - : Option(Option::UnknownClass, ID, "<unknown>", 0, 0) { -} - -Arg *UnknownOption::accept(const ArgList &Args, unsigned &Index) const { - llvm_unreachable("accept() should never be called on an UnknownOption"); -} - -FlagOption::FlagOption(OptSpecifier ID, const char *Name, - const OptionGroup *Group, const Option *Alias) - : Option(Option::FlagClass, ID, Name, Group, Alias) { -} - -Arg *FlagOption::accept(const ArgList &Args, unsigned &Index) const { - // Matches iff this is an exact match. - // FIXME: Avoid strlen. - if (getName().size() != strlen(Args.getArgString(Index))) - return 0; - - return new Arg(getUnaliasedOption(), Index++); -} - -JoinedOption::JoinedOption(OptSpecifier ID, const char *Name, - const OptionGroup *Group, const Option *Alias) - : Option(Option::JoinedClass, ID, Name, Group, Alias) { -} - -Arg *JoinedOption::accept(const ArgList &Args, unsigned &Index) const { - // Always matches. - const char *Value = Args.getArgString(Index) + getName().size(); - return new Arg(getUnaliasedOption(), Index++, Value); -} - -CommaJoinedOption::CommaJoinedOption(OptSpecifier ID, const char *Name, - const OptionGroup *Group, - const Option *Alias) - : Option(Option::CommaJoinedClass, ID, Name, Group, Alias) { -} - -Arg *CommaJoinedOption::accept(const ArgList &Args, - unsigned &Index) const { - // Always matches. - const char *Str = Args.getArgString(Index) + getName().size(); - Arg *A = new Arg(getUnaliasedOption(), Index++); +Arg *Option::accept(const ArgList &Args, + unsigned &Index, + unsigned ArgSize) const { + const Option &UnaliasedOption = getUnaliasedOption(); + StringRef Spelling; + // If the option was an alias, get the spelling from the unaliased one. + if (getID() == UnaliasedOption.getID()) { + Spelling = StringRef(Args.getArgString(Index), ArgSize); + } else { + Spelling = Args.MakeArgString(Twine(UnaliasedOption.getPrefix()) + + Twine(UnaliasedOption.getName())); + } - // Parse out the comma separated values. - const char *Prev = Str; - for (;; ++Str) { - char c = *Str; + switch (getKind()) { + case FlagClass: + if (ArgSize != strlen(Args.getArgString(Index))) + return 0; - if (!c || c == ',') { - if (Prev != Str) { - char *Value = new char[Str - Prev + 1]; - memcpy(Value, Prev, Str - Prev); - Value[Str - Prev] = '\0'; - A->getValues().push_back(Value); + return new Arg(UnaliasedOption, Spelling, Index++); + case JoinedClass: { + const char *Value = Args.getArgString(Index) + ArgSize; + return new Arg(UnaliasedOption, Spelling, Index++, Value); + } + case CommaJoinedClass: { + // Always matches. + const char *Str = Args.getArgString(Index) + ArgSize; + Arg *A = new Arg(UnaliasedOption, Spelling, Index++); + + // Parse out the comma separated values. + const char *Prev = Str; + for (;; ++Str) { + char c = *Str; + + if (!c || c == ',') { + if (Prev != Str) { + char *Value = new char[Str - Prev + 1]; + memcpy(Value, Prev, Str - Prev); + Value[Str - Prev] = '\0'; + A->getValues().push_back(Value); + } + + if (!c) + break; + + Prev = Str + 1; } - - if (!c) - break; - - Prev = Str + 1; } - } - A->setOwnsValues(true); - - return A; -} - -SeparateOption::SeparateOption(OptSpecifier ID, const char *Name, - const OptionGroup *Group, const Option *Alias) - : Option(Option::SeparateClass, ID, Name, Group, Alias) { -} - -Arg *SeparateOption::accept(const ArgList &Args, unsigned &Index) const { - // Matches iff this is an exact match. - // FIXME: Avoid strlen. - if (getName().size() != strlen(Args.getArgString(Index))) - return 0; - - Index += 2; - if (Index > Args.getNumInputArgStrings()) - return 0; - - return new Arg(getUnaliasedOption(), Index - 2, Args.getArgString(Index - 1)); -} - -MultiArgOption::MultiArgOption(OptSpecifier ID, const char *Name, - const OptionGroup *Group, const Option *Alias, - unsigned _NumArgs) - : Option(Option::MultiArgClass, ID, Name, Group, Alias), NumArgs(_NumArgs) { - assert(NumArgs > 1 && "Invalid MultiArgOption!"); -} - -Arg *MultiArgOption::accept(const ArgList &Args, unsigned &Index) const { - // Matches iff this is an exact match. - // FIXME: Avoid strlen. - if (getName().size() != strlen(Args.getArgString(Index))) - return 0; - - Index += 1 + NumArgs; - if (Index > Args.getNumInputArgStrings()) - return 0; + A->setOwnsValues(true); - Arg *A = new Arg(getUnaliasedOption(), Index - 1 - NumArgs, - Args.getArgString(Index - NumArgs)); - for (unsigned i = 1; i != NumArgs; ++i) - A->getValues().push_back(Args.getArgString(Index - NumArgs + i)); - return A; -} - -JoinedOrSeparateOption::JoinedOrSeparateOption(OptSpecifier ID, - const char *Name, - const OptionGroup *Group, - const Option *Alias) - : Option(Option::JoinedOrSeparateClass, ID, Name, Group, Alias) { -} - -Arg *JoinedOrSeparateOption::accept(const ArgList &Args, - unsigned &Index) const { - // If this is not an exact match, it is a joined arg. - // FIXME: Avoid strlen. - if (getName().size() != strlen(Args.getArgString(Index))) { - const char *Value = Args.getArgString(Index) + getName().size(); - return new Arg(this, Index++, Value); + return A; } + case SeparateClass: + // Matches iff this is an exact match. + // FIXME: Avoid strlen. + if (ArgSize != strlen(Args.getArgString(Index))) + return 0; + + Index += 2; + if (Index > Args.getNumInputArgStrings()) + return 0; + + return new Arg(UnaliasedOption, Spelling, + Index - 2, Args.getArgString(Index - 1)); + case MultiArgClass: { + // Matches iff this is an exact match. + // FIXME: Avoid strlen. + if (ArgSize != strlen(Args.getArgString(Index))) + return 0; + + Index += 1 + getNumArgs(); + if (Index > Args.getNumInputArgStrings()) + return 0; + + Arg *A = new Arg(UnaliasedOption, Spelling, Index - 1 - getNumArgs(), + Args.getArgString(Index - getNumArgs())); + for (unsigned i = 1; i != getNumArgs(); ++i) + A->getValues().push_back(Args.getArgString(Index - getNumArgs() + i)); + return A; + } + case JoinedOrSeparateClass: { + // If this is not an exact match, it is a joined arg. + // FIXME: Avoid strlen. + if (ArgSize != strlen(Args.getArgString(Index))) { + const char *Value = Args.getArgString(Index) + ArgSize; + return new Arg(*this, Spelling, Index++, Value); + } - // Otherwise it must be separate. - Index += 2; - if (Index > Args.getNumInputArgStrings()) - return 0; - - return new Arg(getUnaliasedOption(), Index - 2, Args.getArgString(Index - 1)); -} - -JoinedAndSeparateOption::JoinedAndSeparateOption(OptSpecifier ID, - const char *Name, - const OptionGroup *Group, - const Option *Alias) - : Option(Option::JoinedAndSeparateClass, ID, Name, Group, Alias) { -} - -Arg *JoinedAndSeparateOption::accept(const ArgList &Args, - unsigned &Index) const { - // Always matches. - - Index += 2; - if (Index > Args.getNumInputArgStrings()) - return 0; + // Otherwise it must be separate. + Index += 2; + if (Index > Args.getNumInputArgStrings()) + return 0; - return new Arg(getUnaliasedOption(), Index - 2, - Args.getArgString(Index-2)+getName().size(), - Args.getArgString(Index-1)); + return new Arg(UnaliasedOption, Spelling, + Index - 2, Args.getArgString(Index - 1)); + } + case JoinedAndSeparateClass: + // Always matches. + Index += 2; + if (Index > Args.getNumInputArgStrings()) + return 0; + + return new Arg(UnaliasedOption, Spelling, Index - 2, + Args.getArgString(Index - 2) + ArgSize, + Args.getArgString(Index - 1)); + default: + llvm_unreachable("Invalid option kind!"); + } } diff --git a/lib/Driver/SanitizerArgs.h b/lib/Driver/SanitizerArgs.h new file mode 100644 index 000000000000..ecb396ea06cf --- /dev/null +++ b/lib/Driver/SanitizerArgs.h @@ -0,0 +1,106 @@ +//===--- SanitizerArgs.h - Arguments for sanitizer tools -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +#ifndef CLANG_LIB_DRIVER_SANITIZERARGS_H_ +#define CLANG_LIB_DRIVER_SANITIZERARGS_H_ + +#include "clang/Driver/ArgList.h" + +namespace clang { +namespace driver { + +class SanitizerArgs { + /// Assign ordinals to sanitizer flags. We'll use the ordinal values as + /// bit positions within \c Kind. + enum SanitizeOrdinal { +#define SANITIZER(NAME, ID) SO_##ID, +#include "clang/Basic/Sanitizers.def" + SO_Count + }; + + /// Bugs to catch at runtime. + enum SanitizeKind { +#define SANITIZER(NAME, ID) ID = 1 << SO_##ID, +#define SANITIZER_GROUP(NAME, ID, ALIAS) ID = ALIAS, +#include "clang/Basic/Sanitizers.def" + NeedsAsanRt = Address, + NeedsTsanRt = Thread, + NeedsUbsanRt = Undefined + }; + unsigned Kind; + + public: + SanitizerArgs() : Kind(0) {} + /// Parses the sanitizer arguments from an argument list. + SanitizerArgs(const Driver &D, const ArgList &Args); + + bool needsAsanRt() const { return Kind & NeedsAsanRt; } + bool needsTsanRt() const { return Kind & NeedsTsanRt; } + bool needsUbsanRt() const { return Kind & NeedsUbsanRt; } + + bool sanitizesVptr() const { return Kind & Vptr; } + + void addArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + if (!Kind) + return; + llvm::SmallString<256> SanitizeOpt("-fsanitize="); +#define SANITIZER(NAME, ID) \ + if (Kind & ID) \ + SanitizeOpt += NAME ","; +#include "clang/Basic/Sanitizers.def" + SanitizeOpt.pop_back(); + CmdArgs.push_back(Args.MakeArgString(SanitizeOpt)); + } + + private: + /// Parse a single value from a -fsanitize= or -fno-sanitize= value list. + /// Returns a member of the \c SanitizeKind enumeration, or \c 0 if \p Value + /// is not known. + static unsigned parse(const char *Value) { + return llvm::StringSwitch<SanitizeKind>(Value) +#define SANITIZER(NAME, ID) .Case(NAME, ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS) .Case(NAME, ID) +#include "clang/Basic/Sanitizers.def" + .Default(SanitizeKind()); + } + + /// Parse a -fsanitize= or -fno-sanitize= argument's values, diagnosing any + /// invalid components. + static unsigned parse(const Driver &D, const Arg *A) { + unsigned Kind = 0; + for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) { + if (unsigned K = parse(A->getValue(I))) + Kind |= K; + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << A->getValue(I); + } + return Kind; + } + + /// Produce an argument string from argument \p A, which shows how it provides + /// a value in \p Mask. For instance, the argument + /// "-fsanitize=address,alignment" with mask \c NeedsUbsanRt would produce + /// "-fsanitize=alignment". + static std::string describeSanitizeArg(const ArgList &Args, const Arg *A, + unsigned Mask) { + if (!A->getOption().matches(options::OPT_fsanitize_EQ)) + return A->getAsString(Args); + + for (unsigned I = 0, N = A->getNumValues(); I != N; ++I) + if (parse(A->getValue(I)) & Mask) + return std::string("-fsanitize=") + A->getValue(I); + + llvm_unreachable("arg didn't provide expected value"); + } +}; + +} // namespace driver +} // namespace clang + +#endif // CLANG_LIB_DRIVER_SANITIZERARGS_H_ diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 48ed044c8f5c..de8ed1d1c5e7 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -14,6 +14,7 @@ #include "clang/Driver/ArgList.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Option.h" #include "clang/Driver/Options.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" @@ -32,13 +33,32 @@ const Driver &ToolChain::getDriver() const { return D; } +std::string ToolChain::getDefaultUniversalArchName() const { + // In universal driver terms, the arch name accepted by -arch isn't exactly + // the same as the ones that appear in the triple. Roughly speaking, this is + // an inverse of the darwin::getArchTypeForDarwinArchName() function, but the + // only interesting special case is powerpc. + switch (Triple.getArch()) { + case llvm::Triple::ppc: + return "ppc"; + case llvm::Triple::ppc64: + return "ppc64"; + default: + return Triple.getArchName(); + } +} + +bool ToolChain::IsUnwindTablesDefault() const { + return false; +} + std::string ToolChain::GetFilePath(const char *Name) const { return D.GetFilePath(Name, *this); } -std::string ToolChain::GetProgramPath(const char *Name, bool WantFile) const { - return D.GetProgramPath(Name, *this, WantFile); +std::string ToolChain::GetProgramPath(const char *Name) const { + return D.GetProgramPath(Name, *this); } types::ID ToolChain::LookupTypeForExtension(const char *Ext) const { @@ -66,13 +86,13 @@ static const char *getARMTargetCPU(const ArgList &Args, // FIXME: Warn on inconsistent use of -mcpu and -march. // If we have -mcpu=, use that. if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) - return A->getValue(Args); + return A->getValue(); } StringRef MArch; if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { // Otherwise, if we have -march= choose the base CPU for that arch. - MArch = A->getValue(Args); + MArch = A->getValue(); } else { // Otherwise, use the Arch from the triple. MArch = Triple.getArchName(); @@ -91,6 +111,8 @@ static const char *getARMTargetCPU(const ArgList &Args, .Cases("armv6z", "armv6zk", "arm1176jzf-s") .Case("armv6t2", "arm1156t2-s") .Cases("armv7", "armv7a", "armv7-a", "cortex-a8") + .Cases("armv7f", "armv7-f", "cortex-a9-mp") + .Cases("armv7s", "armv7-s", "swift") .Cases("armv7r", "armv7-r", "cortex-r4") .Cases("armv7m", "armv7-m", "cortex-m3") .Case("ep9312", "ep9312") @@ -119,10 +141,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) { .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6") .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6") .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2") - .Cases("cortex-a8", "cortex-a9", "v7") + .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7") .Case("cortex-m3", "v7m") .Case("cortex-m4", "v7m") .Case("cortex-m0", "v6m") + .Case("cortex-a9-mp", "v7f") + .Case("swift", "v7s") .Default(""); } @@ -142,7 +166,7 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, // FIXME: Thumb should just be another -target-feaure, not in the triple. StringRef Suffix = getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple)); - bool ThumbDefault = (Suffix == "v7" && getTriple().isOSDarwin()); + bool ThumbDefault = (Suffix.startswith("v7") && getTriple().isOSDarwin()); std::string ArchName = "arm"; // Assembly files should start in ARM mode. @@ -180,7 +204,7 @@ ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType( const ArgList &Args) const { if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) { - StringRef Value = A->getValue(Args); + StringRef Value = A->getValue(); if (Value == "compiler-rt") return ToolChain::RLT_CompilerRT; if (Value == "libgcc") @@ -194,7 +218,7 @@ ToolChain::RuntimeLibType ToolChain::GetRuntimeLibType( ToolChain::CXXStdlibType ToolChain::GetCXXStdlibType(const ArgList &Args) const{ if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { - StringRef Value = A->getValue(Args); + StringRef Value = A->getValue(); if (Value == "libc++") return ToolChain::CST_Libcxx; if (Value == "libstdc++") @@ -273,3 +297,24 @@ void ToolChain::AddCCKextLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { CmdArgs.push_back("-lcc_kext"); } + +bool ToolChain::AddFastMathRuntimeIfAvailable(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Check if -ffast-math or -funsafe-math is enabled. + Arg *A = Args.getLastArg(options::OPT_ffast_math, + options::OPT_fno_fast_math, + options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations); + + if (!A || A->getOption().getID() == options::OPT_fno_fast_math || + A->getOption().getID() == options::OPT_fno_unsafe_math_optimizations) + return false; + + // If crtfastmath.o exists add it to the arguments. + std::string Path = GetFilePath("crtfastmath.o"); + if (Path == "crtfastmath.o") // Not found. + return false; + + CmdArgs.push_back(Args.MakeArgString(Path)); + return true; +} diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 01c66239a121..a2ccb35ed264 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -31,6 +31,8 @@ #include "llvm/Support/Path.h" #include "llvm/Support/system_error.h" +#include "SanitizerArgs.h" + #include <cstdlib> // ::getenv #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX @@ -80,17 +82,11 @@ bool Darwin::HasNativeLLVMSupport() const { /// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { - if (isTargetIPhoneOS()) { + if (isTargetIPhoneOS()) return ObjCRuntime(ObjCRuntime::iOS, TargetVersion); - } else if (TargetSimulatorVersionFromDefines != VersionTuple()) { - return ObjCRuntime(ObjCRuntime::iOS, TargetSimulatorVersionFromDefines); - } else { - if (isNonFragile) { - return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion); - } else { - return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion); - } - } + if (isNonFragile) + return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion); + return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion); } /// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. @@ -111,6 +107,9 @@ static const char *GetArmArchForMArch(StringRef Value) { .Cases("armv7a", "armv7-a", "armv7") .Cases("armv7r", "armv7-r", "armv7") .Cases("armv7m", "armv7-m", "armv7") + .Cases("armv7f", "armv7-f", "armv7f") + .Cases("armv7k", "armv7-k", "armv7k") + .Cases("armv7s", "armv7-s", "armv7s") .Default(0); } @@ -122,7 +121,10 @@ static const char *GetArmArchForMCpu(StringRef Value) { .Case("xscale", "xscale") .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "arm1176jzf-s", "cortex-m0", "armv6") - .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "armv7") + .Cases("cortex-a8", "cortex-r4", "cortex-m3", "cortex-a9", "cortex-a15", + "armv7") + .Case("cortex-a9-mp", "armv7f") + .Case("swift", "armv7s") .Default(0); } @@ -134,11 +136,11 @@ StringRef Darwin::getDarwinArchName(const ArgList &Args) const { case llvm::Triple::thumb: case llvm::Triple::arm: { if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) - if (const char *Arch = GetArmArchForMArch(A->getValue(Args))) + if (const char *Arch = GetArmArchForMArch(A->getValue())) return Arch; if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) - if (const char *Arch = GetArmArchForMCpu(A->getValue(Args))) + if (const char *Arch = GetArmArchForMCpu(A->getValue())) return Arch; return "arm"; @@ -175,24 +177,11 @@ void Generic_ELF::anchor() {} Tool &Darwin::SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const { Action::ActionClass Key = JA.getKind(); - bool useClang = false; if (getDriver().ShouldUseClangCompiler(C, JA, getTriple())) { - useClang = true; - // Fallback to llvm-gcc for i386 kext compiles, we don't support that ABI. - if (!getDriver().shouldForceClangUse() && - Inputs.size() == 1 && - types::isCXX(Inputs[0]->getType()) && - getTriple().isOSDarwin() && - getTriple().getArch() == llvm::Triple::x86 && - (C.getArgs().getLastArg(options::OPT_fapple_kext) || - C.getArgs().getLastArg(options::OPT_mkernel))) - useClang = false; - } - - // FIXME: This seems like a hacky way to choose clang frontend. - if (useClang) + // FIXME: This seems like a hacky way to choose clang frontend. Key = Action::AnalyzeJobClass; + } bool UseIntegratedAs = C.getArgs().hasFlag(options::OPT_integrated_as, options::OPT_no_integrated_as, @@ -245,30 +234,6 @@ DarwinClang::DarwinClang(const Driver &D, const llvm::Triple& Triple) getProgramPaths().push_back(getDriver().getInstalledDir()); if (getDriver().getInstalledDir() != getDriver().Dir) getProgramPaths().push_back(getDriver().Dir); - - // For fallback, we need to know how to find the GCC cc1 executables, so we - // also add the GCC libexec paths. This is legacy code that can be removed - // once fallback is no longer useful. - AddGCCLibexecPath(DarwinVersion[0]); - AddGCCLibexecPath(DarwinVersion[0] - 2); - AddGCCLibexecPath(DarwinVersion[0] - 1); - AddGCCLibexecPath(DarwinVersion[0] + 1); - AddGCCLibexecPath(DarwinVersion[0] + 2); -} - -void DarwinClang::AddGCCLibexecPath(unsigned darwinVersion) { - std::string ToolChainDir = "i686-apple-darwin"; - ToolChainDir += llvm::utostr(darwinVersion); - ToolChainDir += "/4.2.1"; - - std::string Path = getDriver().Dir; - Path += "/../llvm-gcc-4.2/libexec/gcc/"; - Path += ToolChainDir; - getProgramPaths().push_back(Path); - - Path = "/usr/llvm-gcc-4.2/libexec/gcc/"; - Path += ToolChainDir; - getProgramPaths().push_back(Path); } void DarwinClang::AddLinkARCArgs(const ArgList &Args, @@ -287,9 +252,6 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args, s += "iphonesimulator"; else if (isTargetIPhoneOS()) s += "iphoneos"; - // FIXME: Remove this once we depend fully on -mios-simulator-version-min. - else if (TargetSimulatorVersionFromDefines != VersionTuple()) - s += "iphonesimulator"; else s += "macosx"; s += ".a"; @@ -320,13 +282,15 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, break; default: getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) - << Args.getLastArg(options::OPT_rtlib_EQ)->getValue(Args) << "darwin"; + << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "darwin"; return; } // Darwin doesn't support real static executables, don't link any runtime // libraries with -static. - if (Args.hasArg(options::OPT_static)) + if (Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_fapple_kext) || + Args.hasArg(options::OPT_mkernel)) return; // Reject -static-libgcc for now, we can deal with this when and if someone @@ -351,15 +315,16 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } + SanitizerArgs Sanitize(getDriver(), Args); + // Add ASAN runtime library, if required. Dynamic libraries and bundles // should not be linked with the runtime library. - if (Args.hasFlag(options::OPT_faddress_sanitizer, - options::OPT_fno_address_sanitizer, false)) { + if (Sanitize.needsAsanRt()) { if (Args.hasArg(options::OPT_dynamiclib) || Args.hasArg(options::OPT_bundle)) return; if (isTargetIPhoneOS()) { getDriver().Diag(diag::err_drv_clang_unsupported_per_platform) - << "-faddress-sanitizer"; + << "-fsanitize=address"; } else { AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.asan_osx.a"); @@ -410,67 +375,28 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } -static inline StringRef SimulatorVersionDefineName() { - return "__IPHONE_OS_VERSION_MIN_REQUIRED"; -} - -/// \brief Parse the simulator version define: -/// __IPHONE_OS_VERSION_MIN_REQUIRED=([0-9])([0-9][0-9])([0-9][0-9]) -// and return the grouped values as integers, e.g: -// __IPHONE_OS_VERSION_MIN_REQUIRED=40201 -// will return Major=4, Minor=2, Micro=1. -static bool GetVersionFromSimulatorDefine(StringRef define, - unsigned &Major, unsigned &Minor, - unsigned &Micro) { - assert(define.startswith(SimulatorVersionDefineName())); - StringRef name, version; - llvm::tie(name, version) = define.split('='); - if (version.empty()) - return false; - std::string verstr = version.str(); - char *end; - unsigned num = (unsigned) strtol(verstr.c_str(), &end, 10); - if (*end != '\0') - return false; - Major = num / 10000; - num = num % 10000; - Minor = num / 100; - Micro = num % 100; - return true; -} - void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { const OptTable &Opts = getDriver().getOpts(); + // Support allowing the SDKROOT environment variable used by xcrun and other + // Xcode tools to define the default sysroot, by making it the default for + // isysroot. + if (!Args.hasArg(options::OPT_isysroot)) { + if (char *env = ::getenv("SDKROOT")) { + // We only use this value as the default if it is an absolute path and + // exists. + if (llvm::sys::path::is_absolute(env) && llvm::sys::fs::exists(env)) { + Args.append(Args.MakeSeparateArg( + 0, Opts.getOption(options::OPT_isysroot), env)); + } + } + } + Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ); Arg *iOSSimVersion = Args.getLastArg( options::OPT_mios_simulator_version_min_EQ); - // FIXME: HACK! When compiling for the simulator we don't get a - // '-miphoneos-version-min' to help us know whether there is an ARC runtime - // or not; try to parse a __IPHONE_OS_VERSION_MIN_REQUIRED - // define passed in command-line. - if (!iOSVersion && !iOSSimVersion) { - for (arg_iterator it = Args.filtered_begin(options::OPT_D), - ie = Args.filtered_end(); it != ie; ++it) { - StringRef define = (*it)->getValue(Args); - if (define.startswith(SimulatorVersionDefineName())) { - unsigned Major = 0, Minor = 0, Micro = 0; - if (GetVersionFromSimulatorDefine(define, Major, Minor, Micro) && - Major < 10 && Minor < 100 && Micro < 100) { - TargetSimulatorVersionFromDefines = VersionTuple(Major, Minor, Micro); - } - // When using the define to indicate the simulator, we force - // 10.6 macosx target. - const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); - OSXVersion = Args.MakeJoinedArg(0, O, "10.6"); - Args.append(OSXVersion); - break; - } - } - } - if (OSXVersion && (iOSVersion || iOSSimVersion)) { getDriver().Diag(diag::err_drv_argument_not_allowed_with) << OSXVersion->getAsString(Args) @@ -500,7 +426,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { if (iOSTarget.empty()) { if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef first, second; - StringRef isysroot = A->getValue(Args); + StringRef isysroot = A->getValue(); llvm::tie(first, second) = isysroot.split(StringRef("SDKs/iPhoneOS")); if (second != "") iOSTarget = second.substr(0,3); @@ -510,7 +436,8 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { // If no OSX or iOS target has been specified and we're compiling for armv7, // go ahead as assume we're targeting iOS. if (OSXTarget.empty() && iOSTarget.empty() && - getDarwinArchName(Args) == "armv7") + (getDarwinArchName(Args) == "armv7" || + getDarwinArchName(Args) == "armv7s")) iOSTarget = iOSVersionMin; // Handle conflicting deployment targets @@ -536,21 +463,21 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } if (!OSXTarget.empty()) { - const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); + const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); OSXVersion = Args.MakeJoinedArg(0, O, OSXTarget); Args.append(OSXVersion); } else if (!iOSTarget.empty()) { - const Option *O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); + const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); iOSVersion = Args.MakeJoinedArg(0, O, iOSTarget); Args.append(iOSVersion); } else if (!iOSSimTarget.empty()) { - const Option *O = Opts.getOption( + const Option O = Opts.getOption( options::OPT_mios_simulator_version_min_EQ); iOSSimVersion = Args.MakeJoinedArg(0, O, iOSSimTarget); Args.append(iOSSimVersion); } else { // Otherwise, assume we are targeting OS X. - const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); + const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); OSXVersion = Args.MakeJoinedArg(0, O, MacosxVersionMin); Args.append(OSXVersion); } @@ -568,7 +495,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { bool HadExtra; if (OSXVersion) { assert((!iOSVersion && !iOSSimVersion) && "Unknown target platform!"); - if (!Driver::GetReleaseVersion(OSXVersion->getValue(Args), Major, Minor, + if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor, Micro, HadExtra) || HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) @@ -576,7 +503,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } else { const Arg *Version = iOSVersion ? iOSVersion : iOSSimVersion; assert(Version && "Unknown target platform!"); - if (!Driver::GetReleaseVersion(Version->getValue(Args), Major, Minor, + if (!Driver::GetReleaseVersion(Version->getValue(), Major, Minor, Micro, HadExtra) || HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) @@ -614,7 +541,7 @@ void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, // Check in the sysroot first. bool Exists; if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - llvm::sys::Path P(A->getValue(Args)); + llvm::sys::Path P(A->getValue()); P.appendComponent("usr"); P.appendComponent("lib"); P.appendComponent("libstdc++.dylib"); @@ -655,7 +582,14 @@ void DarwinClang::AddCCKextLibArgs(const ArgList &Args, llvm::sys::Path P(getDriver().ResourceDir); P.appendComponent("lib"); P.appendComponent("darwin"); - P.appendComponent("libclang_rt.cc_kext.a"); + + // Use the newer cc_kext for iOS ARM after 6.0. + if (!isTargetIPhoneOS() || isTargetIOSSimulator() || + !isIPhoneOSVersionLT(6, 0)) { + P.appendComponent("libclang_rt.cc_kext.a"); + } else { + P.appendComponent("libclang_rt.cc_kext_ios5.a"); + } // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build. @@ -683,15 +617,15 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches either the toolchain // triple arch, or the arch being bound. - // - // FIXME: Canonicalize name. - StringRef XarchArch = A->getValue(Args, 0); - if (!(XarchArch == getArchName() || - (BoundArch && XarchArch == BoundArch))) + llvm::Triple::ArchType XarchArch = + tools::darwin::getArchTypeForDarwinArchName(A->getValue(0)); + if (!(XarchArch == getArch() || + (BoundArch && XarchArch == + tools::darwin::getArchTypeForDarwinArchName(BoundArch)))) continue; Arg *OriginalArg = A; - unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(Args, 1)); + unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); unsigned Prev = Index; Arg *XarchArg = Opts.ParseOneArg(Args, Index); @@ -707,7 +641,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) << A->getAsString(Args); continue; - } else if (XarchArg->getOption().isDriverOption()) { + } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) << A->getAsString(Args); continue; @@ -721,12 +655,12 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // Linker input arguments require custom handling. The problem is that we // have already constructed the phase actions, so we can not treat them as // "input arguments". - if (A->getOption().isLinkerInput()) { + if (A->getOption().hasFlag(options::LinkerInput)) { // Convert the argument into individual Zlinker_input_args. for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) { DAL->AddSeparateArg(OriginalArg, Opts.getOption(options::OPT_Zlinker_input), - A->getValue(Args, i)); + A->getValue(i)); } continue; @@ -749,7 +683,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, case options::OPT_dependency_file: DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF), - A->getValue(Args)); + A->getValue()); break; case options::OPT_gfull: @@ -805,8 +739,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, // how the driver driver works. if (BoundArch) { StringRef Name = BoundArch; - const Option *MCpu = Opts.getOption(options::OPT_mcpu_EQ); - const Option *MArch = Opts.getOption(options::OPT_march_EQ); + const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ); + const Option MArch = Opts.getOption(options::OPT_march_EQ); // This code must be kept in sync with LLVM's getArchTypeForDarwinArch, // which defines the list of which architectures we accept. @@ -864,6 +798,12 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, DAL->AddJoinedArg(0, MArch, "armv6k"); else if (Name == "armv7") DAL->AddJoinedArg(0, MArch, "armv7a"); + else if (Name == "armv7f") + DAL->AddJoinedArg(0, MArch, "armv7f"); + else if (Name == "armv7k") + DAL->AddJoinedArg(0, MArch, "armv7k"); + else if (Name == "armv7s") + DAL->AddJoinedArg(0, MArch, "armv7s"); else llvm_unreachable("invalid Darwin arch"); @@ -875,6 +815,25 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, if (BoundArch) AddDeploymentTarget(*DAL); + // For iOS 6, undo the translation to add -static for -mkernel/-fapple-kext. + // FIXME: It would be far better to avoid inserting those -static arguments, + // but we can't check the deployment target in the translation code until + // it is set here. + if (isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) { + for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) { + Arg *A = *it; + ++it; + if (A->getOption().getID() != options::OPT_mkernel && + A->getOption().getID() != options::OPT_fapple_kext) + continue; + assert(it != ie && "unexpected argument translation"); + A = *it; + assert(A->getOption().getID() == options::OPT_static && + "missing expected -static argument"); + it = DAL->getArgs().erase(it); + } + } + // Validate the C++ standard library choice. CXXStdlibType Type = GetCXXStdlibType(*DAL); if (Type == ToolChain::CST_Libcxx) { @@ -882,13 +841,8 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, StringRef where; // Complain about targetting iOS < 5.0 in any way. - if (TargetSimulatorVersionFromDefines != VersionTuple()) { - if (TargetSimulatorVersionFromDefines < VersionTuple(5, 0)) - where = "iOS 5.0"; - } else if (isTargetIPhoneOS()) { - if (isIPhoneOSVersionLT(5, 0)) - where = "iOS 5.0"; - } + if (isTargetIPhoneOS() && isIPhoneOSVersionLT(5, 0)) + where = "iOS 5.0"; if (where != StringRef()) { getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) @@ -900,9 +854,7 @@ DerivedArgList *Darwin::TranslateArgs(const DerivedArgList &Args, } bool Darwin::IsUnwindTablesDefault() const { - // FIXME: Gross; we should probably have some separate target - // definition, possibly even reusing the one in clang. - return getArchName() == "x86_64"; + return getArch() == llvm::Triple::x86_64; } bool Darwin::UseDwarfDebugFlags() const { @@ -917,19 +869,17 @@ bool Darwin::UseSjLjExceptions() const { getTriple().getArch() == llvm::Triple::thumb); } -const char *Darwin::GetDefaultRelocationModel() const { - return "pic"; +bool Darwin::isPICDefault() const { + return true; } -const char *Darwin::GetForcedPicModel() const { - if (getArchName() == "x86_64") - return "pic"; - return 0; +bool Darwin::isPICDefaultForced() const { + return getArch() == llvm::Triple::x86_64; } bool Darwin::SupportsProfiling() const { // Profiling instrumentation is only supported on x86. - return getArchName() == "i386" || getArchName() == "x86_64"; + return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64; } bool Darwin::SupportsObjCGC() const { @@ -937,8 +887,10 @@ bool Darwin::SupportsObjCGC() const { return !isTargetIPhoneOS(); } -bool Darwin::SupportsObjCARC() const { - return isTargetIPhoneOS() || !isMacosxVersionLT(10, 6); +void Darwin::CheckObjCARC() const { + if (isTargetIPhoneOS() || !isMacosxVersionLT(10, 6)) + return; + getDriver().Diag(diag::err_arc_unsupported_on_toolchain); } std::string @@ -1013,7 +965,7 @@ bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const { static StringRef getGCCToolchainDir(const ArgList &Args) { const Arg *A = Args.getLastArg(options::OPT_gcc_toolchain); if (A) - return A->getValue(Args); + return A->getValue(); return GCC_INSTALL_PREFIX; } @@ -1072,7 +1024,8 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( if (!llvm::sys::fs::exists(LibDir)) continue; for (unsigned k = 0, ke = CandidateTripleAliases.size(); k < ke; ++k) - ScanLibDirForGCCTriple(TargetArch, LibDir, CandidateTripleAliases[k]); + ScanLibDirForGCCTriple(TargetArch, Args, LibDir, + CandidateTripleAliases[k]); } for (unsigned j = 0, je = CandidateMultiarchLibDirs.size(); j < je; ++j) { const std::string LibDir @@ -1081,7 +1034,7 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( continue; for (unsigned k = 0, ke = CandidateMultiarchTripleAliases.size(); k < ke; ++k) - ScanLibDirForGCCTriple(TargetArch, LibDir, + ScanLibDirForGCCTriple(TargetArch, Args, LibDir, CandidateMultiarchTripleAliases[k], /*NeedsMultiarchSuffix=*/true); } @@ -1136,7 +1089,10 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( static const char *const MIPSLibDirs[] = { "/lib" }; static const char *const MIPSTriples[] = { "mips-linux-gnu" }; static const char *const MIPSELLibDirs[] = { "/lib" }; - static const char *const MIPSELTriples[] = { "mipsel-linux-gnu" }; + static const char *const MIPSELTriples[] = { + "mipsel-linux-gnu", + "mipsel-linux-android" + }; static const char *const MIPS64LibDirs[] = { "/lib64", "/lib" }; static const char *const MIPS64Triples[] = { "mips64-linux-gnu" }; @@ -1264,8 +1220,32 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector( MultiarchTripleAliases.push_back(MultiarchTriple.str()); } +// FIXME: There is the same routine in the Tools.cpp. +static bool hasMipsN32ABIArg(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mabi_EQ); + return A && (A->getValue() == StringRef("n32")); +} + +static StringRef getTargetMultiarchSuffix(llvm::Triple::ArchType TargetArch, + const ArgList &Args) { + if (TargetArch == llvm::Triple::x86_64 || + TargetArch == llvm::Triple::ppc64) + return "/64"; + + if (TargetArch == llvm::Triple::mips64 || + TargetArch == llvm::Triple::mips64el) { + if (hasMipsN32ABIArg(Args)) + return "/n32"; + else + return "/64"; + } + + return "/32"; +} + void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( - llvm::Triple::ArchType TargetArch, const std::string &LibDir, + llvm::Triple::ArchType TargetArch, const ArgList &Args, + const std::string &LibDir, StringRef CandidateTriple, bool NeedsMultiarchSuffix) { // There are various different suffixes involving the triple we // check for. We also record what is necessary to walk from each back @@ -1274,6 +1254,10 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( "/gcc/" + CandidateTriple.str(), "/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), + // The Freescale PPC SDK has the gcc libraries in + // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. + "/" + CandidateTriple.str(), + // Ubuntu has a strange mis-matched pair of triples that this happens to // match. // FIXME: It may be worthwhile to generalize this and look for a second @@ -1283,6 +1267,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( const std::string InstallSuffixes[] = { "/../../..", "/../../../..", + "/../..", "/../../../.." }; // Only look at the final, weird Ubuntu suffix for i386-linux-gnu. @@ -1307,11 +1292,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( // *if* there is a subdirectory of the right name with crtbegin.o in it, // we use that. If not, and if not a multiarch triple, we look for // crtbegin.o without the subdirectory. - StringRef MultiarchSuffix - = (TargetArch == llvm::Triple::x86_64 || - TargetArch == llvm::Triple::ppc64 || - TargetArch == llvm::Triple::mips64 || - TargetArch == llvm::Triple::mips64el) ? "/64" : "/32"; + StringRef MultiarchSuffix = getTargetMultiarchSuffix(TargetArch, Args); if (llvm::sys::fs::exists(LI->path() + MultiarchSuffix + "/crtbegin.o")) { GCCMultiarchSuffix = MultiarchSuffix.str(); } else { @@ -1392,18 +1373,17 @@ Tool &Generic_GCC::SelectTool(const Compilation &C, } bool Generic_GCC::IsUnwindTablesDefault() const { - // FIXME: Gross; we should probably have some separate target - // definition, possibly even reusing the one in clang. - return getArchName() == "x86_64"; + return getArch() == llvm::Triple::x86_64; } -const char *Generic_GCC::GetDefaultRelocationModel() const { - return "static"; +bool Generic_GCC::isPICDefault() const { + return false; } -const char *Generic_GCC::GetForcedPicModel() const { - return 0; +bool Generic_GCC::isPICDefaultForced() const { + return false; } + /// Hexagon Toolchain Hexagon_TC::Hexagon_TC(const Driver &D, const llvm::Triple& Triple) @@ -1457,21 +1437,14 @@ Tool &Hexagon_TC::SelectTool(const Compilation &C, return *T; } -bool Hexagon_TC::IsUnwindTablesDefault() const { - // FIXME: Gross; we should probably have some separate target - // definition, possibly even reusing the one in clang. - return getArchName() == "x86_64"; +bool Hexagon_TC::isPICDefault() const { + return false; } -const char *Hexagon_TC::GetDefaultRelocationModel() const { - return "static"; +bool Hexagon_TC::isPICDefaultForced() const { + return false; } -const char *Hexagon_TC::GetForcedPicModel() const { - return 0; -} // End Hexagon - - /// TCEToolChain - A tool chain using the llvm bitcode tools to perform /// all subcommands. See http://tce.cs.tut.fi for our peculiar target. /// Currently does not support anything else but compilation. @@ -1495,16 +1468,12 @@ bool TCEToolChain::IsMathErrnoDefault() const { return true; } -bool TCEToolChain::IsUnwindTablesDefault() const { +bool TCEToolChain::isPICDefault() const { return false; } -const char *TCEToolChain::GetDefaultRelocationModel() const { - return "static"; -} - -const char *TCEToolChain::GetForcedPicModel() const { - return 0; +bool TCEToolChain::isPICDefaultForced() const { + return false; } Tool &TCEToolChain::SelectTool(const Compilation &C, @@ -1613,19 +1582,43 @@ void Bitrig::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, DriverArgs.hasArg(options::OPT_nostdincxx)) return; - std::string Triple = getTriple().str(); - if (Triple.substr(0, 5) == "amd64") - Triple.replace(0, 5, "x86_64"); - - addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/4.6.2"); - addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/4.6.2/backward"); - addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/4.6.2/" + Triple); + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/"); + break; + case ToolChain::CST_Libstdcxx: + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/stdc++"); + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/stdc++/backward"); + StringRef Triple = getTriple().str(); + if (Triple.startswith("amd64")) + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/stdc++/x86_64" + + Triple.substr(5)); + else + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/include/c++/stdc++/" + + Triple); + break; + } } void Bitrig::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - CmdArgs.push_back("-lstdc++"); + switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lcxxrt"); + // Include supc++ to provide Unwind until provided by libcxx. + CmdArgs.push_back("-lgcc"); + break; + case ToolChain::CST_Libstdcxx: + CmdArgs.push_back("-lstdc++"); + break; + } } /// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. @@ -2020,6 +2013,46 @@ static void addPathIfExists(Twine Path, ToolChain::path_list &Paths) { if (llvm::sys::fs::exists(Path)) Paths.push_back(Path.str()); } +static bool isMipsArch(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mips || + Arch == llvm::Triple::mipsel || + Arch == llvm::Triple::mips64 || + Arch == llvm::Triple::mips64el; +} + +static bool isMipsR2Arch(llvm::Triple::ArchType Arch, + const ArgList &Args) { + if (Arch != llvm::Triple::mips && + Arch != llvm::Triple::mipsel) + return false; + + Arg *A = Args.getLastArg(options::OPT_march_EQ, + options::OPT_mcpu_EQ, + options::OPT_mips_CPUs_Group); + + if (!A) + return false; + + if (A->getOption().matches(options::OPT_mips_CPUs_Group)) + return A->getOption().matches(options::OPT_mips32r2); + + return A->getValue() == StringRef("mips32r2"); +} + +static StringRef getMultilibDir(const llvm::Triple &Triple, + const ArgList &Args) { + if (!isMipsArch(Triple.getArch())) + return Triple.isArch32Bit() ? "lib32" : "lib64"; + + // lib32 directory has a special meaning on MIPS targets. + // It contains N32 ABI binaries. Use this folder if produce + // code for N32 ABI only. + if (hasMipsN32ABIArg(Args)) + return "lib32"; + + return Triple.isArch32Bit() ? "lib" : "lib64"; +} + Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { llvm::Triple::ArchType Arch = Triple.getArch(); @@ -2043,19 +2076,14 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) ExtraOpts.push_back("-X"); - const bool IsMips = Arch == llvm::Triple::mips || - Arch == llvm::Triple::mipsel || - Arch == llvm::Triple::mips64 || - Arch == llvm::Triple::mips64el; - - const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::ANDROIDEABI; + const bool IsAndroid = Triple.getEnvironment() == llvm::Triple::Android; // Do not use 'gnu' hash style for Mips targets because .gnu.hash // and the MIPS ABI require .dynsym to be sorted in different ways. // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS // ABI requires a mapping between the GOT and the symbol table. // Android loader does not support .gnu.hash. - if (!IsMips && !IsAndroid) { + if (!isMipsArch(Arch) && !IsAndroid) { if (IsRedhat(Distro) || IsOpenSuse(Distro) || (IsUbuntu(Distro) && Distro >= UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); @@ -2084,16 +2112,23 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // to the link paths. path_list &Paths = getFilePaths(); - const std::string Multilib = Triple.isArch32Bit() ? "lib32" : "lib64"; + const std::string Multilib = getMultilibDir(Triple, Args); const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot); // Add the multilib suffixed paths where they are available. if (GCCInstallation.isValid()) { const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); const std::string &LibPath = GCCInstallation.getParentLibPath(); - addPathIfExists((GCCInstallation.getInstallPath() + - GCCInstallation.getMultiarchSuffix()), - Paths); + + if (IsAndroid && isMipsR2Arch(Triple.getArch(), Args)) + addPathIfExists(GCCInstallation.getInstallPath() + + GCCInstallation.getMultiarchSuffix() + + "/mips-r2", + Paths); + else + addPathIfExists((GCCInstallation.getInstallPath() + + GCCInstallation.getMultiarchSuffix()), + Paths); // If the GCC installation we found is inside of the sysroot, we want to // prefer libraries installed in the parent prefix of the GCC installation. @@ -2108,6 +2143,11 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) addPathIfExists(LibPath + "/" + MultiarchTriple, Paths); addPathIfExists(LibPath + "/../" + Multilib, Paths); } + // On Android, libraries in the parent prefix of the GCC installation are + // preferred to the ones under sysroot. + if (IsAndroid) { + addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths); + } } addPathIfExists(SysRoot + "/lib/" + MultiarchTriple, Paths); addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths); @@ -2326,16 +2366,25 @@ void Linux::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, StringRef LibDir = GCCInstallation.getParentLibPath(); StringRef InstallDir = GCCInstallation.getInstallPath(); StringRef Version = GCCInstallation.getVersion().Text; - if (!addLibStdCXXIncludePaths(LibDir + "/../include/c++/" + Version, - (GCCInstallation.getTriple().str() + - GCCInstallation.getMultiarchSuffix()), - DriverArgs, CC1Args)) { + StringRef TripleStr = GCCInstallation.getTriple().str(); + + const std::string IncludePathCandidates[] = { + LibDir.str() + "/../include/c++/" + Version.str(), // Gentoo is weird and places its headers inside the GCC install, so if the // first attempt to find the headers fails, try this pattern. - addLibStdCXXIncludePaths(InstallDir + "/include/g++-v4", - (GCCInstallation.getTriple().str() + - GCCInstallation.getMultiarchSuffix()), - DriverArgs, CC1Args); + InstallDir.str() + "/include/g++-v4", + // Android standalone toolchain has C++ headers in yet another place. + LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.str(), + // Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++, + // without a subdirectory corresponding to the gcc version. + LibDir.str() + "/../include/c++", + }; + + for (unsigned i = 0; i < llvm::array_lengthof(IncludePathCandidates); ++i) { + if (addLibStdCXXIncludePaths(IncludePathCandidates[i], (TripleStr + + GCCInstallation.getMultiarchSuffix()), + DriverArgs, CC1Args)) + break; } } diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 95a11beea158..4c267e8a8bfc 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -111,6 +111,7 @@ protected: SmallVectorImpl<StringRef> &MultiarchTripleAliases); void ScanLibDirForGCCTriple(llvm::Triple::ArchType TargetArch, + const ArgList &Args, const std::string &LibDir, StringRef CandidateTriple, bool NeedsMultiarchSuffix = false); @@ -128,8 +129,8 @@ public: const ActionList &Inputs) const; virtual bool IsUnwindTablesDefault() const; - virtual const char *GetDefaultRelocationModel() const; - virtual const char *GetForcedPicModel() const; + virtual bool isPICDefault() const; + virtual bool isPICDefaultForced() const; protected: /// \name ToolChain Implementation Helper Functions @@ -155,9 +156,8 @@ public: virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; - virtual bool IsUnwindTablesDefault() const; - virtual const char *GetDefaultRelocationModel() const; - virtual const char *GetForcedPicModel() const; + virtual bool isPICDefault() const; + virtual bool isPICDefaultForced() const; }; /// Darwin - The base Darwin tool chain. @@ -185,11 +185,6 @@ private: /// The OS version we are targeting. mutable VersionTuple TargetVersion; -protected: - // FIXME: Remove this once there is a proper way to detect an ARC runtime - // for the simulator. - mutable VersionTuple TargetSimulatorVersionFromDefines; - private: /// The default macosx-version-min of this tool chain; empty until /// initialized. @@ -243,9 +238,7 @@ public: } bool isTargetMacOS() const { - return !isTargetIOSSimulator() && - !isTargetIPhoneOS() && - TargetSimulatorVersionFromDefines == VersionTuple(); + return !isTargetIOSSimulator() && !isTargetIPhoneOS(); } bool isTargetInitialized() const { return TargetInitialized; } @@ -325,6 +318,10 @@ public: return true; } + virtual bool IsEncodeExtendedBlockSignatureDefault() const { + return true; + } + virtual bool IsObjCNonFragileABIDefault() const { // Non-fragile ABI is default for everything but i386. return getTriple().getArch() != llvm::Triple::x86; @@ -347,14 +344,14 @@ public: virtual RuntimeLibType GetDefaultRuntimeLibType() const { return ToolChain::RLT_CompilerRT; } - virtual const char *GetDefaultRelocationModel() const; - virtual const char *GetForcedPicModel() const; + virtual bool isPICDefault() const; + virtual bool isPICDefaultForced() const; virtual bool SupportsProfiling() const; virtual bool SupportsObjCGC() const; - virtual bool SupportsObjCARC() const; + virtual void CheckObjCARC() const; virtual bool UseDwarfDebugFlags() const; @@ -365,9 +362,6 @@ public: /// DarwinClang - The Darwin toolchain used by Clang. class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { -private: - void AddGCCLibexecPath(unsigned darwinVersion); - public: DarwinClang(const Driver &D, const llvm::Triple& Triple); @@ -399,7 +393,7 @@ public: std::string ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const; - virtual const char *GetDefaultRelocationModel() const { return "pic"; } + virtual bool isPICDefault() const { return false; }; }; class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC { @@ -540,9 +534,8 @@ public: virtual Tool &SelectTool(const Compilation &C, const JobAction &JA, const ActionList &Inputs) const; bool IsMathErrnoDefault() const; - bool IsUnwindTablesDefault() const; - const char* GetDefaultRelocationModel() const; - const char* GetForcedPicModel() const; + bool isPICDefault() const; + bool isPICDefaultForced() const; private: mutable llvm::DenseMap<unsigned, Tool*> Tools; @@ -564,8 +557,8 @@ public: virtual bool IsIntegratedAssemblerDefault() const; virtual bool IsUnwindTablesDefault() const; - virtual const char *GetDefaultRelocationModel() const; - virtual const char *GetForcedPicModel() const; + virtual bool isPICDefault() const; + virtual bool isPICDefaultForced() const; virtual void AddClangSystemIncludeArgs(const ArgList &DriverArgs, ArgStringList &CC1Args) const; diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp index ed67f7b9a1e4..e37959be4efa 100644 --- a/lib/Driver/Tools.cpp +++ b/lib/Driver/Tools.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/ErrorHandling.h" #include "InputInfo.h" +#include "SanitizerArgs.h" #include "ToolChains.h" using namespace clang::driver; @@ -93,9 +94,15 @@ static void addDirectoryList(const ArgList &Args, const char *ArgName, const char *EnvVar) { const char *DirList = ::getenv(EnvVar); + bool CombinedArg = false; + if (!DirList) return; // Nothing to do. + StringRef Name(ArgName); + if (Name.equals("-I") || Name.equals("-L")) + CombinedArg = true; + StringRef Dirs(DirList); if (Dirs.empty()) // Empty string should not add '.'. return; @@ -103,21 +110,37 @@ static void addDirectoryList(const ArgList &Args, StringRef::size_type Delim; while ((Delim = Dirs.find(llvm::sys::PathSeparator)) != StringRef::npos) { if (Delim == 0) { // Leading colon. - CmdArgs.push_back(ArgName); - CmdArgs.push_back("."); + if (CombinedArg) { + CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); + } else { + CmdArgs.push_back(ArgName); + CmdArgs.push_back("."); + } } else { - CmdArgs.push_back(ArgName); - CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim))); + if (CombinedArg) { + CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs.substr(0, Delim))); + } else { + CmdArgs.push_back(ArgName); + CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim))); + } } Dirs = Dirs.substr(Delim + 1); } if (Dirs.empty()) { // Trailing colon. - CmdArgs.push_back(ArgName); - CmdArgs.push_back("."); + if (CombinedArg) { + CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); + } else { + CmdArgs.push_back(ArgName); + CmdArgs.push_back("."); + } } else { // Add the last path. - CmdArgs.push_back(ArgName); - CmdArgs.push_back(Args.MakeArgString(Dirs)); + if (CombinedArg) { + CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs)); + } else { + CmdArgs.push_back(ArgName); + CmdArgs.push_back(Args.MakeArgString(Dirs)); + } } } @@ -200,6 +223,12 @@ static void addProfileRT(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(ProfileRT)); } +static bool forwardToGCC(const Option &O) { + return !O.hasFlag(options::NoForward) && + !O.hasFlag(options::DriverOption) && + !O.hasFlag(options::LinkerInput); +} + void Clang::AddPreprocessingOptions(Compilation &C, const Driver &D, const ArgList &Args, @@ -219,11 +248,11 @@ void Clang::AddPreprocessingOptions(Compilation &C, (A = Args.getLastArg(options::OPT_MMD))) { // Determine the output location. const char *DepFile; - if (Output.getType() == types::TY_Dependencies) { - DepFile = Output.getFilename(); - } else if (Arg *MF = Args.getLastArg(options::OPT_MF)) { - DepFile = MF->getValue(Args); + if (Arg *MF = Args.getLastArg(options::OPT_MF)) { + DepFile = MF->getValue(); C.addFailureResultFile(DepFile); + } else if (Output.getType() == types::TY_Dependencies) { + DepFile = Output.getFilename(); } else if (A->getOption().matches(options::OPT_M) || A->getOption().matches(options::OPT_MM)) { DepFile = "-"; @@ -242,7 +271,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, // when we are only generating a dependency file. Arg *OutputOpt = Args.getLastArg(options::OPT_o); if (OutputOpt && Output.getType() != types::TY_Dependencies) { - DepTarget = OutputOpt->getValue(Args); + DepTarget = OutputOpt->getValue(); } else { // Otherwise derive from the base input. // @@ -282,7 +311,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, if (A->getOption().matches(options::OPT_MQ)) { CmdArgs.push_back("-MT"); SmallString<128> Quoted; - QuoteTarget(A->getValue(Args), Quoted); + QuoteTarget(A->getValue(), Quoted); CmdArgs.push_back(Args.MakeArgString(Quoted)); // -MT flag - no change @@ -310,7 +339,7 @@ void Clang::AddPreprocessingOptions(Compilation &C, bool FoundPTH = false; bool FoundPCH = false; - llvm::sys::Path P(A->getValue(Args)); + llvm::sys::Path P(A->getValue()); bool Exists; if (UsePCH) { P.appendSuffix("pch"); @@ -442,10 +471,12 @@ static const char *getLLVMArchSuffixForARM(StringRef CPU) { .Cases("arm1136j-s", "arm1136jf-s", "arm1176jz-s", "v6") .Cases("arm1176jzf-s", "mpcorenovfp", "mpcore", "v6") .Cases("arm1156t2-s", "arm1156t2f-s", "v6t2") - .Cases("cortex-a8", "cortex-a9", "v7") + .Cases("cortex-a8", "cortex-a9", "cortex-a15", "v7") .Case("cortex-m3", "v7m") .Case("cortex-m4", "v7m") .Case("cortex-m0", "v6m") + .Case("cortex-a9-mp", "v7f") + .Case("swift", "v7s") .Default(""); } @@ -458,7 +489,7 @@ static std::string getARMTargetCPU(const ArgList &Args, // If we have -mcpu=, use that. if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - StringRef MCPU = A->getValue(Args); + StringRef MCPU = A->getValue(); // Handle -mcpu=native. if (MCPU == "native") return llvm::sys::getHostCPUName(); @@ -469,7 +500,7 @@ static std::string getARMTargetCPU(const ArgList &Args, StringRef MArch; if (Arg *A = Args.getLastArg(options::OPT_march_EQ)) { // Otherwise, if we have -march= choose the base CPU for that arch. - MArch = A->getValue(Args); + MArch = A->getValue(); } else { // Otherwise, use the Arch from the triple. MArch = Triple.getArchName(); @@ -500,6 +531,8 @@ static std::string getARMTargetCPU(const ArgList &Args, .Cases("armv6z", "armv6zk", "arm1176jzf-s") .Case("armv6t2", "arm1156t2-s") .Cases("armv7", "armv7a", "armv7-a", "cortex-a8") + .Cases("armv7f", "armv7-f", "cortex-a9-mp") + .Cases("armv7s", "armv7-s", "swift") .Cases("armv7r", "armv7-r", "cortex-r4") .Cases("armv7m", "armv7-m", "cortex-m3") .Case("ep9312", "ep9312") @@ -531,7 +564,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { // frontend target. static void addFPUArgs(const Driver &D, const Arg *A, const ArgList &Args, ArgStringList &CmdArgs) { - StringRef FPU = A->getValue(Args); + StringRef FPU = A->getValue(); // Set the target features based on the FPU. if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") { @@ -569,14 +602,15 @@ static void addFPUArgs(const Driver &D, const Arg *A, const ArgList &Args, // Handle -mfpmath=. static void addFPMathArgs(const Driver &D, const Arg *A, const ArgList &Args, ArgStringList &CmdArgs, StringRef CPU) { - StringRef FPMath = A->getValue(Args); + StringRef FPMath = A->getValue(); // Set the target features based on the FPMath. if (FPMath == "neon") { CmdArgs.push_back("-target-feature"); CmdArgs.push_back("+neonfp"); - if (CPU != "cortex-a8" && CPU != "cortex-a9" && CPU != "cortex-a9-mp") + if (CPU != "cortex-a8" && CPU != "cortex-a9" && CPU != "cortex-a9-mp" && + CPU != "cortex-a15") D.Diag(diag::err_drv_invalid_feature) << "-mfpmath=neon" << CPU; } else if (FPMath == "vfp" || FPMath == "vfp2" || FPMath == "vfp3" || @@ -603,7 +637,7 @@ static StringRef getARMFloatABI(const Driver &D, else if (A->getOption().matches(options::OPT_mhard_float)) FloatABI = "hard"; else { - FloatABI = A->getValue(Args); + FloatABI = A->getValue(); if (FloatABI != "soft" && FloatABI != "softfp" && FloatABI != "hard") { D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); @@ -643,7 +677,7 @@ static StringRef getARMFloatABI(const Driver &D, // EABI is always AAPCS, and if it was not marked 'hard', it's softfp FloatABI = "softfp"; break; - case llvm::Triple::ANDROIDEABI: { + case llvm::Triple::Android: { std::string ArchName = getLLVMArchSuffixForARM(getARMTargetCPU(Args, Triple)); if (StringRef(ArchName).startswith("v7")) @@ -669,18 +703,29 @@ void Clang::AddARMTargetArgs(const ArgList &Args, ArgStringList &CmdArgs, bool KernelOrKext) const { const Driver &D = getToolChain().getDriver(); - llvm::Triple Triple = getToolChain().getTriple(); + // Get the effective triple, which takes into account the deployment target. + std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args); + llvm::Triple Triple(TripleStr); + std::string CPUName = getARMTargetCPU(Args, Triple); // Select the ABI to use. // // FIXME: Support -meabi. const char *ABIName = 0; if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { - ABIName = A->getValue(Args); + ABIName = A->getValue(); + } else if (Triple.isOSDarwin()) { + // The backend is hardwired to assume AAPCS for M-class processors, ensure + // the frontend matches that. + if (StringRef(CPUName).startswith("cortex-m")) { + ABIName = "aapcs"; + } else { + ABIName = "apcs-gnu"; + } } else { // Select the default based on the platform. switch(Triple.getEnvironment()) { - case llvm::Triple::ANDROIDEABI: + case llvm::Triple::Android: case llvm::Triple::GNUEABI: case llvm::Triple::GNUEABIHF: ABIName = "aapcs-linux"; @@ -697,7 +742,7 @@ void Clang::AddARMTargetArgs(const ArgList &Args, // Set the CPU based on -march= and -mcpu=. CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(Args.MakeArgString(getARMTargetCPU(Args, Triple))); + CmdArgs.push_back(Args.MakeArgString(CPUName)); // Determine floating point ABI from the options & target defaults. StringRef FloatABI = getARMFloatABI(D, Args, Triple); @@ -754,8 +799,10 @@ void Clang::AddARMTargetArgs(const ArgList &Args, // Kernel code has more strict alignment requirements. if (KernelOrKext) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-long-calls"); + if (Triple.getOS() != llvm::Triple::IOS || Triple.isOSVersionLT(6)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-long-calls"); + } CmdArgs.push_back("-backend-option"); CmdArgs.push_back("-arm-strict-align"); @@ -777,44 +824,18 @@ void Clang::AddARMTargetArgs(const ArgList &Args, CmdArgs.push_back("-no-implicit-float"); } -// Get default architecture. -static const char* getMipsArchFromCPU(StringRef CPUName) { - if (CPUName == "mips32" || CPUName == "mips32r2") - return "mips"; - - assert((CPUName == "mips64" || CPUName == "mips64r2") && - "Unexpected cpu name."); - - return "mips64"; -} - -// Check that ArchName is a known Mips architecture name. -static bool checkMipsArchName(StringRef ArchName) { - return ArchName == "mips" || - ArchName == "mipsel" || - ArchName == "mips64" || - ArchName == "mips64el"; -} - -// Get default target cpu. -static const char* getMipsCPUFromArch(StringRef ArchName) { - if (ArchName == "mips" || ArchName == "mipsel") +// Translate MIPS CPU name alias option to CPU name. +static StringRef getMipsCPUFromAlias(const Arg &A) { + if (A.getOption().matches(options::OPT_mips32)) return "mips32"; - - assert((ArchName == "mips64" || ArchName == "mips64el") && - "Unexpected arch name."); - - return "mips64"; -} - -// Get default ABI. -static const char* getMipsABIFromArch(StringRef ArchName) { - if (ArchName == "mips" || ArchName == "mipsel") - return "o32"; - - assert((ArchName == "mips64" || ArchName == "mips64el") && - "Unexpected arch name."); - return "n64"; + if (A.getOption().matches(options::OPT_mips32r2)) + return "mips32r2"; + if (A.getOption().matches(options::OPT_mips64)) + return "mips64"; + if (A.getOption().matches(options::OPT_mips64r2)) + return "mips64r2"; + llvm_unreachable("Unexpected option"); + return ""; } // Get CPU and ABI names. They are not independent @@ -823,26 +844,53 @@ static void getMipsCPUAndABI(const ArgList &Args, const ToolChain &TC, StringRef &CPUName, StringRef &ABIName) { - StringRef ArchName; - - // Select target cpu and architecture. - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - CPUName = A->getValue(Args); - ArchName = getMipsArchFromCPU(CPUName); - } - else { - ArchName = Args.MakeArgString(TC.getArchName()); - if (!checkMipsArchName(ArchName)) - TC.getDriver().Diag(diag::err_drv_invalid_arch_name) << ArchName; + const char *DefMips32CPU = "mips32"; + const char *DefMips64CPU = "mips64"; + + if (Arg *A = Args.getLastArg(options::OPT_march_EQ, + options::OPT_mcpu_EQ, + options::OPT_mips_CPUs_Group)) { + if (A->getOption().matches(options::OPT_mips_CPUs_Group)) + CPUName = getMipsCPUFromAlias(*A); else - CPUName = getMipsCPUFromArch(ArchName); + CPUName = A->getValue(); } - - // Select the ABI to use. + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) - ABIName = A->getValue(Args); - else - ABIName = getMipsABIFromArch(ArchName); + ABIName = A->getValue(); + + // Setup default CPU and ABI names. + if (CPUName.empty() && ABIName.empty()) { + switch (TC.getTriple().getArch()) { + default: + llvm_unreachable("Unexpected triple arch name"); + case llvm::Triple::mips: + case llvm::Triple::mipsel: + CPUName = DefMips32CPU; + break; + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + CPUName = DefMips64CPU; + break; + } + } + + if (!ABIName.empty()) { + // Deduce CPU name from ABI name. + CPUName = llvm::StringSwitch<const char *>(ABIName) + .Cases("o32", "eabi", DefMips32CPU) + .Cases("n32", "n64", DefMips64CPU) + .Default(""); + } + else if (!CPUName.empty()) { + // Deduce ABI name from CPU name. + ABIName = llvm::StringSwitch<const char *>(CPUName) + .Cases("mips32", "mips32r2", "o32") + .Cases("mips64", "mips64r2", "n64") + .Default(""); + } + + // FIXME: Warn on inconsistent cpu and abi usage. } // Select the MIPS float ABI as determined by -msoft-float, -mhard-float, @@ -859,7 +907,7 @@ static StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) { else if (A->getOption().matches(options::OPT_mhard_float)) FloatABI = "hard"; else { - FloatABI = A->getValue(Args); + FloatABI = A->getValue(); if (FloatABI != "soft" && FloatABI != "single" && FloatABI != "hard") { D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args); FloatABI = "hard"; @@ -941,12 +989,19 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, AddTargetFeature(Args, CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2, "dspr2"); + + if (Arg *A = Args.getLastArg(options::OPT_G)) { + StringRef v = A->getValue(); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-mips-ssection-threshold=" + v)); + A->claim(); + } } /// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting. static std::string getPPCTargetCPU(const ArgList &Args) { if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - StringRef CPUName = A->getValue(Args); + StringRef CPUName = A->getValue(); if (CPUName == "native") { std::string CPU = llvm::sys::getHostCPUName(); @@ -978,6 +1033,8 @@ static std::string getPPCTargetCPU(const ArgList &Args) { .Case("970", "970") .Case("G5", "g5") .Case("a2", "a2") + .Case("e500mc", "e500mc") + .Case("e5500", "e5500") .Case("power6", "pwr6") .Case("power7", "pwr7") .Case("powerpc", "ppc") @@ -1015,7 +1072,7 @@ void Clang::AddSparcTargetArgs(const ArgList &Args, if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } // Select the float ABI as determined by -msoft-float, -mhard-float, and @@ -1054,6 +1111,8 @@ void Clang::AddSparcTargetArgs(const ArgList &Args, void Clang::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + const bool isAndroid = + getToolChain().getTriple().getEnvironment() == llvm::Triple::Android; if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || @@ -1068,7 +1127,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, const char *CPUName = 0; if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - if (StringRef(A->getValue(Args)) == "native") { + if (StringRef(A->getValue()) == "native") { // FIXME: Reject attempts to use -march=native unless the target matches // the host. // @@ -1078,7 +1137,7 @@ void Clang::AddX86TargetArgs(const ArgList &Args, if (!CPU.empty() && CPU != "generic") CPUName = Args.MakeArgString(CPU); } else - CPUName = A->getValue(Args); + CPUName = A->getValue(); } // Select the default CPU if none was given (or detection failed). @@ -1118,7 +1177,9 @@ void Clang::AddX86TargetArgs(const ArgList &Args, if (getToolChain().getArch() == llvm::Triple::x86_64) CPUName = "x86-64"; else if (getToolChain().getArch() == llvm::Triple::x86) - CPUName = "pentium4"; + // All x86 devices running Android have core2 as their common + // denominator. This makes a better choice than pentium4. + CPUName = isAndroid ? "core2" : "pentium4"; } } @@ -1141,8 +1202,8 @@ void Clang::AddX86TargetArgs(const ArgList &Args, (*it)->claim(); // Skip over "-m". - assert(Name.startswith("-m") && "Invalid feature name."); - Name = Name.substr(2); + assert(Name.startswith("m") && "Invalid feature name."); + Name = Name.substr(1); bool IsNegative = Name.startswith("no-"); if (IsNegative) @@ -1174,7 +1235,7 @@ static Arg* getLastHexagonArchArg (const ArgList &Args) A->claim(); } else if ((*it)->getOption().matches(options::OPT_m_Joined)){ - StringRef Value = (*it)->getValue(Args,0); + StringRef Value = (*it)->getValue(0); if (Value.startswith("v")) { A = *it; A->claim(); @@ -1191,7 +1252,7 @@ static StringRef getHexagonTargetCPU(const ArgList &Args) // Select the default CPU (v4) if none was given or detection failed. if ((A = getLastHexagonArchArg (Args))) { - WhichHexagon = A->getValue(Args); + WhichHexagon = A->getValue(); if (WhichHexagon == "") return "v4"; else @@ -1216,7 +1277,7 @@ void Clang::AddHexagonTargetArgs(const ArgList &Args, if (Arg *A = Args.getLastArg(options::OPT_G, options::OPT_msmall_data_threshold_EQ)) { std::string SmallDataThreshold="-small-data-threshold="; - SmallDataThreshold += A->getValue(Args); + SmallDataThreshold += A->getValue(); CmdArgs.push_back ("-mllvm"); CmdArgs.push_back(Args.MakeArgString(SmallDataThreshold)); A->claim(); @@ -1392,25 +1453,80 @@ static bool UseRelaxAll(Compilation &C, const ArgList &Args) { RelaxDefault); } +SanitizerArgs::SanitizerArgs(const Driver &D, const ArgList &Args) { + Kind = 0; + + const Arg *AsanArg, *TsanArg, *UbsanArg; + for (ArgList::const_iterator I = Args.begin(), E = Args.end(); I != E; ++I) { + unsigned Add = 0, Remove = 0; + const char *DeprecatedReplacement = 0; + if ((*I)->getOption().matches(options::OPT_faddress_sanitizer)) { + Add = Address; + DeprecatedReplacement = "-fsanitize=address"; + } else if ((*I)->getOption().matches(options::OPT_fno_address_sanitizer)) { + Remove = Address; + DeprecatedReplacement = "-fno-sanitize=address"; + } else if ((*I)->getOption().matches(options::OPT_fthread_sanitizer)) { + Add = Thread; + DeprecatedReplacement = "-fsanitize=thread"; + } else if ((*I)->getOption().matches(options::OPT_fno_thread_sanitizer)) { + Remove = Thread; + DeprecatedReplacement = "-fno-sanitize=thread"; + } else if ((*I)->getOption().matches(options::OPT_fcatch_undefined_behavior)) { + Add = Undefined; + DeprecatedReplacement = "-fsanitize=undefined"; + } else if ((*I)->getOption().matches(options::OPT_fsanitize_EQ)) { + Add = parse(D, *I); + } else if ((*I)->getOption().matches(options::OPT_fno_sanitize_EQ)) { + Remove = parse(D, *I); + } else { + continue; + } + + (*I)->claim(); + + Kind |= Add; + Kind &= ~Remove; + + if (Add & NeedsAsanRt) AsanArg = *I; + if (Add & NeedsTsanRt) TsanArg = *I; + if (Add & NeedsUbsanRt) UbsanArg = *I; + + // If this is a deprecated synonym, produce a warning directing users + // towards the new spelling. + if (DeprecatedReplacement) + D.Diag(diag::warn_drv_deprecated_arg) + << (*I)->getAsString(Args) << DeprecatedReplacement; + } + + // Only one runtime library can be used at once. + // FIXME: Allow Ubsan to be combined with the other two. + bool NeedsAsan = needsAsanRt(); + bool NeedsTsan = needsTsanRt(); + bool NeedsUbsan = needsUbsanRt(); + if (NeedsAsan + NeedsTsan + NeedsUbsan > 1) + D.Diag(diag::err_drv_argument_not_allowed_with) + << describeSanitizeArg(Args, NeedsAsan ? AsanArg : TsanArg, + NeedsAsan ? NeedsAsanRt : NeedsTsanRt) + << describeSanitizeArg(Args, NeedsUbsan ? UbsanArg : TsanArg, + NeedsUbsan ? NeedsUbsanRt : NeedsTsanRt); +} + /// If AddressSanitizer is enabled, add appropriate linker flags (Linux). /// This needs to be called before we add the C run-time (malloc, etc). static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { - if (!Args.hasFlag(options::OPT_faddress_sanitizer, - options::OPT_fno_address_sanitizer, false)) - return; - if(TC.getTriple().getEnvironment() == llvm::Triple::ANDROIDEABI) { + if(TC.getTriple().getEnvironment() == llvm::Triple::Android) { if (!Args.hasArg(options::OPT_shared)) { if (!Args.hasArg(options::OPT_pie)) TC.getDriver().Diag(diag::err_drv_asan_android_requires_pie); - // For an executable, we add a .preinit_array stub. - CmdArgs.push_back("-u"); - CmdArgs.push_back("__asan_preinit"); - CmdArgs.push_back("-lasan"); } - CmdArgs.push_back("-lasan_preload"); - CmdArgs.push_back("-ldl"); + SmallString<128> LibAsan(TC.getDriver().ResourceDir); + llvm::sys::path::append(LibAsan, "lib", "linux", + (Twine("libclang_rt.asan-") + + TC.getArchName() + "-android.so")); + CmdArgs.push_back(Args.MakeArgString(LibAsan)); } else { if (!Args.hasArg(options::OPT_shared)) { // LibAsan is "libclang_rt.asan-<ArchName>.a" in the Linux library @@ -1431,9 +1547,6 @@ static void addAsanRTLinux(const ToolChain &TC, const ArgList &Args, /// This needs to be called before we add the C run-time (malloc, etc). static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) { - if (!Args.hasFlag(options::OPT_fthread_sanitizer, - options::OPT_fno_thread_sanitizer, false)) - return; if (!Args.hasArg(options::OPT_shared)) { // LibTsan is "libclang_rt.tsan-<ArchName>.a" in the Linux library // resource directory. @@ -1448,6 +1561,22 @@ static void addTsanRTLinux(const ToolChain &TC, const ArgList &Args, } } +/// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags +/// (Linux). +static void addUbsanRTLinux(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (!Args.hasArg(options::OPT_shared)) { + // LibUbsan is "libclang_rt.ubsan-<ArchName>.a" in the Linux library + // resource directory. + SmallString<128> LibUbsan(TC.getDriver().ResourceDir); + llvm::sys::path::append(LibUbsan, "lib", "linux", + (Twine("libclang_rt.ubsan-") + + TC.getArchName() + ".a")); + CmdArgs.push_back(Args.MakeArgString(LibUbsan)); + CmdArgs.push_back("-lpthread"); + } +} + static bool shouldUseFramePointer(const ArgList &Args, const llvm::Triple &Triple) { if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer, @@ -1516,7 +1645,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) { - StringRef Value = A->getValue(Args, i); + StringRef Value = A->getValue(i); if (Value == "-force_cpusubtype_ALL") { // Do nothing, this is the default and we don't support anything else. @@ -1600,8 +1729,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-analyzer-eagerly-assume"); - CmdArgs.push_back("-analyzer-ipa=inlining"); - // Add default argument set. if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { CmdArgs.push_back("-analyzer-checker=core"); @@ -1627,7 +1754,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // reasons. CmdArgs.push_back("-analyzer-output"); if (Arg *A = Args.getLastArg(options::OPT__analyzer_output)) - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); else CmdArgs.push_back("plist"); @@ -1642,67 +1769,90 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CheckCodeGenerationOptions(D, Args); - // Perform argument translation for LLVM backend. This - // takes some care in reconciling with llvm-gcc. The - // issue is that llvm-gcc translates these options based on - // the values in cc1, whereas we are processing based on - // the driver arguments. - - // This comes from the default translation the driver + cc1 - // would do to enable flag_pic. - - Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, - options::OPT_fpic, options::OPT_fno_pic, - options::OPT_fPIE, options::OPT_fno_PIE, - options::OPT_fpie, options::OPT_fno_pie); - bool PICDisabled = false; - bool PICEnabled = false; - bool PICForPIE = false; - if (LastPICArg) { - PICForPIE = (LastPICArg->getOption().matches(options::OPT_fPIE) || - LastPICArg->getOption().matches(options::OPT_fpie)); - PICEnabled = (PICForPIE || - LastPICArg->getOption().matches(options::OPT_fPIC) || - LastPICArg->getOption().matches(options::OPT_fpic)); - PICDisabled = !PICEnabled; + // For the PIC and PIE flag options, this logic is different from the legacy + // logic in very old versions of GCC, as that logic was just a bug no one had + // ever fixed. This logic is both more rational and consistent with GCC's new + // logic now that the bugs are fixed. The last argument relating to either + // PIC or PIE wins, and no other argument is used. If the last argument is + // any flavor of the '-fno-...' arguments, both PIC and PIE are disabled. Any + // PIE option implicitly enables PIC at the same level. + bool PIE = false; + bool PIC = getToolChain().isPICDefault(); + bool IsPICLevelTwo = PIC; + if (Arg *A = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, + options::OPT_fpie, options::OPT_fno_pie)) { + Option O = A->getOption(); + if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || + O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { + PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); + PIC = PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic); + IsPICLevelTwo = O.matches(options::OPT_fPIE) || + O.matches(options::OPT_fPIC); + } else { + PIE = PIC = false; + } } + // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness + // is forced, then neither PIC nor PIE flags will have no effect. + if (getToolChain().isPICDefaultForced()) { + PIE = false; + PIC = getToolChain().isPICDefault(); + IsPICLevelTwo = PIC; + } + + // Inroduce a Darwin-specific hack. If the default is PIC but the flags + // specified while enabling PIC enabled level 1 PIC, just force it back to + // level 2 PIC instead. This matches the behavior of Darwin GCC (based on my + // informal testing). + if (PIC && getToolChain().getTriple().isOSDarwin()) + IsPICLevelTwo |= getToolChain().isPICDefault(); + // Note that these flags are trump-cards. Regardless of the order w.r.t. the // PIC or PIE options above, if these show up, PIC is disabled. - if (Args.hasArg(options::OPT_mkernel)) - PICDisabled = true; + llvm::Triple Triple(TripleStr); + if ((Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_fapple_kext)) && + (Triple.getOS() != llvm::Triple::IOS || + Triple.isOSVersionLT(6))) + PIC = PIE = false; if (Args.hasArg(options::OPT_static)) - PICDisabled = true; - bool DynamicNoPIC = Args.hasArg(options::OPT_mdynamic_no_pic); - - // Select the relocation model. - const char *Model = getToolChain().GetForcedPicModel(); - if (!Model) { - if (DynamicNoPIC) - Model = "dynamic-no-pic"; - else if (PICDisabled) - Model = "static"; - else if (PICEnabled) - Model = "pic"; - else - Model = getToolChain().GetDefaultRelocationModel(); - } - StringRef ModelStr = Model ? Model : ""; - if (Model && ModelStr != "pic") { - CmdArgs.push_back("-mrelocation-model"); - CmdArgs.push_back(Model); - } + PIC = PIE = false; - // Infer the __PIC__ and __PIE__ values. - if (ModelStr == "pic" && PICForPIE) { - CmdArgs.push_back("-pie-level"); - CmdArgs.push_back((LastPICArg && - LastPICArg->getOption().matches(options::OPT_fPIE)) ? - "2" : "1"); - } else if (ModelStr == "pic" || ModelStr == "dynamic-no-pic") { - CmdArgs.push_back("-pic-level"); - CmdArgs.push_back(((ModelStr != "dynamic-no-pic" && LastPICArg && - LastPICArg->getOption().matches(options::OPT_fPIC)) || - getToolChain().getTriple().isOSDarwin()) ? "2" : "1"); + if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { + // This is a very special mode. It trumps the other modes, almost no one + // uses it, and it isn't even valid on any OS but Darwin. + if (!getToolChain().getTriple().isOSDarwin()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << getToolChain().getTriple().str(); + + // FIXME: Warn when this flag trumps some other PIC or PIE flag. + + CmdArgs.push_back("-mrelocation-model"); + CmdArgs.push_back("dynamic-no-pic"); + + // Only a forced PIC mode can cause the actual compile to have PIC defines + // etc., no flags are sufficient. This behavior was selected to closely + // match that of llvm-gcc and Apple GCC before that. + if (getToolChain().isPICDefault() && getToolChain().isPICDefaultForced()) { + CmdArgs.push_back("-pic-level"); + CmdArgs.push_back("2"); + } + } else { + // Currently, LLVM only knows about PIC vs. static; the PIE differences are + // handled in Clang's IRGen by the -pie-level flag. + CmdArgs.push_back("-mrelocation-model"); + CmdArgs.push_back(PIC ? "pic" : "static"); + + if (PIC) { + CmdArgs.push_back("-pic-level"); + CmdArgs.push_back(IsPICLevelTwo ? "2" : "1"); + if (PIE) { + CmdArgs.push_back("-pie-level"); + CmdArgs.push_back(IsPICLevelTwo ? "2" : "1"); + } + } } if (!Args.hasFlag(options::OPT_fmerge_all_constants, @@ -1713,7 +1863,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { CmdArgs.push_back("-mregparm"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) @@ -1741,25 +1891,30 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // flag disables them after the flag enabling them, enable the codegen // optimization. This is complicated by several "umbrella" flags. if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + options::OPT_fno_fast_math, options::OPT_ffinite_math_only, options::OPT_fno_finite_math_only, options::OPT_fhonor_infinities, options::OPT_fno_honor_infinities)) - if (A->getOption().getID() != options::OPT_fno_finite_math_only && + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_finite_math_only && A->getOption().getID() != options::OPT_fhonor_infinities) CmdArgs.push_back("-menable-no-infs"); if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + options::OPT_fno_fast_math, options::OPT_ffinite_math_only, options::OPT_fno_finite_math_only, options::OPT_fhonor_nans, options::OPT_fno_honor_nans)) - if (A->getOption().getID() != options::OPT_fno_finite_math_only && + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_finite_math_only && A->getOption().getID() != options::OPT_fhonor_nans) CmdArgs.push_back("-menable-no-nans"); // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. bool MathErrno = getToolChain().IsMathErrnoDefault(); if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + options::OPT_fno_fast_math, options::OPT_fmath_errno, options::OPT_fno_math_errno)) MathErrno = A->getOption().getID() == options::OPT_fmath_errno; @@ -1772,38 +1927,46 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // madness. bool AssociativeMath = false; if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, options::OPT_fassociative_math, options::OPT_fno_associative_math)) - if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && A->getOption().getID() != options::OPT_fno_associative_math) AssociativeMath = true; bool ReciprocalMath = false; if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, options::OPT_freciprocal_math, options::OPT_fno_reciprocal_math)) - if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && A->getOption().getID() != options::OPT_fno_reciprocal_math) ReciprocalMath = true; bool SignedZeros = true; if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, options::OPT_fsigned_zeros, options::OPT_fno_signed_zeros)) - if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && A->getOption().getID() != options::OPT_fsigned_zeros) SignedZeros = false; bool TrappingMath = true; if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, options::OPT_fno_unsafe_math_optimizations, options::OPT_ftrapping_math, options::OPT_fno_trapping_math)) - if (A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && A->getOption().getID() != options::OPT_ftrapping_math) TrappingMath = false; if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros && @@ -1813,16 +1976,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Validate and pass through -fp-contract option. if (Arg *A = Args.getLastArg(options::OPT_ffast_math, + options::OPT_fno_fast_math, options::OPT_ffp_contract)) { if (A->getOption().getID() == options::OPT_ffp_contract) { - StringRef Val = A->getValue(Args); + StringRef Val = A->getValue(); if (Val == "fast" || Val == "on" || Val == "off") { CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + Val)); } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; } - } else { // A is OPT_ffast_math + } else if (A->getOption().getID() == options::OPT_ffast_math) { // If fast-math is set then set the fp-contract mode to fast. CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); } @@ -1833,10 +1997,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // preprocessor macros. This is distinct from enabling any optimizations as // these options induce language changes which must survive serialization // and deserialization, etc. - if (Args.hasArg(options::OPT_ffast_math)) - CmdArgs.push_back("-ffast-math"); - if (Args.hasArg(options::OPT_ffinite_math_only)) - CmdArgs.push_back("-ffinite-math-only"); + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, options::OPT_fno_fast_math)) + if (A->getOption().matches(options::OPT_ffast_math)) + CmdArgs.push_back("-ffast-math"); + if (Arg *A = Args.getLastArg(options::OPT_ffinite_math_only, options::OPT_fno_fast_math)) + if (A->getOption().matches(options::OPT_ffinite_math_only)) + CmdArgs.push_back("-ffinite-math-only"); // Decide whether to use verbose asm. Verbose assembly is the default on // toolchains which have the integrated assembler on by default. @@ -1885,7 +2051,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } // FIXME: Handle -mtune=. @@ -1893,7 +2059,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { CmdArgs.push_back("-mcode-model"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } // Add target specific cpu and features flags. @@ -1937,7 +2103,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Pass the linker version in use. if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { CmdArgs.push_back("-target-linker-version"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } // -mno-omit-leaf-frame-pointer is the default on Darwin. @@ -1991,6 +2157,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // We ignore flags -gstrict-dwarf and -grecord-gcc-switches for now. Args.ClaimAllArgs(options::OPT_g_flags_Group); + if (Args.hasArg(options::OPT_gcolumn_info)) + CmdArgs.push_back("-dwarf-column-info"); Args.AddAllArgs(CmdArgs, options::OPT_ffunction_sections); Args.AddAllArgs(CmdArgs, options::OPT_fdata_sections); @@ -2008,7 +2176,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, C.getArgs().hasArg(options::OPT_S)) { if (Output.isFilename()) { CmdArgs.push_back("-coverage-file"); - CmdArgs.push_back(Args.MakeArgString(Output.getFilename())); + SmallString<128> absFilename(Output.getFilename()); + llvm::sys::fs::make_absolute(absFilename); + CmdArgs.push_back(Args.MakeArgString(absFilename)); } } @@ -2047,7 +2217,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, case options::OPT_ccc_arcmt_migrate: CmdArgs.push_back("-arcmt-migrate"); CmdArgs.push_back("-mt-migrate-directory"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output); Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors); @@ -2062,7 +2232,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, << A->getAsString(Args) << "-ccc-arcmt-migrate"; } CmdArgs.push_back("-mt-migrate-directory"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); if (!Args.hasArg(options::OPT_objcmt_migrate_literals, options::OPT_objcmt_migrate_subscripting)) { @@ -2094,7 +2264,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (A->getOption().matches(options::OPT_O4)) CmdArgs.push_back("-O3"); else if (A->getOption().matches(options::OPT_O) && - A->getValue(Args)[0] == '\0') + A->getValue()[0] == '\0') CmdArgs.push_back("-O2"); else A->render(Args, CmdArgs); @@ -2132,8 +2302,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // eventually we want to do all the standard defaulting here instead of // splitting it between the driver and clang -cc1. if (!types::isCXX(InputType)) - Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, - "-std=", /*Joined=*/true); + Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, + "-std=", /*Joined=*/true); + else if (getToolChain().getTriple().getOS() == llvm::Triple::Win32) + CmdArgs.push_back("-std=c++11"); + Args.AddLastArg(CmdArgs, options::OPT_trigraphs); } @@ -2182,18 +2355,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, options::OPT_ftemplate_depth_EQ)) { CmdArgs.push_back("-ftemplate-depth"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) { CmdArgs.push_back("-fconstexpr-depth"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ, options::OPT_Wlarge_by_value_copy_def)) { if (A->getNumValues()) { - StringRef bytes = A->getValue(Args); + StringRef bytes = A->getValue(); CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes)); } else CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value @@ -2202,50 +2375,50 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_fbounds_checking, options::OPT_fbounds_checking_EQ)) { if (A->getNumValues()) { - StringRef val = A->getValue(Args); + StringRef val = A->getValue(); CmdArgs.push_back(Args.MakeArgString("-fbounds-checking=" + val)); } else CmdArgs.push_back("-fbounds-checking=1"); } - if (Args.hasArg(options::OPT__relocatable_pch)) + if (Args.hasArg(options::OPT_relocatable_pch)) CmdArgs.push_back("-relocatable-pch"); if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { CmdArgs.push_back("-fconstant-string-class"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) { CmdArgs.push_back("-ftabstop"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } CmdArgs.push_back("-ferror-limit"); if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ)) - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); else CmdArgs.push_back("19"); if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) { CmdArgs.push_back("-fmacro-backtrace-limit"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) { CmdArgs.push_back("-ftemplate-backtrace-limit"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) { CmdArgs.push_back("-fconstexpr-backtrace-limit"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } // Pass -fmessage-length=. CmdArgs.push_back("-fmessage-length"); if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } else { // If -fmessage-length=N was not specified, determine whether this is a // terminal and, if so, implicitly define -fmessage-length appropriately. @@ -2255,7 +2428,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ)) { CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden); @@ -2268,7 +2441,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-ffreestanding"); // Forward -f (flag) options which we can pass directly. - Args.AddLastArg(CmdArgs, options::OPT_fcatch_undefined_behavior); Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); Args.AddLastArg(CmdArgs, options::OPT_flimit_debug_info); @@ -2278,6 +2450,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree); Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type); + SanitizerArgs Sanitize(D, Args); + Sanitize.addArgs(Args, CmdArgs); + // Report and error for -faltivec on anything other then PowerPC. if (const Arg *A = Args.getLastArg(options::OPT_faltivec)) if (!(getToolChain().getTriple().getArch() == llvm::Triple::ppc || @@ -2288,14 +2463,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (getToolChain().SupportsProfiling()) Args.AddLastArg(CmdArgs, options::OPT_pg); - if (Args.hasFlag(options::OPT_faddress_sanitizer, - options::OPT_fno_address_sanitizer, false)) - CmdArgs.push_back("-faddress-sanitizer"); - - if (Args.hasFlag(options::OPT_fthread_sanitizer, - options::OPT_fno_thread_sanitizer, false)) - CmdArgs.push_back("-fthread-sanitizer"); - // -flax-vector-conversions is default. if (!Args.hasFlag(options::OPT_flax_vector_conversions, options::OPT_fno_lax_vector_conversions)) @@ -2316,7 +2483,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { CmdArgs.push_back("-ftrapv-handler"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ); @@ -2337,6 +2504,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_pthread); + // -stack-protector=0 is default. unsigned StackProtectorLevel = 0; if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, @@ -2355,6 +2523,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel))); } + // --param ssp-buffer-size= + for (arg_iterator it = Args.filtered_begin(options::OPT__param), + ie = Args.filtered_end(); it != ie; ++it) { + StringRef Str((*it)->getValue()); + if (Str.startswith("ssp-buffer-size=")) { + if (StackProtectorLevel) { + CmdArgs.push_back("-stack-protector-buffer-size"); + // FIXME: Verify the argument is a valid integer. + CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16))); + } + (*it)->claim(); + } + } + // Translate -mstackrealign if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, false)) { @@ -2370,6 +2552,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment); CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment)); } + if (Args.hasArg(options::OPT_mstrict_align)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-strict-align"); + } // Forward -f options with positive and negative forms; we translate // these by hand. @@ -2427,9 +2613,20 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -frtti is default. if (!Args.hasFlag(options::OPT_frtti, options::OPT_fno_rtti) || - KernelOrKext) + KernelOrKext) { CmdArgs.push_back("-fno-rtti"); + // -fno-rtti cannot usefully be combined with -fsanitize=vptr. + if (Sanitize.sanitizesVptr()) { + std::string NoRttiArg = + Args.getLastArg(options::OPT_mkernel, + options::OPT_fapple_kext, + options::OPT_fno_rtti)->getAsString(Args); + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fsanitize=vptr" << NoRttiArg; + } + } + // -fshort-enums=0 is default for all architectures except Hexagon. if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums, @@ -2537,12 +2734,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fobjc-default-synthesize-properties"); } + // -fencode-extended-block-signature=1 is default. + if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) { + CmdArgs.push_back("-fencode-extended-block-signature"); + } + // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc. // NOTE: This logic is duplicated in ToolChains.cpp. bool ARC = isObjCAutoRefCount(Args); if (ARC) { - if (!getToolChain().SupportsObjCARC()) - D.Diag(diag::err_arc_unsupported); + getToolChain().CheckObjCARC(); CmdArgs.push_back("-fobjc-arc"); @@ -2629,7 +2830,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fno-pack-struct doesn't apply to -fpack-struct=. if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) { std::string PackStructStr = "-fpack-struct="; - PackStructStr += A->getValue(Args); + PackStructStr += A->getValue(); CmdArgs.push_back(Args.MakeArgString(PackStructStr)); } else if (Args.hasFlag(options::OPT_fpack_struct, options::OPT_fno_pack_struct, false)) { @@ -2678,13 +2879,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { CmdArgs.push_back("-fdiagnostics-show-category"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { CmdArgs.push_back("-fdiagnostics-format"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } if (Arg *A = Args.getLastArg( @@ -2776,9 +2977,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Handle serialized diagnostics. if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) { CmdArgs.push_back("-serialize-diagnostic-file"); - CmdArgs.push_back(Args.MakeArgString(A->getValue(Args))); + CmdArgs.push_back(Args.MakeArgString(A->getValue())); } + if (Args.hasArg(options::OPT_fretain_comments_from_system_headers)) + CmdArgs.push_back("-fretain-comments-from-system-headers"); + // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option // parser. Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); @@ -2788,7 +2992,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // We translate this by hand to the -cc1 argument, since nightly test uses // it and developers have been trained to spell it with -mllvm. - if (StringRef((*it)->getValue(Args, 0)) == "-disable-llvm-optzns") + if (StringRef((*it)->getValue(0)) == "-disable-llvm-optzns") CmdArgs.push_back("-disable-llvm-optzns"); else (*it)->render(Args, CmdArgs); @@ -2807,7 +3011,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) { const InputInfo &II = *it; CmdArgs.push_back("-x"); - CmdArgs.push_back(types::getTypeName(II.getType())); + if (Args.hasArg(options::OPT_rewrite_objc)) + CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX)); + else + CmdArgs.push_back(types::getTypeName(II.getType())); if (II.isFilename()) CmdArgs.push_back(II.getFilename()); else @@ -2894,7 +3101,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, if (runtimeArg && runtimeArg->getOption().matches(options::OPT_fobjc_runtime_EQ)) { ObjCRuntime runtime; - StringRef value = runtimeArg->getValue(args); + StringRef value = runtimeArg->getValue(); if (runtime.tryParse(value)) { getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime) << value; @@ -2912,7 +3119,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, unsigned objcABIVersion = 1; // If -fobjc-abi-version= is present, use that to set the version. if (Arg *abiArg = args.getLastArg(options::OPT_fobjc_abi_version_EQ)) { - StringRef value = abiArg->getValue(args); + StringRef value = abiArg->getValue(); if (value == "1") objcABIVersion = 1; else if (value == "2") @@ -2940,7 +3147,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, if (Arg *abiArg = args.getLastArg( options::OPT_fobjc_nonfragile_abi_version_EQ)) { - StringRef value = abiArg->getValue(args); + StringRef value = abiArg->getValue(); if (value == "1") nonFragileABIVersion = 1; else if (value == "2") @@ -2993,7 +3200,7 @@ ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, // Legacy behaviour is to target the gnustep runtime if we are i // non-fragile mode or the GCC runtime in fragile mode. if (isNonFragile) - runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple()); + runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1,6)); else runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple()); } @@ -3116,7 +3323,7 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; - if (A->getOption().hasForwardToGCC()) { + if (forwardToGCC(A->getOption())) { // Don't forward any -g arguments to assembly steps. if (isa<AssembleJobAction>(JA) && A->getOption().matches(options::OPT_g_Group)) @@ -3134,17 +3341,17 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, RenderExtraToolArgs(JA, CmdArgs); // If using a driver driver, force the arch. - const std::string &Arch = getToolChain().getArchName(); + llvm::Triple::ArchType Arch = getToolChain().getArch(); if (getToolChain().getTriple().isOSDarwin()) { CmdArgs.push_back("-arch"); // FIXME: Remove these special cases. - if (Arch == "powerpc") + if (Arch == llvm::Triple::ppc) CmdArgs.push_back("ppc"); - else if (Arch == "powerpc64") + else if (Arch == llvm::Triple::ppc64) CmdArgs.push_back("ppc64"); else - CmdArgs.push_back(Args.MakeArgString(Arch)); + CmdArgs.push_back(Args.MakeArgString(getToolChain().getArchName())); } // Try to force gcc to match the tool chain we want, if we recognize @@ -3152,9 +3359,9 @@ void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, // // FIXME: The triple class should directly provide the information we want // here. - if (Arch == "i386" || Arch == "powerpc") + if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::ppc) CmdArgs.push_back("-m32"); - else if (Arch == "x86_64" || Arch == "powerpc64") + else if (Arch == llvm::Triple::x86_64 || Arch == llvm::Triple::x86_64) CmdArgs.push_back("-m64"); if (Output.isFilename()) { @@ -3341,7 +3548,7 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA, for (ArgList::const_iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { Arg *A = *it; - if (A->getOption().hasForwardToGCC()) { + if (forwardToGCC(A->getOption())) { // Don't forward any -g arguments to assembly steps. if (isa<AssembleJobAction>(JA) && A->getOption().matches(options::OPT_g_Group)) @@ -3409,6 +3616,37 @@ void hexagon::Link::ConstructJob(Compilation &C, const JobAction &JA, } // Hexagon tools end. +llvm::Triple::ArchType darwin::getArchTypeForDarwinArchName(StringRef Str) { + // See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for + // archs which Darwin doesn't use. + + // The matching this routine does is fairly pointless, since it is neither the + // complete architecture list, nor a reasonable subset. The problem is that + // historically the driver driver accepts this and also ties its -march= + // handling to the architecture name, so we need to be careful before removing + // support for it. + + // This code must be kept in sync with Clang's Darwin specific argument + // translation. + + return llvm::StringSwitch<llvm::Triple::ArchType>(Str) + .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc) + .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc) + .Case("ppc64", llvm::Triple::ppc64) + .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86) + .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4", + llvm::Triple::x86) + .Case("x86_64", llvm::Triple::x86_64) + // This is derived from the driver driver. + .Cases("arm", "armv4t", "armv5", "armv6", llvm::Triple::arm) + .Cases("armv7", "armv7f", "armv7k", "armv7s", "xscale", llvm::Triple::arm) + .Case("r600", llvm::Triple::r600) + .Case("nvptx", llvm::Triple::nvptx) + .Case("nvptx64", llvm::Triple::nvptx64) + .Case("amdil", llvm::Triple::amdil) + .Case("spir", llvm::Triple::spir) + .Default(llvm::Triple::UnknownArch); +} const char *darwin::CC1::getCC1Name(types::ID Type) const { switch (Type) { @@ -3457,7 +3695,7 @@ darwin::CC1::getDependencyFileName(const ArgList &Args, std::string Res; if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) { - std::string Str(OutputOpt->getValue(Args)); + std::string Str(OutputOpt->getValue()); Res = Str.substr(0, Str.rfind('.')); } else { Res = darwin::CC1::getBaseInputStem(Args, Inputs); @@ -3546,6 +3784,7 @@ void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const { .Case("duplicate-method-arg", true) .Case("dynamic-class-memaccess", true) .Case("enum-compare", true) + .Case("enum-conversion", true) .Case("exit-time-destructors", true) .Case("gnu", true) .Case("gnu-designator", true) @@ -3555,6 +3794,7 @@ void darwin::CC1::RemoveCC1UnsupportedArgs(ArgStringList &CmdArgs) const { .Case("implicit-atomic-properties", true) .Case("incompatible-pointer-types", true) .Case("incomplete-implementation", true) + .Case("int-conversion", true) .Case("initializer-overrides", true) .Case("invalid-noreturn", true) .Case("invalid-token-paste", true) @@ -3619,7 +3859,10 @@ void darwin::CC1::AddCC1Args(const ArgList &Args, CheckCodeGenerationOptions(D, Args); // Derived from cc1 spec. - if (!Args.hasArg(options::OPT_mkernel) && !Args.hasArg(options::OPT_static) && + if ((!Args.hasArg(options::OPT_mkernel) || + (getDarwinToolChain().isTargetIPhoneOS() && + !getDarwinToolChain().isIPhoneOSVersionLT(6, 0))) && + !Args.hasArg(options::OPT_static) && !Args.hasArg(options::OPT_mdynamic_no_pic)) CmdArgs.push_back("-fPIC"); @@ -3672,7 +3915,7 @@ void darwin::CC1::AddCC1OptionsArgs(const ArgList &Args, ArgStringList &CmdArgs, Args.hasArg(options::OPT_o)) { Arg *OutputOpt = Args.getLastArg(options::OPT_o); CmdArgs.push_back("-auxbase-strip"); - CmdArgs.push_back(OutputOpt->getValue(Args)); + CmdArgs.push_back(OutputOpt->getValue()); } else { CmdArgs.push_back("-auxbase"); CmdArgs.push_back(darwin::CC1::getBaseInputStem(Args, Inputs)); @@ -3811,7 +4054,7 @@ void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args, Args.AddLastArg(CmdArgs, options::OPT_P); // FIXME: Handle %I properly. - if (getToolChain().getArchName() == "x86_64") { + if (getToolChain().getArch() == llvm::Triple::x86_64) { CmdArgs.push_back("-imultilib"); CmdArgs.push_back("x86_64"); } @@ -3837,7 +4080,7 @@ void darwin::CC1::AddCPPUniqueOptionsArgs(const ArgList &Args, (Args.hasArg(options::OPT_MD) || Args.hasArg(options::OPT_MMD))) { if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) { CmdArgs.push_back("-MQ"); - CmdArgs.push_back(OutputOpt->getValue(Args)); + CmdArgs.push_back(OutputOpt->getValue()); } } @@ -4073,9 +4316,11 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-force_cpusubtype_ALL"); if (getToolChain().getTriple().getArch() != llvm::Triple::x86_64 && - (Args.hasArg(options::OPT_mkernel) || - Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_fapple_kext))) + (((Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_fapple_kext)) && + (!getDarwinToolChain().isTargetIPhoneOS() || + getDarwinToolChain().isIPhoneOSVersionLT(6, 0))) || + Args.hasArg(options::OPT_static))) CmdArgs.push_back("-static"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -4110,16 +4355,29 @@ void darwin::DarwinTool::AddDarwinArch(const ArgList &Args, CmdArgs.push_back("-force_cpusubtype_ALL"); } +bool darwin::Link::NeedsTempPath(const InputInfoList &Inputs) const { + // We only need to generate a temp path for LTO if we aren't compiling object + // files. When compiling source files, we run 'dsymutil' after linking. We + // don't run 'dsymutil' when compiling object files. + for (InputInfoList::const_iterator + it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) + if (it->getType() != types::TY_Object) + return true; + + return false; +} + void darwin::Link::AddLinkArgs(Compilation &C, const ArgList &Args, - ArgStringList &CmdArgs) const { + ArgStringList &CmdArgs, + const InputInfoList &Inputs) const { const Driver &D = getToolChain().getDriver(); const toolchains::Darwin &DarwinTC = getDarwinToolChain(); unsigned Version[3] = { 0, 0, 0 }; if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { bool HadExtra; - if (!Driver::GetReleaseVersion(A->getValue(Args), Version[0], + if (!Driver::GetReleaseVersion(A->getValue(), Version[0], Version[1], Version[2], HadExtra) || HadExtra) D.Diag(diag::err_drv_invalid_version_number) @@ -4140,7 +4398,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) - if (StringRef(A->getValue(Args, i)) == "-kext") + if (StringRef(A->getValue(i)) == "-kext") UsesLdClassic = true; } } @@ -4151,7 +4409,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, // If we are using LTO, then automatically create a temporary file path for // the linker to use, so that it's lifetime will extend past a possible // dsymutil step. - if (Version[0] >= 116 && D.IsUsingLTO(Args)) { + if (Version[0] >= 116 && D.IsUsingLTO(Args) && NeedsTempPath(Inputs)) { const char *TmpPath = C.getArgs().MakeArgString( D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object))); C.addTempFile(TmpPath); @@ -4286,7 +4544,7 @@ void darwin::Link::AddLinkArgs(Compilation &C, CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { CmdArgs.push_back("-syslibroot"); - CmdArgs.push_back(A->getValue(Args)); + CmdArgs.push_back(A->getValue()); } Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace); @@ -4338,7 +4596,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, // I'm not sure why this particular decomposition exists in gcc, but // we follow suite for ease of comparison. - AddLinkArgs(C, Args, CmdArgs); + AddLinkArgs(C, Args, CmdArgs, Inputs); Args.AddAllArgs(CmdArgs, options::OPT_d_Flag); Args.AddAllArgs(CmdArgs, options::OPT_s); @@ -4423,7 +4681,7 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, } else if (getDarwinToolChain().isTargetIPhoneOS()) { if (getDarwinToolChain().isIPhoneOSVersionLT(3, 1)) CmdArgs.push_back("-lcrt1.o"); - else + else if (getDarwinToolChain().isIPhoneOSVersionLT(6, 0)) CmdArgs.push_back("-lcrt1.3.1.o"); } else { if (getDarwinToolChain().isMacosxVersionLT(10, 5)) @@ -4451,11 +4709,12 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_L); - // If we're building a dynamic lib with -faddress-sanitizer, unresolved - // symbols may appear. Mark all of them as dynamic_lookup. - // Linking executables is handled in lib/Driver/ToolChains.cpp. - if (Args.hasFlag(options::OPT_faddress_sanitizer, - options::OPT_fno_address_sanitizer, false)) { + SanitizerArgs Sanitize(getToolChain().getDriver(), Args); + // If we're building a dynamic lib with -fsanitize=address, or + // -fsanitize=undefined, unresolved symbols may appear. Mark all + // of them as dynamic_lookup. Linking executables is handled in + // lib/Driver/ToolChains.cpp. + if (Sanitize.needsAsanRt() || Sanitize.needsUbsanRt()) { if (Args.hasArg(options::OPT_dynamiclib) || Args.hasArg(options::OPT_bundle)) { CmdArgs.push_back("-undefined"); @@ -4474,14 +4733,14 @@ void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA, !Args.hasArg(options::OPT_nodefaultlibs)) { // Avoid linking compatibility stubs on i386 mac. if (!getDarwinToolChain().isTargetMacOS() || - getDarwinToolChain().getArchName() != "i386") { + getDarwinToolChain().getArch() != llvm::Triple::x86) { // If we don't have ARC or subscripting runtime support, link in the // runtime stubs. We have to do this *before* adding any of the normal // linker inputs so that its initializer gets run first. ObjCRuntime runtime = getDarwinToolChain().getDefaultObjCRuntime(/*nonfragile*/ true); // We use arclite library for both ARC and subscripting support. - if ((!runtime.hasARC() && isObjCAutoRefCount(Args)) || + if ((!runtime.hasNativeARC() && isObjCAutoRefCount(Args)) || !runtime.hasSubscripting()) getDarwinToolChain().AddLinkARCArgs(Args, CmdArgs); } @@ -4937,14 +5196,21 @@ void openbsd::Link::ConstructJob(Compilation &C, const JobAction &JA, // the default system libraries. Just mimic this for now. CmdArgs.push_back("-lgcc"); - if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-lpthread"); + if (Args.hasArg(options::OPT_pthread)) { + if (!Args.hasArg(options::OPT_shared) && + Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lpthread_p"); + else + CmdArgs.push_back("-lpthread"); + } + if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) + if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lc_p"); else CmdArgs.push_back("-lc"); } + CmdArgs.push_back("-lgcc"); } @@ -5056,8 +5322,14 @@ void bitrig::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lm"); } - if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-lpthread"); + if (Args.hasArg(options::OPT_pthread)) { + if (!Args.hasArg(options::OPT_shared) && + Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lpthread_p"); + else + CmdArgs.push_back("-lpthread"); + } + if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lc_p"); @@ -5108,17 +5380,48 @@ void freebsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. - if (getToolChain().getArchName() == "i386") + if (getToolChain().getArch() == llvm::Triple::x86) CmdArgs.push_back("--32"); - - if (getToolChain().getArchName() == "powerpc") + else if (getToolChain().getArch() == llvm::Triple::ppc) CmdArgs.push_back("-a32"); + else if (getToolChain().getArch() == llvm::Triple::mips || + getToolChain().getArch() == llvm::Triple::mipsel || + getToolChain().getArch() == llvm::Triple::mips64 || + getToolChain().getArch() == llvm::Triple::mips64el) { + StringRef CPUName; + StringRef ABIName; + getMipsCPUAndABI(Args, getToolChain(), CPUName, ABIName); - // Set byte order explicitly - if (getToolChain().getArchName() == "mips") - CmdArgs.push_back("-EB"); - else if (getToolChain().getArchName() == "mipsel") - CmdArgs.push_back("-EL"); + CmdArgs.push_back("-march"); + CmdArgs.push_back(CPUName.data()); + + // Convert ABI name to the GNU tools acceptable variant. + if (ABIName == "o32") + ABIName = "32"; + else if (ABIName == "n64") + ABIName = "64"; + + CmdArgs.push_back("-mabi"); + CmdArgs.push_back(ABIName.data()); + + if (getToolChain().getArch() == llvm::Triple::mips || + getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("-EB"); + else + CmdArgs.push_back("-EL"); + + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, + options::OPT_fpie, options::OPT_fno_pie); + if (LastPICArg && + (LastPICArg->getOption().matches(options::OPT_fPIC) || + LastPICArg->getOption().matches(options::OPT_fpic) || + LastPICArg->getOption().matches(options::OPT_fPIE) || + LastPICArg->getOption().matches(options::OPT_fpie))) { + CmdArgs.push_back("-KPIC"); + } + } Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -5142,7 +5445,9 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { - const Driver &D = getToolChain().getDriver(); + const toolchains::FreeBSD& ToolChain = + static_cast<const toolchains::FreeBSD&>(getToolChain()); + const Driver &D = ToolChain.getDriver(); ArgStringList CmdArgs; // Silence warning for "clang -g foo.o -o foo" @@ -5156,6 +5461,9 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + if (Args.hasArg(options::OPT_pie)) + CmdArgs.push_back("-pie"); + if (Args.hasArg(options::OPT_static)) { CmdArgs.push_back("-Bstatic"); } else { @@ -5168,8 +5476,8 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld-elf.so.1"); } - if (getToolChain().getTriple().getOSMajorVersion() >= 9) { - llvm::Triple::ArchType Arch = getToolChain().getArch(); + if (ToolChain.getTriple().getOSMajorVersion() >= 9) { + llvm::Triple::ArchType Arch = ToolChain.getArch(); if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { CmdArgs.push_back("--hash-style=both"); @@ -5180,12 +5488,12 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct ld in the base system to link 32-bit code. - if (getToolChain().getArchName() == "i386") { + if (ToolChain.getArch() == llvm::Triple::x86) { CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386_fbsd"); } - if (getToolChain().getArchName() == "powerpc") { + if (ToolChain.getArch() == llvm::Triple::ppc) { CmdArgs.push_back("-m"); CmdArgs.push_back("elf32ppc_fbsd"); } @@ -5199,29 +5507,33 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { + const char *crt1 = NULL; if (!Args.hasArg(options::OPT_shared)) { if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("gcrt1.o"))); - else { - const char *crt = Args.hasArg(options::OPT_pie) ? "Scrt1.o" : "crt1.o"; - CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath(crt))); - } - CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("crti.o"))); - CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("crtbegin.o"))); - } else { - CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("crti.o"))); - CmdArgs.push_back(Args.MakeArgString( - getToolChain().GetFilePath("crtbeginS.o"))); + crt1 = "gcrt1.o"; + else if (Args.hasArg(options::OPT_pie)) + crt1 = "Scrt1.o"; + else + crt1 = "crt1.o"; } + if (crt1) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + + const char *crtbegin = NULL; + if (Args.hasArg(options::OPT_static)) + crtbegin = "crtbeginT.o"; + else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + crtbegin = "crtbeginS.o"; + else + crtbegin = "crtbegin.o"; + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } Args.AddAllArgs(CmdArgs, options::OPT_L); - const ToolChain::path_list Paths = getToolChain().getFilePaths(); + const ToolChain::path_list Paths = ToolChain.getFilePaths(); for (ToolChain::path_list::const_iterator i = Paths.begin(), e = Paths.end(); i != e; ++i) CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + *i)); @@ -5232,12 +5544,12 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { if (D.CCCIsCXX) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else @@ -5290,20 +5602,17 @@ void freebsd::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( - "crtend.o"))); + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); else - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( - "crtendS.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath( - "crtn.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); } - addProfileRT(getToolChain(), Args, CmdArgs, getToolChain().getTriple()); + addProfileRT(ToolChain, Args, CmdArgs, ToolChain.getTriple()); const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("ld")); + Args.MakeArgString(ToolChain.GetProgramPath("ld")); C.addCommand(new Command(JA, *this, Exec, CmdArgs)); } @@ -5320,9 +5629,9 @@ void netbsd::Assemble::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("--32"); // Set byte order explicitly - if (getToolChain().getArchName() == "mips") + if (getToolChain().getArch() == llvm::Triple::mips) CmdArgs.push_back("-EB"); - else if (getToolChain().getArchName() == "mipsel") + else if (getToolChain().getArch() == llvm::Triple::mipsel) CmdArgs.push_back("-EL"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -5547,7 +5856,7 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA, static void AddLibgcc(llvm::Triple Triple, const Driver &D, ArgStringList &CmdArgs, const ArgList &Args) { - bool isAndroid = Triple.getEnvironment() == llvm::Triple::ANDROIDEABI; + bool isAndroid = Triple.getEnvironment() == llvm::Triple::Android; bool StaticLibgcc = isAndroid || Args.hasArg(options::OPT_static) || Args.hasArg(options::OPT_static_libgcc); if (!D.CCCIsCXX) @@ -5570,6 +5879,11 @@ static void AddLibgcc(llvm::Triple Triple, const Driver &D, CmdArgs.push_back("-lgcc"); } +static bool hasMipsN32ABIArg(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mabi_EQ); + return A && (A->getValue() == StringRef("n32")); +} + void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -5578,8 +5892,8 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, const toolchains::Linux& ToolChain = static_cast<const toolchains::Linux&>(getToolChain()); const Driver &D = ToolChain.getDriver(); - const bool isAndroid = ToolChain.getTriple().getEnvironment() == - llvm::Triple::ANDROIDEABI; + const bool isAndroid = + ToolChain.getTriple().getEnvironment() == llvm::Triple::Android; ArgStringList CmdArgs; @@ -5626,10 +5940,18 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("elf32btsmip"); else if (ToolChain.getArch() == llvm::Triple::mipsel) CmdArgs.push_back("elf32ltsmip"); - else if (ToolChain.getArch() == llvm::Triple::mips64) - CmdArgs.push_back("elf64btsmip"); - else if (ToolChain.getArch() == llvm::Triple::mips64el) - CmdArgs.push_back("elf64ltsmip"); + else if (ToolChain.getArch() == llvm::Triple::mips64) { + if (hasMipsN32ABIArg(Args)) + CmdArgs.push_back("elf32btsmipn32"); + else + CmdArgs.push_back("elf64btsmip"); + } + else if (ToolChain.getArch() == llvm::Triple::mips64el) { + if (hasMipsN32ABIArg(Args)) + CmdArgs.push_back("elf32ltsmipn32"); + else + CmdArgs.push_back("elf64ltsmip"); + } else CmdArgs.push_back("elf_x86_64"); @@ -5641,8 +5963,7 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-static"); } else if (Args.hasArg(options::OPT_shared)) { CmdArgs.push_back("-shared"); - if ((ToolChain.getArch() == llvm::Triple::arm - || ToolChain.getArch() == llvm::Triple::thumb) && isAndroid) { + if (isAndroid) { CmdArgs.push_back("-Bsymbolic"); } } @@ -5667,8 +5988,12 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, ToolChain.getArch() == llvm::Triple::mipsel) CmdArgs.push_back("/lib/ld.so.1"); else if (ToolChain.getArch() == llvm::Triple::mips64 || - ToolChain.getArch() == llvm::Triple::mips64el) - CmdArgs.push_back("/lib64/ld.so.1"); + ToolChain.getArch() == llvm::Triple::mips64el) { + if (hasMipsN32ABIArg(Args)) + CmdArgs.push_back("/lib32/ld.so.1"); + else + CmdArgs.push_back("/lib64/ld.so.1"); + } else if (ToolChain.getArch() == llvm::Triple::ppc) CmdArgs.push_back("/lib/ld.so.1"); else if (ToolChain.getArch() == llvm::Triple::ppc64) @@ -5699,11 +6024,16 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, const char *crtbegin; if (Args.hasArg(options::OPT_static)) crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; - else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + else if (Args.hasArg(options::OPT_shared)) crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; + else if (Args.hasArg(options::OPT_pie)) + crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; else crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + + // Add crtfastmath.o if available and fast math is enabled. + ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs); } Args.AddAllArgs(CmdArgs, options::OPT_L); @@ -5728,6 +6058,12 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs); + SanitizerArgs Sanitize(D, Args); + + // Call this before we add the C++ ABI library. + if (Sanitize.needsUbsanRt()) + addUbsanRTLinux(getToolChain(), Args, CmdArgs); + if (D.CCCIsCXX && !Args.hasArg(options::OPT_nostdlib) && !Args.hasArg(options::OPT_nodefaultlibs)) { @@ -5742,8 +6078,10 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, } // Call this before we add the C run-time. - addAsanRTLinux(getToolChain(), Args, CmdArgs); - addTsanRTLinux(getToolChain(), Args, CmdArgs); + if (Sanitize.needsAsanRt()) + addAsanRTLinux(getToolChain(), Args, CmdArgs); + if (Sanitize.needsTsanRt()) + addTsanRTLinux(getToolChain(), Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib)) { if (!Args.hasArg(options::OPT_nodefaultlibs)) { @@ -5766,8 +6104,10 @@ void linuxtools::Link::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostartfiles)) { const char *crtend; - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + if (Args.hasArg(options::OPT_shared)) crtend = isAndroid ? "crtend_so.o" : "crtendS.o"; + else if (Args.hasArg(options::OPT_pie)) + crtend = isAndroid ? "crtend_android.o" : "crtendS.o"; else crtend = isAndroid ? "crtend_android.o" : "crtend.o"; @@ -5873,7 +6213,7 @@ void dragonfly::Assemble::ConstructJob(Compilation &C, const JobAction &JA, // When building 32-bit code on DragonFly/pc64, we have to explicitly // instruct as in the base system to assemble 32-bit code. - if (getToolChain().getArchName() == "i386") + if (getToolChain().getArch() == llvm::Triple::x86) CmdArgs.push_back("--32"); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, @@ -5917,7 +6257,7 @@ void dragonfly::Link::ConstructJob(Compilation &C, const JobAction &JA, // When building 32-bit code on DragonFly/pc64, we have to explicitly // instruct ld in the base system to link 32-bit code. - if (getToolChain().getArchName() == "i386") { + if (getToolChain().getArch() == llvm::Triple::x86) { CmdArgs.push_back("-m"); CmdArgs.push_back("elf_i386"); } diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index 999c57a2b63a..5898c660a499 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -202,6 +202,8 @@ namespace hexagon { namespace darwin { + llvm::Triple::ArchType getArchTypeForDarwinArchName(StringRef Str); + class LLVM_LIBRARY_VISIBILITY DarwinTool : public Tool { virtual void anchor(); protected: @@ -288,8 +290,9 @@ namespace darwin { }; class LLVM_LIBRARY_VISIBILITY Link : public DarwinTool { + bool NeedsTempPath(const InputInfoList &Inputs) const; void AddLinkArgs(Compilation &C, const ArgList &Args, - ArgStringList &CmdArgs) const; + ArgStringList &CmdArgs, const InputInfoList &Inputs) const; public: Link(const ToolChain &TC) : DarwinTool("darwin::Link", "linker", TC) {} diff --git a/lib/Driver/Types.cpp b/lib/Driver/Types.cpp index 9d8fcfd6bb44..862025ed9a1a 100644 --- a/lib/Driver/Types.cpp +++ b/lib/Driver/Types.cpp @@ -94,20 +94,6 @@ bool types::isAcceptedByClang(ID Id) { } } -bool types::isOnlyAcceptedByClang(ID Id) { - switch (Id) { - default: - return false; - - case TY_AST: - case TY_LLVM_IR: - case TY_LLVM_BC: - case TY_RewrittenObjC: - case TY_RewrittenLegacyObjC: - return true; - } -} - bool types::isObjC(ID Id) { switch (Id) { default: diff --git a/lib/Driver/WindowsToolChain.cpp b/lib/Driver/WindowsToolChain.cpp index 6827034ef4ca..de2d5352b716 100644 --- a/lib/Driver/WindowsToolChain.cpp +++ b/lib/Driver/WindowsToolChain.cpp @@ -81,19 +81,15 @@ bool Windows::IsIntegratedAssemblerDefault() const { } bool Windows::IsUnwindTablesDefault() const { - // FIXME: Gross; we should probably have some separate target - // definition, possibly even reusing the one in clang. - return getArchName() == "x86_64"; + return getArch() == llvm::Triple::x86_64; } -const char *Windows::GetDefaultRelocationModel() const { - return "static"; +bool Windows::isPICDefault() const { + return getArch() == llvm::Triple::x86_64; } -const char *Windows::GetForcedPicModel() const { - if (getArchName() == "x86_64") - return "pic"; - return 0; +bool Windows::isPICDefaultForced() const { + return getArch() == llvm::Triple::x86_64; } // FIXME: This probably should goto to some platform utils place. diff --git a/lib/Edit/RewriteObjCFoundationAPI.cpp b/lib/Edit/RewriteObjCFoundationAPI.cpp index d15b7a75e8f0..de96fee41618 100644 --- a/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -920,6 +920,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, case CK_ARCExtendBlockObject: case CK_NonAtomicToAtomic: case CK_CopyAndAutoreleaseBlockObject: + case CK_BuiltinFnToFnPtr: return false; } } diff --git a/lib/Frontend/ASTConsumers.cpp b/lib/Frontend/ASTConsumers.cpp index 0f0d8352046d..882d400c4292 100644 --- a/lib/Frontend/ASTConsumers.cpp +++ b/lib/Frontend/ASTConsumers.cpp @@ -58,7 +58,7 @@ namespace { bool shouldWalkTypesOfTypeLocs() const { return false; } bool TraverseDecl(Decl *D) { - if (filterMatches(D)) { + if (D != NULL && filterMatches(D)) { Out.changeColor(llvm::raw_ostream::BLUE) << (Dump ? "Dumping " : "Printing ") << getName(D) << ":\n"; Out.resetColor(); @@ -66,6 +66,7 @@ namespace { D->dump(Out); else D->print(Out, /*Indentation=*/0, /*PrintInstantiation=*/true); + Out << "\n"; // Don't traverse child nodes to avoid output duplication. return true; } @@ -89,8 +90,6 @@ namespace { class ASTDeclNodeLister : public ASTConsumer, public RecursiveASTVisitor<ASTDeclNodeLister> { - typedef RecursiveASTVisitor<ASTDeclNodeLister> base; - public: ASTDeclNodeLister(raw_ostream *Out = NULL) : Out(Out ? *Out : llvm::outs()) {} diff --git a/lib/Frontend/ASTMerge.cpp b/lib/Frontend/ASTMerge.cpp index 9feb3de4f0db..31b1df43df79 100644 --- a/lib/Frontend/ASTMerge.cpp +++ b/lib/Frontend/ASTMerge.cpp @@ -41,8 +41,9 @@ void ASTMergeAction::ExecuteAction() { DiagIDs(CI.getDiagnostics().getDiagnosticIDs()); for (unsigned I = 0, N = ASTFiles.size(); I != N; ++I) { IntrusiveRefCntPtr<DiagnosticsEngine> - Diags(new DiagnosticsEngine(DiagIDs, CI.getDiagnostics().getClient(), - /*ShouldOwnClient=*/false)); + Diags(new DiagnosticsEngine(DiagIDs, &CI.getDiagnosticOpts(), + CI.getDiagnostics().getClient(), + /*ShouldOwnClient=*/false)); ASTUnit *Unit = ASTUnit::LoadFromASTFile(ASTFiles[I], Diags, CI.getFileSystemOpts(), false); if (!Unit) diff --git a/lib/Frontend/ASTUnit.cpp b/lib/Frontend/ASTUnit.cpp index 42a67720c353..5576854a7d8b 100644 --- a/lib/Frontend/ASTUnit.cpp +++ b/lib/Frontend/ASTUnit.cpp @@ -27,6 +27,7 @@ #include "clang/Serialization/ASTWriter.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Basic/TargetOptions.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Diagnostic.h" @@ -180,6 +181,14 @@ void OnDiskData::Cleanup() { CleanPreambleFile(); } +struct ASTUnit::ASTWriterData { + SmallString<128> Buffer; + llvm::BitstreamWriter Stream; + ASTWriter Writer; + + ASTWriterData() : Stream(Buffer), Writer(Stream) { } +}; + void ASTUnit::clearFileLevelDecls() { for (FileDeclsTy::iterator I = FileDecls.begin(), E = FileDecls.end(); I != E; ++I) @@ -495,8 +504,8 @@ class ASTInfoCollector : public ASTReaderListener { ASTContext &Context; LangOptions &LangOpt; HeaderSearch &HSI; + IntrusiveRefCntPtr<TargetOptions> &TargetOpts; IntrusiveRefCntPtr<TargetInfo> &Target; - std::string &Predefines; unsigned &Counter; unsigned NumHeaderInfos; @@ -504,54 +513,38 @@ class ASTInfoCollector : public ASTReaderListener { bool InitializedLanguage; public: ASTInfoCollector(Preprocessor &PP, ASTContext &Context, LangOptions &LangOpt, - HeaderSearch &HSI, + HeaderSearch &HSI, + IntrusiveRefCntPtr<TargetOptions> &TargetOpts, IntrusiveRefCntPtr<TargetInfo> &Target, - std::string &Predefines, unsigned &Counter) - : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI), Target(Target), - Predefines(Predefines), Counter(Counter), NumHeaderInfos(0), + : PP(PP), Context(Context), LangOpt(LangOpt), HSI(HSI), + TargetOpts(TargetOpts), Target(Target), + Counter(Counter), NumHeaderInfos(0), InitializedLanguage(false) {} - virtual bool ReadLanguageOptions(const LangOptions &LangOpts) { + virtual bool ReadLanguageOptions(const LangOptions &LangOpts, + bool Complain) { if (InitializedLanguage) return false; LangOpt = LangOpts; - - // Initialize the preprocessor. - PP.Initialize(*Target); - - // Initialize the ASTContext - Context.InitBuiltinTypes(*Target); - InitializedLanguage = true; + + updated(); return false; } - virtual bool ReadTargetTriple(StringRef Triple) { + virtual bool ReadTargetOptions(const TargetOptions &TargetOpts, + bool Complain) { // If we've already initialized the target, don't do it again. if (Target) return false; - // FIXME: This is broken, we should store the TargetOptions in the AST file. - TargetOptions TargetOpts; - TargetOpts.ABI = ""; - TargetOpts.CXXABI = ""; - TargetOpts.CPU = ""; - TargetOpts.Features.clear(); - TargetOpts.Triple = Triple; - Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), TargetOpts); - return false; - } + this->TargetOpts = new TargetOptions(TargetOpts); + Target = TargetInfo::CreateTargetInfo(PP.getDiagnostics(), + *this->TargetOpts); - virtual bool ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, - StringRef OriginalFileName, - std::string &SuggestedPredefines, - FileManager &FileMgr) { - Predefines = Buffers[0].Data; - for (unsigned I = 1, N = Buffers.size(); I != N; ++I) { - Predefines += Buffers[I].Data; - } + updated(); return false; } @@ -559,9 +552,27 @@ public: HSI.setHeaderFileInfoForUID(HFI, NumHeaderInfos++); } - virtual void ReadCounter(unsigned Value) { + virtual void ReadCounter(const serialization::ModuleFile &M, unsigned Value) { Counter = Value; } + +private: + void updated() { + if (!Target || !InitializedLanguage) + return; + + // Inform the target of the language options. + // + // FIXME: We shouldn't need to do this, the target should be immutable once + // created. This complexity should be lifted elsewhere. + Target->setForcedLangOptions(LangOpt); + + // Initialize the preprocessor. + PP.Initialize(*Target); + + // Initialize the ASTContext + Context.InitBuiltinTypes(*Target); + } }; class StoredDiagnosticConsumer : public DiagnosticConsumer { @@ -621,8 +632,10 @@ void StoredDiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level Level, StoredDiags.push_back(StoredDiagnostic(Level, Info)); } -const std::string &ASTUnit::getOriginalSourceFileName() { - return OriginalSourceFile; +ASTDeserializationListener *ASTUnit::getDeserializationListener() { + if (WriterData) + return &WriterData->Writer; + return 0; } llvm::MemoryBuffer *ASTUnit::getBufferForFile(StringRef Filename, @@ -638,11 +651,11 @@ void ASTUnit::ConfigureDiags(IntrusiveRefCntPtr<DiagnosticsEngine> &Diags, if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. - DiagnosticOptions DiagOpts; DiagnosticConsumer *Client = 0; if (CaptureDiagnostics) Client = new StoredDiagnosticConsumer(AST.StoredDiagnostics); - Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd-ArgBegin, + Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(), + ArgEnd-ArgBegin, ArgBegin, Client, /*ShouldOwnClient=*/true, /*ShouldCloneClient=*/false); @@ -679,7 +692,10 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, AST->SourceMgr = new SourceManager(AST->getDiagnostics(), AST->getFileManager(), UserFilesAreVolatile); - AST->HeaderInfo.reset(new HeaderSearch(AST->getFileManager(), + AST->HSOpts = new HeaderSearchOptions(); + + AST->HeaderInfo.reset(new HeaderSearch(AST->HSOpts, + AST->getFileManager(), AST->getDiagnostics(), AST->ASTFileLangOpts, /*Target=*/0)); @@ -734,12 +750,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, // Gather Info for preprocessor construction later on. HeaderSearch &HeaderInfo = *AST->HeaderInfo.get(); - std::string Predefines; unsigned Counter; OwningPtr<ASTReader> Reader; - AST->PP = new Preprocessor(AST->getDiagnostics(), AST->ASTFileLangOpts, + AST->PP = new Preprocessor(new PreprocessorOptions(), + AST->getDiagnostics(), AST->ASTFileLangOpts, /*Target=*/0, AST->getSourceManager(), HeaderInfo, *AST, /*IILookup=*/0, @@ -757,10 +773,12 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, /*DelayInitialization=*/true); ASTContext &Context = *AST->Ctx; + bool disableValid = false; + if (::getenv("LIBCLANG_DISABLE_PCH_VALIDATION")) + disableValid = true; Reader.reset(new ASTReader(PP, Context, /*isysroot=*/"", - /*DisableValidation=*/false, - /*DisableStatCache=*/false, + /*DisableValidation=*/disableValid, AllowPCHWithCompilerErrors)); // Recover resources if we crash before exiting this method. @@ -769,21 +787,25 @@ ASTUnit *ASTUnit::LoadFromASTFile(const std::string &Filename, Reader->setListener(new ASTInfoCollector(*AST->PP, Context, AST->ASTFileLangOpts, HeaderInfo, - AST->Target, Predefines, Counter)); + AST->TargetOpts, AST->Target, + Counter)); - switch (Reader->ReadAST(Filename, serialization::MK_MainFile)) { + switch (Reader->ReadAST(Filename, serialization::MK_MainFile, + ASTReader::ARR_None)) { case ASTReader::Success: break; case ASTReader::Failure: - case ASTReader::IgnorePCH: + case ASTReader::OutOfDate: + case ASTReader::VersionMismatch: + case ASTReader::ConfigurationMismatch: + case ASTReader::HadErrors: AST->getDiagnostics().Report(diag::err_fe_unable_to_load_pch); return NULL; } AST->OriginalSourceFile = Reader->getOriginalSourceFile(); - PP.setPredefines(Reader->getSuggestedPredefines()); PP.setCounterValue(Counter); // Attach the AST reader to the AST context as an external AST @@ -897,6 +919,10 @@ public: for (DeclGroupRef::iterator it = D.begin(), ie = D.end(); it != ie; ++it) handleTopLevelDecl(*it); } + + virtual ASTDeserializationListener *GetASTDeserializationListener() { + return Unit.getDeserializationListener(); + } }; class TopLevelDeclTrackerAction : public ASTFrontendAction { @@ -1047,14 +1073,13 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { CCInvocation(new CompilerInvocation(*Invocation)); Clang->setInvocation(CCInvocation.getPtr()); - OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; + OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing any diagnostics that would // otherwise be dropped. Clang->setDiagnostics(&getDiagnostics()); // Create the target instance. - Clang->getTargetOpts().Features = TargetFeatures; Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), Clang->getTargetOpts())); if (!Clang->hasTarget()) { @@ -1070,9 +1095,9 @@ bool ASTUnit::Parse(llvm::MemoryBuffer *OverrideMainBuffer) { assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && "IR inputs not support here!"); // Configure the various subsystems. @@ -1217,7 +1242,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, // command line (to another file) or directly through the compiler invocation // (to a memory buffer). llvm::MemoryBuffer *Buffer = 0; - llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File); + llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].getFile()); if (const llvm::sys::FileStatus *MainFileStatus = MainFilePath.getFileStatus()) { // Check whether there is a file-file remapping of the main file for (PreprocessorOptions::remapped_file_iterator @@ -1267,7 +1292,7 @@ ASTUnit::ComputePreamble(CompilerInvocation &Invocation, // If the main source file was not remapped, load it now. if (!Buffer) { - Buffer = getBufferForFile(FrontendOpts.Inputs[0].File); + Buffer = getBufferForFile(FrontendOpts.Inputs[0].getFile()); if (!Buffer) return std::make_pair((llvm::MemoryBuffer*)0, std::make_pair(0, true)); @@ -1429,7 +1454,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // buffer size we reserved when creating the preamble. return CreatePaddedMainFileBuffer(NewPreamble.first, PreambleReservedSize, - FrontendOpts.Inputs[0].File); + FrontendOpts.Inputs[0].getFile()); } } @@ -1482,7 +1507,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( // Save the preamble text for later; we'll need to compare against it for // subsequent reparses. - StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].File; + StringRef MainFilename = PreambleInvocation->getFrontendOpts().Inputs[0].getFile(); Preamble.assign(FileMgr->getFile(MainFilename), NewPreamble.first->getBufferStart(), NewPreamble.first->getBufferStart() @@ -1492,7 +1517,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( delete PreambleBuffer; PreambleBuffer = llvm::MemoryBuffer::getNewUninitMemBuffer(PreambleReservedSize, - FrontendOpts.Inputs[0].File); + FrontendOpts.Inputs[0].getFile()); memcpy(const_cast<char*>(PreambleBuffer->getBufferStart()), NewPreamble.first->getBufferStart(), Preamble.size()); memset(const_cast<char*>(PreambleBuffer->getBufferStart()) + Preamble.size(), @@ -1500,7 +1525,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( const_cast<char*>(PreambleBuffer->getBufferEnd())[-1] = '\n'; // Remap the main source file to the preamble buffer. - llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].File); + llvm::sys::PathWithStatus MainFilePath(FrontendOpts.Inputs[0].getFile()); PreprocessorOpts.addRemappedFile(MainFilePath.str(), PreambleBuffer); // Tell the compiler invocation to generate a temporary precompiled header. @@ -1518,15 +1543,14 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( CICleanup(Clang.get()); Clang->setInvocation(&*PreambleInvocation); - OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; + OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing all of the diagnostics produced. Clang->setDiagnostics(&getDiagnostics()); // Create the target instance. - Clang->getTargetOpts().Features = TargetFeatures; Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), - Clang->getTargetOpts())); + Clang->getTargetOpts())); if (!Clang->hasTarget()) { llvm::sys::Path(FrontendOpts.OutputFile).eraseFromDisk(); Preamble.clear(); @@ -1544,9 +1568,9 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && "IR inputs not support here!"); // Clear out old caches and data. @@ -1633,7 +1657,7 @@ llvm::MemoryBuffer *ASTUnit::getMainBufferWithPrecompiledPreamble( return CreatePaddedMainFileBuffer(NewPreamble.first, PreambleReservedSize, - FrontendOpts.Inputs[0].File); + FrontendOpts.Inputs[0].getFile()); } void ASTUnit::RealizeTopLevelDeclsFromPreamble() { @@ -1664,7 +1688,7 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) { } StringRef ASTUnit::getMainFileName() const { - return Invocation->getFrontendOpts().Inputs[0].File; + return Invocation->getFrontendOpts().Inputs[0].getFile(); } ASTUnit *ASTUnit::create(CompilerInvocation *CI, @@ -1733,9 +1757,6 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, CI->getFrontendOpts().DisableFree = false; ProcessWarningOptions(AST->getDiagnostics(), CI->getDiagnosticOpts()); - // Save the target features. - AST->TargetFeatures = CI->getTargetOpts().Features; - // Create the compiler instance to use for building the AST. OwningPtr<CompilerInstance> Clang(new CompilerInstance()); @@ -1744,14 +1765,13 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, CICleanup(Clang.get()); Clang->setInvocation(CI); - AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; + AST->OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing any diagnostics that would // otherwise be dropped. Clang->setDiagnostics(&AST->getDiagnostics()); // Create the target instance. - Clang->getTargetOpts().Features = AST->TargetFeatures; Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), Clang->getTargetOpts())); if (!Clang->hasTarget()) @@ -1765,9 +1785,9 @@ ASTUnit *ASTUnit::LoadFromCompilerInvocationAction(CompilerInvocation *CI, assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && "IR inputs not supported here!"); // Configure the various subsystems. @@ -1840,9 +1860,6 @@ bool ASTUnit::LoadFromCompilerInvocation(bool PrecompilePreamble) { Invocation->getFrontendOpts().DisableFree = false; ProcessWarningOptions(getDiagnostics(), Invocation->getDiagnosticOpts()); - // Save the target features. - TargetFeatures = Invocation->getTargetOpts().Features; - llvm::MemoryBuffer *OverrideMainBuffer = 0; if (PrecompilePreamble) { PreambleRebuildCounter = 2; @@ -1909,12 +1926,13 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, bool AllowPCHWithCompilerErrors, bool SkipFunctionBodies, bool UserFilesAreVolatile, + bool ForSerialization, OwningPtr<ASTUnit> *ErrAST) { if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. - DiagnosticOptions DiagOpts; - Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgEnd - ArgBegin, + Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions(), + ArgEnd - ArgBegin, ArgBegin); } @@ -1972,6 +1990,8 @@ ASTUnit *ASTUnit::LoadFromCommandLine(const char **ArgBegin, AST->NumStoredDiagnosticsFromDriver = StoredDiagnostics.size(); AST->StoredDiagnostics.swap(StoredDiagnostics); AST->Invocation = CI; + if (ForSerialization) + AST->WriterData.reset(new ASTWriterData()); CI = 0; // Zero out now to ease cleanup during crash recovery. // Recover resources if we crash before exiting this method. @@ -2002,7 +2022,6 @@ bool ASTUnit::Reparse(RemappedFile *RemappedFiles, unsigned NumRemappedFiles) { // Remap files. PreprocessorOptions &PPOpts = Invocation->getPreprocessorOpts(); - PPOpts.DisableStatCache = true; for (PreprocessorOptions::remapped_file_buffer_iterator R = PPOpts.remapped_file_buffer_begin(), REnd = PPOpts.remapped_file_buffer_end(); @@ -2238,7 +2257,6 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, // Adjust priority based on similar type classes. unsigned Priority = C->Priority; - CXCursorKind CursorKind = C->Kind; CodeCompletionString *Completion = C->Completion; if (!Context.getPreferredType().isNull()) { if (C->Kind == CXCursor_MacroDefinition) { @@ -2272,12 +2290,11 @@ void AugmentedCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &S, CodeCompletionBuilder Builder(getAllocator(), getCodeCompletionTUInfo(), CCP_CodePattern, C->Availability); Builder.AddTypedTextChunk(C->Completion->getTypedText()); - CursorKind = CXCursor_NotImplemented; Priority = CCP_CodePattern; Completion = Builder.TakeString(); } - AllResults.push_back(Result(Completion, Priority, CursorKind, + AllResults.push_back(Result(Completion, Priority, C->Kind, C->Availability)); } @@ -2341,7 +2358,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, CICleanup(Clang.get()); Clang->setInvocation(&*CCInvocation); - OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].File; + OriginalSourceFile = Clang->getFrontendOpts().Inputs[0].getFile(); // Set up diagnostics, capturing any diagnostics produced. Clang->setDiagnostics(&Diag); @@ -2351,7 +2368,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, StoredDiagnostics); // Create the target instance. - Clang->getTargetOpts().Features = TargetFeatures; Clang->setTarget(TargetInfo::CreateTargetInfo(Clang->getDiagnostics(), Clang->getTargetOpts())); if (!Clang->hasTarget()) { @@ -2367,9 +2383,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, assert(Clang->getFrontendOpts().Inputs.size() == 1 && "Invocation must have exactly one source file!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_AST && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_AST && "FIXME: AST inputs not yet supported here!"); - assert(Clang->getFrontendOpts().Inputs[0].Kind != IK_LLVM_IR && + assert(Clang->getFrontendOpts().Inputs[0].getKind() != IK_LLVM_IR && "IR inputs not support here!"); @@ -2398,8 +2414,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, = new AugmentedCodeCompleteConsumer(*this, Consumer, CodeCompleteOpts); Clang->setCodeCompletionConsumer(AugmentedConsumer); - Clang->getFrontendOpts().SkipFunctionBodies = true; - // If we have a precompiled preamble, try to use it. We only allow // the use of the precompiled preamble if we're if the completion // point is within the main file, after the end of the precompiled @@ -2420,7 +2434,6 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, // If the main file has been overridden due to the use of a preamble, // make that override happen and introduce the preamble. - PreprocessorOpts.DisableStatCache = true; StoredDiagnostics.insert(StoredDiagnostics.end(), stored_diag_begin(), stored_diag_afterDriver_begin()); @@ -2438,8 +2451,9 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, PreprocessorOpts.PrecompiledPreambleBytes.second = false; } - // Disable the preprocessing record - PreprocessorOpts.DetailedRecord = false; + // Disable the preprocessing record if modules are not enabled. + if (!Clang->getLangOpts().Modules) + PreprocessorOpts.DetailedRecord = false; OwningPtr<SyntaxOnlyAction> Act; Act.reset(new SyntaxOnlyAction); @@ -2457,7 +2471,7 @@ void ASTUnit::CodeComplete(StringRef File, unsigned Line, unsigned Column, checkAndSanitizeDiags(StoredDiagnostics, getSourceManager()); } -CXSaveError ASTUnit::Save(StringRef File) { +bool ASTUnit::Save(StringRef File) { // Write to a temporary file and later rename it to the actual file, to avoid // possible race conditions. SmallString<128> TempPath; @@ -2466,7 +2480,7 @@ CXSaveError ASTUnit::Save(StringRef File) { int fd; if (llvm::sys::fs::unique_file(TempPath.str(), fd, TempPath, /*makeAbsolute=*/false)) - return CXSaveError_Unknown; + return true; // FIXME: Can we somehow regenerate the stat cache here, or do we need to // unconditionally create a stat cache when we parse the file? @@ -2476,32 +2490,43 @@ CXSaveError ASTUnit::Save(StringRef File) { Out.close(); if (Out.has_error()) { Out.clear_error(); - return CXSaveError_Unknown; + return true; } if (llvm::sys::fs::rename(TempPath.str(), File)) { bool exists; llvm::sys::fs::remove(TempPath.str(), exists); - return CXSaveError_Unknown; + return true; } - return CXSaveError_None; + return false; +} + +static bool serializeUnit(ASTWriter &Writer, + SmallVectorImpl<char> &Buffer, + Sema &S, + bool hasErrors, + raw_ostream &OS) { + Writer.WriteAST(S, std::string(), 0, "", hasErrors); + + // Write the generated bitstream to "Out". + if (!Buffer.empty()) + OS.write(Buffer.data(), Buffer.size()); + + return false; } bool ASTUnit::serialize(raw_ostream &OS) { bool hasErrors = getDiagnostics().hasErrorOccurred(); + if (WriterData) + return serializeUnit(WriterData->Writer, WriterData->Buffer, + getSema(), hasErrors, OS); + SmallString<128> Buffer; llvm::BitstreamWriter Stream(Buffer); ASTWriter Writer(Stream); - // FIXME: Handle modules - Writer.WriteAST(getSema(), 0, std::string(), 0, "", hasErrors); - - // Write the generated bitstream to "Out". - if (!Buffer.empty()) - OS.write((char *)&Buffer.front(), Buffer.size()); - - return false; + return serializeUnit(Writer, Buffer, getSema(), hasErrors, OS); } typedef ContinuousRangeMap<unsigned, int, 2> SLocRemap; @@ -2761,6 +2786,85 @@ SourceLocation ASTUnit::getStartOfMainFileID() { return SourceMgr->getLocForStartOfFile(FID); } +std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> +ASTUnit::getLocalPreprocessingEntities() const { + if (isMainFileAST()) { + serialization::ModuleFile & + Mod = Reader->getModuleManager().getPrimaryModule(); + return Reader->getModulePreprocessedEntities(Mod); + } + + if (PreprocessingRecord *PPRec = PP->getPreprocessingRecord()) + return std::make_pair(PPRec->local_begin(), PPRec->local_end()); + + return std::make_pair(PreprocessingRecord::iterator(), + PreprocessingRecord::iterator()); +} + +bool ASTUnit::visitLocalTopLevelDecls(void *context, DeclVisitorFn Fn) { + if (isMainFileAST()) { + serialization::ModuleFile & + Mod = Reader->getModuleManager().getPrimaryModule(); + ASTReader::ModuleDeclIterator MDI, MDE; + llvm::tie(MDI, MDE) = Reader->getModuleFileLevelDecls(Mod); + for (; MDI != MDE; ++MDI) { + if (!Fn(context, *MDI)) + return false; + } + + return true; + } + + for (ASTUnit::top_level_iterator TL = top_level_begin(), + TLEnd = top_level_end(); + TL != TLEnd; ++TL) { + if (!Fn(context, *TL)) + return false; + } + + return true; +} + +namespace { +struct PCHLocatorInfo { + serialization::ModuleFile *Mod; + PCHLocatorInfo() : Mod(0) {} +}; +} + +static bool PCHLocator(serialization::ModuleFile &M, void *UserData) { + PCHLocatorInfo &Info = *static_cast<PCHLocatorInfo*>(UserData); + switch (M.Kind) { + case serialization::MK_Module: + return true; // skip dependencies. + case serialization::MK_PCH: + Info.Mod = &M; + return true; // found it. + case serialization::MK_Preamble: + return false; // look in dependencies. + case serialization::MK_MainFile: + return false; // look in dependencies. + } + + return true; +} + +const FileEntry *ASTUnit::getPCHFile() { + if (!Reader) + return 0; + + PCHLocatorInfo Info; + Reader->getModuleManager().visit(PCHLocator, &Info); + if (Info.Mod) + return Info.Mod->File; + + return 0; +} + +bool ASTUnit::isModuleFile() { + return isMainFileAST() && !ASTFileLangOpts.CurrentModule.empty(); +} + void ASTUnit::PreambleData::countLines() const { NumLines = 0; if (empty()) diff --git a/lib/Frontend/ChainedDiagnosticConsumer.cpp b/lib/Frontend/ChainedDiagnosticConsumer.cpp index c1d3db873f1f..d77fd180ea0d 100644 --- a/lib/Frontend/ChainedDiagnosticConsumer.cpp +++ b/lib/Frontend/ChainedDiagnosticConsumer.cpp @@ -1,4 +1,4 @@ -//===- ChainedDiagnosticConsumer.cpp - Chain Diagnostic Clients -*- C++ -*-===// +//===- ChainedDiagnosticConsumer.cpp - Chain Diagnostic Clients -----------===// // // The LLVM Compiler Infrastructure // diff --git a/lib/Frontend/ChainedIncludesSource.cpp b/lib/Frontend/ChainedIncludesSource.cpp index dbb06bd23cdc..2d586400ec46 100644 --- a/lib/Frontend/ChainedIncludesSource.cpp +++ b/lib/Frontend/ChainedIncludesSource.cpp @@ -39,14 +39,18 @@ static ASTReader *createASTReader(CompilerInstance &CI, Reader->addInMemoryBuffer(sr, memBufs[ti]); } Reader->setDeserializationListener(deserialListener); - switch (Reader->ReadAST(pchFile, serialization::MK_PCH)) { + switch (Reader->ReadAST(pchFile, serialization::MK_PCH, + ASTReader::ARR_None)) { case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. PP.setPredefines(Reader->getSuggestedPredefines()); return Reader.take(); case ASTReader::Failure: - case ASTReader::IgnorePCH: + case ASTReader::OutOfDate: + case ASTReader::VersionMismatch: + case ASTReader::ConfigurationMismatch: + case ASTReader::HadErrors: break; } return 0; @@ -63,7 +67,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { assert(!includes.empty() && "No '-chain-include' in options!"); OwningPtr<ChainedIncludesSource> source(new ChainedIncludesSource()); - InputKind IK = CI.getFrontendOpts().Inputs[0].Kind; + InputKind IK = CI.getFrontendOpts().Inputs[0].getKind(); SmallVector<llvm::MemoryBuffer *, 4> serialBufs; SmallVector<std::string, 4> serialBufNames; @@ -82,14 +86,14 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { CInvok->getPreprocessorOpts().Macros.clear(); CInvok->getFrontendOpts().Inputs.clear(); - CInvok->getFrontendOpts().Inputs.push_back(FrontendInputFile(includes[i], - IK)); + FrontendInputFile InputFile(includes[i], IK); + CInvok->getFrontendOpts().Inputs.push_back(InputFile); TextDiagnosticPrinter *DiagClient = - new TextDiagnosticPrinter(llvm::errs(), DiagnosticOptions()); + new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions()); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( - new DiagnosticsEngine(DiagID, DiagClient)); + new DiagnosticsEngine(DiagID, &CI.getDiagnosticOpts(), DiagClient)); OwningPtr<CompilerInstance> Clang(new CompilerInstance()); Clang->setInvocation(CInvok.take()); @@ -108,6 +112,8 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { OwningPtr<ASTConsumer> consumer; consumer.reset(new PCHGenerator(Clang->getPreprocessor(), "-", 0, /*isysroot=*/"", &OS)); + Clang->getPreprocessor().setPPMutationListener( + consumer->GetPPMutationListener()); Clang->getASTContext().setASTMutationListener( consumer->GetASTMutationListener()); Clang->setASTConsumer(consumer.take()); @@ -141,7 +147,7 @@ ChainedIncludesSource *ChainedIncludesSource::create(CompilerInstance &CI) { Clang->getASTContext().setExternalSource(Reader); } - if (!Clang->InitializeSourceManager(includes[i])) + if (!Clang->InitializeSourceManager(InputFile)) return 0; ParseAST(Clang->getSema()); diff --git a/lib/Frontend/CompilerInstance.cpp b/lib/Frontend/CompilerInstance.cpp index 6de153107f3b..22a74fcc35d9 100644 --- a/lib/Frontend/CompilerInstance.cpp +++ b/lib/Frontend/CompilerInstance.cpp @@ -52,6 +52,7 @@ CompilerInstance::CompilerInstance() } CompilerInstance::~CompilerInstance() { + assert(OutputFiles.empty() && "Still output files in flight?"); } void CompilerInstance::setInvocation(CompilerInvocation *Value) { @@ -88,19 +89,18 @@ void CompilerInstance::setASTConsumer(ASTConsumer *Value) { void CompilerInstance::setCodeCompletionConsumer(CodeCompleteConsumer *Value) { CompletionConsumer.reset(Value); - getFrontendOpts().SkipFunctionBodies = Value != 0; } // Diagnostics -static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, +static void SetUpBuildDumpLog(DiagnosticOptions *DiagOpts, unsigned argc, const char* const *argv, DiagnosticsEngine &Diags) { std::string ErrorInfo; OwningPtr<raw_ostream> OS( - new llvm::raw_fd_ostream(DiagOpts.DumpBuildInformation.c_str(), ErrorInfo)); + new llvm::raw_fd_ostream(DiagOpts->DumpBuildInformation.c_str(),ErrorInfo)); if (!ErrorInfo.empty()) { Diags.Report(diag::err_fe_unable_to_open_logfile) - << DiagOpts.DumpBuildInformation << ErrorInfo; + << DiagOpts->DumpBuildInformation << ErrorInfo; return; } @@ -115,20 +115,20 @@ static void SetUpBuildDumpLog(const DiagnosticOptions &DiagOpts, Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger)); } -static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts, +static void SetUpDiagnosticLog(DiagnosticOptions *DiagOpts, const CodeGenOptions *CodeGenOpts, DiagnosticsEngine &Diags) { std::string ErrorInfo; bool OwnsStream = false; raw_ostream *OS = &llvm::errs(); - if (DiagOpts.DiagnosticLogFile != "-") { + if (DiagOpts->DiagnosticLogFile != "-") { // Create the output stream. llvm::raw_fd_ostream *FileOS( - new llvm::raw_fd_ostream(DiagOpts.DiagnosticLogFile.c_str(), + new llvm::raw_fd_ostream(DiagOpts->DiagnosticLogFile.c_str(), ErrorInfo, llvm::raw_fd_ostream::F_Append)); if (!ErrorInfo.empty()) { Diags.Report(diag::warn_fe_cc_log_diagnostics_failure) - << DiagOpts.DumpBuildInformation << ErrorInfo; + << DiagOpts->DumpBuildInformation << ErrorInfo; } else { FileOS->SetUnbuffered(); FileOS->SetUseAtomicWrites(true); @@ -145,7 +145,7 @@ static void SetUpDiagnosticLog(const DiagnosticOptions &DiagOpts, Diags.setClient(new ChainedDiagnosticConsumer(Diags.takeClient(), Logger)); } -static void SetupSerializedDiagnostics(const DiagnosticOptions &DiagOpts, +static void SetupSerializedDiagnostics(DiagnosticOptions *DiagOpts, DiagnosticsEngine &Diags, StringRef OutputFile) { std::string ErrorInfo; @@ -171,13 +171,13 @@ void CompilerInstance::createDiagnostics(int Argc, const char* const *Argv, DiagnosticConsumer *Client, bool ShouldOwnClient, bool ShouldCloneClient) { - Diagnostics = createDiagnostics(getDiagnosticOpts(), Argc, Argv, Client, + Diagnostics = createDiagnostics(&getDiagnosticOpts(), Argc, Argv, Client, ShouldOwnClient, ShouldCloneClient, &getCodeGenOpts()); } IntrusiveRefCntPtr<DiagnosticsEngine> -CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, +CompilerInstance::createDiagnostics(DiagnosticOptions *Opts, int Argc, const char* const *Argv, DiagnosticConsumer *Client, bool ShouldOwnClient, @@ -185,7 +185,7 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, const CodeGenOptions *CodeGenOpts) { IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> - Diags(new DiagnosticsEngine(DiagID)); + Diags(new DiagnosticsEngine(DiagID, Opts)); // Create the diagnostic client for reporting errors or for // implementing -verify. @@ -198,22 +198,22 @@ CompilerInstance::createDiagnostics(const DiagnosticOptions &Opts, Diags->setClient(new TextDiagnosticPrinter(llvm::errs(), Opts)); // Chain in -verify checker, if requested. - if (Opts.VerifyDiagnostics) + if (Opts->VerifyDiagnostics) Diags->setClient(new VerifyDiagnosticConsumer(*Diags)); // Chain in -diagnostic-log-file dumper, if requested. - if (!Opts.DiagnosticLogFile.empty()) + if (!Opts->DiagnosticLogFile.empty()) SetUpDiagnosticLog(Opts, CodeGenOpts, *Diags); - if (!Opts.DumpBuildInformation.empty()) + if (!Opts->DumpBuildInformation.empty()) SetUpBuildDumpLog(Opts, Argc, Argv, *Diags); - if (!Opts.DiagnosticSerializationFile.empty()) + if (!Opts->DiagnosticSerializationFile.empty()) SetupSerializedDiagnostics(Opts, *Diags, - Opts.DiagnosticSerializationFile); + Opts->DiagnosticSerializationFile); // Configure our handling of diagnostics. - ProcessWarningOptions(*Diags, Opts); + ProcessWarningOptions(*Diags, *Opts); return Diags; } @@ -241,11 +241,13 @@ void CompilerInstance::createPreprocessor() { PTHMgr = PTHManager::Create(PPOpts.TokenCache, getDiagnostics()); // Create the Preprocessor. - HeaderSearch *HeaderInfo = new HeaderSearch(getFileManager(), + HeaderSearch *HeaderInfo = new HeaderSearch(&getHeaderSearchOpts(), + getFileManager(), getDiagnostics(), getLangOpts(), &getTarget()); - PP = new Preprocessor(getDiagnostics(), getLangOpts(), &getTarget(), + PP = new Preprocessor(&getPreprocessorOpts(), + getDiagnostics(), getLangOpts(), &getTarget(), getSourceManager(), *HeaderInfo, *this, PTHMgr, /*OwnsHeaderSearch=*/true); @@ -306,14 +308,12 @@ void CompilerInstance::createASTContext() { void CompilerInstance::createPCHExternalASTSource(StringRef Path, bool DisablePCHValidation, - bool DisableStatCache, bool AllowPCHWithCompilerErrors, void *DeserializationListener){ OwningPtr<ExternalASTSource> Source; bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; Source.reset(createPCHExternalASTSource(Path, getHeaderSearchOpts().Sysroot, DisablePCHValidation, - DisableStatCache, AllowPCHWithCompilerErrors, getPreprocessor(), getASTContext(), DeserializationListener, @@ -326,7 +326,6 @@ ExternalASTSource * CompilerInstance::createPCHExternalASTSource(StringRef Path, const std::string &Sysroot, bool DisablePCHValidation, - bool DisableStatCache, bool AllowPCHWithCompilerErrors, Preprocessor &PP, ASTContext &Context, @@ -335,14 +334,15 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path, OwningPtr<ASTReader> Reader; Reader.reset(new ASTReader(PP, Context, Sysroot.empty() ? "" : Sysroot.c_str(), - DisablePCHValidation, DisableStatCache, + DisablePCHValidation, AllowPCHWithCompilerErrors)); Reader->setDeserializationListener( static_cast<ASTDeserializationListener *>(DeserializationListener)); switch (Reader->ReadAST(Path, Preamble ? serialization::MK_Preamble - : serialization::MK_PCH)) { + : serialization::MK_PCH, + ASTReader::ARR_None)) { case ASTReader::Success: // Set the predefines buffer as suggested by the PCH reader. Typically, the // predefines buffer will be empty. @@ -353,7 +353,10 @@ CompilerInstance::createPCHExternalASTSource(StringRef Path, // Unrecoverable failure: don't even try to process the input file. break; - case ASTReader::IgnorePCH: + case ASTReader::OutOfDate: + case ASTReader::VersionMismatch: + case ASTReader::ConfigurationMismatch: + case ASTReader::HadErrors: // No suitable PCH file could be found. Return an error. break; } @@ -586,19 +589,29 @@ CompilerInstance::createOutputFile(StringRef OutputPath, // Initialization Utilities -bool CompilerInstance::InitializeSourceManager(StringRef InputFile, - SrcMgr::CharacteristicKind Kind){ - return InitializeSourceManager(InputFile, Kind, getDiagnostics(), +bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input){ + return InitializeSourceManager(Input, getDiagnostics(), getFileManager(), getSourceManager(), getFrontendOpts()); } -bool CompilerInstance::InitializeSourceManager(StringRef InputFile, - SrcMgr::CharacteristicKind Kind, +bool CompilerInstance::InitializeSourceManager(const FrontendInputFile &Input, DiagnosticsEngine &Diags, FileManager &FileMgr, SourceManager &SourceMgr, const FrontendOptions &Opts) { + SrcMgr::CharacteristicKind + Kind = Input.isSystem() ? SrcMgr::C_System : SrcMgr::C_User; + + if (Input.isBuffer()) { + SourceMgr.createMainFileIDForMemBuffer(Input.getBuffer(), Kind); + assert(!SourceMgr.getMainFileID().isInvalid() && + "Couldn't establish MainFileID!"); + return true; + } + + StringRef InputFile = Input.getFile(); + // Figure out where to get and map in the main file. if (InputFile != "-") { const FileEntry *File = FileMgr.getFile(InputFile); @@ -607,6 +620,19 @@ bool CompilerInstance::InitializeSourceManager(StringRef InputFile, return false; } SourceMgr.createMainFileID(File, Kind); + + // The natural SourceManager infrastructure can't currently handle named + // pipes, but we would at least like to accept them for the main + // file. Detect them here, read them with the more generic MemoryBuffer + // function, and simply override their contents as we do for STDIN. + if (File->isNamedPipe()) { + OwningPtr<llvm::MemoryBuffer> MB; + if (llvm::error_code ec = llvm::MemoryBuffer::getFile(InputFile, MB)) { + Diags.Report(diag::err_cannot_open_file) << InputFile << ec.message(); + return false; + } + SourceMgr.overrideFileContents(File, MB.take()); + } } else { OwningPtr<llvm::MemoryBuffer> SB; if (llvm::MemoryBuffer::getSTDIN(SB)) { @@ -746,7 +772,7 @@ static void compileModule(CompilerInstance &ImportingInstance, // Someone else is responsible for building the module. Wait for them to // finish. Locked.waitForUnlock(); - break; + return; } ModuleMap &ModMap @@ -836,6 +862,7 @@ static void compileModule(CompilerInstance &ImportingInstance, // FIXME: Even though we're executing under crash protection, it would still // be nice to do this with RemoveFileOnSignal when we can. However, that // doesn't make sense for all clients, so clean this up manually. + Instance.clearOutputFiles(/*EraseFiles=*/true); if (!TempModuleMapFileName.empty()) llvm::sys::Path(TempModuleMapFileName).eraseFromDisk(); } @@ -939,13 +966,14 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, const PreprocessorOptions &PPOpts = getPreprocessorOpts(); ModuleManager = new ASTReader(getPreprocessor(), *Context, Sysroot.empty() ? "" : Sysroot.c_str(), - PPOpts.DisablePCHValidation, - PPOpts.DisableStatCache); + PPOpts.DisablePCHValidation); if (hasASTConsumer()) { ModuleManager->setDeserializationListener( getASTConsumer().GetASTDeserializationListener()); getASTContext().setASTMutationListener( getASTConsumer().GetASTMutationListener()); + getPreprocessor().setPPMutationListener( + getASTConsumer().GetPPMutationListener()); } OwningPtr<ExternalASTSource> Source; Source.reset(ModuleManager); @@ -957,12 +985,39 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, } // Try to load the module we found. + unsigned ARRFlags = ASTReader::ARR_None; + if (Module) + ARRFlags |= ASTReader::ARR_OutOfDate; switch (ModuleManager->ReadAST(ModuleFile->getName(), - serialization::MK_Module)) { + serialization::MK_Module, + ARRFlags)) { case ASTReader::Success: break; - case ASTReader::IgnorePCH: + case ASTReader::OutOfDate: { + // The module file is out-of-date. Rebuild it. + getFileManager().invalidateCache(ModuleFile); + bool Existed; + llvm::sys::fs::remove(ModuleFileName, Existed); + compileModule(*this, Module, ModuleFileName); + + // Try loading the module again. + ModuleFile = FileMgr->getFile(ModuleFileName); + if (!ModuleFile || + ModuleManager->ReadAST(ModuleFileName, + serialization::MK_Module, + ASTReader::ARR_None) != ASTReader::Success) { + KnownModules[Path[0].first] = 0; + return 0; + } + + // Okay, we've rebuilt and now loaded the module. + break; + } + + case ASTReader::VersionMismatch: + case ASTReader::ConfigurationMismatch: + case ASTReader::HadErrors: // FIXME: The ASTReader will already have complained, but can we showhorn // that diagnostic information into a more useful form? KnownModules[Path[0].first] = 0; @@ -980,6 +1035,9 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, Module = PP->getHeaderSearchInfo().getModuleMap() .findModule((Path[0].first->getName())); } + + if (Module) + Module->setASTFile(ModuleFile); // Cache the result of this top-level module lookup for later. Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first; @@ -1079,9 +1137,12 @@ Module *CompilerInstance::loadModule(SourceLocation ImportLoc, // implicit import declaration to capture it in the AST. if (IsInclusionDirective && hasASTContext()) { TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); - TU->addDecl(ImportDecl::CreateImplicit(getASTContext(), TU, - ImportLoc, Module, - Path.back().second)); + ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, + ImportLoc, Module, + Path.back().second); + TU->addDecl(ImportD); + if (Consumer) + Consumer->HandleImplicitImportDecl(ImportD); } LastModuleImportLoc = ImportLoc; diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index d39679caf13e..b9c198b11191 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -11,6 +11,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/Version.h" #include "clang/Basic/FileManager.h" +#include "clang/Lex/HeaderSearchOptions.h" #include "clang/Driver/Arg.h" #include "clang/Driver/ArgList.h" #include "clang/Driver/Options.h" @@ -20,6 +21,7 @@ #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/LangStandard.h" #include "clang/Serialization/ASTReader.h" +#include "llvm/ADT/Hashing.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" @@ -35,917 +37,21 @@ using namespace clang; //===----------------------------------------------------------------------===// CompilerInvocationBase::CompilerInvocationBase() - : LangOpts(new LangOptions()) {} + : LangOpts(new LangOptions()), TargetOpts(new TargetOptions()), + DiagnosticOpts(new DiagnosticOptions()), + HeaderSearchOpts(new HeaderSearchOptions()), + PreprocessorOpts(new PreprocessorOptions()) {} CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &X) : RefCountedBase<CompilerInvocation>(), - LangOpts(new LangOptions(*X.getLangOpts())) {} + LangOpts(new LangOptions(*X.getLangOpts())), + TargetOpts(new TargetOptions(X.getTargetOpts())), + DiagnosticOpts(new DiagnosticOptions(X.getDiagnosticOpts())), + HeaderSearchOpts(new HeaderSearchOptions(X.getHeaderSearchOpts())), + PreprocessorOpts(new PreprocessorOptions(X.getPreprocessorOpts())) {} //===----------------------------------------------------------------------===// -// Utility functions. -//===----------------------------------------------------------------------===// - -static const char *getAnalysisStoreName(AnalysisStores Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis store!"); -#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ - case NAME##Model: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -static const char *getAnalysisConstraintName(AnalysisConstraints Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis constraints!"); -#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ - case NAME##Model: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -static const char *getAnalysisDiagClientName(AnalysisDiagClients Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis client!"); -#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREATE) \ - case PD_##NAME: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -static const char *getAnalysisPurgeModeName(AnalysisPurgeMode Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis purge mode!"); -#define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \ - case NAME: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -static const char *getAnalysisIPAModeName(AnalysisIPAMode Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis ipa mode!"); -#define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \ - case NAME: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -static const char * - getAnalysisInliningModeName(AnalysisInliningMode Kind) { - switch (Kind) { - default: - llvm_unreachable("Unknown analysis inlining mode!"); -#define ANALYSIS_INLINE_SELECTION(NAME, CMDFLAG, DESC) \ - case NAME: return CMDFLAG; -#include "clang/Frontend/Analyses.def" - } -} - -//===----------------------------------------------------------------------===// -// Serialization (to args) -//===----------------------------------------------------------------------===// - -namespace { - /// ToArgsList - Helper class to create a list of std::strings. - class ToArgsList { - std::vector<std::string> &Res; - public: - explicit ToArgsList(std::vector<std::string> &Res) : Res(Res) {} - - void push_back(StringRef Str) { - // Avoid creating a temporary string. - Res.push_back(std::string()); - Res.back().assign(Str.data(), Str.size()); - } - - void push_back(StringRef Str1, StringRef Str2) { - push_back(Str1); - push_back(Str2); - } - }; -} - -static void AnalyzerOptsToArgs(const AnalyzerOptions &Opts, ToArgsList &Res) { - if (Opts.ShowCheckerHelp) - Res.push_back("-analyzer-checker-help"); - if (Opts.AnalysisStoreOpt != RegionStoreModel) - Res.push_back("-analyzer-store", - getAnalysisStoreName(Opts.AnalysisStoreOpt)); - if (Opts.AnalysisConstraintsOpt != RangeConstraintsModel) - Res.push_back("-analyzer-constraints", - getAnalysisConstraintName(Opts.AnalysisConstraintsOpt)); - if (Opts.AnalysisDiagOpt != PD_HTML) - Res.push_back("-analyzer-output", - getAnalysisDiagClientName(Opts.AnalysisDiagOpt)); - if (Opts.AnalysisPurgeOpt != PurgeStmt) - Res.push_back("-analyzer-purge", - getAnalysisPurgeModeName(Opts.AnalysisPurgeOpt)); - if (!Opts.AnalyzeSpecificFunction.empty()) - Res.push_back("-analyze-function", Opts.AnalyzeSpecificFunction); - if (Opts.IPAMode != Inlining) - Res.push_back("-analyzer-ipa", getAnalysisIPAModeName(Opts.IPAMode)); - if (Opts.InliningMode != NoRedundancy) - Res.push_back("-analyzer-inlining-mode", - getAnalysisInliningModeName(Opts.InliningMode)); - - if (Opts.AnalyzeAll) - Res.push_back("-analyzer-opt-analyze-headers"); - if (Opts.AnalyzerDisplayProgress) - Res.push_back("-analyzer-display-progress"); - if (Opts.AnalyzeNestedBlocks) - Res.push_back("-analyzer-opt-analyze-nested-blocks"); - if (Opts.EagerlyAssume) - Res.push_back("-analyzer-eagerly-assume"); - if (Opts.TrimGraph) - Res.push_back("-trim-egraph"); - if (Opts.VisualizeEGDot) - Res.push_back("-analyzer-viz-egraph-graphviz"); - if (Opts.VisualizeEGUbi) - Res.push_back("-analyzer-viz-egraph-ubigraph"); - if (Opts.NoRetryExhausted) - Res.push_back("-analyzer-disable-retry-exhausted"); - - for (unsigned i = 0, e = Opts.CheckersControlList.size(); i != e; ++i) { - const std::pair<std::string, bool> &opt = Opts.CheckersControlList[i]; - if (opt.second) - Res.push_back("-analyzer-disable-checker"); - else - Res.push_back("-analyzer-checker"); - Res.push_back(opt.first); - } -} - -static void CodeGenOptsToArgs(const CodeGenOptions &Opts, ToArgsList &Res) { - switch (Opts.DebugInfo) { - case CodeGenOptions::NoDebugInfo: - break; - case CodeGenOptions::DebugLineTablesOnly: - Res.push_back("-gline-tables-only"); - break; - case CodeGenOptions::LimitedDebugInfo: - Res.push_back("-g"); - Res.push_back("-flimit-debug-info"); - break; - case CodeGenOptions::FullDebugInfo: - Res.push_back("-g"); - Res.push_back("-fno-limit-debug-info"); - break; - } - if (Opts.DisableLLVMOpts) - Res.push_back("-disable-llvm-optzns"); - if (Opts.DisableRedZone) - Res.push_back("-disable-red-zone"); - if (Opts.DisableTailCalls) - Res.push_back("-mdisable-tail-calls"); - if (!Opts.DebugCompilationDir.empty()) - Res.push_back("-fdebug-compilation-dir", Opts.DebugCompilationDir); - if (!Opts.DwarfDebugFlags.empty()) - Res.push_back("-dwarf-debug-flags", Opts.DwarfDebugFlags); - if (Opts.EmitGcovArcs) - Res.push_back("-femit-coverage-data"); - if (Opts.EmitGcovNotes) - Res.push_back("-femit-coverage-notes"); - if (Opts.EmitOpenCLArgMetadata) - Res.push_back("-cl-kernel-arg-info"); - if (!Opts.MergeAllConstants) - Res.push_back("-fno-merge-all-constants"); - if (Opts.NoCommon) - Res.push_back("-fno-common"); - if (Opts.ForbidGuardVariables) - Res.push_back("-fforbid-guard-variables"); - if (Opts.UseRegisterSizedBitfieldAccess) - Res.push_back("-fuse-register-sized-bitfield-access"); - if (Opts.NoImplicitFloat) - Res.push_back("-no-implicit-float"); - if (Opts.OmitLeafFramePointer) - Res.push_back("-momit-leaf-frame-pointer"); - if (Opts.OptimizeSize) { - assert(Opts.OptimizationLevel == 2 && "Invalid options!"); - Opts.OptimizeSize == 1 ? Res.push_back("-Os") : Res.push_back("-Oz"); - } else if (Opts.OptimizationLevel != 0) - Res.push_back("-O" + llvm::utostr(Opts.OptimizationLevel)); - if (!Opts.MainFileName.empty()) - Res.push_back("-main-file-name", Opts.MainFileName); - if (Opts.NoInfsFPMath) - Res.push_back("-menable-no-infinities"); - if (Opts.NoNaNsFPMath) - Res.push_back("-menable-no-nans"); - // SimplifyLibCalls is only derived. - // TimePasses is only derived. - // UnitAtATime is unused. - // Inlining is only derived. - - // UnrollLoops is derived, but also accepts an option, no - // harm in pushing it back here. - if (Opts.UnrollLoops) - Res.push_back("-funroll-loops"); - if (Opts.DataSections) - Res.push_back("-fdata-sections"); - if (Opts.FunctionSections) - Res.push_back("-ffunction-sections"); - if (Opts.AsmVerbose) - Res.push_back("-masm-verbose"); - if (!Opts.CodeModel.empty()) - Res.push_back("-mcode-model", Opts.CodeModel); - if (Opts.CUDAIsDevice) - Res.push_back("-fcuda-is-device"); - if (!Opts.CXAAtExit) - Res.push_back("-fno-use-cxa-atexit"); - if (Opts.CXXCtorDtorAliases) - Res.push_back("-mconstructor-aliases"); - if (Opts.ObjCAutoRefCountExceptions) - Res.push_back("-fobjc-arc-eh"); - if (!Opts.DebugPass.empty()) { - Res.push_back("-mdebug-pass", Opts.DebugPass); - } - if (Opts.DisableFPElim) - Res.push_back("-mdisable-fp-elim"); - if (!Opts.FloatABI.empty()) - Res.push_back("-mfloat-abi", Opts.FloatABI); - if (!Opts.LimitFloatPrecision.empty()) - Res.push_back("-mlimit-float-precision", Opts.LimitFloatPrecision); - if (Opts.NoZeroInitializedInBSS) - Res.push_back("-mno-zero-initialized-bss"); - switch (Opts.getObjCDispatchMethod()) { - case CodeGenOptions::Legacy: - break; - case CodeGenOptions::Mixed: - Res.push_back("-fobjc-dispatch-method=mixed"); - break; - case CodeGenOptions::NonLegacy: - Res.push_back("-fobjc-dispatch-method=non-legacy"); - break; - } - if (Opts.BoundsChecking > 0) - Res.push_back("-fbounds-checking=" + llvm::utostr(Opts.BoundsChecking)); - if (Opts.NumRegisterParameters) - Res.push_back("-mregparm", llvm::utostr(Opts.NumRegisterParameters)); - if (Opts.NoGlobalMerge) - Res.push_back("-mno-global-merge"); - if (Opts.NoExecStack) - Res.push_back("-mnoexecstack"); - if (Opts.RelaxAll) - Res.push_back("-mrelax-all"); - if (Opts.SaveTempLabels) - Res.push_back("-msave-temp-labels"); - if (Opts.NoDwarf2CFIAsm) - Res.push_back("-fno-dwarf2-cfi-asm"); - if (Opts.NoDwarfDirectoryAsm) - Res.push_back("-fno-dwarf-directory-asm"); - if (Opts.SoftFloat) - Res.push_back("-msoft-float"); - if (Opts.StrictEnums) - Res.push_back("-fstrict-enums"); - if (Opts.UnwindTables) - Res.push_back("-munwind-tables"); - if (Opts.RelocationModel != "pic") - Res.push_back("-mrelocation-model", Opts.RelocationModel); - if (!Opts.VerifyModule) - Res.push_back("-disable-llvm-verifier"); - for (unsigned i = 0, e = Opts.BackendOptions.size(); i != e; ++i) - Res.push_back("-backend-option", Opts.BackendOptions[i]); - - switch (Opts.DefaultTLSModel) { - case CodeGenOptions::GeneralDynamicTLSModel: - break; - case CodeGenOptions::LocalDynamicTLSModel: - Res.push_back("-ftls-model=local-dynamic"); - break; - case CodeGenOptions::InitialExecTLSModel: - Res.push_back("-ftls-model=initial-exec"); - break; - case CodeGenOptions::LocalExecTLSModel: - Res.push_back("-ftls-model=local-exec"); - break; - } -} - -static void DependencyOutputOptsToArgs(const DependencyOutputOptions &Opts, - ToArgsList &Res) { - if (Opts.IncludeSystemHeaders) - Res.push_back("-sys-header-deps"); - if (Opts.ShowHeaderIncludes) - Res.push_back("-H"); - if (!Opts.HeaderIncludeOutputFile.empty()) - Res.push_back("-header-include-file", Opts.HeaderIncludeOutputFile); - if (Opts.UsePhonyTargets) - Res.push_back("-MP"); - if (!Opts.OutputFile.empty()) - Res.push_back("-dependency-file", Opts.OutputFile); - for (unsigned i = 0, e = Opts.Targets.size(); i != e; ++i) - Res.push_back("-MT", Opts.Targets[i]); -} - -static void DiagnosticOptsToArgs(const DiagnosticOptions &Opts, - ToArgsList &Res) { - if (Opts.IgnoreWarnings) - Res.push_back("-w"); - if (Opts.NoRewriteMacros) - Res.push_back("-Wno-rewrite-macros"); - if (Opts.Pedantic) - Res.push_back("-pedantic"); - if (Opts.PedanticErrors) - Res.push_back("-pedantic-errors"); - if (!Opts.ShowColumn) - Res.push_back("-fno-show-column"); - if (!Opts.ShowLocation) - Res.push_back("-fno-show-source-location"); - if (!Opts.ShowCarets) - Res.push_back("-fno-caret-diagnostics"); - if (!Opts.ShowFixits) - Res.push_back("-fno-diagnostics-fixit-info"); - if (Opts.ShowSourceRanges) - Res.push_back("-fdiagnostics-print-source-range-info"); - if (Opts.ShowParseableFixits) - Res.push_back("-fdiagnostics-parseable-fixits"); - if (Opts.ShowColors) - Res.push_back("-fcolor-diagnostics"); - if (Opts.VerifyDiagnostics) - Res.push_back("-verify"); - if (Opts.ShowOptionNames) - Res.push_back("-fdiagnostics-show-option"); - if (Opts.ShowCategories == 1) - Res.push_back("-fdiagnostics-show-category=id"); - else if (Opts.ShowCategories == 2) - Res.push_back("-fdiagnostics-show-category=name"); - switch (Opts.Format) { - case DiagnosticOptions::Clang: - Res.push_back("-fdiagnostics-format=clang"); break; - case DiagnosticOptions::Msvc: - Res.push_back("-fdiagnostics-format=msvc"); break; - case DiagnosticOptions::Vi: - Res.push_back("-fdiagnostics-format=vi"); break; - } - if (Opts.ErrorLimit) - Res.push_back("-ferror-limit", llvm::utostr(Opts.ErrorLimit)); - if (!Opts.DiagnosticLogFile.empty()) - Res.push_back("-diagnostic-log-file", Opts.DiagnosticLogFile); - if (Opts.MacroBacktraceLimit - != DiagnosticOptions::DefaultMacroBacktraceLimit) - Res.push_back("-fmacro-backtrace-limit", - llvm::utostr(Opts.MacroBacktraceLimit)); - if (Opts.TemplateBacktraceLimit - != DiagnosticOptions::DefaultTemplateBacktraceLimit) - Res.push_back("-ftemplate-backtrace-limit", - llvm::utostr(Opts.TemplateBacktraceLimit)); - if (Opts.ConstexprBacktraceLimit - != DiagnosticOptions::DefaultConstexprBacktraceLimit) - Res.push_back("-fconstexpr-backtrace-limit", - llvm::utostr(Opts.ConstexprBacktraceLimit)); - - if (Opts.TabStop != DiagnosticOptions::DefaultTabStop) - Res.push_back("-ftabstop", llvm::utostr(Opts.TabStop)); - if (Opts.MessageLength) - Res.push_back("-fmessage-length", llvm::utostr(Opts.MessageLength)); - if (!Opts.DumpBuildInformation.empty()) - Res.push_back("-dump-build-information", Opts.DumpBuildInformation); - for (unsigned i = 0, e = Opts.Warnings.size(); i != e; ++i) - Res.push_back("-W" + Opts.Warnings[i]); -} - -static const char *getInputKindName(InputKind Kind) { - switch (Kind) { - case IK_None: break; - case IK_AST: return "ast"; - case IK_Asm: return "assembler-with-cpp"; - case IK_C: return "c"; - case IK_CXX: return "c++"; - case IK_LLVM_IR: return "ir"; - case IK_ObjC: return "objective-c"; - case IK_ObjCXX: return "objective-c++"; - case IK_OpenCL: return "cl"; - case IK_CUDA: return "cuda"; - case IK_PreprocessedC: return "cpp-output"; - case IK_PreprocessedCXX: return "c++-cpp-output"; - case IK_PreprocessedObjC: return "objective-c-cpp-output"; - case IK_PreprocessedObjCXX:return "objective-c++-cpp-output"; - } - - llvm_unreachable("Unexpected language kind!"); -} - -static const char *getActionName(frontend::ActionKind Kind) { - switch (Kind) { - case frontend::PluginAction: - llvm_unreachable("Invalid kind!"); - - case frontend::ASTDeclList: return "-ast-list"; - case frontend::ASTDump: return "-ast-dump"; - case frontend::ASTDumpXML: return "-ast-dump-xml"; - case frontend::ASTPrint: return "-ast-print"; - case frontend::ASTView: return "-ast-view"; - case frontend::DumpRawTokens: return "-dump-raw-tokens"; - case frontend::DumpTokens: return "-dump-tokens"; - case frontend::EmitAssembly: return "-S"; - case frontend::EmitBC: return "-emit-llvm-bc"; - case frontend::EmitHTML: return "-emit-html"; - case frontend::EmitLLVM: return "-emit-llvm"; - case frontend::EmitLLVMOnly: return "-emit-llvm-only"; - case frontend::EmitCodeGenOnly: return "-emit-codegen-only"; - case frontend::EmitObj: return "-emit-obj"; - case frontend::FixIt: return "-fixit"; - case frontend::GenerateModule: return "-emit-module"; - case frontend::GeneratePCH: return "-emit-pch"; - case frontend::GeneratePTH: return "-emit-pth"; - case frontend::InitOnly: return "-init-only"; - case frontend::ParseSyntaxOnly: return "-fsyntax-only"; - case frontend::PrintDeclContext: return "-print-decl-contexts"; - case frontend::PrintPreamble: return "-print-preamble"; - case frontend::PrintPreprocessedInput: return "-E"; - case frontend::RewriteMacros: return "-rewrite-macros"; - case frontend::RewriteObjC: return "-rewrite-objc"; - case frontend::RewriteTest: return "-rewrite-test"; - case frontend::RunAnalysis: return "-analyze"; - case frontend::MigrateSource: return "-migrate"; - case frontend::RunPreprocessorOnly: return "-Eonly"; - } - - llvm_unreachable("Unexpected language kind!"); -} - -static void FileSystemOptsToArgs(const FileSystemOptions &Opts, ToArgsList &Res){ - if (!Opts.WorkingDir.empty()) - Res.push_back("-working-directory", Opts.WorkingDir); -} - -static void CodeCompleteOptionsToArgs(const CodeCompleteOptions &Opts, - ToArgsList &Res) { - if (Opts.IncludeMacros) - Res.push_back("-code-completion-macros"); - if (Opts.IncludeCodePatterns) - Res.push_back("-code-completion-patterns"); - if (!Opts.IncludeGlobals) - Res.push_back("-no-code-completion-globals"); - if (Opts.IncludeBriefComments) - Res.push_back("-code-completion-brief-comments"); -} - -static void FrontendOptsToArgs(const FrontendOptions &Opts, ToArgsList &Res) { - if (Opts.DisableFree) - Res.push_back("-disable-free"); - if (Opts.RelocatablePCH) - Res.push_back("-relocatable-pch"); - if (Opts.ShowHelp) - Res.push_back("-help"); - if (Opts.ShowStats) - Res.push_back("-print-stats"); - if (Opts.ShowTimers) - Res.push_back("-ftime-report"); - if (Opts.ShowVersion) - Res.push_back("-version"); - if (Opts.FixWhatYouCan) - Res.push_back("-fix-what-you-can"); - if (Opts.FixOnlyWarnings) - Res.push_back("-fix-only-warnings"); - if (Opts.FixAndRecompile) - Res.push_back("-fixit-recompile"); - if (Opts.FixToTemporaries) - Res.push_back("-fixit-to-temporary"); - switch (Opts.ARCMTAction) { - case FrontendOptions::ARCMT_None: - break; - case FrontendOptions::ARCMT_Check: - Res.push_back("-arcmt-check"); - break; - case FrontendOptions::ARCMT_Modify: - Res.push_back("-arcmt-modify"); - break; - case FrontendOptions::ARCMT_Migrate: - Res.push_back("-arcmt-migrate"); - break; - } - CodeCompleteOptionsToArgs(Opts.CodeCompleteOpts, Res); - if (!Opts.MTMigrateDir.empty()) - Res.push_back("-mt-migrate-directory", Opts.MTMigrateDir); - if (!Opts.ARCMTMigrateReportOut.empty()) - Res.push_back("-arcmt-migrate-report-output", Opts.ARCMTMigrateReportOut); - if (Opts.ARCMTMigrateEmitARCErrors) - Res.push_back("-arcmt-migrate-emit-errors"); - - if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Literals) - Res.push_back("-objcmt-migrate-literals"); - if (Opts.ObjCMTAction & ~FrontendOptions::ObjCMT_Subscripting) - Res.push_back("-objcmt-migrate-subscripting"); - - bool NeedLang = false; - for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) - if (FrontendOptions::getInputKindForExtension(Opts.Inputs[i].File) != - Opts.Inputs[i].Kind) - NeedLang = true; - if (NeedLang) - Res.push_back("-x", getInputKindName(Opts.Inputs[0].Kind)); - for (unsigned i = 0, e = Opts.Inputs.size(); i != e; ++i) { - assert((!NeedLang || Opts.Inputs[i].Kind == Opts.Inputs[0].Kind) && - "Unable to represent this input vector!"); - Res.push_back(Opts.Inputs[i].File); - } - - if (!Opts.OutputFile.empty()) - Res.push_back("-o", Opts.OutputFile); - if (!Opts.CodeCompletionAt.FileName.empty()) - Res.push_back("-code-completion-at", - Opts.CodeCompletionAt.FileName + ":" + - llvm::utostr(Opts.CodeCompletionAt.Line) + ":" + - llvm::utostr(Opts.CodeCompletionAt.Column)); - if (Opts.ProgramAction != frontend::PluginAction) - Res.push_back(getActionName(Opts.ProgramAction)); - if (!Opts.ActionName.empty()) { - Res.push_back("-plugin", Opts.ActionName); - for(unsigned i = 0, e = Opts.PluginArgs.size(); i != e; ++i) - Res.push_back("-plugin-arg-" + Opts.ActionName, Opts.PluginArgs[i]); - } - if (!Opts.ASTDumpFilter.empty()) - Res.push_back("-ast-dump-filter", Opts.ASTDumpFilter); - for (unsigned i = 0, e = Opts.Plugins.size(); i != e; ++i) - Res.push_back("-load", Opts.Plugins[i]); - for (unsigned i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { - Res.push_back("-add-plugin", Opts.AddPluginActions[i]); - for(unsigned ai = 0, ae = Opts.AddPluginArgs.size(); ai != ae; ++ai) - Res.push_back("-plugin-arg-" + Opts.AddPluginActions[i], - Opts.AddPluginArgs[i][ai]); - } - for (unsigned i = 0, e = Opts.ASTMergeFiles.size(); i != e; ++i) - Res.push_back("-ast-merge", Opts.ASTMergeFiles[i]); - for (unsigned i = 0, e = Opts.LLVMArgs.size(); i != e; ++i) - Res.push_back("-mllvm", Opts.LLVMArgs[i]); - if (!Opts.OverrideRecordLayoutsFile.empty()) - Res.push_back("-foverride-record-layout=" + Opts.OverrideRecordLayoutsFile); -} - -static void HeaderSearchOptsToArgs(const HeaderSearchOptions &Opts, - ToArgsList &Res) { - if (Opts.Sysroot != "/") { - Res.push_back("-isysroot"); - Res.push_back(Opts.Sysroot); - } - - /// User specified include entries. - for (unsigned i = 0, e = Opts.UserEntries.size(); i != e; ++i) { - const HeaderSearchOptions::Entry &E = Opts.UserEntries[i]; - if (E.IsFramework && (E.Group != frontend::Angled || !E.IsUserSupplied)) - llvm::report_fatal_error("Invalid option set!"); - if (E.IsUserSupplied) { - switch (E.Group) { - case frontend::After: - Res.push_back("-idirafter"); - break; - - case frontend::Quoted: - Res.push_back("-iquote"); - break; - - case frontend::System: - Res.push_back("-isystem"); - break; - - case frontend::IndexHeaderMap: - Res.push_back("-index-header-map"); - Res.push_back(E.IsFramework? "-F" : "-I"); - break; - - case frontend::CSystem: - Res.push_back("-c-isystem"); - break; - - case frontend::CXXSystem: - Res.push_back("-cxx-isystem"); - break; - - case frontend::ObjCSystem: - Res.push_back("-objc-isystem"); - break; - - case frontend::ObjCXXSystem: - Res.push_back("-objcxx-isystem"); - break; - - case frontend::Angled: - Res.push_back(E.IsFramework ? "-F" : "-I"); - break; - } - } else { - if (E.IsInternal) { - assert(E.Group == frontend::System && "Unexpected header search group"); - if (E.ImplicitExternC) - Res.push_back("-internal-externc-isystem"); - else - Res.push_back("-internal-isystem"); - } else { - if (E.Group != frontend::Angled && E.Group != frontend::System) - llvm::report_fatal_error("Invalid option set!"); - Res.push_back(E.Group == frontend::Angled ? "-iwithprefixbefore" : - "-iwithprefix"); - } - } - Res.push_back(E.Path); - } - - /// User-specified system header prefixes. - for (unsigned i = 0, e = Opts.SystemHeaderPrefixes.size(); i != e; ++i) { - if (Opts.SystemHeaderPrefixes[i].IsSystemHeader) - Res.push_back("-isystem-prefix"); - else - Res.push_back("-ino-system-prefix"); - - Res.push_back(Opts.SystemHeaderPrefixes[i].Prefix); - } - - if (!Opts.ResourceDir.empty()) - Res.push_back("-resource-dir", Opts.ResourceDir); - if (!Opts.ModuleCachePath.empty()) - Res.push_back("-fmodule-cache-path", Opts.ModuleCachePath); - if (!Opts.UseStandardSystemIncludes) - Res.push_back("-nostdsysteminc"); - if (!Opts.UseStandardCXXIncludes) - Res.push_back("-nostdinc++"); - if (Opts.UseLibcxx) - Res.push_back("-stdlib=libc++"); - if (Opts.Verbose) - Res.push_back("-v"); -} - -static void LangOptsToArgs(const LangOptions &Opts, ToArgsList &Res) { - LangOptions DefaultLangOpts; - - // FIXME: Need to set -std to get all the implicit options. - - // FIXME: We want to only pass options relative to the defaults, which - // requires constructing a target. :( - // - // It would be better to push the all target specific choices into the driver, - // so that everything below that was more uniform. - - if (Opts.Trigraphs) - Res.push_back("-trigraphs"); - // Implicit based on the input kind: - // AsmPreprocessor, CPlusPlus, ObjC1, ObjC2, OpenCL - // Implicit based on the input language standard: - // BCPLComment, C99, CPlusPlus0x, Digraphs, GNUInline, ImplicitInt, GNUMode - if (Opts.DollarIdents) - Res.push_back("-fdollars-in-identifiers"); - if (Opts.GNUMode && !Opts.GNUKeywords) - Res.push_back("-fno-gnu-keywords"); - if (!Opts.GNUMode && Opts.GNUKeywords) - Res.push_back("-fgnu-keywords"); - if (Opts.MicrosoftExt) - Res.push_back("-fms-extensions"); - if (Opts.MicrosoftMode) - Res.push_back("-fms-compatibility"); - if (Opts.MSCVersion != 0) - Res.push_back("-fmsc-version=" + llvm::utostr(Opts.MSCVersion)); - if (Opts.Borland) - Res.push_back("-fborland-extensions"); - if (Opts.ObjCDefaultSynthProperties) - Res.push_back("-fobjc-default-synthesize-properties"); - // NoInline is implicit. - if (!Opts.CXXOperatorNames) - Res.push_back("-fno-operator-names"); - if (Opts.PascalStrings) - Res.push_back("-fpascal-strings"); - if (Opts.CatchUndefined) - Res.push_back("-fcatch-undefined-behavior"); - if (Opts.AddressSanitizer) - Res.push_back("-faddress-sanitizer"); - if (Opts.ThreadSanitizer) - Res.push_back("-fthread-sanitizer"); - if (Opts.WritableStrings) - Res.push_back("-fwritable-strings"); - if (Opts.ConstStrings) - Res.push_back("-fconst-strings"); - if (!Opts.LaxVectorConversions) - Res.push_back("-fno-lax-vector-conversions"); - if (Opts.AltiVec) - Res.push_back("-faltivec"); - if (Opts.Exceptions) - Res.push_back("-fexceptions"); - if (Opts.ObjCExceptions) - Res.push_back("-fobjc-exceptions"); - if (Opts.CXXExceptions) - Res.push_back("-fcxx-exceptions"); - if (Opts.SjLjExceptions) - Res.push_back("-fsjlj-exceptions"); - if (Opts.TraditionalCPP) - Res.push_back("-traditional-cpp"); - if (!Opts.RTTI) - Res.push_back("-fno-rtti"); - if (Opts.MSBitfields) - Res.push_back("-mms-bitfields"); - if (Opts.Freestanding) - Res.push_back("-ffreestanding"); - if (Opts.NoBuiltin) - Res.push_back("-fno-builtin"); - if (!Opts.AssumeSaneOperatorNew) - Res.push_back("-fno-assume-sane-operator-new"); - if (!Opts.ThreadsafeStatics) - Res.push_back("-fno-threadsafe-statics"); - if (Opts.POSIXThreads) - Res.push_back("-pthread"); - if (Opts.Blocks) - Res.push_back("-fblocks"); - if (Opts.BlocksRuntimeOptional) - Res.push_back("-fblocks-runtime-optional"); - if (Opts.Modules) - Res.push_back("-fmodules"); - if (Opts.EmitAllDecls) - Res.push_back("-femit-all-decls"); - if (Opts.MathErrno) - Res.push_back("-fmath-errno"); - switch (Opts.getSignedOverflowBehavior()) { - case LangOptions::SOB_Undefined: break; - case LangOptions::SOB_Defined: Res.push_back("-fwrapv"); break; - case LangOptions::SOB_Trapping: - Res.push_back("-ftrapv"); - if (!Opts.OverflowHandler.empty()) - Res.push_back("-ftrapv-handler", Opts.OverflowHandler); - break; - } - switch (Opts.getFPContractMode()) { - case LangOptions::FPC_Off: Res.push_back("-ffp-contract=off"); break; - case LangOptions::FPC_On: Res.push_back("-ffp-contract=on"); break; - case LangOptions::FPC_Fast: Res.push_back("-ffp-contract=fast"); break; - } - if (Opts.HeinousExtensions) - Res.push_back("-fheinous-gnu-extensions"); - // Optimize is implicit. - // OptimizeSize is implicit. - if (Opts.FastMath) - Res.push_back("-ffast-math"); - if (Opts.Static) - Res.push_back("-static-define"); - if (Opts.DumpRecordLayoutsSimple) - Res.push_back("-fdump-record-layouts-simple"); - else if (Opts.DumpRecordLayouts) - Res.push_back("-fdump-record-layouts"); - if (Opts.DumpVTableLayouts) - Res.push_back("-fdump-vtable-layouts"); - if (Opts.NoBitFieldTypeAlign) - Res.push_back("-fno-bitfield-type-alignment"); - if (Opts.PICLevel) - Res.push_back("-pic-level", llvm::utostr(Opts.PICLevel)); - if (Opts.PIELevel) - Res.push_back("-pie-level", llvm::utostr(Opts.PIELevel)); - if (Opts.ObjCGCBitmapPrint) - Res.push_back("-print-ivar-layout"); - if (Opts.NoConstantCFStrings) - Res.push_back("-fno-constant-cfstrings"); - if (!Opts.AccessControl) - Res.push_back("-fno-access-control"); - if (!Opts.CharIsSigned) - Res.push_back("-fno-signed-char"); - if (Opts.ShortWChar) - Res.push_back("-fshort-wchar"); - if (!Opts.ElideConstructors) - Res.push_back("-fno-elide-constructors"); - if (Opts.getGC() != LangOptions::NonGC) { - if (Opts.getGC() == LangOptions::HybridGC) { - Res.push_back("-fobjc-gc"); - } else { - assert(Opts.getGC() == LangOptions::GCOnly && "Invalid GC mode!"); - Res.push_back("-fobjc-gc-only"); - } - } - Res.push_back("-fobjc-runtime=" + Opts.ObjCRuntime.getAsString()); - if (Opts.ObjCAutoRefCount) - Res.push_back("-fobjc-arc"); - if (Opts.ObjCRuntimeHasWeak) - Res.push_back("-fobjc-runtime-has-weak"); - if (!Opts.ObjCInferRelatedResultType) - Res.push_back("-fno-objc-infer-related-result-type"); - - if (Opts.AppleKext) - Res.push_back("-fapple-kext"); - - if (Opts.getVisibilityMode() != DefaultVisibility) { - Res.push_back("-fvisibility"); - if (Opts.getVisibilityMode() == HiddenVisibility) { - Res.push_back("hidden"); - } else { - assert(Opts.getVisibilityMode() == ProtectedVisibility && - "Invalid visibility!"); - Res.push_back("protected"); - } - } - if (Opts.InlineVisibilityHidden) - Res.push_back("-fvisibility-inlines-hidden"); - - if (Opts.getStackProtector() != 0) - Res.push_back("-stack-protector", llvm::utostr(Opts.getStackProtector())); - if (Opts.InstantiationDepth != DefaultLangOpts.InstantiationDepth) - Res.push_back("-ftemplate-depth", llvm::utostr(Opts.InstantiationDepth)); - if (Opts.ConstexprCallDepth != DefaultLangOpts.ConstexprCallDepth) - Res.push_back("-fconstexpr-depth", llvm::utostr(Opts.ConstexprCallDepth)); - if (!Opts.ObjCConstantStringClass.empty()) - Res.push_back("-fconstant-string-class", Opts.ObjCConstantStringClass); - if (Opts.FakeAddressSpaceMap) - Res.push_back("-ffake-address-space-map"); - if (Opts.ParseUnknownAnytype) - Res.push_back("-funknown-anytype"); - if (Opts.DebuggerSupport) - Res.push_back("-fdebugger-support"); - if (Opts.DebuggerCastResultToId) - Res.push_back("-fdebugger-cast-result-to-id"); - if (Opts.DebuggerObjCLiteral) - Res.push_back("-fdebugger-objc-literal"); - if (Opts.DelayedTemplateParsing) - Res.push_back("-fdelayed-template-parsing"); - if (Opts.Deprecated) - Res.push_back("-fdeprecated-macro"); - if (Opts.ApplePragmaPack) - Res.push_back("-fapple-pragma-pack"); - if (!Opts.CurrentModule.empty()) - Res.push_back("-fmodule-name=" + Opts.CurrentModule); -} - -static void PreprocessorOptsToArgs(const PreprocessorOptions &Opts, - ToArgsList &Res) { - for (unsigned i = 0, e = Opts.Macros.size(); i != e; ++i) - Res.push_back(std::string(Opts.Macros[i].second ? "-U" : "-D") + - Opts.Macros[i].first); - for (unsigned i = 0, e = Opts.Includes.size(); i != e; ++i) { - // FIXME: We need to avoid reincluding the implicit PCH and PTH includes. - Res.push_back("-include", Opts.Includes[i]); - } - for (unsigned i = 0, e = Opts.MacroIncludes.size(); i != e; ++i) - Res.push_back("-imacros", Opts.MacroIncludes[i]); - if (!Opts.UsePredefines) - Res.push_back("-undef"); - if (Opts.DetailedRecord) - Res.push_back("-detailed-preprocessing-record"); - if (!Opts.ImplicitPCHInclude.empty()) - Res.push_back("-include-pch", Opts.ImplicitPCHInclude); - if (!Opts.ImplicitPTHInclude.empty()) - Res.push_back("-include-pth", Opts.ImplicitPTHInclude); - if (!Opts.TokenCache.empty()) { - if (Opts.ImplicitPTHInclude.empty()) - Res.push_back("-token-cache", Opts.TokenCache); - else - assert(Opts.ImplicitPTHInclude == Opts.TokenCache && - "Unsupported option combination!"); - } - for (unsigned i = 0, e = Opts.ChainedIncludes.size(); i != e; ++i) - Res.push_back("-chain-include", Opts.ChainedIncludes[i]); - for (unsigned i = 0, e = Opts.RemappedFiles.size(); i != e; ++i) { - Res.push_back("-remap-file", Opts.RemappedFiles[i].first + ";" + - Opts.RemappedFiles[i].second); - } -} - -static void PreprocessorOutputOptsToArgs(const PreprocessorOutputOptions &Opts, - ToArgsList &Res) { - if (!Opts.ShowCPP && !Opts.ShowMacros) - llvm::report_fatal_error("Invalid option combination!"); - - if (Opts.ShowCPP && Opts.ShowMacros) - Res.push_back("-dD"); - else if (!Opts.ShowCPP && Opts.ShowMacros) - Res.push_back("-dM"); - - if (!Opts.ShowLineMarkers) - Res.push_back("-P"); - if (Opts.ShowComments) - Res.push_back("-C"); - if (Opts.ShowMacroComments) - Res.push_back("-CC"); -} - -static void TargetOptsToArgs(const TargetOptions &Opts, - ToArgsList &Res) { - Res.push_back("-triple"); - Res.push_back(Opts.Triple); - if (!Opts.CPU.empty()) - Res.push_back("-target-cpu", Opts.CPU); - if (!Opts.ABI.empty()) - Res.push_back("-target-abi", Opts.ABI); - if (!Opts.LinkerVersion.empty()) - Res.push_back("-target-linker-version", Opts.LinkerVersion); - if (!Opts.CXXABI.empty()) - Res.push_back("-cxx-abi", Opts.CXXABI); - for (unsigned i = 0, e = Opts.Features.size(); i != e; ++i) - Res.push_back("-target-feature", Opts.Features[i]); -} - -void CompilerInvocation::toArgs(std::vector<std::string> &Res) const { - ToArgsList List(Res); - AnalyzerOptsToArgs(getAnalyzerOpts(), List); - CodeGenOptsToArgs(getCodeGenOpts(), List); - DependencyOutputOptsToArgs(getDependencyOutputOpts(), List); - DiagnosticOptsToArgs(getDiagnosticOpts(), List); - FileSystemOptsToArgs(getFileSystemOpts(), List); - FrontendOptsToArgs(getFrontendOpts(), List); - HeaderSearchOptsToArgs(getHeaderSearchOpts(), List); - LangOptsToArgs(*getLangOpts(), List); - PreprocessorOptsToArgs(getPreprocessorOpts(), List); - PreprocessorOutputOptsToArgs(getPreprocessorOutputOpts(), List); - TargetOptsToArgs(getTargetOpts(), List); -} - -//===----------------------------------------------------------------------===// -// Deserialization (to args) +// Deserialization (from args) //===----------------------------------------------------------------------===// using namespace clang::driver; @@ -965,7 +71,7 @@ static unsigned getOptimizationLevel(ArgList &Args, InputKind IK, assert (A->getOption().matches(options::OPT_O)); - llvm::StringRef S(A->getValue(Args)); + llvm::StringRef S(A->getValue()); if (S == "s" || S == "z" || S.empty()) return 2; @@ -979,7 +85,7 @@ static unsigned getOptimizationLevelSize(ArgList &Args, InputKind IK, DiagnosticsEngine &Diags) { if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { if (A->getOption().matches(options::OPT_O)) { - switch (A->getValue(Args)[0]) { + switch (A->getValue()[0]) { default: return 0; case 's': @@ -996,14 +102,14 @@ static void addWarningArgs(ArgList &Args, std::vector<std::string> &Warnings) { for (arg_iterator I = Args.filtered_begin(OPT_W_Group), E = Args.filtered_end(); I != E; ++I) { Arg *A = *I; - // If the argument is a pure flag, add its name (minus the "-W" at the beginning) + // If the argument is a pure flag, add its name (minus the "W" at the beginning) // to the warning list. Else, add its value (for the OPT_W case). if (A->getOption().getKind() == Option::FlagClass) { - Warnings.push_back(A->getOption().getName().substr(2)); + Warnings.push_back(A->getOption().getName().substr(1)); } else { for (unsigned Idx = 0, End = A->getNumValues(); Idx < End; ++Idx) { - StringRef V = A->getValue(Args, Idx); + StringRef V = A->getValue(Idx); // "-Wl," and such are not warning options. // FIXME: Should be handled by putting these in separate flags. if (V.startswith("l,") || V.startswith("a,") || V.startswith("p,")) @@ -1020,11 +126,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, using namespace options; bool Success = true; if (Arg *A = Args.getLastArg(OPT_analyzer_store)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisStores Value = llvm::StringSwitch<AnalysisStores>(Name) #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATFN) \ .Case(CMDFLAG, NAME##Model) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NumStores); if (Value == NumStores) { Diags.Report(diag::err_drv_invalid_value) @@ -1036,11 +142,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_constraints)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisConstraints Value = llvm::StringSwitch<AnalysisConstraints>(Name) #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATFN) \ .Case(CMDFLAG, NAME##Model) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NumConstraints); if (Value == NumConstraints) { Diags.Report(diag::err_drv_invalid_value) @@ -1052,11 +158,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_output)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisDiagClients Value = llvm::StringSwitch<AnalysisDiagClients>(Name) #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATFN, AUTOCREAT) \ .Case(CMDFLAG, PD_##NAME) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NUM_ANALYSIS_DIAG_CLIENTS); if (Value == NUM_ANALYSIS_DIAG_CLIENTS) { Diags.Report(diag::err_drv_invalid_value) @@ -1068,11 +174,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_purge)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisPurgeMode Value = llvm::StringSwitch<AnalysisPurgeMode>(Name) #define ANALYSIS_PURGE(NAME, CMDFLAG, DESC) \ .Case(CMDFLAG, NAME) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NumPurgeModes); if (Value == NumPurgeModes) { Diags.Report(diag::err_drv_invalid_value) @@ -1084,11 +190,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_ipa)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisIPAMode Value = llvm::StringSwitch<AnalysisIPAMode>(Name) #define ANALYSIS_IPA(NAME, CMDFLAG, DESC) \ .Case(CMDFLAG, NAME) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NumIPAModes); if (Value == NumIPAModes) { Diags.Report(diag::err_drv_invalid_value) @@ -1100,11 +206,11 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_analyzer_inlining_mode)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); AnalysisInliningMode Value = llvm::StringSwitch<AnalysisInliningMode>(Name) #define ANALYSIS_INLINING_MODE(NAME, CMDFLAG, DESC) \ .Case(CMDFLAG, NAME) -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" .Default(NumInliningModes); if (Value == NumInliningModes) { Diags.Report(diag::err_drv_invalid_value) @@ -1116,21 +222,21 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, } Opts.ShowCheckerHelp = Args.hasArg(OPT_analyzer_checker_help); - Opts.VisualizeEGDot = Args.hasArg(OPT_analyzer_viz_egraph_graphviz); - Opts.VisualizeEGUbi = Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); + Opts.visualizeExplodedGraphWithGraphViz = + Args.hasArg(OPT_analyzer_viz_egraph_graphviz); + Opts.visualizeExplodedGraphWithUbiGraph = + Args.hasArg(OPT_analyzer_viz_egraph_ubigraph); Opts.NoRetryExhausted = Args.hasArg(OPT_analyzer_disable_retry_exhausted); Opts.AnalyzeAll = Args.hasArg(OPT_analyzer_opt_analyze_headers); Opts.AnalyzerDisplayProgress = Args.hasArg(OPT_analyzer_display_progress); Opts.AnalyzeNestedBlocks = Args.hasArg(OPT_analyzer_opt_analyze_nested_blocks); - Opts.EagerlyAssume = Args.hasArg(OPT_analyzer_eagerly_assume); + Opts.eagerlyAssumeBinOpBifurcation = Args.hasArg(OPT_analyzer_eagerly_assume); Opts.AnalyzeSpecificFunction = Args.getLastArgValue(OPT_analyze_function); Opts.UnoptimizedCFG = Args.hasArg(OPT_analysis_UnoptimizedCFG); - Opts.CFGAddImplicitDtors = Args.hasArg(OPT_analysis_CFGAddImplicitDtors); Opts.TrimGraph = Args.hasArg(OPT_trim_egraph); Opts.MaxNodes = Args.getLastArgIntValue(OPT_analyzer_max_nodes, 150000,Diags); - Opts.MaxLoop = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags); - Opts.EagerlyTrimEGraph = !Args.hasArg(OPT_analyzer_no_eagerly_trim_egraph); + Opts.maxBlockVisitOnPath = Args.getLastArgIntValue(OPT_analyzer_max_loop, 4, Diags); Opts.PrintStats = Args.hasArg(OPT_analyzer_stats); Opts.InlineMaxStackDepth = Args.getLastArgIntValue(OPT_analyzer_inline_max_stack_depth, @@ -1148,12 +254,42 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, bool enable = (A->getOption().getID() == OPT_analyzer_checker); // We can have a list of comma separated checker names, e.g: // '-analyzer-checker=cocoa,unix' - StringRef checkerList = A->getValue(Args); + StringRef checkerList = A->getValue(); SmallVector<StringRef, 4> checkers; checkerList.split(checkers, ","); for (unsigned i = 0, e = checkers.size(); i != e; ++i) Opts.CheckersControlList.push_back(std::make_pair(checkers[i], enable)); } + + // Go through the analyzer configuration options. + for (arg_iterator it = Args.filtered_begin(OPT_analyzer_config), + ie = Args.filtered_end(); it != ie; ++it) { + const Arg *A = *it; + A->claim(); + // We can have a list of comma separated config names, e.g: + // '-analyzer-config key1=val1,key2=val2' + StringRef configList = A->getValue(); + SmallVector<StringRef, 4> configVals; + configList.split(configVals, ","); + for (unsigned i = 0, e = configVals.size(); i != e; ++i) { + StringRef key, val; + llvm::tie(key, val) = configVals[i].split("="); + if (val.empty()) { + Diags.Report(SourceLocation(), + diag::err_analyzer_config_no_value) << configVals[i]; + Success = false; + break; + } + if (val.find('=') != StringRef::npos) { + Diags.Report(SourceLocation(), + diag::err_analyzer_config_multiple_values) + << configVals[i]; + Success = false; + break; + } + Opts.Config[key] = val; + } + } return Success; } @@ -1179,21 +315,23 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.OptimizationLevel = OptLevel; // We must always run at least the always inlining pass. - Opts.Inlining = (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining - : CodeGenOptions::OnlyAlwaysInlining; + Opts.setInlining( + (Opts.OptimizationLevel > 1) ? CodeGenOptions::NormalInlining + : CodeGenOptions::OnlyAlwaysInlining); // -fno-inline-functions overrides OptimizationLevel > 1. Opts.NoInline = Args.hasArg(OPT_fno_inline); - Opts.Inlining = Args.hasArg(OPT_fno_inline_functions) ? - CodeGenOptions::OnlyAlwaysInlining : Opts.Inlining; + Opts.setInlining(Args.hasArg(OPT_fno_inline_functions) ? + CodeGenOptions::OnlyAlwaysInlining : Opts.getInlining()); if (Args.hasArg(OPT_gline_tables_only)) { - Opts.DebugInfo = CodeGenOptions::DebugLineTablesOnly; + Opts.setDebugInfo(CodeGenOptions::DebugLineTablesOnly); } else if (Args.hasArg(OPT_g_Flag)) { if (Args.hasFlag(OPT_flimit_debug_info, OPT_fno_limit_debug_info, true)) - Opts.DebugInfo = CodeGenOptions::LimitedDebugInfo; + Opts.setDebugInfo(CodeGenOptions::LimitedDebugInfo); else - Opts.DebugInfo = CodeGenOptions::FullDebugInfo; + Opts.setDebugInfo(CodeGenOptions::FullDebugInfo); } + Opts.DebugColumnInfo = Args.hasArg(OPT_dwarf_column_info); Opts.DisableLLVMOpts = Args.hasArg(OPT_disable_llvm_optzns); Opts.DisableRedZone = Args.hasArg(OPT_disable_red_zone); @@ -1263,18 +401,21 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.EmitGcovArcs = Args.hasArg(OPT_femit_coverage_data); Opts.EmitGcovNotes = Args.hasArg(OPT_femit_coverage_notes); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); - Opts.EmitMicrosoftInlineAsm = Args.hasArg(OPT_fenable_experimental_ms_inline_asm); Opts.CoverageFile = Args.getLastArgValue(OPT_coverage_file); Opts.DebugCompilationDir = Args.getLastArgValue(OPT_fdebug_compilation_dir); Opts.LinkBitcodeFile = Args.getLastArgValue(OPT_mlink_bitcode_file); + Opts.SSPBufferSize = + Args.getLastArgIntValue(OPT_stack_protector_buffer_size, 8, Diags); Opts.StackRealignment = Args.hasArg(OPT_mstackrealign); if (Arg *A = Args.getLastArg(OPT_mstack_alignment)) { - StringRef Val = A->getValue(Args); - Val.getAsInteger(10, Opts.StackAlignment); + StringRef Val = A->getValue(); + unsigned StackAlignment = Opts.StackAlignment; + Val.getAsInteger(10, StackAlignment); + Opts.StackAlignment = StackAlignment; } if (Arg *A = Args.getLastArg(OPT_fobjc_dispatch_method_EQ)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); unsigned Method = llvm::StringSwitch<unsigned>(Name) .Case("legacy", CodeGenOptions::Legacy) .Case("non-legacy", CodeGenOptions::NonLegacy) @@ -1284,12 +425,13 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; Success = false; } else { - Opts.ObjCDispatchMethod = Method; + Opts.setObjCDispatchMethod( + static_cast<CodeGenOptions::ObjCDispatchMethodKind>(Method)); } } if (Arg *A = Args.getLastArg(OPT_ftlsmodel_EQ)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); unsigned Model = llvm::StringSwitch<unsigned>(Name) .Case("global-dynamic", CodeGenOptions::GeneralDynamicTLSModel) .Case("local-dynamic", CodeGenOptions::LocalDynamicTLSModel) @@ -1300,7 +442,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Name; Success = false; } else { - Opts.DefaultTLSModel = static_cast<CodeGenOptions::TLSModel>(Model); + Opts.setDefaultTLSModel(static_cast<CodeGenOptions::TLSModel>(Model)); } } @@ -1351,9 +493,9 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, StringRef ShowOverloads = Args.getLastArgValue(OPT_fshow_overloads_EQ, "all"); if (ShowOverloads == "best") - Opts.ShowOverloads = DiagnosticsEngine::Ovl_Best; + Opts.setShowOverloads(Ovl_Best); else if (ShowOverloads == "all") - Opts.ShowOverloads = DiagnosticsEngine::Ovl_All; + Opts.setShowOverloads(Ovl_All); else { Success = false; if (Diags) @@ -1381,11 +523,11 @@ bool clang::ParseDiagnosticArgs(DiagnosticOptions &Opts, ArgList &Args, StringRef Format = Args.getLastArgValue(OPT_fdiagnostics_format, "clang"); if (Format == "clang") - Opts.Format = DiagnosticOptions::Clang; + Opts.setFormat(DiagnosticOptions::Clang); else if (Format == "msvc") - Opts.Format = DiagnosticOptions::Msvc; + Opts.setFormat(DiagnosticOptions::Msvc); else if (Format == "vi") - Opts.Format = DiagnosticOptions::Vi; + Opts.setFormat(DiagnosticOptions::Vi); else { Success = false; if (Diags) @@ -1467,7 +609,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, case OPT_emit_obj: Opts.ProgramAction = frontend::EmitObj; break; case OPT_fixit_EQ: - Opts.FixItSuffix = A->getValue(Args); + Opts.FixItSuffix = A->getValue(); // fall-through! case OPT_fixit: Opts.ProgramAction = frontend::FixIt; break; @@ -1503,14 +645,14 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, } if (const Arg* A = Args.getLastArg(OPT_plugin)) { - Opts.Plugins.push_back(A->getValue(Args,0)); + Opts.Plugins.push_back(A->getValue(0)); Opts.ProgramAction = frontend::PluginAction; - Opts.ActionName = A->getValue(Args); + Opts.ActionName = A->getValue(); for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg), end = Args.filtered_end(); it != end; ++it) { - if ((*it)->getValue(Args, 0) == Opts.ActionName) - Opts.PluginArgs.push_back((*it)->getValue(Args, 1)); + if ((*it)->getValue(0) == Opts.ActionName) + Opts.PluginArgs.push_back((*it)->getValue(1)); } } @@ -1519,17 +661,17 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, for (int i = 0, e = Opts.AddPluginActions.size(); i != e; ++i) { for (arg_iterator it = Args.filtered_begin(OPT_plugin_arg), end = Args.filtered_end(); it != end; ++it) { - if ((*it)->getValue(Args, 0) == Opts.AddPluginActions[i]) - Opts.AddPluginArgs[i].push_back((*it)->getValue(Args, 1)); + if ((*it)->getValue(0) == Opts.AddPluginActions[i]) + Opts.AddPluginArgs[i].push_back((*it)->getValue(1)); } } if (const Arg *A = Args.getLastArg(OPT_code_completion_at)) { Opts.CodeCompletionAt = - ParsedSourceLocation::FromString(A->getValue(Args)); + ParsedSourceLocation::FromString(A->getValue()); if (Opts.CodeCompletionAt.FileName.empty()) Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(Args); + << A->getAsString(Args) << A->getValue(); } Opts.DisableFree = Args.hasArg(OPT_disable_free); @@ -1595,7 +737,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, InputKind DashX = IK_None; if (const Arg *A = Args.getLastArg(OPT_x)) { - DashX = llvm::StringSwitch<InputKind>(A->getValue(Args)) + DashX = llvm::StringSwitch<InputKind>(A->getValue()) .Case("c", IK_C) .Case("cl", IK_OpenCL) .Case("cuda", IK_CUDA) @@ -1619,7 +761,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, .Default(IK_None); if (DashX == IK_None) Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(Args); + << A->getAsString(Args) << A->getValue(); } // '-' is the default input if none is given. @@ -1667,7 +809,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { Opts.UseStandardSystemIncludes = !Args.hasArg(OPT_nostdsysteminc); Opts.UseStandardCXXIncludes = !Args.hasArg(OPT_nostdincxx); if (const Arg *A = Args.getLastArg(OPT_stdlib_EQ)) - Opts.UseLibcxx = (strcmp(A->getValue(Args), "libc++") == 0); + Opts.UseLibcxx = (strcmp(A->getValue(), "libc++") == 0); Opts.ResourceDir = Args.getLastArgValue(OPT_resource_dir); Opts.ModuleCachePath = Args.getLastArgValue(OPT_fmodule_cache_path); Opts.DisableModuleHash = Args.hasArg(OPT_fdisable_module_hash); @@ -1686,7 +828,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { frontend::IncludeDirGroup Group = IsIndexHeaderMap? frontend::IndexHeaderMap : frontend::Angled; - Opts.AddPath((*it)->getValue(Args), Group, true, + Opts.AddPath((*it)->getValue(), Group, true, /*IsFramework=*/ (*it)->getOption().matches(OPT_F), false); IsIndexHeaderMap = false; } @@ -1698,43 +840,43 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; if (A->getOption().matches(OPT_iprefix)) - Prefix = A->getValue(Args); + Prefix = A->getValue(); else if (A->getOption().matches(OPT_iwithprefix)) - Opts.AddPath(Prefix.str() + A->getValue(Args), + Opts.AddPath(Prefix.str() + A->getValue(), frontend::System, false, false, false); else - Opts.AddPath(Prefix.str() + A->getValue(Args), + Opts.AddPath(Prefix.str() + A->getValue(), frontend::Angled, false, false, false); } for (arg_iterator it = Args.filtered_begin(OPT_idirafter), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::After, true, false, false); + Opts.AddPath((*it)->getValue(), frontend::After, true, false, false); for (arg_iterator it = Args.filtered_begin(OPT_iquote), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::Quoted, true, false, false); + Opts.AddPath((*it)->getValue(), frontend::Quoted, true, false, false); for (arg_iterator it = Args.filtered_begin(OPT_isystem, OPT_iwithsysroot), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::System, true, false, + Opts.AddPath((*it)->getValue(), frontend::System, true, false, !(*it)->getOption().matches(OPT_iwithsysroot)); for (arg_iterator it = Args.filtered_begin(OPT_iframework), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::System, true, true, + Opts.AddPath((*it)->getValue(), frontend::System, true, true, true); // Add the paths for the various language specific isystem flags. for (arg_iterator it = Args.filtered_begin(OPT_c_isystem), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::CSystem, true, false, true); + Opts.AddPath((*it)->getValue(), frontend::CSystem, true, false, true); for (arg_iterator it = Args.filtered_begin(OPT_cxx_isystem), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::CXXSystem, true, false, true); + Opts.AddPath((*it)->getValue(), frontend::CXXSystem, true, false, true); for (arg_iterator it = Args.filtered_begin(OPT_objc_isystem), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::ObjCSystem, true, false,true); + Opts.AddPath((*it)->getValue(), frontend::ObjCSystem, true, false,true); for (arg_iterator it = Args.filtered_begin(OPT_objcxx_isystem), ie = Args.filtered_end(); it != ie; ++it) - Opts.AddPath((*it)->getValue(Args), frontend::ObjCXXSystem, true, false, + Opts.AddPath((*it)->getValue(), frontend::ObjCXXSystem, true, false, true); // Add the internal paths from a driver that detects standard include paths. @@ -1742,7 +884,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { OPT_internal_externc_isystem), E = Args.filtered_end(); I != E; ++I) - Opts.AddPath((*I)->getValue(Args), frontend::System, + Opts.AddPath((*I)->getValue(), frontend::System, false, false, /*IgnoreSysRoot=*/true, /*IsInternal=*/true, (*I)->getOption().matches(OPT_internal_externc_isystem)); @@ -1751,7 +893,7 @@ static void ParseHeaderSearchArgs(HeaderSearchOptions &Opts, ArgList &Args) { OPT_ino_system_prefix), E = Args.filtered_end(); I != E; ++I) - Opts.AddSystemHeaderPrefix((*I)->getValue(Args), + Opts.AddSystemHeaderPrefix((*I)->getValue(), (*I)->getOption().matches(OPT_isystem_prefix)); } @@ -1799,11 +941,12 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, } const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); - Opts.BCPLComment = Std.hasBCPLComments(); + Opts.LineComment = Std.hasLineComments(); Opts.C99 = Std.isC99(); Opts.C11 = Std.isC11(); Opts.CPlusPlus = Std.isCPlusPlus(); Opts.CPlusPlus0x = Std.isCPlusPlus0x(); + Opts.CPlusPlus1y = Std.isCPlusPlus1y(); Opts.Digraphs = Std.hasDigraphs(); Opts.GNUMode = Std.isGNUMode(); Opts.GNUInline = !Std.isC99(); @@ -1838,6 +981,9 @@ void CompilerInvocation::setLangDefaults(LangOptions &Opts, InputKind IK, // OpenCL and C++ both have bool, true, false keywords. Opts.Bool = Opts.OpenCL || Opts.CPlusPlus; + // C++ has wchar_t keyword. + Opts.WChar = Opts.CPlusPlus; + Opts.GNUKeywords = Opts.GNUMode; Opts.CXXOperatorNames = Opts.CPlusPlus; @@ -1853,14 +999,14 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // FIXME: Cleanup per-file based stuff. LangStandard::Kind LangStd = LangStandard::lang_unspecified; if (const Arg *A = Args.getLastArg(OPT_std_EQ)) { - LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args)) + LangStd = llvm::StringSwitch<LangStandard::Kind>(A->getValue()) #define LANGSTANDARD(id, name, desc, features) \ .Case(name, LangStandard::lang_##id) #include "clang/Frontend/LangStandards.def" .Default(LangStandard::lang_unspecified); if (LangStd == LangStandard::lang_unspecified) Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(Args); + << A->getAsString(Args) << A->getValue(); else { // Valid standard, check to make sure language and standard are compatable. const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd); @@ -1901,7 +1047,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, // Override the -std option in this case. if (const Arg *A = Args.getLastArg(OPT_cl_std_EQ)) { LangStandard::Kind OpenCLLangStd - = llvm::StringSwitch<LangStandard::Kind>(A->getValue(Args)) + = llvm::StringSwitch<LangStandard::Kind>(A->getValue()) .Case("CL", LangStandard::lang_opencl) .Case("CL1.1", LangStandard::lang_opencl11) .Case("CL1.2", LangStandard::lang_opencl12) @@ -1909,7 +1055,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (OpenCLLangStd == LangStandard::lang_unspecified) { Diags.Report(diag::err_drv_invalid_value) - << A->getAsString(Args) << A->getValue(Args); + << A->getAsString(Args) << A->getValue(); } else LangStd = OpenCLLangStd; @@ -1930,7 +1076,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, if (Opts.ObjC1) { if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) { - StringRef value = arg->getValue(Args); + StringRef value = arg->getValue(); if (Opts.ObjCRuntime.tryParse(value)) Diags.Report(diag::err_drv_unknown_objc_runtime) << value; } @@ -1941,14 +1087,16 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.setGC(LangOptions::HybridGC); else if (Args.hasArg(OPT_fobjc_arc)) { Opts.ObjCAutoRefCount = 1; - if (!Opts.ObjCRuntime.isNonFragile()) - Diags.Report(diag::err_arc_nonfragile_abi); + if (!Opts.ObjCRuntime.allowsARC()) + Diags.Report(diag::err_arc_unsupported_on_runtime); + + // Only set ObjCARCWeak if ARC is enabled. + if (Args.hasArg(OPT_fobjc_runtime_has_weak)) + Opts.ObjCARCWeak = 1; + else + Opts.ObjCARCWeak = Opts.ObjCRuntime.allowsWeak(); } - Opts.ObjCRuntimeHasWeak = Opts.ObjCRuntime.hasWeak(); - if (Args.hasArg(OPT_fobjc_runtime_has_weak)) - Opts.ObjCRuntimeHasWeak = 1; - if (Args.hasArg(OPT_fno_objc_infer_related_result_type)) Opts.ObjCInferRelatedResultType = 0; } @@ -1990,7 +1138,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis; if (Arg *A = Args.getLastArg(OPT_ffp_contract)) { - StringRef Val = A->getValue(Args); + StringRef Val = A->getValue(); if (Val == "fast") Opts.setFPContractMode(LangOptions::FPC_Fast); else if (Val == "on") @@ -2043,6 +1191,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional); Opts.Modules = Args.hasArg(OPT_fmodules); Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char); + Opts.WChar = Opts.CPlusPlus && !Args.hasArg(OPT_fno_wchar); Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar); Opts.ShortEnums = Args.hasArg(OPT_fshort_enums); Opts.Freestanding = Args.hasArg(OPT_ffreestanding); @@ -2064,7 +1213,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Args.getLastArgValue(OPT_fconstant_string_class); Opts.ObjCDefaultSynthProperties = Args.hasArg(OPT_fobjc_default_synthesize_properties); - Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior); + Opts.EncodeExtendedBlockSig = + Args.hasArg(OPT_fencode_extended_block_signature); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); Opts.PackStruct = Args.getLastArgIntValue(OPT_fpack_struct_EQ, 0, Diags); Opts.PICLevel = Args.getLastArgIntValue(OPT_pic_level, 0, Diags); @@ -2085,8 +1235,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.DebuggerSupport = Args.hasArg(OPT_fdebugger_support); Opts.DebuggerCastResultToId = Args.hasArg(OPT_fdebugger_cast_result_to_id); Opts.DebuggerObjCLiteral = Args.hasArg(OPT_fdebugger_objc_literal); - Opts.AddressSanitizer = Args.hasArg(OPT_faddress_sanitizer); - Opts.ThreadSanitizer = Args.hasArg(OPT_fthread_sanitizer); Opts.ApplePragmaPack = Args.hasArg(OPT_fapple_pragma_pack); Opts.CurrentModule = Args.getLastArgValue(OPT_fmodule_name); @@ -2109,6 +1257,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.FastMath = Args.hasArg(OPT_ffast_math); Opts.FiniteMathOnly = Args.hasArg(OPT_ffinite_math_only); + Opts.EmitMicrosoftInlineAsm = Args.hasArg(OPT_fenable_experimental_ms_inline_asm); + + Opts.RetainCommentsFromSystemHeaders = + Args.hasArg(OPT_fretain_comments_from_system_headers); + unsigned SSP = Args.getLastArgIntValue(OPT_stack_protector, 0, Diags); switch (SSP) { default: @@ -2119,6 +1272,37 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, case 1: Opts.setStackProtector(LangOptions::SSPOn); break; case 2: Opts.setStackProtector(LangOptions::SSPReq); break; } + + // Parse -fsanitize= arguments. + std::vector<std::string> Sanitizers = Args.getAllArgValues(OPT_fsanitize_EQ); + for (unsigned I = 0, N = Sanitizers.size(); I != N; ++I) { + // Since the Opts.Sanitize* values are bitfields, it's a little tricky to + // efficiently map string values to them. Perform the mapping indirectly: + // convert strings to enumerated values, then switch over the enum to set + // the right bitfield value. + enum Sanitizer { +#define SANITIZER(NAME, ID) \ + ID, +#include "clang/Basic/Sanitizers.def" + Unknown + }; + switch (llvm::StringSwitch<unsigned>(Sanitizers[I]) +#define SANITIZER(NAME, ID) \ + .Case(NAME, ID) +#include "clang/Basic/Sanitizers.def" + .Default(Unknown)) { +#define SANITIZER(NAME, ID) \ + case ID: \ + Opts.Sanitize##ID = true; \ + break; +#include "clang/Basic/Sanitizers.def" + + case Unknown: + Diags.Report(diag::err_drv_invalid_value) + << "-fsanitize=" << Sanitizers[I]; + break; + } + } } static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, @@ -2128,7 +1312,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, Opts.ImplicitPCHInclude = Args.getLastArgValue(OPT_include_pch); Opts.ImplicitPTHInclude = Args.getLastArgValue(OPT_include_pth); if (const Arg *A = Args.getLastArg(OPT_token_cache)) - Opts.TokenCache = A->getValue(Args); + Opts.TokenCache = A->getValue(); else Opts.TokenCache = Opts.ImplicitPTHInclude; Opts.UsePredefines = !Args.hasArg(OPT_undef); @@ -2139,11 +1323,11 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, for (arg_iterator it = Args.filtered_begin(OPT_error_on_deserialized_pch_decl), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; - Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue(Args)); + Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue()); } if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { - StringRef Value(A->getValue(Args)); + StringRef Value(A->getValue()); size_t Comma = Value.find(','); unsigned Bytes = 0; unsigned EndOfLine = 0; @@ -2162,9 +1346,9 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, for (arg_iterator it = Args.filtered_begin(OPT_D, OPT_U), ie = Args.filtered_end(); it != ie; ++it) { if ((*it)->getOption().matches(OPT_D)) - Opts.addMacroDef((*it)->getValue(Args)); + Opts.addMacroDef((*it)->getValue()); else - Opts.addMacroUndef((*it)->getValue(Args)); + Opts.addMacroUndef((*it)->getValue()); } Opts.MacroIncludes = Args.getAllArgValues(OPT_imacros); @@ -2174,22 +1358,13 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, OPT_include_pth), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; - // PCH is handled specially, we need to extra the original include path. - if (A->getOption().matches(OPT_include_pch)) { - std::string OriginalFile = - ASTReader::getOriginalSourceFile(A->getValue(Args), FileMgr, Diags); - if (OriginalFile.empty()) - continue; - - Opts.Includes.push_back(OriginalFile); - } else - Opts.Includes.push_back(A->getValue(Args)); + Opts.Includes.push_back(A->getValue()); } for (arg_iterator it = Args.filtered_begin(OPT_chain_include), ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; - Opts.ChainedIncludes.push_back(A->getValue(Args)); + Opts.ChainedIncludes.push_back(A->getValue()); } // Include 'altivec.h' if -faltivec option present @@ -2200,7 +1375,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, ie = Args.filtered_end(); it != ie; ++it) { const Arg *A = *it; std::pair<StringRef,StringRef> Split = - StringRef(A->getValue(Args)).split(';'); + StringRef(A->getValue()).split(';'); if (Split.second.empty()) { Diags.Report(diag::err_drv_invalid_remap_file) << A->getAsString(Args); @@ -2211,7 +1386,7 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, } if (Arg *A = Args.getLastArg(OPT_fobjc_arc_cxxlib_EQ)) { - StringRef Name = A->getValue(Args); + StringRef Name = A->getValue(); unsigned Library = llvm::StringSwitch<unsigned>(Name) .Case("libc++", ARCXX_libcxx) .Case("libstdc++", ARCXX_libstdcxx) @@ -2240,7 +1415,7 @@ static void ParseTargetArgs(TargetOptions &Opts, ArgList &Args) { Opts.ABI = Args.getLastArgValue(OPT_target_abi); Opts.CXXABI = Args.getLastArgValue(OPT_cxx_abi); Opts.CPU = Args.getLastArgValue(OPT_target_cpu); - Opts.Features = Args.getAllArgValues(OPT_target_feature); + Opts.FeaturesAsWritten = Args.getAllArgValues(OPT_target_feature); Opts.LinkerVersion = Args.getLastArgValue(OPT_target_linker_version); Opts.Triple = llvm::Triple::normalize(Args.getLastArgValue(OPT_triple)); @@ -2280,13 +1455,13 @@ bool CompilerInvocation::CreateFromArgs(CompilerInvocation &Res, // Issue errors on arguments that are not valid for CC1. for (ArgList::iterator I = Args->begin(), E = Args->end(); I != E; ++I) { - if (!(*I)->getOption().isCC1Option()) { + if (!(*I)->getOption().hasFlag(options::CC1Option)) { Diags.Report(diag::err_drv_unknown_argument) << (*I)->getAsString(*Args); Success = false; } } - Success = ParseAnalyzerArgs(Res.getAnalyzerOpts(), *Args, Diags) && Success; + Success = ParseAnalyzerArgs(*Res.getAnalyzerOpts(), *Args, Diags) && Success; Success = ParseMigratorArgs(Res.getMigratorOpts(), *Args) && Success; ParseDependencyOutputArgs(Res.getDependencyOutputOpts(), *Args); Success = ParseDiagnosticArgs(Res.getDiagnosticOpts(), *Args, &Diags) @@ -2368,53 +1543,49 @@ llvm::APInt ModuleSignature::getAsInteger() const { } std::string CompilerInvocation::getModuleHash() const { - ModuleSignature Signature; - + using llvm::hash_code; + using llvm::hash_value; + using llvm::hash_combine; + // Start the signature with the compiler version. - // FIXME: The full version string can be quite long. Omit it from the - // module hash for now to avoid failures where the path name becomes too - // long. An MD5 or similar checksum would work well here. - // Signature.add(getClangFullRepositoryVersion()); - + // FIXME: We'd rather use something more cryptographically sound than + // CityHash, but this will do for now. + hash_code code = hash_value(getClangFullRepositoryVersion()); + // Extend the signature with the language options #define LANGOPT(Name, Bits, Default, Description) \ - Signature.add(LangOpts->Name, Bits); + code = hash_combine(code, LangOpts->Name); #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ - Signature.add(static_cast<unsigned>(LangOpts->get##Name()), Bits); + code = hash_combine(code, static_cast<unsigned>(LangOpts->get##Name())); #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" - // Extend the signature with the target triple - llvm::Triple T(TargetOpts.Triple); - Signature.add((unsigned)T.getArch(), 5); - Signature.add((unsigned)T.getVendor(), 4); - Signature.add((unsigned)T.getOS(), 5); - Signature.add((unsigned)T.getEnvironment(), 4); + // Extend the signature with the target options. + code = hash_combine(code, TargetOpts->Triple, TargetOpts->CPU, + TargetOpts->ABI, TargetOpts->CXXABI, + TargetOpts->LinkerVersion); + for (unsigned i = 0, n = TargetOpts->FeaturesAsWritten.size(); i != n; ++i) + code = hash_combine(code, TargetOpts->FeaturesAsWritten[i]); // Extend the signature with preprocessor options. - Signature.add(getPreprocessorOpts().UsePredefines, 1); - Signature.add(getPreprocessorOpts().DetailedRecord, 1); - - // Hash the preprocessor defines. - // FIXME: This is terrible. Use an MD5 sum of the preprocessor defines. + const PreprocessorOptions &ppOpts = getPreprocessorOpts(); + code = hash_combine(code, ppOpts.UsePredefines, ppOpts.DetailedRecord); + std::vector<StringRef> MacroDefs; for (std::vector<std::pair<std::string, bool/*isUndef*/> >::const_iterator I = getPreprocessorOpts().Macros.begin(), IEnd = getPreprocessorOpts().Macros.end(); I != IEnd; ++I) { - if (!I->second) - MacroDefs.push_back(I->first); + code = hash_combine(code, I->first, I->second); } - llvm::array_pod_sort(MacroDefs.begin(), MacroDefs.end()); - - unsigned PPHashResult = 0; - for (unsigned I = 0, N = MacroDefs.size(); I != N; ++I) - PPHashResult = llvm::HashString(MacroDefs[I], PPHashResult); - Signature.add(PPHashResult, 32); - - // We've generated the signature. Treat it as one large APInt that we'll - // encode in base-36 and return. - Signature.flush(); - return Signature.getAsInteger().toString(36, /*Signed=*/false); + + // Extend the signature with the sysroot. + const HeaderSearchOptions &hsOpts = getHeaderSearchOpts(); + code = hash_combine(code, hsOpts.Sysroot, hsOpts.UseBuiltinIncludes, + hsOpts.UseStandardSystemIncludes, + hsOpts.UseStandardCXXIncludes, + hsOpts.UseLibcxx); + + return llvm::APInt(64, code).toString(36, /*Signed=*/false); } diff --git a/lib/Frontend/CreateInvocationFromCommandLine.cpp b/lib/Frontend/CreateInvocationFromCommandLine.cpp index 0aca86e2c97f..d82cb6d05157 100644 --- a/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Frontend/Utils.h" #include "clang/Frontend/CompilerInstance.h" -#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -34,8 +34,8 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList, if (!Diags.getPtr()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. - DiagnosticOptions DiagOpts; - Diags = CompilerInstance::createDiagnostics(DiagOpts, ArgList.size(), + Diags = CompilerInstance::createDiagnostics(new DiagnosticOptions, + ArgList.size(), ArgList.begin()); } @@ -49,11 +49,6 @@ clang::createInvocationFromCommandLine(ArrayRef<const char *> ArgList, // FIXME: We shouldn't have to pass in the path info. driver::Driver TheDriver("clang", llvm::sys::getDefaultTargetTriple(), "a.out", false, *Diags); - // Force driver to use clang. - // FIXME: This seems like a hack. Maybe the "Clang" tool subclass should be - // available for using it to get the arguments, thus avoiding the overkill - // of using the driver. - TheDriver.setForcedClangUse(); // Don't check that inputs exist, they may have been remapped. TheDriver.setCheckInputsExist(false); diff --git a/lib/Frontend/DependencyFile.cpp b/lib/Frontend/DependencyFile.cpp index 21f5daa9ee39..53ea8befbc09 100644 --- a/lib/Frontend/DependencyFile.cpp +++ b/lib/Frontend/DependencyFile.cpp @@ -59,10 +59,11 @@ public: const Token &IncludeTok, StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, - SourceLocation EndLoc, StringRef SearchPath, - StringRef RelativePath); + StringRef RelativePath, + const Module *Imported); virtual void EndOfMainFile() { OutputDependencyFile(); @@ -132,10 +133,11 @@ void DependencyFileCallback::InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, - SourceLocation EndLoc, StringRef SearchPath, - StringRef RelativePath) { + StringRef RelativePath, + const Module *Imported) { if (!File) { if (AddMissingHeaderDeps) AddFilename(FileName); diff --git a/lib/Frontend/DependencyGraph.cpp b/lib/Frontend/DependencyGraph.cpp index eebaf0c8fe48..28d9c5d320e2 100644 --- a/lib/Frontend/DependencyGraph.cpp +++ b/lib/Frontend/DependencyGraph.cpp @@ -51,10 +51,11 @@ public: const Token &IncludeTok, StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, - SourceLocation EndLoc, StringRef SearchPath, - StringRef RelativePath); + StringRef RelativePath, + const Module *Imported); virtual void EndOfMainFile() { OutputGraphFile(); @@ -72,10 +73,11 @@ void DependencyGraphCallback::InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, - SourceLocation EndLoc, StringRef SearchPath, - StringRef RelativePath) { + StringRef RelativePath, + const Module *Imported) { if (!File) return; diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp index f052f90fa953..359b82be6062 100644 --- a/lib/Frontend/DiagnosticRenderer.cpp +++ b/lib/Frontend/DiagnosticRenderer.cpp @@ -8,9 +8,9 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/DiagnosticRenderer.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" -#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Lex/Lexer.h" #include "clang/Edit/EditedSource.h" #include "clang/Edit/Commit.h" @@ -18,6 +18,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" #include <algorithm> using namespace clang; @@ -60,8 +61,8 @@ static StringRef getImmediateMacroName(SourceLocation Loc, } DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts, - const DiagnosticOptions &DiagOpts) -: LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {} + DiagnosticOptions *DiagOpts) + : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {} DiagnosticRenderer::~DiagnosticRenderer() {} @@ -194,7 +195,7 @@ void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, return; LastIncludeLoc = Loc; - if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) + if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) return; emitIncludeStackRecursively(Loc, SM); @@ -218,6 +219,53 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, emitIncludeLocation(Loc, PLoc, SM); } +// Helper function to fix up source ranges. It takes in an array of ranges, +// and outputs an array of ranges where we want to draw the range highlighting +// around the location specified by CaretLoc. +// +// To find locations which correspond to the caret, we crawl the macro caller +// chain for the beginning and end of each range. If the caret location +// is in a macro expansion, we search each chain for a location +// in the same expansion as the caret; otherwise, we crawl to the top of +// each chain. Two locations are part of the same macro expansion +// iff the FileID is the same. +static void mapDiagnosticRanges( + SourceLocation CaretLoc, + const SmallVectorImpl<CharSourceRange>& Ranges, + SmallVectorImpl<CharSourceRange>& SpellingRanges, + const SourceManager *SM) { + FileID CaretLocFileID = SM->getFileID(CaretLoc); + + for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(), + E = Ranges.end(); + I != E; ++I) { + SourceLocation Begin = I->getBegin(), End = I->getEnd(); + bool IsTokenRange = I->isTokenRange(); + + // Search the macro caller chain for the beginning of the range. + while (Begin.isMacroID() && SM->getFileID(Begin) != CaretLocFileID) + Begin = SM->getImmediateMacroCallerLoc(Begin); + + // Search the macro caller chain for the beginning of the range. + while (End.isMacroID() && SM->getFileID(End) != CaretLocFileID) { + // The computation of the next End is an inlined version of + // getImmediateMacroCallerLoc, except it chooses the end of an + // expansion range. + if (SM->isMacroArgExpansion(End)) { + End = SM->getImmediateSpellingLoc(End); + } else { + End = SM->getImmediateExpansionRange(End).second; + } + } + + // Return the spelling location of the beginning and end of the range. + Begin = SM->getSpellingLoc(Begin); + End = SM->getSpellingLoc(End); + SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End), + IsTokenRange)); + } +} + /// \brief Recursively emit notes for each macro expansion and caret /// diagnostics where appropriate. /// @@ -245,9 +293,13 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( // If this is a file source location, directly emit the source snippet and // caret line. Also record the macro depth reached. if (Loc.isFileID()) { + // Map the ranges. + SmallVector<CharSourceRange, 4> SpellingRanges; + mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); + assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!"); MacroDepth = OnMacroInst; - emitCodeContext(Loc, Level, Ranges, Hints, SM); + emitCodeContext(Loc, Level, SpellingRanges, Hints, SM); return; } // Otherwise recurse through each macro expansion layer. @@ -257,8 +309,7 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( Loc = SM.skipToMacroArgExpansion(Loc); SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc); - - // FIXME: Map ranges? + emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, SM, MacroDepth, OnMacroInst + 1); @@ -269,28 +320,17 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( Loc = SM.getImmediateMacroCalleeLoc(Loc); unsigned MacroSkipStart = 0, MacroSkipEnd = 0; - if (MacroDepth > DiagOpts.MacroBacktraceLimit && - DiagOpts.MacroBacktraceLimit != 0) { - MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 + - DiagOpts.MacroBacktraceLimit % 2; - MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2; + if (MacroDepth > DiagOpts->MacroBacktraceLimit && + DiagOpts->MacroBacktraceLimit != 0) { + MacroSkipStart = DiagOpts->MacroBacktraceLimit / 2 + + DiagOpts->MacroBacktraceLimit % 2; + MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2; } // Whether to suppress printing this macro expansion. bool Suppressed = (OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd); - // Map the ranges. - for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), - E = Ranges.end(); - I != E; ++I) { - SourceLocation Start = I->getBegin(), End = I->getEnd(); - if (Start.isMacroID()) - I->setBegin(SM.getImmediateMacroCalleeLoc(Start)); - if (End.isMacroID()) - I->setEnd(SM.getImmediateMacroCalleeLoc(End)); - } - if (Suppressed) { // Tell the user that we've skipped contexts. if (OnMacroInst == MacroSkipStart) { @@ -303,14 +343,18 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( } return; } - + + // Map the ranges. + SmallVector<CharSourceRange, 4> SpellingRanges; + mapDiagnosticRanges(MacroLoc, Ranges, SpellingRanges, &SM); + SmallString<100> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); Message << "expanded from macro '" << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'"; emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note, Message.str(), - Ranges, ArrayRef<FixItHint>(), &SM); + SpellingRanges, ArrayRef<FixItHint>(), &SM); } DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {} diff --git a/lib/Frontend/FrontendAction.cpp b/lib/Frontend/FrontendAction.cpp index a4321e720ed0..2e9a791c3039 100644 --- a/lib/Frontend/FrontendAction.cpp +++ b/lib/Frontend/FrontendAction.cpp @@ -23,10 +23,12 @@ #include "clang/Parse/ParseAST.h" #include "clang/Serialization/ASTDeserializationListener.h" #include "clang/Serialization/ASTReader.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Timer.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/system_error.h" +#include "llvm/Support/Timer.h" using namespace clang; namespace { @@ -155,20 +157,22 @@ ASTConsumer* FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI, return new MultiplexConsumer(Consumers); } + bool FrontendAction::BeginSourceFile(CompilerInstance &CI, const FrontendInputFile &Input) { assert(!Instance && "Already processing a source file!"); - assert(!Input.File.empty() && "Unexpected empty filename!"); + assert(!Input.isEmpty() && "Unexpected empty filename!"); setCurrentInput(Input); setCompilerInstance(&CI); + StringRef InputFile = Input.getFile(); bool HasBegunSourceFile = false; if (!BeginInvocation(CI)) goto failure; // AST files follow a very different path, since they share objects via the // AST unit. - if (Input.Kind == IK_AST) { + if (Input.getKind() == IK_AST) { assert(!usesPreprocessorOnly() && "Attempt to pass AST file to preprocessor only action!"); assert(hasASTFileSupport() && @@ -176,7 +180,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, IntrusiveRefCntPtr<DiagnosticsEngine> Diags(&CI.getDiagnostics()); std::string Error; - ASTUnit *AST = ASTUnit::LoadFromASTFile(Input.File, Diags, + ASTUnit *AST = ASTUnit::LoadFromASTFile(InputFile, Diags, CI.getFileSystemOpts()); if (!AST) goto failure; @@ -191,11 +195,11 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.setASTContext(&AST->getASTContext()); // Initialize the action. - if (!BeginSourceFileAction(CI, Input.File)) + if (!BeginSourceFileAction(CI, InputFile)) goto failure; /// Create the AST consumer. - CI.setASTConsumer(CreateWrappedASTConsumer(CI, Input.File)); + CI.setASTConsumer(CreateWrappedASTConsumer(CI, InputFile)); if (!CI.hasASTConsumer()) goto failure; @@ -209,7 +213,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.createSourceManager(CI.getFileManager()); // IR files bypass the rest of initialization. - if (Input.Kind == IK_LLVM_IR) { + if (Input.getKind() == IK_LLVM_IR) { assert(hasIRSupport() && "This action does not have IR file support!"); @@ -218,12 +222,51 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, HasBegunSourceFile = true; // Initialize the action. - if (!BeginSourceFileAction(CI, Input.File)) + if (!BeginSourceFileAction(CI, InputFile)) goto failure; return true; } + // If the implicit PCH include is actually a directory, rather than + // a single file, search for a suitable PCH file in that directory. + if (!CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) { + FileManager &FileMgr = CI.getFileManager(); + PreprocessorOptions &PPOpts = CI.getPreprocessorOpts(); + StringRef PCHInclude = PPOpts.ImplicitPCHInclude; + if (const DirectoryEntry *PCHDir = FileMgr.getDirectory(PCHInclude)) { + llvm::error_code EC; + SmallString<128> DirNative; + llvm::sys::path::native(PCHDir->getName(), DirNative); + bool Found = false; + for (llvm::sys::fs::directory_iterator Dir(DirNative.str(), EC), DirEnd; + Dir != DirEnd && !EC; Dir.increment(EC)) { + // Check whether this is an acceptable AST file. + if (ASTReader::isAcceptableASTFile(Dir->path(), FileMgr, + CI.getLangOpts(), + CI.getTargetOpts(), + CI.getPreprocessorOpts())) { + for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I) { + if (PPOpts.Includes[I] == PPOpts.ImplicitPCHInclude) { + PPOpts.Includes[I] = Dir->path(); + PPOpts.ImplicitPCHInclude = Dir->path(); + Found = true; + break; + } + } + + assert(Found && "Implicit PCH include not in includes list?"); + break; + } + } + + if (!Found) { + CI.getDiagnostics().Report(diag::err_fe_no_pch_in_dir) << PCHInclude; + return true; + } + } + } + // Set up the preprocessor. CI.createPreprocessor(); @@ -233,7 +276,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, HasBegunSourceFile = true; // Initialize the action. - if (!BeginSourceFileAction(CI, Input.File)) + if (!BeginSourceFileAction(CI, InputFile)) goto failure; /// Create the AST context and consumer unless this is a preprocessor only @@ -242,12 +285,14 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.createASTContext(); OwningPtr<ASTConsumer> Consumer( - CreateWrappedASTConsumer(CI, Input.File)); + CreateWrappedASTConsumer(CI, InputFile)); if (!Consumer) goto failure; CI.getASTContext().setASTMutationListener(Consumer->GetASTMutationListener()); - + CI.getPreprocessor().setPPMutationListener( + Consumer->GetPPMutationListener()); + if (!CI.getPreprocessorOpts().ChainedIncludes.empty()) { // Convert headers to PCH and chain them. OwningPtr<ExternalASTSource> source; @@ -270,7 +315,6 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, CI.createPCHExternalASTSource( CI.getPreprocessorOpts().ImplicitPCHInclude, CI.getPreprocessorOpts().DisablePCHValidation, - CI.getPreprocessorOpts().DisableStatCache, CI.getPreprocessorOpts().AllowPCHWithCompilerErrors, DeserialListener); if (!CI.getASTContext().getExternalSource()) @@ -314,6 +358,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, if (HasBegunSourceFile) CI.getDiagnosticClient().EndSourceFile(); + CI.clearOutputFiles(/*EraseFiles=*/true); setCurrentInput(FrontendInputFile()); setCompilerInstance(0); return false; @@ -325,10 +370,7 @@ bool FrontendAction::Execute() { // Initialize the main file entry. This needs to be delayed until after PCH // has loaded. if (!isCurrentFileAST()) { - if (!CI.InitializeSourceManager(getCurrentFile(), - getCurrentInput().IsSystem - ? SrcMgr::C_System - : SrcMgr::C_User)) + if (!CI.InitializeSourceManager(getCurrentInput())) return false; } diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 24960cf6a0c9..47063f78b5d9 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -131,8 +131,31 @@ ASTConsumer *GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI, Sysroot, OS); } +static SmallVectorImpl<char> & +operator+=(SmallVectorImpl<char> &Includes, StringRef RHS) { + Includes.append(RHS.begin(), RHS.end()); + return Includes; +} + +static void addHeaderInclude(StringRef HeaderName, + SmallVectorImpl<char> &Includes, + const LangOptions &LangOpts) { + if (LangOpts.ObjC1) + Includes += "#import \""; + else + Includes += "#include \""; + Includes += HeaderName; + Includes += "\"\n"; +} + +static void addHeaderInclude(const FileEntry *Header, + SmallVectorImpl<char> &Includes, + const LangOptions &LangOpts) { + addHeaderInclude(Header->getName(), Includes, LangOpts); +} + /// \brief Collect the set of header includes needed to construct the given -/// module. +/// module and update the TopHeaders file set of the module. /// /// \param Module The module we're collecting includes from. /// @@ -142,30 +165,23 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts, FileManager &FileMgr, ModuleMap &ModMap, clang::Module *Module, - SmallString<256> &Includes) { + SmallVectorImpl<char> &Includes) { // Don't collect any headers for unavailable modules. if (!Module->isAvailable()) return; // Add includes for each of these headers. for (unsigned I = 0, N = Module->Headers.size(); I != N; ++I) { - if (LangOpts.ObjC1) - Includes += "#import \""; - else - Includes += "#include \""; - Includes += Module->Headers[I]->getName(); - Includes += "\"\n"; + const FileEntry *Header = Module->Headers[I]; + Module->TopHeaders.insert(Header); + addHeaderInclude(Header, Includes, LangOpts); } if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) { + Module->TopHeaders.insert(UmbrellaHeader); if (Module->Parent) { // Include the umbrella header for submodules. - if (LangOpts.ObjC1) - Includes += "#import \""; - else - Includes += "#include \""; - Includes += UmbrellaHeader->getName(); - Includes += "\"\n"; + addHeaderInclude(UmbrellaHeader, Includes, LangOpts); } } else if (const DirectoryEntry *UmbrellaDir = Module->getUmbrellaDir()) { // Add all of the headers we find in this subdirectory. @@ -184,17 +200,14 @@ static void collectModuleHeaderIncludes(const LangOptions &LangOpts, // If this header is marked 'unavailable' in this module, don't include // it. - if (const FileEntry *Header = FileMgr.getFile(Dir->path())) + if (const FileEntry *Header = FileMgr.getFile(Dir->path())) { if (ModMap.isHeaderInUnavailableModule(Header)) continue; + Module->TopHeaders.insert(Header); + } // Include this header umbrella header for submodules. - if (LangOpts.ObjC1) - Includes += "#import \""; - else - Includes += "#include \""; - Includes += Dir->path(); - Includes += "\"\n"; + addHeaderInclude(Dir->path(), Includes, LangOpts); } } @@ -250,77 +263,29 @@ bool GenerateModuleAction::BeginSourceFileAction(CompilerInstance &CI, return false; } - // Do we have an umbrella header for this module? - const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader(); - + FileManager &FileMgr = CI.getFileManager(); + // Collect the set of #includes we need to build the module. SmallString<256> HeaderContents; - collectModuleHeaderIncludes(CI.getLangOpts(), CI.getFileManager(), + if (const FileEntry *UmbrellaHeader = Module->getUmbrellaHeader()) + addHeaderInclude(UmbrellaHeader, HeaderContents, CI.getLangOpts()); + collectModuleHeaderIncludes(CI.getLangOpts(), FileMgr, CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(), Module, HeaderContents); - if (UmbrellaHeader && HeaderContents.empty()) { - // Simple case: we have an umbrella header and there are no additional - // includes, we can just parse the umbrella header directly. - setCurrentInput(FrontendInputFile(UmbrellaHeader->getName(), - getCurrentFileKind(), - Module->IsSystem)); - return true; - } - - FileManager &FileMgr = CI.getFileManager(); - SmallString<128> HeaderName; - time_t ModTime; - if (UmbrellaHeader) { - // Read in the umbrella header. - // FIXME: Go through the source manager; the umbrella header may have - // been overridden. - std::string ErrorStr; - llvm::MemoryBuffer *UmbrellaContents - = FileMgr.getBufferForFile(UmbrellaHeader, &ErrorStr); - if (!UmbrellaContents) { - CI.getDiagnostics().Report(diag::err_missing_umbrella_header) - << UmbrellaHeader->getName() << ErrorStr; - return false; - } - - // Combine the contents of the umbrella header with the automatically- - // generated includes. - SmallString<256> OldContents = HeaderContents; - HeaderContents = UmbrellaContents->getBuffer(); - HeaderContents += "\n\n"; - HeaderContents += "/* Module includes */\n"; - HeaderContents += OldContents; - - // Pretend that we're parsing the umbrella header. - HeaderName = UmbrellaHeader->getName(); - ModTime = UmbrellaHeader->getModificationTime(); - - delete UmbrellaContents; - } else { - // Pick an innocuous-sounding name for the umbrella header. - HeaderName = Module->Name + ".h"; - if (FileMgr.getFile(HeaderName, /*OpenFile=*/false, - /*CacheFailure=*/false)) { - // Try again! - HeaderName = Module->Name + "-module.h"; - if (FileMgr.getFile(HeaderName, /*OpenFile=*/false, - /*CacheFailure=*/false)) { - // Pick something ridiculous and go with it. - HeaderName = Module->Name + "-module.hmod"; - } - } - ModTime = time(0); - } - - // Remap the contents of the header name we're using to our synthesized - // buffer. - const FileEntry *HeaderFile = FileMgr.getVirtualFile(HeaderName, + + StringRef InputName = Module::getModuleInputBufferName(); + + // We consistently construct a buffer as input to build the module. + // This means the main file for modules will always be a virtual one. + // FIXME: Maybe allow using a memory buffer as input directly instead of + // messing with virtual files. + const FileEntry *HeaderFile = FileMgr.getVirtualFile(InputName, HeaderContents.size(), - ModTime); + time(0)); llvm::MemoryBuffer *HeaderContentsBuf = llvm::MemoryBuffer::getMemBufferCopy(HeaderContents); CI.getSourceManager().overrideFileContents(HeaderFile, HeaderContentsBuf); - setCurrentInput(FrontendInputFile(HeaderName, getCurrentFileKind(), + setCurrentInput(FrontendInputFile(InputName, getCurrentFileKind(), Module->IsSystem)); return true; } diff --git a/lib/Frontend/InitHeaderSearch.cpp b/lib/Frontend/InitHeaderSearch.cpp index 8178f7a9362a..4fddd112df7e 100644 --- a/lib/Frontend/InitHeaderSearch.cpp +++ b/lib/Frontend/InitHeaderSearch.cpp @@ -14,7 +14,7 @@ #include "clang/Frontend/Utils.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/LangOptions.h" -#include "clang/Frontend/HeaderSearchOptions.h" +#include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/HeaderSearch.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallPtrSet.h" @@ -320,7 +320,9 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, P.appendComponent("../../../include"); // <sysroot>/include AddPath(P.str(), System, true, false, false); AddPath("/mingw/include", System, true, false, false); +#if defined(_WIN32) AddPath("c:/mingw/include", System, true, false, false); +#endif } break; @@ -396,12 +398,14 @@ AddDefaultCPlusPlusIncludePaths(const llvm::Triple &triple, const HeaderSearchOp AddMinGW64CXXPaths(HSOpts.ResourceDir, "4.7.0"); // mingw.org C++ include paths AddMinGWCPlusPlusIncludePaths("/mingw/lib/gcc", "mingw32", "4.5.2"); //MSYS +#if defined(_WIN32) AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.2"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.6.1"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.2"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.5.0"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0"); AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0"); +#endif break; case llvm::Triple::DragonFly: AddPath("/usr/include/c++/4.1", CXXSystem, true, false, false); diff --git a/lib/Frontend/InitPreprocessor.cpp b/lib/Frontend/InitPreprocessor.cpp index 1440da6e3755..4bbd033f1c2e 100644 --- a/lib/Frontend/InitPreprocessor.cpp +++ b/lib/Frontend/InitPreprocessor.cpp @@ -17,11 +17,12 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendOptions.h" -#include "clang/Frontend/PreprocessorOptions.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" +#include "clang/Serialization/ASTReader.h" #include "llvm/ADT/APFloat.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" @@ -83,6 +84,19 @@ static void AddImplicitIncludePTH(MacroBuilder &Builder, Preprocessor &PP, AddImplicitInclude(Builder, OriginalFile, PP.getFileManager()); } +/// \brief Add an implicit \#include using the original file used to generate +/// a PCH file. +static void AddImplicitIncludePCH(MacroBuilder &Builder, Preprocessor &PP, + StringRef ImplicitIncludePCH) { + std::string OriginalFile = + ASTReader::getOriginalSourceFile(ImplicitIncludePCH, PP.getFileManager(), + PP.getDiagnostics()); + if (OriginalFile.empty()) + return; + + AddImplicitInclude(Builder, OriginalFile, PP.getFileManager()); +} + /// PickFP - This is used to pick a value based on the FP semantics of the /// specified FP model. template <typename T> @@ -102,51 +116,51 @@ static T PickFP(const llvm::fltSemantics *Sem, T IEEESingleVal, } static void DefineFloatMacros(MacroBuilder &Builder, StringRef Prefix, - const llvm::fltSemantics *Sem) { + const llvm::fltSemantics *Sem, StringRef Ext) { const char *DenormMin, *Epsilon, *Max, *Min; - DenormMin = PickFP(Sem, "1.40129846e-45F", "4.9406564584124654e-324", - "3.64519953188247460253e-4951L", - "4.94065645841246544176568792868221e-324L", - "6.47517511943802511092443895822764655e-4966L"); + DenormMin = PickFP(Sem, "1.40129846e-45", "4.9406564584124654e-324", + "3.64519953188247460253e-4951", + "4.94065645841246544176568792868221e-324", + "6.47517511943802511092443895822764655e-4966"); int Digits = PickFP(Sem, 6, 15, 18, 31, 33); - Epsilon = PickFP(Sem, "1.19209290e-7F", "2.2204460492503131e-16", - "1.08420217248550443401e-19L", - "4.94065645841246544176568792868221e-324L", - "1.92592994438723585305597794258492732e-34L"); + Epsilon = PickFP(Sem, "1.19209290e-7", "2.2204460492503131e-16", + "1.08420217248550443401e-19", + "4.94065645841246544176568792868221e-324", + "1.92592994438723585305597794258492732e-34"); int MantissaDigits = PickFP(Sem, 24, 53, 64, 106, 113); int Min10Exp = PickFP(Sem, -37, -307, -4931, -291, -4931); int Max10Exp = PickFP(Sem, 38, 308, 4932, 308, 4932); int MinExp = PickFP(Sem, -125, -1021, -16381, -968, -16381); int MaxExp = PickFP(Sem, 128, 1024, 16384, 1024, 16384); - Min = PickFP(Sem, "1.17549435e-38F", "2.2250738585072014e-308", - "3.36210314311209350626e-4932L", - "2.00416836000897277799610805135016e-292L", - "3.36210314311209350626267781732175260e-4932L"); - Max = PickFP(Sem, "3.40282347e+38F", "1.7976931348623157e+308", - "1.18973149535723176502e+4932L", - "1.79769313486231580793728971405301e+308L", - "1.18973149535723176508575932662800702e+4932L"); + Min = PickFP(Sem, "1.17549435e-38", "2.2250738585072014e-308", + "3.36210314311209350626e-4932", + "2.00416836000897277799610805135016e-292", + "3.36210314311209350626267781732175260e-4932"); + Max = PickFP(Sem, "3.40282347e+38", "1.7976931348623157e+308", + "1.18973149535723176502e+4932", + "1.79769313486231580793728971405301e+308", + "1.18973149535723176508575932662800702e+4932"); SmallString<32> DefPrefix; DefPrefix = "__"; DefPrefix += Prefix; DefPrefix += "_"; - Builder.defineMacro(DefPrefix + "DENORM_MIN__", DenormMin); + Builder.defineMacro(DefPrefix + "DENORM_MIN__", Twine(DenormMin)+Ext); Builder.defineMacro(DefPrefix + "HAS_DENORM__"); Builder.defineMacro(DefPrefix + "DIG__", Twine(Digits)); - Builder.defineMacro(DefPrefix + "EPSILON__", Twine(Epsilon)); + Builder.defineMacro(DefPrefix + "EPSILON__", Twine(Epsilon)+Ext); Builder.defineMacro(DefPrefix + "HAS_INFINITY__"); Builder.defineMacro(DefPrefix + "HAS_QUIET_NAN__"); Builder.defineMacro(DefPrefix + "MANT_DIG__", Twine(MantissaDigits)); Builder.defineMacro(DefPrefix + "MAX_10_EXP__", Twine(Max10Exp)); Builder.defineMacro(DefPrefix + "MAX_EXP__", Twine(MaxExp)); - Builder.defineMacro(DefPrefix + "MAX__", Twine(Max)); + Builder.defineMacro(DefPrefix + "MAX__", Twine(Max)+Ext); Builder.defineMacro(DefPrefix + "MIN_10_EXP__","("+Twine(Min10Exp)+")"); Builder.defineMacro(DefPrefix + "MIN_EXP__", "("+Twine(MinExp)+")"); - Builder.defineMacro(DefPrefix + "MIN__", Twine(Min)); + Builder.defineMacro(DefPrefix + "MIN__", Twine(Min)+Ext); } @@ -247,7 +261,7 @@ static void AddObjCXXARCLibstdcxxDefines(const LangOptions &LangOpts, << "};\n" << "\n"; - if (LangOpts.ObjCRuntimeHasWeak) { + if (LangOpts.ObjCARCWeak) { Out << "template<typename _Tp>\n" << "struct __is_scalar<__attribute__((objc_ownership(weak))) _Tp> {\n" << " enum { __value = 0 };\n" @@ -288,6 +302,8 @@ static void InitializeStandardPredefinedMacros(const TargetInfo &TI, else if (!LangOpts.GNUMode && LangOpts.Digraphs) Builder.defineMacro("__STDC_VERSION__", "199409L"); } else { + // FIXME: LangOpts.CPlusPlus1y + // C++11 [cpp.predefined]p1: // The name __cplusplus is defined to the value 201103L when compiling a // C++ translation unit. @@ -325,8 +341,8 @@ static void InitializePredefinedMacros(const TargetInfo &TI, Builder.defineMacro("__clang_patchlevel__", "0"); #endif Builder.defineMacro("__clang_version__", - "\"" CLANG_VERSION_STRING " (" - + getClangFullRepositoryVersion() + ")\""); + "\"" CLANG_VERSION_STRING " " + + getClangFullRepositoryVersion() + "\""); #undef TOSTR #undef TOSTR2 if (!LangOpts.MicrosoftMode) { @@ -420,19 +436,17 @@ static void InitializePredefinedMacros(const TargetInfo &TI, // Both __PRETTY_FUNCTION__ and __FUNCTION__ are GCC extensions, however // VC++ appears to only like __FUNCTION__. Builder.defineMacro("__PRETTY_FUNCTION__", "__FUNCTION__"); - // Work around some issues with Visual C++ headerws. - if (LangOpts.CPlusPlus) { - // Since we define wchar_t in C++ mode. + // Work around some issues with Visual C++ headers. + if (LangOpts.WChar) { + // wchar_t supported as a keyword. Builder.defineMacro("_WCHAR_T_DEFINED"); Builder.defineMacro("_NATIVE_WCHAR_T_DEFINED"); + } + if (LangOpts.CPlusPlus) { // FIXME: Support Microsoft's __identifier extension in the lexer. Builder.append("#define __identifier(x) x"); Builder.append("class type_info;"); } - - if (LangOpts.CPlusPlus0x) { - Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", "1"); - } } if (LangOpts.Optimize) @@ -511,9 +525,9 @@ static void InitializePredefinedMacros(const TargetInfo &TI, DefineType("__CHAR16_TYPE__", TI.getChar16Type(), Builder); DefineType("__CHAR32_TYPE__", TI.getChar32Type(), Builder); - DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat()); - DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat()); - DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat()); + DefineFloatMacros(Builder, "FLT", &TI.getFloatFormat(), "F"); + DefineFloatMacros(Builder, "DBL", &TI.getDoubleFormat(), ""); + DefineFloatMacros(Builder, "LDBL", &TI.getLongDoubleFormat(), "L"); // Define a __POINTER_WIDTH__ macro for stdint.h. Builder.defineMacro("__POINTER_WIDTH__", @@ -763,6 +777,8 @@ void clang::InitializePreprocessor(Preprocessor &PP, const std::string &Path = InitOpts.Includes[i]; if (Path == InitOpts.ImplicitPTHInclude) AddImplicitIncludePTH(Builder, PP, Path); + else if (Path == InitOpts.ImplicitPCHInclude) + AddImplicitIncludePCH(Builder, PP, Path); else AddImplicitInclude(Builder, Path, PP.getFileManager()); } diff --git a/lib/Frontend/LogDiagnosticPrinter.cpp b/lib/Frontend/LogDiagnosticPrinter.cpp index 3fee95749986..3a04f1859bda 100644 --- a/lib/Frontend/LogDiagnosticPrinter.cpp +++ b/lib/Frontend/LogDiagnosticPrinter.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/LogDiagnosticPrinter.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallString.h" @@ -16,9 +17,9 @@ using namespace clang; LogDiagnosticPrinter::LogDiagnosticPrinter(raw_ostream &os, - const DiagnosticOptions &diags, + DiagnosticOptions *diags, bool _OwnsOutputStream) - : OS(os), LangOpts(0), DiagOpts(&diags), + : OS(os), LangOpts(0), DiagOpts(diags), OwnsOutputStream(_OwnsOutputStream) { } @@ -172,6 +173,6 @@ void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, DiagnosticConsumer * LogDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { - return new LogDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); + return new LogDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false); } diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 5311ed52cd29..30707dc0c008 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -570,8 +570,12 @@ static void DoPrintMacros(Preprocessor &PP, raw_ostream *OS) { do PP.Lex(Tok); while (Tok.isNot(tok::eof)); - SmallVector<id_macro_pair, 128> - MacrosByID(PP.macro_begin(), PP.macro_end()); + SmallVector<id_macro_pair, 128> MacrosByID; + for (Preprocessor::macro_iterator I = PP.macro_begin(), E = PP.macro_end(); + I != E; ++I) { + if (I->first->hasMacroDefinition()) + MacrosByID.push_back(id_macro_pair(I->first, I->second)); + } llvm::array_pod_sort(MacrosByID.begin(), MacrosByID.end(), MacroIDCompare); for (unsigned i = 0, e = MacrosByID.size(); i != e; ++i) { diff --git a/lib/Frontend/SerializedDiagnosticPrinter.cpp b/lib/Frontend/SerializedDiagnosticPrinter.cpp index a20f30d6be83..5f8fc1ecfc60 100644 --- a/lib/Frontend/SerializedDiagnosticPrinter.cpp +++ b/lib/Frontend/SerializedDiagnosticPrinter.cpp @@ -12,6 +12,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/DenseSet.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/Diagnostic.h" @@ -50,13 +51,10 @@ class SDiagsWriter; class SDiagsRenderer : public DiagnosticNoteRenderer { SDiagsWriter &Writer; - RecordData &Record; public: - SDiagsRenderer(SDiagsWriter &Writer, RecordData &Record, - const LangOptions &LangOpts, - const DiagnosticOptions &DiagOpts) - : DiagnosticNoteRenderer(LangOpts, DiagOpts), - Writer(Writer), Record(Record){} + SDiagsRenderer(SDiagsWriter &Writer, const LangOptions &LangOpts, + DiagnosticOptions *DiagOpts) + : DiagnosticNoteRenderer(LangOpts, DiagOpts), Writer(Writer) {} virtual ~SDiagsRenderer() {} @@ -73,15 +71,16 @@ protected: DiagnosticsEngine::Level Level, ArrayRef<CharSourceRange> Ranges, const SourceManager &SM) {} - - void emitNote(SourceLocation Loc, StringRef Message, const SourceManager *SM); - + + virtual void emitNote(SourceLocation Loc, StringRef Message, + const SourceManager *SM); + virtual void emitCodeContext(SourceLocation Loc, DiagnosticsEngine::Level Level, SmallVectorImpl<CharSourceRange>& Ranges, ArrayRef<FixItHint> Hints, const SourceManager &SM); - + virtual void beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level); virtual void endDiagnostic(DiagOrStoredDiag D, @@ -91,13 +90,12 @@ protected: class SDiagsWriter : public DiagnosticConsumer { friend class SDiagsRenderer; public: - explicit SDiagsWriter(llvm::raw_ostream *os, const DiagnosticOptions &diags) - : LangOpts(0), DiagOpts(diags), - Stream(Buffer), OS(os), inNonNoteDiagnostic(false) - { + explicit SDiagsWriter(llvm::raw_ostream *os, DiagnosticOptions *diags) + : LangOpts(0), DiagOpts(diags), Stream(Buffer), OS(os), + EmittedAnyDiagBlocks(false) { EmitPreamble(); } - + ~SDiagsWriter() {} void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, @@ -124,7 +122,26 @@ private: /// \brief Emit the META data block. void EmitMetaBlock(); - + + /// \brief Start a DIAG block. + void EnterDiagBlock(); + + /// \brief End a DIAG block. + void ExitDiagBlock(); + + /// \brief Emit a DIAG record. + void EmitDiagnosticMessage(SourceLocation Loc, + PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + StringRef Message, + const SourceManager *SM, + DiagOrStoredDiag D); + + /// \brief Emit FIXIT and SOURCE_RANGE records for a diagnostic. + void EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM); + /// \brief Emit a record for a CharSourceRange. void EmitCharSourceRange(CharSourceRange R, const SourceManager &SM); @@ -159,7 +176,7 @@ private: enum { Version = 1 }; const LangOptions *LangOpts; - const DiagnosticOptions &DiagOpts; + llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; /// \brief The byte buffer for the serialized content. SmallString<1024> Buffer; @@ -190,17 +207,18 @@ private: /// \brief Map for uniquing strings. DiagFlagsTy DiagFlags; - - /// \brief Flag indicating whether or not we are in the process of - /// emitting a non-note diagnostic. - bool inNonNoteDiagnostic; + + /// \brief Whether we have already started emission of any DIAG blocks. Once + /// this becomes \c true, we never close a DIAG block until we know that we're + /// starting another one or we're done. + bool EmittedAnyDiagBlocks; }; } // end anonymous namespace namespace clang { namespace serialized_diags { DiagnosticConsumer *create(llvm::raw_ostream *OS, - const DiagnosticOptions &diags) { + DiagnosticOptions *diags) { return new SDiagsWriter(OS, diags); } } // end namespace serialized_diags @@ -474,31 +492,69 @@ unsigned SDiagsWriter::getEmitDiagnosticFlag(DiagnosticsEngine::Level DiagLevel, void SDiagsWriter::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { + // Enter the block for a non-note diagnostic immediately, rather than waiting + // for beginDiagnostic, in case associated notes are emitted before we get + // there. if (DiagLevel != DiagnosticsEngine::Note) { - if (inNonNoteDiagnostic) { - // We have encountered a non-note diagnostic. Finish up the previous - // diagnostic block before starting a new one. - Stream.ExitBlock(); - } - inNonNoteDiagnostic = true; + if (EmittedAnyDiagBlocks) + ExitDiagBlock(); + + EnterDiagBlock(); + EmittedAnyDiagBlocks = true; } // Compute the diagnostic text. - diagBuf.clear(); + diagBuf.clear(); Info.FormatDiagnostic(diagBuf); - const SourceManager * - SM = Info.hasSourceManager() ? &Info.getSourceManager() : 0; - SDiagsRenderer Renderer(*this, Record, *LangOpts, DiagOpts); + if (Info.getLocation().isInvalid()) { + // Special-case diagnostics with no location. We may not have entered a + // source file in this case, so we can't use the normal DiagnosticsRenderer + // machinery. + EmitDiagnosticMessage(SourceLocation(), PresumedLoc(), DiagLevel, + diagBuf, 0, &Info); + return; + } + + assert(Info.hasSourceManager() && LangOpts && + "Unexpected diagnostic with valid location outside of a source file"); + SDiagsRenderer Renderer(*this, *LangOpts, &*DiagOpts); Renderer.emitDiagnostic(Info.getLocation(), DiagLevel, diagBuf.str(), Info.getRanges(), llvm::makeArrayRef(Info.getFixItHints(), Info.getNumFixItHints()), - SM, + &Info.getSourceManager(), &Info); } +void SDiagsWriter::EmitDiagnosticMessage(SourceLocation Loc, + PresumedLoc PLoc, + DiagnosticsEngine::Level Level, + StringRef Message, + const SourceManager *SM, + DiagOrStoredDiag D) { + // Emit the RECORD_DIAG record. + Record.clear(); + Record.push_back(RECORD_DIAG); + Record.push_back(Level); + AddLocToRecord(Loc, SM, PLoc, Record); + + if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) { + // Emit the category string lazily and get the category ID. + unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID()); + Record.push_back(getEmitCategory(DiagID)); + // Emit the diagnostic flag string lazily and get the mapped ID. + Record.push_back(getEmitDiagnosticFlag(Level, Info->getID())); + } else { + Record.push_back(getEmitCategory()); + Record.push_back(getEmitDiagnosticFlag(Level)); + } + + Record.push_back(Message.size()); + Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_DIAG), Record, Message); +} + void SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc, @@ -507,94 +563,80 @@ SDiagsRenderer::emitDiagnosticMessage(SourceLocation Loc, ArrayRef<clang::CharSourceRange> Ranges, const SourceManager *SM, DiagOrStoredDiag D) { - // Emit the RECORD_DIAG record. - Writer.Record.clear(); - Writer.Record.push_back(RECORD_DIAG); - Writer.Record.push_back(Level); - Writer.AddLocToRecord(Loc, SM, PLoc, Record); + Writer.EmitDiagnosticMessage(Loc, PLoc, Level, Message, SM, D); +} - if (const Diagnostic *Info = D.dyn_cast<const Diagnostic*>()) { - // Emit the category string lazily and get the category ID. - unsigned DiagID = DiagnosticIDs::getCategoryNumberForDiag(Info->getID()); - Writer.Record.push_back(Writer.getEmitCategory(DiagID)); - // Emit the diagnostic flag string lazily and get the mapped ID. - Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level, Info->getID())); - } - else { - Writer.Record.push_back(Writer.getEmitCategory()); - Writer.Record.push_back(Writer.getEmitDiagnosticFlag(Level)); - } +void SDiagsWriter::EnterDiagBlock() { + Stream.EnterSubblock(BLOCK_DIAG, 4); +} - Writer.Record.push_back(Message.size()); - Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG), - Writer.Record, Message); +void SDiagsWriter::ExitDiagBlock() { + Stream.ExitBlock(); } void SDiagsRenderer::beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level) { - Writer.Stream.EnterSubblock(BLOCK_DIAG, 4); + if (Level == DiagnosticsEngine::Note) + Writer.EnterDiagBlock(); } void SDiagsRenderer::endDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level) { - if (D && Level != DiagnosticsEngine::Note) - return; - Writer.Stream.ExitBlock(); + // Only end note diagnostics here, because we can't be sure when we've seen + // the last note associated with a non-note diagnostic. + if (Level == DiagnosticsEngine::Note) + Writer.ExitDiagBlock(); } -void SDiagsRenderer::emitCodeContext(SourceLocation Loc, - DiagnosticsEngine::Level Level, - SmallVectorImpl<CharSourceRange> &Ranges, - ArrayRef<FixItHint> Hints, - const SourceManager &SM) { +void SDiagsWriter::EmitCodeContext(SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM) { // Emit Source Ranges. - for (ArrayRef<CharSourceRange>::iterator it=Ranges.begin(), ei=Ranges.end(); - it != ei; ++it) { - if (it->isValid()) - Writer.EmitCharSourceRange(*it, SM); - } - + for (ArrayRef<CharSourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); + I != E; ++I) + if (I->isValid()) + EmitCharSourceRange(*I, SM); + // Emit FixIts. - for (ArrayRef<FixItHint>::iterator it = Hints.begin(), et = Hints.end(); - it != et; ++it) { - const FixItHint &fix = *it; - if (fix.isNull()) + for (ArrayRef<FixItHint>::iterator I = Hints.begin(), E = Hints.end(); + I != E; ++I) { + const FixItHint &Fix = *I; + if (Fix.isNull()) continue; - Writer.Record.clear(); - Writer.Record.push_back(RECORD_FIXIT); - Writer.AddCharSourceRangeToRecord(fix.RemoveRange, Record, SM); - Writer.Record.push_back(fix.CodeToInsert.size()); - Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_FIXIT), Record, - fix.CodeToInsert); + Record.clear(); + Record.push_back(RECORD_FIXIT); + AddCharSourceRangeToRecord(Fix.RemoveRange, Record, SM); + Record.push_back(Fix.CodeToInsert.size()); + Stream.EmitRecordWithBlob(Abbrevs.get(RECORD_FIXIT), Record, + Fix.CodeToInsert); } } +void SDiagsRenderer::emitCodeContext(SourceLocation Loc, + DiagnosticsEngine::Level Level, + SmallVectorImpl<CharSourceRange> &Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM) { + Writer.EmitCodeContext(Ranges, Hints, SM); +} + void SDiagsRenderer::emitNote(SourceLocation Loc, StringRef Message, const SourceManager *SM) { - Writer.Stream.EnterSubblock(BLOCK_DIAG, 4); - RecordData Record; - Record.push_back(RECORD_DIAG); - Record.push_back(DiagnosticsEngine::Note); - Writer.AddLocToRecord(Loc, Record, SM); - Record.push_back(Writer.getEmitCategory()); - Record.push_back(Writer.getEmitDiagnosticFlag(DiagnosticsEngine::Note)); - Record.push_back(Message.size()); - Writer.Stream.EmitRecordWithBlob(Writer.Abbrevs.get(RECORD_DIAG), - Record, Message); - Writer.Stream.ExitBlock(); + Writer.EnterDiagBlock(); + PresumedLoc PLoc = SM ? SM->getPresumedLoc(Loc) : PresumedLoc(); + Writer.EmitDiagnosticMessage(Loc, PLoc, DiagnosticsEngine::Note, + Message, SM, DiagOrStoredDiag()); + Writer.ExitDiagBlock(); } void SDiagsWriter::finish() { - if (inNonNoteDiagnostic) { - // Finish off any diagnostics we were in the process of emitting. - Stream.ExitBlock(); - inNonNoteDiagnostic = false; - } + // Finish off any diagnostic we were in the process of emitting. + if (EmittedAnyDiagBlocks) + ExitDiagBlock(); // Write the generated bitstream to "Out". OS->write((char *)&Buffer.front(), Buffer.size()); OS->flush(); - + OS.reset(0); } - diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp index 9bb3e1dce8c7..35dabad60657 100644 --- a/lib/Frontend/TextDiagnostic.cpp +++ b/lib/Frontend/TextDiagnostic.cpp @@ -11,7 +11,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/ConvertUTF.h" -#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" @@ -43,19 +43,22 @@ static const enum raw_ostream::Colors savedColor = /// \brief Add highlights to differences in template strings. static void applyTemplateHighlighting(raw_ostream &OS, StringRef Str, bool &Normal, bool Bold) { - for (unsigned i = 0, e = Str.size(); i < e; ++i) - if (Str[i] != ToggleHighlight) { - OS << Str[i]; - } else { - if (Normal) - OS.changeColor(templateColor, true); - else { - OS.resetColor(); - if (Bold) - OS.changeColor(savedColor, true); - } - Normal = !Normal; + while (1) { + size_t Pos = Str.find(ToggleHighlight); + OS << Str.slice(0, Pos); + if (Pos == StringRef::npos) + break; + + Str = Str.substr(Pos + 1); + if (Normal) + OS.changeColor(templateColor, true); + else { + OS.resetColor(); + if (Bold) + OS.changeColor(savedColor, true); } + Normal = !Normal; + } } /// \brief Number of spaces to indent when word-wrapping. @@ -110,28 +113,15 @@ printableTextForNextCharacter(StringRef SourceLine, size_t *i, return std::make_pair(expandedTab, true); } - // FIXME: this data is copied from the private implementation of ConvertUTF.h - static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 - }; - unsigned char const *begin, *end; begin = reinterpret_cast<unsigned char const *>(&*(SourceLine.begin() + *i)); - end = begin + SourceLine.size(); + end = begin + (SourceLine.size() - *i); if (isLegalUTF8Sequence(begin, end)) { UTF32 c; UTF32 *cptr = &c; unsigned char const *original_begin = begin; - char trailingBytes = trailingBytesForUTF8[(unsigned char)SourceLine[*i]]; - unsigned char const *cp_end = begin+trailingBytes+1; + unsigned char const *cp_end = begin+getNumBytesForUTF8(SourceLine[*i]); ConversionResult res = ConvertUTF8toUTF32(&begin, cp_end, &cptr, cptr+1, strictConversion); @@ -274,14 +264,44 @@ struct SourceColumnMap { } int columns() const { return m_byteToColumn.back(); } int bytes() const { return m_columnToByte.back(); } + + /// \brief Map a byte to the column which it is at the start of, or return -1 + /// if it is not at the start of a column (for a UTF-8 trailing byte). int byteToColumn(int n) const { assert(0<=n && n<static_cast<int>(m_byteToColumn.size())); return m_byteToColumn[n]; } + + /// \brief Map a byte to the first column which contains it. + int byteToContainingColumn(int N) const { + assert(0 <= N && N < static_cast<int>(m_byteToColumn.size())); + while (m_byteToColumn[N] == -1) + --N; + return m_byteToColumn[N]; + } + + /// \brief Map a column to the byte which starts the column, or return -1 if + /// the column the second or subsequent column of an expanded tab or similar + /// multi-column entity. int columnToByte(int n) const { assert(0<=n && n<static_cast<int>(m_columnToByte.size())); return m_columnToByte[n]; } + + /// \brief Map from a byte index to the next byte which starts a column. + int startOfNextColumn(int N) const { + assert(0 <= N && N < static_cast<int>(m_columnToByte.size() - 1)); + while (byteToColumn(++N) == -1) {} + return N; + } + + /// \brief Map from a byte index to the previous byte which starts a column. + int startOfPreviousColumn(int N) const { + assert(0 < N && N < static_cast<int>(m_columnToByte.size())); + while (byteToColumn(--N) == -1) {} + return N; + } + StringRef getSourceLine() const { return m_SourceLine; } @@ -398,25 +418,24 @@ static void selectInterestingSourceRegion(std::string &SourceLine, bool ExpandedRegion = false; if (SourceStart>0) { - unsigned NewStart = SourceStart-1; + unsigned NewStart = map.startOfPreviousColumn(SourceStart); // Skip over any whitespace we see here; we're looking for // another bit of interesting text. + // FIXME: Detect non-ASCII whitespace characters too. while (NewStart && - (map.byteToColumn(NewStart)==-1 || - isspace(static_cast<unsigned char>(SourceLine[NewStart])))) - --NewStart; + isspace(static_cast<unsigned char>(SourceLine[NewStart]))) + NewStart = map.startOfPreviousColumn(NewStart); // Skip over this bit of "interesting" text. - while (NewStart && - (map.byteToColumn(NewStart)!=-1 && - !isspace(static_cast<unsigned char>(SourceLine[NewStart])))) - --NewStart; - - // Move up to the non-whitespace character we just saw. - if (NewStart) - ++NewStart; + while (NewStart) { + unsigned Prev = map.startOfPreviousColumn(NewStart); + if (isspace(static_cast<unsigned char>(SourceLine[Prev]))) + break; + NewStart = Prev; + } + assert(map.byteToColumn(NewStart) != -1); unsigned NewColumns = map.byteToColumn(SourceEnd) - map.byteToColumn(NewStart); if (NewColumns <= TargetColumns) { @@ -426,21 +445,21 @@ static void selectInterestingSourceRegion(std::string &SourceLine, } if (SourceEnd<SourceLine.size()) { - unsigned NewEnd = SourceEnd+1; + unsigned NewEnd = map.startOfNextColumn(SourceEnd); // Skip over any whitespace we see here; we're looking for // another bit of interesting text. - while (NewEnd<SourceLine.size() && - (map.byteToColumn(NewEnd)==-1 || - isspace(static_cast<unsigned char>(SourceLine[NewEnd])))) - ++NewEnd; + // FIXME: Detect non-ASCII whitespace characters too. + while (NewEnd < SourceLine.size() && + isspace(static_cast<unsigned char>(SourceLine[NewEnd]))) + NewEnd = map.startOfNextColumn(NewEnd); // Skip over this bit of "interesting" text. - while (NewEnd<SourceLine.size() && - (map.byteToColumn(NewEnd)!=-1 && - !isspace(static_cast<unsigned char>(SourceLine[NewEnd])))) - ++NewEnd; + while (NewEnd < SourceLine.size() && + !isspace(static_cast<unsigned char>(SourceLine[NewEnd]))) + NewEnd = map.startOfNextColumn(NewEnd); + assert(map.byteToColumn(NewEnd) != -1); unsigned NewColumns = map.byteToColumn(NewEnd) - map.byteToColumn(SourceStart); if (NewColumns <= TargetColumns) { @@ -475,7 +494,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine, // The line needs some trunctiona, and we'd prefer to keep the front // if possible, so remove the back - if (BackColumnsRemoved) + if (BackColumnsRemoved > strlen(back_ellipse)) SourceLine.replace(SourceEnd, std::string::npos, back_ellipse); // If that's enough then we're done @@ -483,7 +502,7 @@ static void selectInterestingSourceRegion(std::string &SourceLine, return; // Otherwise remove the front as well - if (FrontColumnsRemoved) { + if (FrontColumnsRemoved > strlen(front_ellipse)) { SourceLine.replace(0, SourceStart, front_ellipse); CaretLine.replace(0, CaretStart, front_space); if (!FixItInsertionLine.empty()) @@ -651,7 +670,7 @@ static bool printWordWrapped(raw_ostream &OS, StringRef Str, TextDiagnostic::TextDiagnostic(raw_ostream &OS, const LangOptions &LangOpts, - const DiagnosticOptions &DiagOpts) + DiagnosticOptions *DiagOpts) : DiagnosticRenderer(LangOpts, DiagOpts), OS(OS) {} TextDiagnostic::~TextDiagnostic() {} @@ -670,13 +689,13 @@ TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc, if (Loc.isValid()) emitDiagnosticLoc(Loc, PLoc, Level, Ranges, *SM); - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.resetColor(); - printDiagnosticLevel(OS, Level, DiagOpts.ShowColors); + printDiagnosticLevel(OS, Level, DiagOpts->ShowColors); printDiagnosticMessage(OS, Level, Message, OS.tell() - StartOfLocationInfo, - DiagOpts.MessageLength, DiagOpts.ShowColors); + DiagOpts->MessageLength, DiagOpts->ShowColors); } /*static*/ void @@ -770,36 +789,36 @@ void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, } unsigned LineNo = PLoc.getLine(); - if (!DiagOpts.ShowLocation) + if (!DiagOpts->ShowLocation) return; - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); OS << PLoc.getFilename(); - switch (DiagOpts.Format) { + switch (DiagOpts->getFormat()) { case DiagnosticOptions::Clang: OS << ':' << LineNo; break; case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; case DiagnosticOptions::Vi: OS << " +" << LineNo; break; } - if (DiagOpts.ShowColumn) + if (DiagOpts->ShowColumn) // Compute the column number. if (unsigned ColNo = PLoc.getColumn()) { - if (DiagOpts.Format == DiagnosticOptions::Msvc) { + if (DiagOpts->getFormat() == DiagnosticOptions::Msvc) { OS << ','; ColNo--; } else OS << ':'; OS << ColNo; } - switch (DiagOpts.Format) { + switch (DiagOpts->getFormat()) { case DiagnosticOptions::Clang: case DiagnosticOptions::Vi: OS << ':'; break; case DiagnosticOptions::Msvc: OS << ") : "; break; } - if (DiagOpts.ShowSourceRanges && !Ranges.empty()) { + if (DiagOpts->ShowSourceRanges && !Ranges.empty()) { FileID CaretFileID = SM.getFileID(SM.getExpansionLoc(Loc)); bool PrintedRange = false; @@ -858,7 +877,7 @@ void TextDiagnostic::emitBasicNote(StringRef Message) { void TextDiagnostic::emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, const SourceManager &SM) { - if (DiagOpts.ShowLocation) + if (DiagOpts->ShowLocation) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else @@ -886,7 +905,7 @@ void TextDiagnostic::emitSnippetAndCaret( // was part of a different warning or error diagnostic, or if the // diagnostic has ranges. We don't want to emit the same caret // multiple times if one loc has multiple diagnostics. - if (!DiagOpts.ShowCarets) + if (!DiagOpts->ShowCarets) return; if (Loc == LastLoc && Ranges.empty() && Hints.empty() && (LastLevel != DiagnosticsEngine::Note || Level == LastLevel)) @@ -924,7 +943,7 @@ void TextDiagnostic::emitSnippetAndCaret( // length as the line of source code. std::string CaretLine(LineEnd-LineStart, ' '); - const SourceColumnMap sourceColMap(SourceLine, DiagOpts.TabStop); + const SourceColumnMap sourceColMap(SourceLine, DiagOpts->TabStop); // Highlight all of the characters covered by Ranges with ~ characters. for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(), @@ -933,7 +952,7 @@ void TextDiagnostic::emitSnippetAndCaret( highlightRange(*I, LineNo, FID, sourceColMap, CaretLine, SM); // Next, insert the caret itself. - ColNo = sourceColMap.byteToColumn(ColNo-1); + ColNo = sourceColMap.byteToContainingColumn(ColNo-1); if (CaretLine.size()<ColNo+1) CaretLine.resize(ColNo+1, ' '); CaretLine[ColNo] = '^'; @@ -944,7 +963,7 @@ void TextDiagnostic::emitSnippetAndCaret( // If the source line is too long for our terminal, select only the // "interesting" source region within that line. - unsigned Columns = DiagOpts.MessageLength; + unsigned Columns = DiagOpts->MessageLength; if (Columns) selectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, Columns, sourceColMap); @@ -953,7 +972,7 @@ void TextDiagnostic::emitSnippetAndCaret( // to produce easily machine parsable output. Add a space before the // source line and the caret to make it trivial to tell the main diagnostic // line from what the user is intended to see. - if (DiagOpts.ShowSourceRanges) { + if (DiagOpts->ShowSourceRanges) { SourceLine = ' ' + SourceLine; CaretLine = ' ' + CaretLine; } @@ -965,20 +984,20 @@ void TextDiagnostic::emitSnippetAndCaret( // Emit what we have computed. emitSnippet(SourceLine); - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.changeColor(caretColor, true); OS << CaretLine << '\n'; - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.resetColor(); if (!FixItInsertionLine.empty()) { - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) // Print fixit line in color OS.changeColor(fixitColor, false); - if (DiagOpts.ShowSourceRanges) + if (DiagOpts->ShowSourceRanges) OS << ' '; OS << FixItInsertionLine << '\n'; - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.resetColor(); } @@ -997,15 +1016,15 @@ void TextDiagnostic::emitSnippet(StringRef line) { while (i<line.size()) { std::pair<SmallString<16>,bool> res - = printableTextForNextCharacter(line, &i, DiagOpts.TabStop); + = printableTextForNextCharacter(line, &i, DiagOpts->TabStop); bool was_printable = res.second; - if (DiagOpts.ShowColors && was_printable == print_reversed) { + if (DiagOpts->ShowColors && was_printable == print_reversed) { if (print_reversed) OS.reverseColor(); OS << to_print; to_print.clear(); - if (DiagOpts.ShowColors) + if (DiagOpts->ShowColors) OS.resetColor(); } @@ -1013,10 +1032,10 @@ void TextDiagnostic::emitSnippet(StringRef line) { to_print += res.first.str(); } - if (print_reversed && DiagOpts.ShowColors) + if (print_reversed && DiagOpts->ShowColors) OS.reverseColor(); OS << to_print; - if (print_reversed && DiagOpts.ShowColors) + if (print_reversed && DiagOpts->ShowColors) OS.resetColor(); OS << '\n'; @@ -1030,16 +1049,8 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, const SourceManager &SM) { if (!R.isValid()) return; - SourceLocation Begin = SM.getExpansionLoc(R.getBegin()); - SourceLocation End = SM.getExpansionLoc(R.getEnd()); - - // If the End location and the start location are the same and are a macro - // location, then the range was something that came from a macro expansion - // or _Pragma. If this is an object-like macro, the best we can do is to - // highlight the range. If this is a function-like macro, we'd also like to - // highlight the arguments. - if (Begin == End && R.getEnd().isMacroID()) - End = SM.getExpansionRange(R.getEnd()).second; + SourceLocation Begin = R.getBegin(); + SourceLocation End = R.getEnd(); unsigned StartLineNo = SM.getExpansionLineNumber(Begin); if (StartLineNo > LineNo || SM.getFileID(Begin) != FID) @@ -1080,7 +1091,7 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, while (StartColNo < map.getSourceLine().size() && (map.getSourceLine()[StartColNo] == ' ' || map.getSourceLine()[StartColNo] == '\t')) - ++StartColNo; + StartColNo = map.startOfNextColumn(StartColNo); // Pick the last non-whitespace column. if (EndColNo > map.getSourceLine().size()) @@ -1088,7 +1099,7 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, while (EndColNo-1 && (map.getSourceLine()[EndColNo-1] == ' ' || map.getSourceLine()[EndColNo-1] == '\t')) - --EndColNo; + EndColNo = map.startOfPreviousColumn(EndColNo); // If the start/end passed each other, then we are trying to highlight a // range that just exists in whitespace, which must be some sort of other @@ -1100,8 +1111,8 @@ void TextDiagnostic::highlightRange(const CharSourceRange &R, assert(EndColNo <= map.getSourceLine().size() && "Invalid range!"); // Fill the range with ~'s. - StartColNo = map.byteToColumn(StartColNo); - EndColNo = map.byteToColumn(EndColNo); + StartColNo = map.byteToContainingColumn(StartColNo); + EndColNo = map.byteToContainingColumn(EndColNo); assert(StartColNo <= EndColNo && "Invalid range!"); if (CaretLine.size() < EndColNo) @@ -1116,7 +1127,7 @@ std::string TextDiagnostic::buildFixItInsertionLine( const SourceManager &SM) { std::string FixItInsertionLine; - if (Hints.empty() || !DiagOpts.ShowFixits) + if (Hints.empty() || !DiagOpts->ShowFixits) return FixItInsertionLine; unsigned PrevHintEndCol = 0; @@ -1139,7 +1150,7 @@ std::string TextDiagnostic::buildFixItInsertionLine( // The hint must start inside the source or right at the end assert(HintByteOffset < static_cast<unsigned>(map.bytes())+1); - unsigned HintCol = map.byteToColumn(HintByteOffset); + unsigned HintCol = map.byteToContainingColumn(HintByteOffset); // If we inserted a long previous hint, push this one forwards, and add // an extra space to show that this is not part of the previous @@ -1176,14 +1187,14 @@ std::string TextDiagnostic::buildFixItInsertionLine( } } - expandTabs(FixItInsertionLine, DiagOpts.TabStop); + expandTabs(FixItInsertionLine, DiagOpts->TabStop); return FixItInsertionLine; } void TextDiagnostic::emitParseableFixits(ArrayRef<FixItHint> Hints, const SourceManager &SM) { - if (!DiagOpts.ShowParseableFixits) + if (!DiagOpts->ShowParseableFixits) return; // We follow FixItRewriter's example in not (yet) handling diff --git a/lib/Frontend/TextDiagnosticPrinter.cpp b/lib/Frontend/TextDiagnosticPrinter.cpp index 382e1567c7f4..aa7a61a60f9e 100644 --- a/lib/Frontend/TextDiagnosticPrinter.cpp +++ b/lib/Frontend/TextDiagnosticPrinter.cpp @@ -12,9 +12,9 @@ //===----------------------------------------------------------------------===// #include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" -#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/TextDiagnostic.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/MemoryBuffer.h" @@ -25,9 +25,9 @@ using namespace clang; TextDiagnosticPrinter::TextDiagnosticPrinter(raw_ostream &os, - const DiagnosticOptions &diags, + DiagnosticOptions *diags, bool _OwnsOutputStream) - : OS(os), DiagOpts(&diags), + : OS(os), DiagOpts(diags), OwnsOutputStream(_OwnsOutputStream) { } @@ -39,7 +39,7 @@ TextDiagnosticPrinter::~TextDiagnosticPrinter() { void TextDiagnosticPrinter::BeginSourceFile(const LangOptions &LO, const Preprocessor *PP) { // Build the TextDiagnostic utility. - TextDiag.reset(new TextDiagnostic(OS, LO, *DiagOpts)); + TextDiag.reset(new TextDiagnostic(OS, LO, &*DiagOpts)); } void TextDiagnosticPrinter::EndSourceFile() { @@ -158,5 +158,5 @@ void TextDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, DiagnosticConsumer * TextDiagnosticPrinter::clone(DiagnosticsEngine &Diags) const { - return new TextDiagnosticPrinter(OS, *DiagOpts, /*OwnsOutputStream=*/false); + return new TextDiagnosticPrinter(OS, &*DiagOpts, /*OwnsOutputStream=*/false); } diff --git a/lib/Frontend/VerifyDiagnosticConsumer.cpp b/lib/Frontend/VerifyDiagnosticConsumer.cpp index a9378a117d6b..1750946af497 100644 --- a/lib/Frontend/VerifyDiagnosticConsumer.cpp +++ b/lib/Frontend/VerifyDiagnosticConsumer.cpp @@ -31,14 +31,17 @@ VerifyDiagnosticConsumer::VerifyDiagnosticConsumer(DiagnosticsEngine &_Diags) : Diags(_Diags), PrimaryClient(Diags.getClient()), OwnsPrimaryClient(Diags.ownsClient()), Buffer(new TextDiagnosticBuffer()), CurrentPreprocessor(0), - ActiveSourceFiles(0) + LangOpts(0), SrcManager(0), ActiveSourceFiles(0), Status(HasNoDirectives) { Diags.takeClient(); + if (Diags.hasSourceManager()) + setSourceManager(Diags.getSourceManager()); } VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() { assert(!ActiveSourceFiles && "Incomplete parsing of source files!"); assert(!CurrentPreprocessor && "CurrentPreprocessor should be invalid!"); + SrcManager = 0; CheckDiagnostics(); Diags.takeClient(); if (OwnsPrimaryClient) @@ -48,21 +51,20 @@ VerifyDiagnosticConsumer::~VerifyDiagnosticConsumer() { #ifndef NDEBUG namespace { class VerifyFileTracker : public PPCallbacks { - typedef VerifyDiagnosticConsumer::FilesParsedForDirectivesSet ListType; - ListType &FilesList; + VerifyDiagnosticConsumer &Verify; SourceManager &SM; public: - VerifyFileTracker(ListType &FilesList, SourceManager &SM) - : FilesList(FilesList), SM(SM) { } + VerifyFileTracker(VerifyDiagnosticConsumer &Verify, SourceManager &SM) + : Verify(Verify), SM(SM) { } /// \brief Hook into the preprocessor and update the list of parsed /// files when the preprocessor indicates a new file is entered. virtual void FileChanged(SourceLocation Loc, FileChangeReason Reason, SrcMgr::CharacteristicKind FileType, FileID PrevFID) { - if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(Loc))) - FilesList.insert(E); + Verify.UpdateParsedFileStatus(SM, SM.getFileID(Loc), + VerifyDiagnosticConsumer::IsParsed); } }; } // End anonymous namespace. @@ -76,10 +78,12 @@ void VerifyDiagnosticConsumer::BeginSourceFile(const LangOptions &LangOpts, if (++ActiveSourceFiles == 1) { if (PP) { CurrentPreprocessor = PP; + this->LangOpts = &LangOpts; + setSourceManager(PP->getSourceManager()); const_cast<Preprocessor*>(PP)->addCommentHandler(this); #ifndef NDEBUG - VerifyFileTracker *V = new VerifyFileTracker(FilesParsedForDirectives, - PP->getSourceManager()); + // Debug build tracks parsed files. + VerifyFileTracker *V = new VerifyFileTracker(*this, *SrcManager); const_cast<Preprocessor*>(PP)->addPPCallbacks(V); #endif } @@ -101,18 +105,40 @@ void VerifyDiagnosticConsumer::EndSourceFile() { // Check diagnostics once last file completed. CheckDiagnostics(); CurrentPreprocessor = 0; + LangOpts = 0; } } void VerifyDiagnosticConsumer::HandleDiagnostic( DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) { + if (Info.hasSourceManager()) + setSourceManager(Info.getSourceManager()); + #ifndef NDEBUG - if (Info.hasSourceManager()) { - FileID FID = Info.getSourceManager().getFileID(Info.getLocation()); - if (!FID.isInvalid()) - FilesWithDiagnostics.insert(FID); + // Debug build tracks unparsed files for possible + // unparsed expected-* directives. + if (SrcManager) { + SourceLocation Loc = Info.getLocation(); + if (Loc.isValid()) { + ParsedStatus PS = IsUnparsed; + + Loc = SrcManager->getExpansionLoc(Loc); + FileID FID = SrcManager->getFileID(Loc); + + const FileEntry *FE = SrcManager->getFileEntryForID(FID); + if (FE && CurrentPreprocessor && SrcManager->isLoadedFileID(FID)) { + // If the file is a modules header file it shall not be parsed + // for expected-* directives. + HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo(); + if (HS.findModuleForHeader(FE)) + PS = IsUnparsedNoDirectives; + } + + UpdateParsedFileStatus(*SrcManager, FID, PS); + } } #endif + // Send the diagnostic to the buffer, we will check it once we reach the end // of the source file (or are destructed). Buffer->HandleDiagnostic(DiagLevel, Info); @@ -200,10 +226,22 @@ public: // Return true if string literal is found. // When true, P marks begin-position of S in content. - bool Search(StringRef S) { - P = std::search(C, End, S.begin(), S.end()); - PEnd = P + S.size(); - return P != End; + bool Search(StringRef S, bool EnsureStartOfWord = false) { + do { + P = std::search(C, End, S.begin(), S.end()); + PEnd = P + S.size(); + if (P == End) + break; + if (!EnsureStartOfWord + // Check if string literal starts a new word. + || P == Begin || isspace(P[-1]) + // Or it could be preceeded by the start of a comment. + || (P > (Begin + 1) && (P[-1] == '/' || P[-1] == '*') + && P[-2] == '/')) + return true; + // Otherwise, skip and search again. + } while (Advance()); + return false; } // Advance 1-past previous next/search. @@ -240,12 +278,13 @@ private: /// /// Returns true if any valid directives were found. static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, - SourceLocation Pos, DiagnosticsEngine &Diags) { + SourceLocation Pos, DiagnosticsEngine &Diags, + VerifyDiagnosticConsumer::DirectiveStatus &Status) { // A single comment may contain multiple directives. bool FoundDirective = false; for (ParseHelper PH(S); !PH.Done();) { // Search for token: expected - if (!PH.Search("expected")) + if (!PH.Search("expected", true)) break; PH.Advance(); @@ -262,10 +301,24 @@ static bool ParseDirective(StringRef S, ExpectedData *ED, SourceManager &SM, DL = ED ? &ED->Warnings : NULL; else if (PH.Next("note")) DL = ED ? &ED->Notes : NULL; - else + else if (PH.Next("no-diagnostics")) { + if (Status == VerifyDiagnosticConsumer::HasOtherExpectedDirectives) + Diags.Report(Pos, diag::err_verify_invalid_no_diags) + << /*IsExpectedNoDiagnostics=*/true; + else + Status = VerifyDiagnosticConsumer::HasExpectedNoDiagnostics; + continue; + } else continue; PH.Advance(); + if (Status == VerifyDiagnosticConsumer::HasExpectedNoDiagnostics) { + Diags.Report(Pos, diag::err_verify_invalid_no_diags) + << /*IsExpectedNoDiagnostics=*/false; + continue; + } + Status = VerifyDiagnosticConsumer::HasOtherExpectedDirectives; + // If a directive has been found but we're not interested // in storing the directive information, return now. if (!DL) @@ -412,7 +465,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, // Fold any "\<EOL>" sequences size_t loc = C.find('\\'); if (loc == StringRef::npos) { - ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics()); + ParseDirective(C, &ED, SM, CommentBegin, PP.getDiagnostics(), Status); return false; } @@ -442,7 +495,7 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, } if (!C2.empty()) - ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics()); + ParseDirective(C2, &ED, SM, CommentBegin, PP.getDiagnostics(), Status); return false; } @@ -452,34 +505,36 @@ bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, /// Preprocessor, directives inside skipped #if blocks will still be found. /// /// \return true if any directives were found. -static bool findDirectives(const Preprocessor &PP, FileID FID) { +static bool findDirectives(SourceManager &SM, FileID FID, + const LangOptions &LangOpts) { // Create a raw lexer to pull all the comments out of FID. if (FID.isInvalid()) return false; - SourceManager& SM = PP.getSourceManager(); // Create a lexer to lex all the tokens of the main file in raw mode. const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); - Lexer RawLex(FID, FromFile, SM, PP.getLangOpts()); + Lexer RawLex(FID, FromFile, SM, LangOpts); // Return comments as tokens, this is how we find expected diagnostics. RawLex.SetCommentRetentionState(true); Token Tok; Tok.setKind(tok::comment); - bool Found = false; + VerifyDiagnosticConsumer::DirectiveStatus Status = + VerifyDiagnosticConsumer::HasNoDirectives; while (Tok.isNot(tok::eof)) { RawLex.Lex(Tok); if (!Tok.is(tok::comment)) continue; - std::string Comment = PP.getSpelling(Tok); + std::string Comment = RawLex.getSpelling(Tok, SM, LangOpts); if (Comment.empty()) continue; - // Find all expected errors/warnings/notes. - Found |= ParseDirective(Comment, 0, SM, Tok.getLocation(), - PP.getDiagnostics()); + // Find first directive. + if (ParseDirective(Comment, 0, SM, Tok.getLocation(), + SM.getDiagnostics(), Status)) + return true; } - return Found; + return false; } #endif // !NDEBUG @@ -601,41 +656,95 @@ static unsigned CheckResults(DiagnosticsEngine &Diags, SourceManager &SourceMgr, return NumProblems; } +void VerifyDiagnosticConsumer::UpdateParsedFileStatus(SourceManager &SM, + FileID FID, + ParsedStatus PS) { + // Check SourceManager hasn't changed. + setSourceManager(SM); + +#ifndef NDEBUG + if (FID.isInvalid()) + return; + + const FileEntry *FE = SM.getFileEntryForID(FID); + + if (PS == IsParsed) { + // Move the FileID from the unparsed set to the parsed set. + UnparsedFiles.erase(FID); + ParsedFiles.insert(std::make_pair(FID, FE)); + } else if (!ParsedFiles.count(FID) && !UnparsedFiles.count(FID)) { + // Add the FileID to the unparsed set if we haven't seen it before. + + // Check for directives. + bool FoundDirectives; + if (PS == IsUnparsedNoDirectives) + FoundDirectives = false; + else + FoundDirectives = !LangOpts || findDirectives(SM, FID, *LangOpts); + + // Add the FileID to the unparsed set. + UnparsedFiles.insert(std::make_pair(FID, + UnparsedFileStatus(FE, FoundDirectives))); + } +#endif +} + void VerifyDiagnosticConsumer::CheckDiagnostics() { // Ensure any diagnostics go to the primary client. bool OwnsCurClient = Diags.ownsClient(); DiagnosticConsumer *CurClient = Diags.takeClient(); Diags.setClient(PrimaryClient, false); - // If we have a preprocessor, scan the source for expected diagnostic - // markers. If not then any diagnostics are unexpected. - if (CurrentPreprocessor) { - SourceManager &SM = CurrentPreprocessor->getSourceManager(); - #ifndef NDEBUG - // In a debug build, scan through any files that may have been missed - // during parsing and issue a fatal error if directives are contained - // within these files. If a fatal error occurs, this suggests that - // this file is being parsed separately from the main file. - HeaderSearch &HS = CurrentPreprocessor->getHeaderSearchInfo(); - for (FilesWithDiagnosticsSet::iterator I = FilesWithDiagnostics.begin(), - End = FilesWithDiagnostics.end(); - I != End; ++I) { - const FileEntry *E = SM.getFileEntryForID(*I); - // Don't check files already parsed or those handled as modules. - if (E && (FilesParsedForDirectives.count(E) - || HS.findModuleForHeader(E))) + // In a debug build, scan through any files that may have been missed + // during parsing and issue a fatal error if directives are contained + // within these files. If a fatal error occurs, this suggests that + // this file is being parsed separately from the main file, in which + // case consider moving the directives to the correct place, if this + // is applicable. + if (UnparsedFiles.size() > 0) { + // Generate a cache of parsed FileEntry pointers for alias lookups. + llvm::SmallPtrSet<const FileEntry *, 8> ParsedFileCache; + for (ParsedFilesMap::iterator I = ParsedFiles.begin(), + End = ParsedFiles.end(); I != End; ++I) { + if (const FileEntry *FE = I->second) + ParsedFileCache.insert(FE); + } + + // Iterate through list of unparsed files. + for (UnparsedFilesMap::iterator I = UnparsedFiles.begin(), + End = UnparsedFiles.end(); I != End; ++I) { + const UnparsedFileStatus &Status = I->second; + const FileEntry *FE = Status.getFile(); + + // Skip files that have been parsed via an alias. + if (FE && ParsedFileCache.count(FE)) continue; - if (findDirectives(*CurrentPreprocessor, *I)) + // Report a fatal error if this file contained directives. + if (Status.foundDirectives()) { llvm::report_fatal_error(Twine("-verify directives found after rather" " than during normal parsing of ", - StringRef(E ? E->getName() : "(unknown)"))); + StringRef(FE ? FE->getName() : "(unknown)"))); + } + } + + // UnparsedFiles has been processed now, so clear it. + UnparsedFiles.clear(); + } +#endif // !NDEBUG + + if (SrcManager) { + // Produce an error if no expected-* directives could be found in the + // source file(s) processed. + if (Status == HasNoDirectives) { + Diags.Report(diag::err_verify_no_directives).setForceEmit(); + ++NumErrors; + Status = HasNoDirectivesReported; } -#endif // Check that the expected diagnostics occurred. - NumErrors += CheckResults(Diags, SM, *Buffer, ED); + NumErrors += CheckResults(Diags, *SrcManager, *Buffer, ED); } else { NumErrors += (PrintUnexpected(Diags, 0, Buffer->err_begin(), Buffer->err_end(), "error") + diff --git a/lib/Frontend/Warnings.cpp b/lib/Frontend/Warnings.cpp index b7d4a3b92538..f789b7f3053f 100644 --- a/lib/Frontend/Warnings.cpp +++ b/lib/Frontend/Warnings.cpp @@ -24,7 +24,7 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Lex/LexDiagnostic.h" -#include "clang/Frontend/DiagnosticOptions.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include <cstring> #include <utility> @@ -51,8 +51,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags, const DiagnosticOptions &Opts) { Diags.setSuppressSystemWarnings(true); // Default to -Wno-system-headers Diags.setIgnoreAllWarnings(Opts.IgnoreWarnings); - Diags.setShowOverloads( - static_cast<DiagnosticsEngine::OverloadsShown>(Opts.ShowOverloads)); + Diags.setShowOverloads(Opts.getShowOverloads()); Diags.setElideType(Opts.ElideType); Diags.setPrintTemplateTree(Opts.ShowTemplateTree); diff --git a/lib/FrontendTool/CMakeLists.txt b/lib/FrontendTool/CMakeLists.txt index fe9d5896e728..176511b0e4c8 100644 --- a/lib/FrontendTool/CMakeLists.txt +++ b/lib/FrontendTool/CMakeLists.txt @@ -11,7 +11,8 @@ add_dependencies(clangFrontendTool target_link_libraries(clangFrontendTool clangDriver clangFrontend - clangRewrite + clangRewriteCore + clangRewriteFrontend clangCodeGen clangStaticAnalyzerFrontend clangStaticAnalyzerCheckers diff --git a/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/lib/FrontendTool/ExecuteCompilerInvocation.cpp index bd50083bf1c9..c7c55b021145 100644 --- a/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -16,6 +16,7 @@ #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" #include "clang/ARCMigrate/ARCMTActions.h" #include "clang/CodeGen/CodeGenAction.h" +#include "clang/Driver/Option.h" #include "clang/Driver/Options.h" #include "clang/Driver/OptTable.h" #include "clang/Frontend/CompilerInvocation.h" @@ -23,7 +24,7 @@ #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/FrontendPluginRegistry.h" -#include "clang/Rewrite/FrontendActions.h" +#include "clang/Rewrite/Frontend/FrontendActions.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/DynamicLibrary.h" using namespace clang; @@ -137,7 +138,9 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { if (Clang->getFrontendOpts().ShowHelp) { OwningPtr<driver::OptTable> Opts(driver::createDriverOptTable()); Opts->PrintHelp(llvm::outs(), "clang -cc1", - "LLVM 'Clang' Compiler: http://clang.llvm.org"); + "LLVM 'Clang' Compiler: http://clang.llvm.org", + /*Include=*/driver::options::CC1Option, + /*Exclude=*/0); return 0; } @@ -175,7 +178,7 @@ bool clang::ExecuteCompilerInvocation(CompilerInstance *Clang) { // Honor -analyzer-checker-help. // This should happen AFTER plugins have been loaded! - if (Clang->getAnalyzerOpts().ShowCheckerHelp) { + if (Clang->getAnalyzerOpts()->ShowCheckerHelp) { ento::printCheckerHelp(llvm::outs(), Clang->getFrontendOpts().Plugins); return 0; } diff --git a/lib/Headers/CMakeLists.txt b/lib/Headers/CMakeLists.txt index 6e9cc68540b6..25e4d903bb78 100644 --- a/lib/Headers/CMakeLists.txt +++ b/lib/Headers/CMakeLists.txt @@ -6,6 +6,7 @@ set(files bmiintrin.h bmi2intrin.h emmintrin.h + f16cintrin.h float.h fma4intrin.h fmaintrin.h @@ -19,6 +20,7 @@ set(files nmmintrin.h pmmintrin.h popcntintrin.h + rtmintrin.h smmintrin.h stdalign.h stdarg.h @@ -29,6 +31,8 @@ set(files tmmintrin.h varargs.h wmmintrin.h + __wmmintrin_aes.h + __wmmintrin_pclmul.h x86intrin.h xmmintrin.h xopintrin.h diff --git a/lib/Headers/__wmmintrin_aes.h b/lib/Headers/__wmmintrin_aes.h new file mode 100644 index 000000000000..2bfa027e07b1 --- /dev/null +++ b/lib/Headers/__wmmintrin_aes.h @@ -0,0 +1,67 @@ +/*===---- __wmmintrin_aes.h - AES intrinsics -------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ +#ifndef _WMMINTRIN_AES_H +#define _WMMINTRIN_AES_H + +#include <emmintrin.h> + +#if !defined (__AES__) +# error "AES instructions not enabled" +#else + +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_aesenc_si128(__m128i __V, __m128i __R) +{ + return (__m128i)__builtin_ia32_aesenc128(__V, __R); +} + +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_aesenclast_si128(__m128i __V, __m128i __R) +{ + return (__m128i)__builtin_ia32_aesenclast128(__V, __R); +} + +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_aesdec_si128(__m128i __V, __m128i __R) +{ + return (__m128i)__builtin_ia32_aesdec128(__V, __R); +} + +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_aesdeclast_si128(__m128i __V, __m128i __R) +{ + return (__m128i)__builtin_ia32_aesdeclast128(__V, __R); +} + +static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) +_mm_aesimc_si128(__m128i __V) +{ + return (__m128i)__builtin_ia32_aesimc128(__V); +} + +#define _mm_aeskeygenassist_si128(C, R) \ + __builtin_ia32_aeskeygenassist128((C), (R)) + +#endif + +#endif /* _WMMINTRIN_AES_H */ diff --git a/lib/Headers/__wmmintrin_pclmul.h b/lib/Headers/__wmmintrin_pclmul.h new file mode 100644 index 000000000000..8d1f1b7c0868 --- /dev/null +++ b/lib/Headers/__wmmintrin_pclmul.h @@ -0,0 +1,34 @@ +/*===---- __wmmintrin_pclmul.h - AES intrinsics ----------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ +#ifndef _WMMINTRIN_PCLMUL_H +#define _WMMINTRIN_PCLMUL_H + +#if !defined (__PCLMUL__) +# error "PCLMUL instruction is not enabled" +#else +#define _mm_clmulepi64_si128(__X, __Y, __I) \ + ((__m128i)__builtin_ia32_pclmulqdq128((__v2di)(__m128i)(__X), \ + (__v2di)(__m128i)(__Y), (char)(__I))) +#endif + +#endif /* _WMMINTRIN_PCLMUL_H */ diff --git a/lib/Headers/altivec.h b/lib/Headers/altivec.h index a225378c3062..2bf53fb43b9b 100644 --- a/lib/Headers/altivec.h +++ b/lib/Headers/altivec.h @@ -4363,14 +4363,14 @@ vec_perm(vector float a, vector float b, vector unsigned char c) /* vec_vperm */ -vector signed char __ATTRS_o_ai +static vector signed char __ATTRS_o_ai vec_vperm(vector signed char a, vector signed char b, vector unsigned char c) { return (vector signed char) __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); } -vector unsigned char __ATTRS_o_ai +static vector unsigned char __ATTRS_o_ai vec_vperm(vector unsigned char a, vector unsigned char b, vector unsigned char c) @@ -4379,21 +4379,21 @@ vec_vperm(vector unsigned char a, __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); } -vector bool char __ATTRS_o_ai +static vector bool char __ATTRS_o_ai vec_vperm(vector bool char a, vector bool char b, vector unsigned char c) { return (vector bool char) __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); } -vector short __ATTRS_o_ai +static vector short __ATTRS_o_ai vec_vperm(vector short a, vector short b, vector unsigned char c) { return (vector short) __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); } -vector unsigned short __ATTRS_o_ai +static vector unsigned short __ATTRS_o_ai vec_vperm(vector unsigned short a, vector unsigned short b, vector unsigned char c) @@ -4402,41 +4402,41 @@ vec_vperm(vector unsigned short a, __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); } -vector bool short __ATTRS_o_ai +static vector bool short __ATTRS_o_ai vec_vperm(vector bool short a, vector bool short b, vector unsigned char c) { return (vector bool short) __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); } -vector pixel __ATTRS_o_ai +static vector pixel __ATTRS_o_ai vec_vperm(vector pixel a, vector pixel b, vector unsigned char c) { return (vector pixel) __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); } -vector int __ATTRS_o_ai +static vector int __ATTRS_o_ai vec_vperm(vector int a, vector int b, vector unsigned char c) { return (vector int)__builtin_altivec_vperm_4si(a, b, c); } -vector unsigned int __ATTRS_o_ai +static vector unsigned int __ATTRS_o_ai vec_vperm(vector unsigned int a, vector unsigned int b, vector unsigned char c) { return (vector unsigned int) __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); } -vector bool int __ATTRS_o_ai +static vector bool int __ATTRS_o_ai vec_vperm(vector bool int a, vector bool int b, vector unsigned char c) { return (vector bool int) __builtin_altivec_vperm_4si((vector int)a, (vector int)b, c); } -vector float __ATTRS_o_ai +static vector float __ATTRS_o_ai vec_vperm(vector float a, vector float b, vector unsigned char c) { return (vector float) @@ -4445,7 +4445,7 @@ vec_vperm(vector float a, vector float b, vector unsigned char c) /* vec_re */ -vector float __attribute__((__always_inline__)) +static vector float __attribute__((__always_inline__)) vec_re(vector float a) { return __builtin_altivec_vrefp(a); @@ -4453,7 +4453,7 @@ vec_re(vector float a) /* vec_vrefp */ -vector float __attribute__((__always_inline__)) +static vector float __attribute__((__always_inline__)) vec_vrefp(vector float a) { return __builtin_altivec_vrefp(a); diff --git a/lib/Headers/bmi2intrin.h b/lib/Headers/bmi2intrin.h index c60b0c439315..a05cfad3d027 100644 --- a/lib/Headers/bmi2intrin.h +++ b/lib/Headers/bmi2intrin.h @@ -70,6 +70,25 @@ _pext_u64(unsigned long long __X, unsigned long long __Y) return __builtin_ia32_pext_di(__X, __Y); } +static __inline__ unsigned long long __attribute__((__always_inline__, __nodebug__)) +_mulx_u64 (unsigned long long __X, unsigned long long __Y, + unsigned long long *__P) +{ + unsigned __int128 __res = (unsigned __int128) __X * __Y; + *__P = (unsigned long long) (__res >> 64); + return (unsigned long long) __res; +} + +#else /* !__x86_64__ */ + +static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__)) +_mulx_u32 (unsigned int __X, unsigned int __Y, unsigned int *__P) +{ + unsigned long long __res = (unsigned long long) __X * __Y; + *__P = (unsigned int) (__res >> 32); + return (unsigned int) __res; +} + #endif /* !__x86_64__ */ #endif /* __BMI2INTRIN_H */ diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h index 05c293f6bd96..33df7c2d19f0 100644 --- a/lib/Headers/cpuid.h +++ b/lib/Headers/cpuid.h @@ -28,6 +28,6 @@ static inline int __get_cpuid (unsigned int level, unsigned int *eax, unsigned int *ebx, unsigned int *ecx, unsigned int *edx) { - asm("cpuid" : "=a"(*eax), "=b" (*ebx), "=c"(*ecx), "=d"(*edx) : "0"(level)); + __asm("cpuid" : "=a"(*eax), "=b" (*ebx), "=c"(*ecx), "=d"(*edx) : "0"(level)); return 1; } diff --git a/lib/Headers/f16cintrin.h b/lib/Headers/f16cintrin.h new file mode 100644 index 000000000000..2c96952446d6 --- /dev/null +++ b/lib/Headers/f16cintrin.h @@ -0,0 +1,58 @@ +/*===---- f16cintrin.h - F16C intrinsics ---------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#if !defined __X86INTRIN_H && !defined __IMMINTRIN_H +#error "Never use <f16cintrin.h> directly; include <x86intrin.h> instead." +#endif + +#ifndef __F16C__ +# error "F16C instruction is not enabled" +#endif /* __F16C__ */ + +#ifndef __F16CINTRIN_H +#define __F16CINTRIN_H + +typedef float __v8sf __attribute__ ((__vector_size__ (32))); +typedef float __m256 __attribute__ ((__vector_size__ (32))); + +#define _mm_cvtps_ph(a, imm) __extension__ ({ \ + __m128 __a = (a); \ + (__m128i)__builtin_ia32_vcvtps2ph((__v4sf)__a, (imm)); }) + +#define _mm256_cvtps_ph(a, imm) __extension__ ({ \ + __m256 __a = (a); \ + (__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)__a, (imm)); }) + +static __inline __m128 __attribute__((__always_inline__, __nodebug__)) +_mm_cvtph_ps(__m128i a) +{ + return (__m128)__builtin_ia32_vcvtph2ps((__v8hi)a); +} + +static __inline __m256 __attribute__((__always_inline__, __nodebug__)) +_mm256_cvtph_ps(__m128i a) +{ + return (__m256)__builtin_ia32_vcvtph2ps256((__v8hi)a); +} + +#endif /* __F16CINTRIN_H */ diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h index 15b65f3fd8c6..cd733bfc71d3 100644 --- a/lib/Headers/immintrin.h +++ b/lib/Headers/immintrin.h @@ -98,4 +98,8 @@ _rdrand64_step(unsigned long long *__p) #endif #endif /* __RDRND__ */ +#ifdef __RTM__ +#include <rtmintrin.h> +#endif + #endif /* __IMMINTRIN_H */ diff --git a/lib/Headers/module.map b/lib/Headers/module.map index 418ba5009094..b24bccc12056 100644 --- a/lib/Headers/module.map +++ b/lib/Headers/module.map @@ -25,6 +25,11 @@ module _Builtin_intrinsics [system] { header "mmintrin.h" } + explicit module f16c { + requires f16c + header "f16cintrin.h" + } + explicit module sse { requires sse export mmx @@ -62,6 +67,12 @@ module _Builtin_intrinsics [system] { header "nmmintrin.h" } + explicit module sse4a { + requires sse4a + export sse3 + header "ammintrin.h" + } + explicit module avx { requires avx export sse4_2 @@ -84,6 +95,11 @@ module _Builtin_intrinsics [system] { header "bmi2intrin.h" } + explicit module fma { + requires fma + header "fmaintrin.h" + } + explicit module fma4 { requires fma4 export sse3 @@ -104,5 +120,26 @@ module _Builtin_intrinsics [system] { requires mm3dnow header "mm3dnow.h" } + + explicit module xop { + requires xop + export fma4 + header "xopintrin.h" + } + + explicit module aes_pclmul { + requires aes, pclmul + header "wmmintrin.h" + } + + explicit module aes { + requires aes + header "__wmmintrin_aes.h" + } + + explicit module pclmul { + requires pclmul + header "__wmmintrin_pclmul.h" + } } } diff --git a/lib/Headers/rtmintrin.h b/lib/Headers/rtmintrin.h new file mode 100644 index 000000000000..bdc2b994264f --- /dev/null +++ b/lib/Headers/rtmintrin.h @@ -0,0 +1,49 @@ +/*===---- rtmintrin.h - RTM intrinsics -------------------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __IMMINTRIN_H +#error "Never use <rtmintrin.h> directly; include <immintrin.h> instead." +#endif + +#define _XBEGIN_STARTED (~0u) +#define _XABORT_EXPLICIT (1 << 0) +#define _XABORT_RETRY (1 << 1) +#define _XABORT_CONFLICT (1 << 2) +#define _XABORT_CAPACITY (1 << 3) +#define _XABORT_DEBUG (1 << 4) +#define _XABORT_NESTED (1 << 5) +#define _XABORT_CODE(x) (((x) >> 24) & 0xFF) + +static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__)) +_xbegin(void) +{ + return __builtin_ia32_xbegin(); +} + +static __inline__ void __attribute__((__always_inline__, __nodebug__)) +_xend(void) +{ + __builtin_ia32_xend(); +} + +#define _xabort(imm) __builtin_ia32_xabort((imm)) diff --git a/lib/Headers/unwind.h b/lib/Headers/unwind.h index a0659203b15c..6520b8316f3d 100644 --- a/lib/Headers/unwind.h +++ b/lib/Headers/unwind.h @@ -100,7 +100,7 @@ typedef enum { _UVRSR_FAILED = 2 } _Unwind_VRS_Result; -_Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context, +_Unwind_VRS_Result _Unwind_VRS_Get(struct _Unwind_Context *context, _Unwind_VRS_RegClass regclass, uint32_t regno, _Unwind_VRS_DataRepresentation representation, diff --git a/lib/Headers/wmmintrin.h b/lib/Headers/wmmintrin.h index dca896fd65d8..369e3c208e53 100644 --- a/lib/Headers/wmmintrin.h +++ b/lib/Headers/wmmintrin.h @@ -31,48 +31,11 @@ #else #ifdef __AES__ - -static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) -_mm_aesenc_si128(__m128i __V, __m128i __R) -{ - return (__m128i)__builtin_ia32_aesenc128(__V, __R); -} - -static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) -_mm_aesenclast_si128(__m128i __V, __m128i __R) -{ - return (__m128i)__builtin_ia32_aesenclast128(__V, __R); -} - -static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) -_mm_aesdec_si128(__m128i __V, __m128i __R) -{ - return (__m128i)__builtin_ia32_aesdec128(__V, __R); -} - -static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) -_mm_aesdeclast_si128(__m128i __V, __m128i __R) -{ - return (__m128i)__builtin_ia32_aesdeclast128(__V, __R); -} - -static __inline__ __m128i __attribute__((__always_inline__, __nodebug__)) -_mm_aesimc_si128(__m128i __V) -{ - return (__m128i)__builtin_ia32_aesimc128(__V); -} - -#define _mm_aeskeygenassist_si128(C, R) \ - __builtin_ia32_aeskeygenassist128((C), (R)) - +#include <__wmmintrin_aes.h> #endif /* __AES__ */ #ifdef __PCLMUL__ - -#define _mm_clmulepi64_si128(__X, __Y, __I) \ - ((__m128i)__builtin_ia32_pclmulqdq128((__v2di)(__m128i)(__X), \ - (__v2di)(__m128i)(__Y), (char)(__I))) - +#include <__wmmintrin_pclmul.h> #endif /* __PCLMUL__ */ #endif /* __AES__ || __PCLMUL__ */ diff --git a/lib/Headers/x86intrin.h b/lib/Headers/x86intrin.h index 556cd011f05d..68ce106be308 100644 --- a/lib/Headers/x86intrin.h +++ b/lib/Headers/x86intrin.h @@ -58,6 +58,10 @@ #include <xopintrin.h> #endif +#ifdef __F16C__ +#include <f16cintrin.h> +#endif + // FIXME: LWP #endif /* __X86INTRIN_H */ diff --git a/lib/Headers/xmmintrin.h b/lib/Headers/xmmintrin.h index e616157b047c..e2480ec7a0e3 100644 --- a/lib/Headers/xmmintrin.h +++ b/lib/Headers/xmmintrin.h @@ -95,7 +95,8 @@ _mm_div_ps(__m128 a, __m128 b) static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_sqrt_ss(__m128 a) { - return __builtin_ia32_sqrtss(a); + __m128 c = __builtin_ia32_sqrtss(a); + return (__m128) { c[0], a[1], a[2], a[3] }; } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) @@ -107,7 +108,8 @@ _mm_sqrt_ps(__m128 a) static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_rcp_ss(__m128 a) { - return __builtin_ia32_rcpss(a); + __m128 c = __builtin_ia32_rcpss(a); + return (__m128) { c[0], a[1], a[2], a[3] }; } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) @@ -119,7 +121,8 @@ _mm_rcp_ps(__m128 a) static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) _mm_rsqrt_ss(__m128 a) { - return __builtin_ia32_rsqrtss(a); + __m128 c = __builtin_ia32_rsqrtss(a); + return (__m128) { c[0], a[1], a[2], a[3] }; } static __inline__ __m128 __attribute__((__always_inline__, __nodebug__)) diff --git a/lib/Lex/HeaderMap.cpp b/lib/Lex/HeaderMap.cpp index bbfc1df76fdd..7dc0491392cc 100644 --- a/lib/Lex/HeaderMap.cpp +++ b/lib/Lex/HeaderMap.cpp @@ -144,7 +144,7 @@ HMapBucket HeaderMap::getBucket(unsigned BucketNo) const { sizeof(HMapHeader)); const HMapBucket *BucketPtr = BucketArray+BucketNo; - if ((char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) { + if ((const char*)(BucketPtr+1) > FileBuffer->getBufferEnd()) { Result.Prefix = 0; Result.Suffix = 0; return Result; // Invalid buffer, corrupt hmap. diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index bb3a67378ad5..67000b682982 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/HeaderMap.h" #include "clang/Lex/Lexer.h" #include "clang/Basic/Diagnostic.h" @@ -38,10 +39,11 @@ HeaderFileInfo::getControllingMacro(ExternalIdentifierLookup *External) { ExternalHeaderFileInfoSource::~ExternalHeaderFileInfoSource() {} -HeaderSearch::HeaderSearch(FileManager &FM, DiagnosticsEngine &Diags, +HeaderSearch::HeaderSearch(llvm::IntrusiveRefCntPtr<HeaderSearchOptions> HSOpts, + FileManager &FM, DiagnosticsEngine &Diags, const LangOptions &LangOpts, const TargetInfo *Target) - : FileMgr(FM), Diags(Diags), FrameworkMap(64), + : HSOpts(HSOpts), FileMgr(FM), FrameworkMap(64), ModMap(FileMgr, *Diags.getClient(), LangOpts, Target) { AngledDirIdx = 0; @@ -905,7 +907,20 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name, SubmodulePath.push_back(Name); // Walk the directory structure to find any enclosing frameworks. +#ifdef LLVM_ON_UNIX + // Note: as an egregious but useful hack we use the real path here, because + // frameworks moving from top-level frameworks to embedded frameworks tend + // to be symlinked from the top-level location to the embedded location, + // and we need to resolve lookups as if we had found the embedded location. + char RealDirName[PATH_MAX]; + StringRef DirName; + if (realpath(Dir->getName(), RealDirName)) + DirName = RealDirName; + else + DirName = Dir->getName(); +#else StringRef DirName = Dir->getName(); +#endif do { // Get the parent directory name. DirName = llvm::sys::path::parent_path(DirName); @@ -924,7 +939,33 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name, TopFrameworkDir = Dir; } } while (true); - + + // Determine whether we're allowed to infer a module map. + bool canInfer = false; + if (llvm::sys::path::has_parent_path(TopFrameworkDir->getName())) { + // Figure out the parent path. + StringRef Parent = llvm::sys::path::parent_path(TopFrameworkDir->getName()); + if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) { + // If there's a module map file in the parent directory, it can + // explicitly allow us to infer framework modules. + switch (loadModuleMapFile(ParentDir)) { + case LMM_AlreadyLoaded: + case LMM_NewlyLoaded: { + StringRef Name = llvm::sys::path::stem(TopFrameworkDir->getName()); + canInfer = ModMap.canInferFrameworkModule(ParentDir, Name, IsSystem); + break; + } + case LMM_InvalidModuleMap: + case LMM_NoDirectory: + break; + } + } + } + + // If we're not allowed to infer a module map, we're done. + if (!canInfer) + return 0; + // Try to infer a module map from the top-level framework directory. Module *Result = ModMap.inferFrameworkModule(SubmodulePath.back(), TopFrameworkDir, diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 5212dd86e7a1..a5ba7dbe0a93 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -513,10 +513,13 @@ Lexer::ComputePreamble(const llvm::MemoryBuffer *Buffer, // "fake" file source location at offset 1 so that the lexer will track our // position within the file. const unsigned StartOffset = 1; - SourceLocation StartLoc = SourceLocation::getFromRawEncoding(StartOffset); - Lexer TheLexer(StartLoc, LangOpts, Buffer->getBufferStart(), + SourceLocation FileLoc = SourceLocation::getFromRawEncoding(StartOffset); + Lexer TheLexer(FileLoc, LangOpts, Buffer->getBufferStart(), Buffer->getBufferStart(), Buffer->getBufferEnd()); - + + // StartLoc will differ from FileLoc if there is a BOM that was skipped. + SourceLocation StartLoc = TheLexer.getSourceLocation(); + bool InPreprocessorDirective = false; Token TheTok; Token IfStartTok; @@ -1534,7 +1537,7 @@ FinishIdentifier: /// isHexaLiteral - Return true if Start points to a hex constant. /// in microsoft mode (where this is supposed to be several different tokens). -static bool isHexaLiteral(const char *Start, const LangOptions &LangOpts) { +bool Lexer::isHexaLiteral(const char *Start, const LangOptions &LangOpts) { unsigned Size; char C1 = Lexer::getCharAndSizeNoWarn(Start, Size, LangOpts); if (C1 != '0') @@ -1813,17 +1816,18 @@ void Lexer::LexCharConstant(Token &Result, const char *CurPtr, while (C != '\'') { // Skip escaped characters. - if (C == '\\') { - // Skip the escaped character. - // FIXME: UCN's - getAndAdvanceChar(CurPtr, Result); - } else if (C == '\n' || C == '\r' || // Newline. - (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. + if (C == '\\') + C = getAndAdvanceChar(CurPtr, Result); + + if (C == '\n' || C == '\r' || // Newline. + (C == 0 && CurPtr-1 == BufferEnd)) { // End of file. if (!isLexingRawMode() && !LangOpts.AsmPreprocessor) Diag(BufferPtr, diag::ext_unterminated_char); FormTokenWithChars(Result, CurPtr-1, tok::unknown); return; - } else if (C == 0) { + } + + if (C == 0) { if (isCodeCompletionPoint(CurPtr-1)) { PP->CodeCompleteNaturalLanguage(); FormTokenWithChars(Result, CurPtr-1, tok::unknown); @@ -1895,21 +1899,21 @@ bool Lexer::SkipWhitespace(Token &Result, const char *CurPtr) { return false; } -// SkipBCPLComment - We have just read the // characters from input. Skip until -// we find the newline character thats terminate the comment. Then update -/// BufferPtr and return. +/// We have just read the // characters from input. Skip until we find the +/// newline character thats terminate the comment. Then update BufferPtr and +/// return. /// /// If we're in KeepCommentMode or any CommentHandler has inserted /// some tokens, this will store the first token and return true. -bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { - // If BCPL comments aren't explicitly enabled for this language, emit an +bool Lexer::SkipLineComment(Token &Result, const char *CurPtr) { + // If Line comments aren't explicitly enabled for this language, emit an // extension warning. - if (!LangOpts.BCPLComment && !isLexingRawMode()) { - Diag(BufferPtr, diag::ext_bcpl_comment); + if (!LangOpts.LineComment && !isLexingRawMode()) { + Diag(BufferPtr, diag::ext_line_comment); // Mark them enabled so we only emit one warning for this translation // unit. - LangOpts.BCPLComment = true; + LangOpts.LineComment = true; } // Scan over the body of the comment. The common case, when scanning, is that @@ -1973,7 +1977,7 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { } if (!isLexingRawMode()) - Diag(OldPtr-1, diag::ext_multi_line_bcpl_comment); + Diag(OldPtr-1, diag::ext_multi_line_line_comment); break; } } @@ -2002,7 +2006,7 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { // If we are returning comments as tokens, return this comment as a token. if (inKeepCommentMode()) - return SaveBCPLComment(Result, CurPtr); + return SaveLineComment(Result, CurPtr); // If we are inside a preprocessor directive and we see the end of line, // return immediately, so that the lexer can return this as an EOD token. @@ -2026,9 +2030,9 @@ bool Lexer::SkipBCPLComment(Token &Result, const char *CurPtr) { return false; } -/// SaveBCPLComment - If in save-comment mode, package up this BCPL comment in -/// an appropriate way and return it. -bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) { +/// If in save-comment mode, package up this Line comment in an appropriate +/// way and return it. +bool Lexer::SaveLineComment(Token &Result, const char *CurPtr) { // If we're not in a preprocessor directive, just return the // comment // directly. FormTokenWithChars(Result, CurPtr, tok::comment); @@ -2036,19 +2040,19 @@ bool Lexer::SaveBCPLComment(Token &Result, const char *CurPtr) { if (!ParsingPreprocessorDirective || LexingRawMode) return true; - // If this BCPL-style comment is in a macro definition, transmogrify it into + // If this Line-style comment is in a macro definition, transmogrify it into // a C-style block comment. bool Invalid = false; std::string Spelling = PP->getSpelling(Result, &Invalid); if (Invalid) return true; - assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not bcpl comment?"); + assert(Spelling[0] == '/' && Spelling[1] == '/' && "Not line comment?"); Spelling[1] = '*'; // Change prefix to "/*". Spelling += "*/"; // add suffix. Result.setKind(tok::comment); - PP->CreateString(&Spelling[0], Spelling.size(), Result, + PP->CreateString(Spelling, Result, Result.getLocation(), Result.getLocation()); return true; } @@ -2179,7 +2183,8 @@ bool Lexer::SkipBlockComment(Token &Result, const char *CurPtr) { #ifdef __SSE2__ __m128i Slashes = _mm_set1_epi8('/'); while (CurPtr+16 <= BufferEnd) { - int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(__m128i*)CurPtr, Slashes)); + int cmp = _mm_movemask_epi8(_mm_cmpeq_epi8(*(const __m128i*)CurPtr, + Slashes)); if (cmp != 0) { // Adjust the pointer to point directly after the first slash. It's // not necessary to set C here, it will be overwritten at the end of @@ -2669,8 +2674,8 @@ LexNextToken: // If the next token is obviously a // or /* */ comment, skip it efficiently // too (without going through the big switch stmt). if (CurPtr[0] == '/' && CurPtr[1] == '/' && !inKeepCommentMode() && - LangOpts.BCPLComment && !LangOpts.TraditionalCPP) { - if (SkipBCPLComment(Result, CurPtr+2)) + LangOpts.LineComment && !LangOpts.TraditionalCPP) { + if (SkipLineComment(Result, CurPtr+2)) return; // There is a token to return. goto SkipIgnoredUnits; } else if (CurPtr[0] == '/' && CurPtr[1] == '*' && !inKeepCommentMode()) { @@ -2955,19 +2960,19 @@ LexNextToken: case '/': // 6.4.9: Comments Char = getCharAndSize(CurPtr, SizeTmp); - if (Char == '/') { // BCPL comment. - // Even if BCPL comments are disabled (e.g. in C89 mode), we generally + if (Char == '/') { // Line comment. + // Even if Line comments are disabled (e.g. in C89 mode), we generally // want to lex this as a comment. There is one problem with this though, // that in one particular corner case, this can change the behavior of the // resultant program. For example, In "foo //**/ bar", C89 would lex - // this as "foo / bar" and langauges with BCPL comments would lex it as + // this as "foo / bar" and langauges with Line comments would lex it as // "foo". Check to see if the character after the second slash is a '*'. // If so, we will lex that as a "/" instead of the start of a comment. // However, we never do this in -traditional-cpp mode. - if ((LangOpts.BCPLComment || + if ((LangOpts.LineComment || getCharAndSize(CurPtr+SizeTmp, SizeTmp2) != '*') && !LangOpts.TraditionalCPP) { - if (SkipBCPLComment(Result, ConsumeChar(CurPtr, SizeTmp, Result))) + if (SkipLineComment(Result, ConsumeChar(CurPtr, SizeTmp, Result))) return; // There is a token to return. // It is common for the tokens immediately after a // comment to be diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index 9e3c7786a732..e30612e57c5b 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -49,12 +49,46 @@ static unsigned getCharWidth(tok::TokenKind kind, const TargetInfo &Target) { } } +static CharSourceRange MakeCharSourceRange(const LangOptions &Features, + FullSourceLoc TokLoc, + const char *TokBegin, + const char *TokRangeBegin, + const char *TokRangeEnd) { + SourceLocation Begin = + Lexer::AdvanceToTokenCharacter(TokLoc, TokRangeBegin - TokBegin, + TokLoc.getManager(), Features); + SourceLocation End = + Lexer::AdvanceToTokenCharacter(Begin, TokRangeEnd - TokRangeBegin, + TokLoc.getManager(), Features); + return CharSourceRange::getCharRange(Begin, End); +} + +/// \brief Produce a diagnostic highlighting some portion of a literal. +/// +/// Emits the diagnostic \p DiagID, highlighting the range of characters from +/// \p TokRangeBegin (inclusive) to \p TokRangeEnd (exclusive), which must be +/// a substring of a spelling buffer for the token beginning at \p TokBegin. +static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, + const LangOptions &Features, FullSourceLoc TokLoc, + const char *TokBegin, const char *TokRangeBegin, + const char *TokRangeEnd, unsigned DiagID) { + SourceLocation Begin = + Lexer::AdvanceToTokenCharacter(TokLoc, TokRangeBegin - TokBegin, + TokLoc.getManager(), Features); + return Diags->Report(Begin, DiagID) << + MakeCharSourceRange(Features, TokLoc, TokBegin, TokRangeBegin, TokRangeEnd); +} + /// ProcessCharEscape - Parse a standard C escape sequence, which can occur in /// either a character or a string literal. -static unsigned ProcessCharEscape(const char *&ThisTokBuf, +static unsigned ProcessCharEscape(const char *ThisTokBegin, + const char *&ThisTokBuf, const char *ThisTokEnd, bool &HadError, FullSourceLoc Loc, unsigned CharWidth, - DiagnosticsEngine *Diags) { + DiagnosticsEngine *Diags, + const LangOptions &Features) { + const char *EscapeBegin = ThisTokBuf; + // Skip the '\' char. ++ThisTokBuf; @@ -75,12 +109,14 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, break; case 'e': if (Diags) - Diags->Report(Loc, diag::ext_nonstandard_escape) << "e"; + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::ext_nonstandard_escape) << "e"; ResultChar = 27; break; case 'E': if (Diags) - Diags->Report(Loc, diag::ext_nonstandard_escape) << "E"; + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::ext_nonstandard_escape) << "E"; ResultChar = 27; break; case 'f': @@ -102,7 +138,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, ResultChar = 0; if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) { if (Diags) - Diags->Report(Loc, diag::err_hex_escape_no_digits); + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::err_hex_escape_no_digits); HadError = 1; break; } @@ -126,7 +163,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, // Check for overflow. if (Overflow && Diags) // Too many digits to fit in - Diags->Report(Loc, diag::warn_hex_escape_too_large); + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::warn_hex_escape_too_large); break; } case '0': case '1': case '2': case '3': @@ -148,7 +186,8 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, // Check for overflow. Reject '\777', but not L'\777'. if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { if (Diags) - Diags->Report(Loc, diag::warn_octal_escape_too_large); + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::warn_octal_escape_too_large); ResultChar &= ~0U >> (32-CharWidth); } break; @@ -158,19 +197,22 @@ static unsigned ProcessCharEscape(const char *&ThisTokBuf, case '(': case '{': case '[': case '%': // GCC accepts these as extensions. We warn about them as such though. if (Diags) - Diags->Report(Loc, diag::ext_nonstandard_escape) - << std::string()+(char)ResultChar; + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::ext_nonstandard_escape) + << std::string(1, ResultChar); break; default: if (Diags == 0) break; - + if (isgraph(ResultChar)) - Diags->Report(Loc, diag::ext_unknown_escape) - << std::string()+(char)ResultChar; + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::ext_unknown_escape) + << std::string(1, ResultChar); else - Diags->Report(Loc, diag::ext_unknown_escape) - << "x"+llvm::utohexstr(ResultChar); + Diag(Diags, Features, Loc, ThisTokBegin, EscapeBegin, ThisTokBuf, + diag::ext_unknown_escape) + << "x" + llvm::utohexstr(ResultChar); break; } @@ -185,9 +227,6 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, FullSourceLoc Loc, DiagnosticsEngine *Diags, const LangOptions &Features, bool in_char_string_literal = false) { - if (!Features.CPlusPlus && !Features.C99 && Diags) - Diags->Report(Loc, diag::warn_ucn_not_valid_in_c89); - const char *UcnBegin = ThisTokBuf; // Skip the '\u' char's. @@ -195,7 +234,8 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, if (ThisTokBuf == ThisTokEnd || !isxdigit(*ThisTokBuf)) { if (Diags) - Diags->Report(Loc, diag::err_ucn_escape_no_digits); + Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, + diag::err_ucn_escape_no_digits); return false; } UcnLen = (ThisTokBuf[-1] == 'u' ? 4 : 8); @@ -208,12 +248,9 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, } // If we didn't consume the proper number of digits, there is a problem. if (UcnLenSave) { - if (Diags) { - SourceLocation L = - Lexer::AdvanceToTokenCharacter(Loc, UcnBegin - ThisTokBegin, - Loc.getManager(), Features); - Diags->Report(L, diag::err_ucn_escape_incomplete); - } + if (Diags) + Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, + diag::err_ucn_escape_incomplete); return false; } @@ -221,7 +258,8 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, if ((0xD800 <= UcnVal && UcnVal <= 0xDFFF) || // surrogate codepoints UcnVal > 0x10FFFF) { // maximum legal UTF32 value if (Diags) - Diags->Report(Loc, diag::err_ucn_escape_invalid); + Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, + diag::err_ucn_escape_invalid); return false; } @@ -231,22 +269,25 @@ static bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, (UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60)) { // $, @, ` bool IsError = (!Features.CPlusPlus0x || !in_char_string_literal); if (Diags) { - SourceLocation UcnBeginLoc = - Lexer::AdvanceToTokenCharacter(Loc, UcnBegin - ThisTokBegin, - Loc.getManager(), Features); char BasicSCSChar = UcnVal; if (UcnVal >= 0x20 && UcnVal < 0x7f) - Diags->Report(UcnBeginLoc, IsError ? diag::err_ucn_escape_basic_scs : - diag::warn_cxx98_compat_literal_ucn_escape_basic_scs) - << StringRef(&BasicSCSChar, 1); + Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, + IsError ? diag::err_ucn_escape_basic_scs : + diag::warn_cxx98_compat_literal_ucn_escape_basic_scs) + << StringRef(&BasicSCSChar, 1); else - Diags->Report(UcnBeginLoc, IsError ? diag::err_ucn_control_character : - diag::warn_cxx98_compat_literal_ucn_control_character); + Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, + IsError ? diag::err_ucn_control_character : + diag::warn_cxx98_compat_literal_ucn_control_character); } if (IsError) return false; } + if (!Features.CPlusPlus && !Features.C99 && Diags) + Diag(Diags, Features, Loc, ThisTokBegin, UcnBegin, ThisTokBuf, + diag::warn_ucn_not_valid_in_c89); + return true; } @@ -365,10 +406,10 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, // Finally, we write the bytes into ResultBuf. ResultBuf += bytesToWrite; switch (bytesToWrite) { // note: everything falls through. - case 4: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6; - case 3: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6; - case 2: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6; - case 1: *--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]); + case 4: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6; + case 3: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6; + case 2: *--ResultBuf = (UTF8)((UcnVal | byteMark) & byteMask); UcnVal >>= 6; + case 1: *--ResultBuf = (UTF8) (UcnVal | firstByteMark[bytesToWrite]); } // Update the buffer. ResultBuf += bytesToWrite; @@ -417,19 +458,19 @@ static void EncodeUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, /// floating-constant: [C99 6.4.4.2] /// TODO: add rules... /// -NumericLiteralParser:: -NumericLiteralParser(const char *begin, const char *end, - SourceLocation TokLoc, Preprocessor &pp) - : PP(pp), ThisTokBegin(begin), ThisTokEnd(end) { +NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, + SourceLocation TokLoc, + Preprocessor &PP) + : PP(PP), ThisTokBegin(TokSpelling.begin()), ThisTokEnd(TokSpelling.end()) { // This routine assumes that the range begin/end matches the regex for integer // and FP constants (specifically, the 'pp-number' regex), and assumes that // the byte at "*end" is both valid and not part of the regex. Because of // this, it doesn't have to check for 'overscan' in various places. - assert(!isalnum(*end) && *end != '.' && *end != '_' && + assert(!isalnum(*ThisTokEnd) && *ThisTokEnd != '.' && *ThisTokEnd != '_' && "Lexer didn't maximally munch?"); - s = DigitsBegin = begin; + s = DigitsBegin = ThisTokBegin; saw_exponent = false; saw_period = false; saw_ud_suffix = false; @@ -451,7 +492,7 @@ NumericLiteralParser(const char *begin, const char *end, if (s == ThisTokEnd) { // Done. } else if (isxdigit(*s) && !(*s == 'e' || *s == 'E')) { - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin), + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin), diag::err_invalid_decimal_digit) << StringRef(s, 1); hadError = true; return; @@ -469,7 +510,7 @@ NumericLiteralParser(const char *begin, const char *end, if (first_non_digit != s) { s = first_non_digit; } else { - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent-begin), + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, Exponent - ThisTokBegin), diag::err_exponent_has_no_digits); hadError = true; return; @@ -565,7 +606,7 @@ NumericLiteralParser(const char *begin, const char *end, case 'j': case 'J': if (isImaginary) break; // Cannot be repeated. - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-begin), + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin), diag::ext_imaginary_constant); isImaginary = true; continue; // Success. @@ -583,7 +624,7 @@ NumericLiteralParser(const char *begin, const char *end, } // Report an error if there are any. - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin-begin), + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, SuffixBegin - ThisTokBegin), isFPConstant ? diag::err_invalid_suffix_float_constant : diag::err_invalid_suffix_integer_constant) << StringRef(SuffixBegin, ThisTokEnd-SuffixBegin); @@ -619,7 +660,7 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { } if (noSignificand) { - PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s-ThisTokBegin), \ + PP.Diag(PP.AdvanceToTokenCharacter(TokLoc, s - ThisTokBegin), diag::err_hexconstant_requires_digits); hadError = true; return; @@ -722,6 +763,20 @@ void NumericLiteralParser::ParseNumberStartingWithZero(SourceLocation TokLoc) { } } +static bool alwaysFitsInto64Bits(unsigned Radix, unsigned NumDigits) { + switch (Radix) { + case 2: + return NumDigits <= 64; + case 8: + return NumDigits <= 64 / 3; // Digits are groups of 3 bits. + case 10: + return NumDigits <= 19; // floor(log10(2^64)) + case 16: + return NumDigits <= 64 / 4; // Digits are groups of 4 bits. + default: + llvm_unreachable("impossible Radix"); + } +} /// GetIntegerValue - Convert this numeric literal value to an APInt that /// matches Val's input width. If there is an overflow, set Val to the low bits @@ -733,13 +788,11 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) { // integer. This avoids the expensive overflow checking below, and // handles the common cases that matter (small decimal integers and // hex/octal values which don't overflow). - unsigned MaxBitsPerDigit = 1; - while ((1U << MaxBitsPerDigit) < radix) - MaxBitsPerDigit += 1; - if ((SuffixBegin - DigitsBegin) * MaxBitsPerDigit <= 64) { + const unsigned NumDigits = SuffixBegin - DigitsBegin; + if (alwaysFitsInto64Bits(radix, NumDigits)) { uint64_t N = 0; - for (s = DigitsBegin; s != SuffixBegin; ++s) - N = N*radix + HexDigitValue(*s); + for (const char *Ptr = DigitsBegin; Ptr != SuffixBegin; ++Ptr) + N = N * radix + HexDigitValue(*Ptr); // This will truncate the value to Val's input width. Simply check // for overflow by comparing. @@ -748,15 +801,15 @@ bool NumericLiteralParser::GetIntegerValue(llvm::APInt &Val) { } Val = 0; - s = DigitsBegin; + const char *Ptr = DigitsBegin; llvm::APInt RadixVal(Val.getBitWidth(), radix); llvm::APInt CharVal(Val.getBitWidth(), 0); llvm::APInt OldVal = Val; bool OverflowOccurred = false; - while (s < SuffixBegin) { - unsigned C = HexDigitValue(*s++); + while (Ptr < SuffixBegin) { + unsigned C = HexDigitValue(*Ptr++); // If this letter is out of bound for this radix, reject it. assert(C < radix && "NumericLiteralParser ctor should have rejected this"); @@ -943,7 +996,7 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, HadError = true; } else if (*buffer_begin > largest_character_for_kind) { HadError = true; - PP.Diag(Loc,diag::err_character_too_large); + PP.Diag(Loc, diag::err_character_too_large); } ++buffer_begin; @@ -951,9 +1004,9 @@ CharLiteralParser::CharLiteralParser(const char *begin, const char *end, } unsigned CharWidth = getCharWidth(Kind, PP.getTargetInfo()); uint64_t result = - ProcessCharEscape(begin, end, HadError, - FullSourceLoc(Loc,PP.getSourceManager()), - CharWidth, &PP.getDiagnostics()); + ProcessCharEscape(TokBegin, begin, end, HadError, + FullSourceLoc(Loc,PP.getSourceManager()), + CharWidth, &PP.getDiagnostics(), PP.getLangOpts()); *buffer_begin++ = result; } @@ -1110,7 +1163,7 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ Kind = StringToks[i].getKind(); } else { if (Diags) - Diags->Report(FullSourceLoc(StringToks[i].getLocation(), SM), + Diags->Report(StringToks[i].getLocation(), diag::err_unsupported_string_concat); hadError = true; } @@ -1218,9 +1271,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ assert(ThisTokEnd >= ThisTokBuf && "malformed raw string literal"); // Copy the string over - if (CopyStringFragment(StringRef(ThisTokBuf, ThisTokEnd - ThisTokBuf))) - if (DiagnoseBadString(StringToks[i])) - hadError = true; + if (CopyStringFragment(StringToks[i], ThisTokBegin, + StringRef(ThisTokBuf, ThisTokEnd - ThisTokBuf))) + hadError = true; } else { if (ThisTokBuf[0] != '"') { // The file may have come from PCH and then changed after loading the @@ -1251,9 +1304,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ } while (ThisTokBuf != ThisTokEnd && ThisTokBuf[0] != '\\'); // Copy the character span over. - if (CopyStringFragment(StringRef(InStart, ThisTokBuf - InStart))) - if (DiagnoseBadString(StringToks[i])) - hadError = true; + if (CopyStringFragment(StringToks[i], ThisTokBegin, + StringRef(InStart, ThisTokBuf - InStart))) + hadError = true; continue; } // Is this a Universal Character Name escape? @@ -1266,9 +1319,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ } // Otherwise, this is a non-UCN escape character. Process it. unsigned ResultChar = - ProcessCharEscape(ThisTokBuf, ThisTokEnd, hadError, + ProcessCharEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd, hadError, FullSourceLoc(StringToks[i].getLocation(), SM), - CharByteWidth*8, Diags); + CharByteWidth*8, Diags, Features); if (CharByteWidth == 4) { // FIXME: Make the type of the result buffer correct instead of @@ -1308,8 +1361,8 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ // Verify that pascal strings aren't too large. if (GetStringLength() > 256) { - if (Diags) - Diags->Report(FullSourceLoc(StringToks[0].getLocation(), SM), + if (Diags) + Diags->Report(StringToks[0].getLocation(), diag::err_pascal_string_too_long) << SourceRange(StringToks[0].getLocation(), StringToks[NumStringToks-1].getLocation()); @@ -1319,9 +1372,9 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ } else if (Diags) { // Complain if this string literal has too many characters. unsigned MaxChars = Features.CPlusPlus? 65536 : Features.C99 ? 4095 : 509; - + if (GetNumStringChars() > MaxChars) - Diags->Report(FullSourceLoc(StringToks[0].getLocation(), SM), + Diags->Report(StringToks[0].getLocation(), diag::ext_string_too_long) << GetNumStringChars() << MaxChars << (Features.CPlusPlus ? 2 : Features.C99 ? 1 : 0) @@ -1330,21 +1383,61 @@ void StringLiteralParser::init(const Token *StringToks, unsigned NumStringToks){ } } -/// copyStringFragment - This function copies from Start to End into ResultPtr. -/// Performs widening for multi-byte characters. -bool StringLiteralParser::CopyStringFragment(StringRef Fragment) { - return !ConvertUTF8toWide(CharByteWidth, Fragment, ResultPtr); +static const char *resyncUTF8(const char *Err, const char *End) { + if (Err == End) + return End; + End = Err + std::min<unsigned>(getNumBytesForUTF8(*Err), End-Err); + while (++Err != End && (*Err & 0xC0) == 0x80) + ; + return Err; } -bool StringLiteralParser::DiagnoseBadString(const Token &Tok) { +/// \brief This function copies from Fragment, which is a sequence of bytes +/// within Tok's contents (which begin at TokBegin) into ResultPtr. +/// Performs widening for multi-byte characters. +bool StringLiteralParser::CopyStringFragment(const Token &Tok, + const char *TokBegin, + StringRef Fragment) { + const UTF8 *ErrorPtrTmp; + if (ConvertUTF8toWide(CharByteWidth, Fragment, ResultPtr, ErrorPtrTmp)) + return false; + // If we see bad encoding for unprefixed string literals, warn and // simply copy the byte values, for compatibility with gcc and older // versions of clang. bool NoErrorOnBadEncoding = isAscii(); - unsigned Msg = NoErrorOnBadEncoding ? diag::warn_bad_string_encoding : - diag::err_bad_string_encoding; - if (Diags) - Diags->Report(FullSourceLoc(Tok.getLocation(), SM), Msg); + if (NoErrorOnBadEncoding) { + memcpy(ResultPtr, Fragment.data(), Fragment.size()); + ResultPtr += Fragment.size(); + } + + if (Diags) { + const char *ErrorPtr = reinterpret_cast<const char *>(ErrorPtrTmp); + + FullSourceLoc SourceLoc(Tok.getLocation(), SM); + const DiagnosticBuilder &Builder = + Diag(Diags, Features, SourceLoc, TokBegin, + ErrorPtr, resyncUTF8(ErrorPtr, Fragment.end()), + NoErrorOnBadEncoding ? diag::warn_bad_string_encoding + : diag::err_bad_string_encoding); + + const char *NextStart = resyncUTF8(ErrorPtr, Fragment.end()); + StringRef NextFragment(NextStart, Fragment.end()-NextStart); + + // Decode into a dummy buffer. + SmallString<512> Dummy; + Dummy.reserve(Fragment.size() * CharByteWidth); + char *Ptr = Dummy.data(); + + while (!Builder.hasMaxRanges() && + !ConvertUTF8toWide(CharByteWidth, NextFragment, Ptr, ErrorPtrTmp)) { + const char *ErrorPtr = reinterpret_cast<const char *>(ErrorPtrTmp); + NextStart = resyncUTF8(ErrorPtr, Fragment.end()); + Builder << MakeCharSourceRange(Features, SourceLoc, TokBegin, + ErrorPtr, NextStart); + NextFragment = StringRef(NextStart, Fragment.end()-NextStart); + } + } return !NoErrorOnBadEncoding; } @@ -1422,9 +1515,9 @@ unsigned StringLiteralParser::getOffsetOfStringByte(const Token &Tok, } ByteNo -= Len; } else { - ProcessCharEscape(SpellingPtr, SpellingEnd, HadError, + ProcessCharEscape(SpellingStart, SpellingPtr, SpellingEnd, HadError, FullSourceLoc(Tok.getLocation(), SM), - CharByteWidth*8, Diags); + CharByteWidth*8, Diags, Features); --ByteNo; } assert(!HadError && "This method isn't valid on erroneous strings"); diff --git a/lib/Lex/MacroArgs.cpp b/lib/Lex/MacroArgs.cpp index e2b251a4499d..ed8873d08612 100644 --- a/lib/Lex/MacroArgs.cpp +++ b/lib/Lex/MacroArgs.cpp @@ -291,7 +291,7 @@ Token MacroArgs::StringifyArgument(const Token *ArgToks, } } - PP.CreateString(&Result[0], Result.size(), Tok, + PP.CreateString(Result, Tok, ExpansionLocStart, ExpansionLocEnd); return Tok; } diff --git a/lib/Lex/MacroInfo.cpp b/lib/Lex/MacroInfo.cpp index 3d0c9a1c2b51..904f04e4f836 100644 --- a/lib/Lex/MacroInfo.cpp +++ b/lib/Lex/MacroInfo.cpp @@ -15,47 +15,65 @@ #include "clang/Lex/Preprocessor.h" using namespace clang; -MacroInfo::MacroInfo(SourceLocation DefLoc) : Location(DefLoc) { - IsFunctionLike = false; - IsC99Varargs = false; - IsGNUVarargs = false; - IsBuiltinMacro = false; - IsFromAST = false; - ChangedAfterLoad = false; - IsDisabled = false; - IsUsed = false; - IsAllowRedefinitionsWithoutWarning = false; - IsWarnIfUnused = false; - IsDefinitionLengthCached = false; - IsPublic = true; - - ArgumentList = 0; - NumArguments = 0; +MacroInfo::MacroInfo(SourceLocation DefLoc) + : Location(DefLoc), + PreviousDefinition(0), + ArgumentList(0), + NumArguments(0), + IsDefinitionLengthCached(false), + IsFunctionLike(false), + IsC99Varargs(false), + IsGNUVarargs(false), + IsBuiltinMacro(false), + IsFromAST(false), + ChangedAfterLoad(false), + IsDisabled(false), + IsUsed(false), + IsAllowRedefinitionsWithoutWarning(false), + IsWarnIfUnused(false), + IsPublic(true), + IsHidden(false), + IsAmbiguous(false) { } -MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) { - Location = MI.Location; - EndLocation = MI.EndLocation; - ReplacementTokens = MI.ReplacementTokens; - IsFunctionLike = MI.IsFunctionLike; - IsC99Varargs = MI.IsC99Varargs; - IsGNUVarargs = MI.IsGNUVarargs; - IsBuiltinMacro = MI.IsBuiltinMacro; - IsFromAST = MI.IsFromAST; - ChangedAfterLoad = MI.ChangedAfterLoad; - IsDisabled = MI.IsDisabled; - IsUsed = MI.IsUsed; - IsAllowRedefinitionsWithoutWarning = MI.IsAllowRedefinitionsWithoutWarning; - IsWarnIfUnused = MI.IsWarnIfUnused; - IsDefinitionLengthCached = MI.IsDefinitionLengthCached; - DefinitionLength = MI.DefinitionLength; - IsPublic = MI.IsPublic; - - ArgumentList = 0; - NumArguments = 0; +MacroInfo::MacroInfo(const MacroInfo &MI, llvm::BumpPtrAllocator &PPAllocator) + : Location(MI.Location), + EndLocation(MI.EndLocation), + UndefLocation(MI.UndefLocation), + PreviousDefinition(0), + ArgumentList(0), + NumArguments(0), + ReplacementTokens(MI.ReplacementTokens), + DefinitionLength(MI.DefinitionLength), + IsDefinitionLengthCached(MI.IsDefinitionLengthCached), + IsFunctionLike(MI.IsFunctionLike), + IsC99Varargs(MI.IsC99Varargs), + IsGNUVarargs(MI.IsGNUVarargs), + IsBuiltinMacro(MI.IsBuiltinMacro), + IsFromAST(MI.IsFromAST), + ChangedAfterLoad(MI.ChangedAfterLoad), + IsDisabled(MI.IsDisabled), + IsUsed(MI.IsUsed), + IsAllowRedefinitionsWithoutWarning(MI.IsAllowRedefinitionsWithoutWarning), + IsWarnIfUnused(MI.IsWarnIfUnused), + IsPublic(MI.IsPublic), + IsHidden(MI.IsHidden), + IsAmbiguous(MI.IsAmbiguous) { setArgumentList(MI.ArgumentList, MI.NumArguments, PPAllocator); } +const MacroInfo *MacroInfo::findDefinitionAtLoc(SourceLocation L, + SourceManager &SM) const { + assert(L.isValid() && "SourceLocation is invalid."); + for (const MacroInfo *MI = this; MI; MI = MI->PreviousDefinition) { + if (MI->Location.isInvalid() || // For macros defined on the command line. + SM.isBeforeInTranslationUnit(MI->Location, L)) + return (MI->UndefLocation.isInvalid() || + SM.isBeforeInTranslationUnit(L, MI->UndefLocation)) ? MI : NULL; + } + return NULL; +} + unsigned MacroInfo::getDefinitionLengthSlow(SourceManager &SM) const { assert(!IsDefinitionLengthCached); IsDefinitionLengthCached = true; diff --git a/lib/Lex/ModuleMap.cpp b/lib/Lex/ModuleMap.cpp index 5304311ef619..8a936fa8e145 100644 --- a/lib/Lex/ModuleMap.cpp +++ b/lib/Lex/ModuleMap.cpp @@ -16,6 +16,7 @@ #include "clang/Lex/LiteralSupport.h" #include "clang/Lex/LexDiagnostic.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/TargetOptions.h" @@ -26,6 +27,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include <stdlib.h> using namespace clang; Module::ExportDecl @@ -75,7 +77,7 @@ ModuleMap::ModuleMap(FileManager &FileMgr, const DiagnosticConsumer &DC, { IntrusiveRefCntPtr<DiagnosticIDs> DiagIDs(new DiagnosticIDs); Diags = IntrusiveRefCntPtr<DiagnosticsEngine>( - new DiagnosticsEngine(DiagIDs)); + new DiagnosticsEngine(DiagIDs, new DiagnosticOptions)); Diags->setClient(DC.clone(*Diags), /*ShouldOwnClient=*/true); SourceMgr = new SourceManager(*Diags, FileMgr); } @@ -96,16 +98,62 @@ void ModuleMap::setTarget(const TargetInfo &Target) { this->Target = &Target; } +/// \brief "Sanitize" a filename so that it can be used as an identifier. +static StringRef sanitizeFilenameAsIdentifier(StringRef Name, + SmallVectorImpl<char> &Buffer) { + if (Name.empty()) + return Name; + + // Check whether the filename is already an identifier; this is the common + // case. + bool isIdentifier = true; + for (unsigned I = 0, N = Name.size(); I != N; ++I) { + if (isalpha(Name[I]) || Name[I] == '_' || (isdigit(Name[I]) && I > 0)) + continue; + + isIdentifier = false; + break; + } + + if (!isIdentifier) { + // If we don't already have something with the form of an identifier, + // create a buffer with the sanitized name. + Buffer.clear(); + if (isdigit(Name[0])) + Buffer.push_back('_'); + Buffer.reserve(Buffer.size() + Name.size()); + for (unsigned I = 0, N = Name.size(); I != N; ++I) { + if (isalnum(Name[I]) || isspace(Name[I])) + Buffer.push_back(Name[I]); + else + Buffer.push_back('_'); + } + + Name = StringRef(Buffer.data(), Buffer.size()); + } + + while (llvm::StringSwitch<bool>(Name) +#define KEYWORD(Keyword,Conditions) .Case(#Keyword, true) +#define ALIAS(Keyword, AliasOf, Conditions) .Case(Keyword, true) +#include "clang/Basic/TokenKinds.def" + .Default(false)) { + if (Name.data() != Buffer.data()) + Buffer.append(Name.begin(), Name.end()); + Buffer.push_back('_'); + Name = StringRef(Buffer.data(), Buffer.size()); + } + + return Name; +} + Module *ModuleMap::findModuleForHeader(const FileEntry *File) { - llvm::DenseMap<const FileEntry *, Module *>::iterator Known - = Headers.find(File); + HeadersMap::iterator Known = Headers.find(File); if (Known != Headers.end()) { - // If a header corresponds to an unavailable module, don't report - // that it maps to anything. - if (!Known->second->isAvailable()) + // If a header is not available, don't report that it maps to anything. + if (!Known->second.isAvailable()) return 0; - return Known->second; + return Known->second.getModule(); } const DirectoryEntry *Dir = File->getDir(); @@ -134,7 +182,10 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { for (unsigned I = SkippedDirs.size(); I != 0; --I) { // Find or create the module that corresponds to this directory name. - StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName()); + SmallString<32> NameBuf; + StringRef Name = sanitizeFilenameAsIdentifier( + llvm::sys::path::stem(SkippedDirs[I-1]->getName()), + NameBuf); Result = findOrCreateModule(Name, Result, /*IsFramework=*/false, Explicit).first; @@ -148,9 +199,12 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { } // Infer a submodule with the same name as this header file. - StringRef Name = llvm::sys::path::stem(File->getName()); + SmallString<32> NameBuf; + StringRef Name = sanitizeFilenameAsIdentifier( + llvm::sys::path::stem(File->getName()), NameBuf); Result = findOrCreateModule(Name, Result, /*IsFramework=*/false, Explicit).first; + Result->TopHeaders.insert(File); // If inferred submodules export everything they import, add a // wildcard to the set of exports. @@ -163,7 +217,7 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { UmbrellaDirs[SkippedDirs[I]] = Result; } - Headers[File] = Result; + Headers[File] = KnownHeader(Result, /*Excluded=*/false); // If a header corresponds to an unavailable module, don't report // that it maps to anything. @@ -188,10 +242,9 @@ Module *ModuleMap::findModuleForHeader(const FileEntry *File) { } bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) { - llvm::DenseMap<const FileEntry *, Module *>::iterator Known - = Headers.find(Header); + HeadersMap::iterator Known = Headers.find(Header); if (Known != Headers.end()) - return !Known->second->isAvailable(); + return !Known->second.isAvailable(); const DirectoryEntry *Dir = Header->getDir(); llvm::SmallVector<const DirectoryEntry *, 2> SkippedDirs; @@ -216,7 +269,10 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) { if (UmbrellaModule->InferSubmodules) { for (unsigned I = SkippedDirs.size(); I != 0; --I) { // Find or create the module that corresponds to this directory name. - StringRef Name = llvm::sys::path::stem(SkippedDirs[I-1]->getName()); + SmallString<32> NameBuf; + StringRef Name = sanitizeFilenameAsIdentifier( + llvm::sys::path::stem(SkippedDirs[I-1]->getName()), + NameBuf); Found = lookupModuleQualified(Name, Found); if (!Found) return false; @@ -225,7 +281,10 @@ bool ModuleMap::isHeaderInUnavailableModule(const FileEntry *Header) { } // Infer a submodule with the same name as this header file. - StringRef Name = llvm::sys::path::stem(Header->getName()); + SmallString<32> NameBuf; + StringRef Name = sanitizeFilenameAsIdentifier( + llvm::sys::path::stem(Header->getName()), + NameBuf); Found = lookupModuleQualified(Name, Found); if (!Found) return false; @@ -287,8 +346,32 @@ ModuleMap::findOrCreateModule(StringRef Name, Module *Parent, bool IsFramework, return std::make_pair(Result, true); } +bool ModuleMap::canInferFrameworkModule(const DirectoryEntry *ParentDir, + StringRef Name, bool &IsSystem) { + // Check whether we have already looked into the parent directory + // for a module map. + llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::iterator + inferred = InferredDirectories.find(ParentDir); + if (inferred == InferredDirectories.end()) + return false; + + if (!inferred->second.InferModules) + return false; + + // We're allowed to infer for this directory, but make sure it's okay + // to infer this particular module. + bool canInfer = std::find(inferred->second.ExcludedModules.begin(), + inferred->second.ExcludedModules.end(), + Name) == inferred->second.ExcludedModules.end(); + + if (canInfer && inferred->second.InferSystemModules) + IsSystem = true; + + return canInfer; +} + Module * -ModuleMap::inferFrameworkModule(StringRef ModuleName, +ModuleMap::inferFrameworkModule(StringRef ModuleName, const DirectoryEntry *FrameworkDir, bool IsSystem, Module *Parent) { @@ -297,7 +380,54 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, return Mod; FileManager &FileMgr = SourceMgr->getFileManager(); - + + // If the framework has a parent path from which we're allowed to infer + // a framework module, do so. + if (!Parent) { + bool canInfer = false; + if (llvm::sys::path::has_parent_path(FrameworkDir->getName())) { + // Figure out the parent path. + StringRef Parent = llvm::sys::path::parent_path(FrameworkDir->getName()); + if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) { + // Check whether we have already looked into the parent directory + // for a module map. + llvm::DenseMap<const DirectoryEntry *, InferredDirectory>::iterator + inferred = InferredDirectories.find(ParentDir); + if (inferred == InferredDirectories.end()) { + // We haven't looked here before. Load a module map, if there is + // one. + SmallString<128> ModMapPath = Parent; + llvm::sys::path::append(ModMapPath, "module.map"); + if (const FileEntry *ModMapFile = FileMgr.getFile(ModMapPath)) { + parseModuleMapFile(ModMapFile); + inferred = InferredDirectories.find(ParentDir); + } + + if (inferred == InferredDirectories.end()) + inferred = InferredDirectories.insert( + std::make_pair(ParentDir, InferredDirectory())).first; + } + + if (inferred->second.InferModules) { + // We're allowed to infer for this directory, but make sure it's okay + // to infer this particular module. + StringRef Name = llvm::sys::path::filename(FrameworkDir->getName()); + canInfer = std::find(inferred->second.ExcludedModules.begin(), + inferred->second.ExcludedModules.end(), + Name) == inferred->second.ExcludedModules.end(); + + if (inferred->second.InferSystemModules) + IsSystem = true; + } + } + } + + // If we're not allowed to infer a framework module, don't. + if (!canInfer) + return 0; + } + + // Look for an umbrella header. SmallString<128> UmbrellaName = StringRef(FrameworkDir->getName()); llvm::sys::path::append(UmbrellaName, "Headers"); @@ -320,7 +450,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, // umbrella header "umbrella-header-name" Result->Umbrella = UmbrellaHeader; - Headers[UmbrellaHeader] = Result; + Headers[UmbrellaHeader] = KnownHeader(Result, /*Excluded=*/false); UmbrellaDirs[UmbrellaHeader->getDir()] = Result; // export * @@ -343,12 +473,42 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, Dir != DirEnd && !EC; Dir.increment(EC)) { if (!StringRef(Dir->path()).endswith(".framework")) continue; - + if (const DirectoryEntry *SubframeworkDir = FileMgr.getDirectory(Dir->path())) { + // Note: as an egregious but useful hack, we use the real path here and + // check whether it is actually a subdirectory of the parent directory. + // This will not be the case if the 'subframework' is actually a symlink + // out to a top-level framework. +#ifdef LLVM_ON_UNIX + char RealSubframeworkDirName[PATH_MAX]; + if (realpath(Dir->path().c_str(), RealSubframeworkDirName)) { + StringRef SubframeworkDirName = RealSubframeworkDirName; + + bool FoundParent = false; + do { + // Get the parent directory name. + SubframeworkDirName + = llvm::sys::path::parent_path(SubframeworkDirName); + if (SubframeworkDirName.empty()) + break; + + if (FileMgr.getDirectory(SubframeworkDirName) == FrameworkDir) { + FoundParent = true; + break; + } + } while (true); + + if (!FoundParent) + continue; + } +#endif + // FIXME: Do we want to warn about subframeworks without umbrella headers? - inferFrameworkModule(llvm::sys::path::stem(Dir->path()), SubframeworkDir, - IsSystem, Result); + SmallString<32> NameBuf; + inferFrameworkModule(sanitizeFilenameAsIdentifier( + llvm::sys::path::stem(Dir->path()), NameBuf), + SubframeworkDir, IsSystem, Result); } } @@ -356,7 +516,7 @@ ModuleMap::inferFrameworkModule(StringRef ModuleName, } void ModuleMap::setUmbrellaHeader(Module *Mod, const FileEntry *UmbrellaHeader){ - Headers[UmbrellaHeader] = Mod; + Headers[UmbrellaHeader] = KnownHeader(Mod, /*Excluded=*/false); Mod->Umbrella = UmbrellaHeader; UmbrellaDirs[UmbrellaHeader->getDir()] = Mod; } @@ -366,9 +526,13 @@ void ModuleMap::setUmbrellaDir(Module *Mod, const DirectoryEntry *UmbrellaDir) { UmbrellaDirs[UmbrellaDir] = Mod; } -void ModuleMap::addHeader(Module *Mod, const FileEntry *Header) { - Mod->Headers.push_back(Header); - Headers[Header] = Mod; +void ModuleMap::addHeader(Module *Mod, const FileEntry *Header, + bool Excluded) { + if (Excluded) + Mod->ExcludedHeaders.push_back(Header); + else + Mod->Headers.push_back(Header); + Headers[Header] = KnownHeader(Mod, Excluded); } const FileEntry * @@ -388,12 +552,10 @@ void ModuleMap::dump() { M->getValue()->print(llvm::errs(), 2); llvm::errs() << "Headers:"; - for (llvm::DenseMap<const FileEntry *, Module *>::iterator - H = Headers.begin(), - HEnd = Headers.end(); + for (HeadersMap::iterator H = Headers.begin(), HEnd = Headers.end(); H != HEnd; ++H) { llvm::errs() << " \"" << H->first->getName() << "\" -> " - << H->second->getFullModuleName() << "\n"; + << H->second.getModule()->getFullModuleName() << "\n"; } } @@ -454,6 +616,7 @@ namespace clang { EndOfFile, HeaderKeyword, Identifier, + ExcludeKeyword, ExplicitKeyword, ExportKeyword, FrameworkKeyword, @@ -490,10 +653,24 @@ namespace clang { return StringRef(StringData, StringLength); } }; + + /// \brief The set of attributes that can be attached to a module. + struct Attributes { + Attributes() : IsSystem() { } + + /// \brief Whether this is a system module. + unsigned IsSystem : 1; + }; + class ModuleMapParser { Lexer &L; SourceManager &SourceMgr; + + /// \brief Default target information, used only for string literal + /// parsing. + const TargetInfo *Target; + DiagnosticsEngine &Diags; ModuleMap ⤅ @@ -505,11 +682,7 @@ namespace clang { /// \brief Whether an error occurred. bool HadError; - - /// \brief Default target information, used only for string literal - /// parsing. - OwningPtr<TargetInfo> Target; - + /// \brief Stores string data for the various string literals referenced /// during parsing. llvm::BumpPtrAllocator StringData; @@ -532,27 +705,25 @@ namespace clang { bool parseModuleId(ModuleId &Id); void parseModuleDecl(); void parseRequiresDecl(); - void parseHeaderDecl(SourceLocation UmbrellaLoc); + void parseHeaderDecl(SourceLocation UmbrellaLoc, SourceLocation ExcludeLoc); void parseUmbrellaDirDecl(SourceLocation UmbrellaLoc); void parseExportDecl(); - void parseInferredSubmoduleDecl(bool Explicit); - + void parseInferredModuleDecl(bool Framework, bool Explicit); + bool parseOptionalAttributes(Attributes &Attrs); + const DirectoryEntry *getOverriddenHeaderSearchDir(); public: explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr, + const TargetInfo *Target, DiagnosticsEngine &Diags, ModuleMap &Map, const DirectoryEntry *Directory, const DirectoryEntry *BuiltinIncludeDir) - : L(L), SourceMgr(SourceMgr), Diags(Diags), Map(Map), + : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map), Directory(Directory), BuiltinIncludeDir(BuiltinIncludeDir), HadError(false), ActiveModule(0) { - TargetOptions TargetOpts; - TargetOpts.Triple = llvm::sys::getDefaultTargetTriple(); - Target.reset(TargetInfo::CreateTargetInfo(Diags, TargetOpts)); - Tok.clear(); consumeToken(); } @@ -575,6 +746,7 @@ retry: Tok.StringLength = LToken.getLength(); Tok.Kind = llvm::StringSwitch<MMToken::TokenKind>(Tok.getString()) .Case("header", MMToken::HeaderKeyword) + .Case("exclude", MMToken::ExcludeKeyword) .Case("explicit", MMToken::ExplicitKeyword) .Case("export", MMToken::ExportKeyword) .Case("framework", MMToken::FrameworkKeyword) @@ -743,13 +915,6 @@ namespace { /// 'explicit'[opt] 'framework'[opt] 'module' module-id attributes[opt] /// { module-member* } /// -/// attributes: -/// attribute attributes -/// attribute -/// -/// attribute: -/// [ identifier ] -/// /// module-member: /// requires-declaration /// header-declaration @@ -791,7 +956,7 @@ void ModuleMapParser::parseModuleDecl() { // If we have a wildcard for the module name, this is an inferred submodule. // Parse it. if (Tok.is(MMToken::Star)) - return parseInferredSubmoduleDecl(Explicit); + return parseInferredModuleDecl(Framework, Explicit); // Parse the module name. ModuleId Id; @@ -799,7 +964,7 @@ void ModuleMapParser::parseModuleDecl() { HadError = true; return; } - + if (ActiveModule) { if (Id.size() > 1) { Diags.Report(Id.front().second, diag::err_mmap_nested_submodule_id) @@ -842,47 +1007,8 @@ void ModuleMapParser::parseModuleDecl() { SourceLocation ModuleNameLoc = Id.back().second; // Parse the optional attribute list. - bool IsSystem = false; - while (Tok.is(MMToken::LSquare)) { - // Consume the '['. - SourceLocation LSquareLoc = consumeToken(); - - // Check whether we have an attribute name here. - if (!Tok.is(MMToken::Identifier)) { - Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute); - skipUntil(MMToken::RSquare); - if (Tok.is(MMToken::RSquare)) - consumeToken(); - continue; - } - - // Decode the attribute name. - AttributeKind Attribute - = llvm::StringSwitch<AttributeKind>(Tok.getString()) - .Case("system", AT_system) - .Default(AT_unknown); - switch (Attribute) { - case AT_unknown: - Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute) - << Tok.getString(); - break; - - case AT_system: - IsSystem = true; - break; - } - consumeToken(); - - // Consume the ']'. - if (!Tok.is(MMToken::RSquare)) { - Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare); - Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match); - skipUntil(MMToken::RSquare); - } - - if (Tok.is(MMToken::RSquare)) - consumeToken(); - } + Attributes Attrs; + parseOptionalAttributes(Attrs); // Parse the opening brace. if (!Tok.is(MMToken::LBrace)) { @@ -925,7 +1051,7 @@ void ModuleMapParser::parseModuleDecl() { ActiveModule = Map.findOrCreateModule(ModuleName, ActiveModule, Framework, Explicit).first; ActiveModule->DefinitionLoc = ModuleNameLoc; - if (IsSystem) + if (Attrs.IsSystem) ActiveModule->IsSystem = true; bool Done = false; @@ -953,14 +1079,25 @@ void ModuleMapParser::parseModuleDecl() { case MMToken::UmbrellaKeyword: { SourceLocation UmbrellaLoc = consumeToken(); if (Tok.is(MMToken::HeaderKeyword)) - parseHeaderDecl(UmbrellaLoc); + parseHeaderDecl(UmbrellaLoc, SourceLocation()); else parseUmbrellaDirDecl(UmbrellaLoc); break; } + case MMToken::ExcludeKeyword: { + SourceLocation ExcludeLoc = consumeToken(); + if (Tok.is(MMToken::HeaderKeyword)) { + parseHeaderDecl(SourceLocation(), ExcludeLoc); + } else { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) + << "exclude"; + } + break; + } + case MMToken::HeaderKeyword: - parseHeaderDecl(SourceLocation()); + parseHeaderDecl(SourceLocation(), SourceLocation()); break; default: @@ -1062,12 +1199,15 @@ static bool isBuiltinHeader(StringRef FileName) { /// /// header-declaration: /// 'umbrella'[opt] 'header' string-literal -void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) { +/// 'exclude'[opt] 'header' string-literal +void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc, + SourceLocation ExcludeLoc) { assert(Tok.is(MMToken::HeaderKeyword)); consumeToken(); bool Umbrella = UmbrellaLoc.isValid(); - + bool Exclude = ExcludeLoc.isValid(); + assert(!(Umbrella && Exclude) && "Cannot have both 'umbrella' and 'exclude'"); // Parse the header name. if (!Tok.is(MMToken::StringLiteral)) { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_header) @@ -1145,15 +1285,15 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) { // FIXME: We shouldn't be eagerly stat'ing every file named in a module map. // Come up with a lazy way to do this. if (File) { - if (const Module *OwningModule = Map.Headers[File]) { + if (ModuleMap::KnownHeader OwningModule = Map.Headers[File]) { Diags.Report(FileNameLoc, diag::err_mmap_header_conflict) - << FileName << OwningModule->getFullModuleName(); + << FileName << OwningModule.getModule()->getFullModuleName(); HadError = true; } else if (Umbrella) { const DirectoryEntry *UmbrellaDir = File->getDir(); - if ((OwningModule = Map.UmbrellaDirs[UmbrellaDir])) { + if (Module *UmbrellaModule = Map.UmbrellaDirs[UmbrellaDir]) { Diags.Report(UmbrellaLoc, diag::err_mmap_umbrella_clash) - << OwningModule->getFullModuleName(); + << UmbrellaModule->getFullModuleName(); HadError = true; } else { // Record this umbrella header. @@ -1161,11 +1301,11 @@ void ModuleMapParser::parseHeaderDecl(SourceLocation UmbrellaLoc) { } } else { // Record this header. - Map.addHeader(ActiveModule, File); + Map.addHeader(ActiveModule, File, Exclude); // If there is a builtin counterpart to this file, add it now. if (BuiltinFile) - Map.addHeader(ActiveModule, BuiltinFile); + Map.addHeader(ActiveModule, BuiltinFile, Exclude); } } else { Diags.Report(FileNameLoc, diag::err_mmap_header_not_found) @@ -1274,32 +1414,52 @@ void ModuleMapParser::parseExportDecl() { ActiveModule->UnresolvedExports.push_back(Unresolved); } -void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) { +/// \brief Parse an inferried module declaration (wildcard modules). +/// +/// module-declaration: +/// 'explicit'[opt] 'framework'[opt] 'module' * attributes[opt] +/// { inferred-module-member* } +/// +/// inferred-module-member: +/// 'export' '*' +/// 'exclude' identifier +void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) { assert(Tok.is(MMToken::Star)); SourceLocation StarLoc = consumeToken(); bool Failed = false; - + // Inferred modules must be submodules. - if (!ActiveModule) { + if (!ActiveModule && !Framework) { Diags.Report(StarLoc, diag::err_mmap_top_level_inferred_submodule); Failed = true; } - - // Inferred modules must have umbrella directories. - if (!Failed && !ActiveModule->getUmbrellaDir()) { - Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella); - Failed = true; - } - - // Check for redefinition of an inferred module. - if (!Failed && ActiveModule->InferSubmodules) { - Diags.Report(StarLoc, diag::err_mmap_inferred_redef); - if (ActiveModule->InferredSubmoduleLoc.isValid()) - Diags.Report(ActiveModule->InferredSubmoduleLoc, - diag::note_mmap_prev_definition); - Failed = true; + + if (ActiveModule) { + // Inferred modules must have umbrella directories. + if (!Failed && !ActiveModule->getUmbrellaDir()) { + Diags.Report(StarLoc, diag::err_mmap_inferred_no_umbrella); + Failed = true; + } + + // Check for redefinition of an inferred module. + if (!Failed && ActiveModule->InferSubmodules) { + Diags.Report(StarLoc, diag::err_mmap_inferred_redef); + if (ActiveModule->InferredSubmoduleLoc.isValid()) + Diags.Report(ActiveModule->InferredSubmoduleLoc, + diag::note_mmap_prev_definition); + Failed = true; + } + + // Check for the 'framework' keyword, which is not permitted here. + if (Framework) { + Diags.Report(StarLoc, diag::err_mmap_inferred_framework_submodule); + Framework = false; + } + } else if (Explicit) { + Diags.Report(StarLoc, diag::err_mmap_explicit_inferred_framework); + Explicit = false; } - + // If there were any problems with this inferred submodule, skip its body. if (Failed) { if (Tok.is(MMToken::LBrace)) { @@ -1311,12 +1471,22 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) { HadError = true; return; } - - // Note that we have an inferred submodule. - ActiveModule->InferSubmodules = true; - ActiveModule->InferredSubmoduleLoc = StarLoc; - ActiveModule->InferExplicitSubmodules = Explicit; - + + // Parse optional attributes. + Attributes Attrs; + parseOptionalAttributes(Attrs); + + if (ActiveModule) { + // Note that we have an inferred submodule. + ActiveModule->InferSubmodules = true; + ActiveModule->InferredSubmoduleLoc = StarLoc; + ActiveModule->InferExplicitSubmodules = Explicit; + } else { + // We'll be inferring framework modules for this directory. + Map.InferredDirectories[Directory].InferModules = true; + Map.InferredDirectories[Directory].InferSystemModules = Attrs.IsSystem; + } + // Parse the opening brace. if (!Tok.is(MMToken::LBrace)) { Diags.Report(Tok.getLocation(), diag::err_mmap_expected_lbrace_wildcard); @@ -1333,8 +1503,35 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) { case MMToken::RBrace: Done = true; break; - - case MMToken::ExportKeyword: { + + case MMToken::ExcludeKeyword: { + if (ActiveModule) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member) + << (ActiveModule != 0); + consumeToken(); + break; + } + + consumeToken(); + if (!Tok.is(MMToken::Identifier)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_missing_exclude_name); + break; + } + + Map.InferredDirectories[Directory].ExcludedModules + .push_back(Tok.getString()); + consumeToken(); + break; + } + + case MMToken::ExportKeyword: + if (!ActiveModule) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member) + << (ActiveModule != 0); + consumeToken(); + break; + } + consumeToken(); if (Tok.is(MMToken::Star)) ActiveModule->InferExportWildcard = true; @@ -1343,14 +1540,14 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) { diag::err_mmap_expected_export_wildcard); consumeToken(); break; - } - + case MMToken::ExplicitKeyword: case MMToken::ModuleKeyword: case MMToken::HeaderKeyword: case MMToken::UmbrellaKeyword: default: - Diags.Report(Tok.getLocation(), diag::err_mmap_expected_wildcard_member); + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_inferred_member) + << (ActiveModule != 0); consumeToken(); break; } @@ -1365,6 +1562,66 @@ void ModuleMapParser::parseInferredSubmoduleDecl(bool Explicit) { } } +/// \brief Parse optional attributes. +/// +/// attributes: +/// attribute attributes +/// attribute +/// +/// attribute: +/// [ identifier ] +/// +/// \param Attrs Will be filled in with the parsed attributes. +/// +/// \returns true if an error occurred, false otherwise. +bool ModuleMapParser::parseOptionalAttributes(Attributes &Attrs) { + bool HadError = false; + + while (Tok.is(MMToken::LSquare)) { + // Consume the '['. + SourceLocation LSquareLoc = consumeToken(); + + // Check whether we have an attribute name here. + if (!Tok.is(MMToken::Identifier)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_attribute); + skipUntil(MMToken::RSquare); + if (Tok.is(MMToken::RSquare)) + consumeToken(); + HadError = true; + } + + // Decode the attribute name. + AttributeKind Attribute + = llvm::StringSwitch<AttributeKind>(Tok.getString()) + .Case("system", AT_system) + .Default(AT_unknown); + switch (Attribute) { + case AT_unknown: + Diags.Report(Tok.getLocation(), diag::warn_mmap_unknown_attribute) + << Tok.getString(); + break; + + case AT_system: + Attrs.IsSystem = true; + break; + } + consumeToken(); + + // Consume the ']'. + if (!Tok.is(MMToken::RSquare)) { + Diags.Report(Tok.getLocation(), diag::err_mmap_expected_rsquare); + Diags.Report(LSquareLoc, diag::note_mmap_lsquare_match); + skipUntil(MMToken::RSquare); + HadError = true; + } + + if (Tok.is(MMToken::RSquare)) + consumeToken(); + } + + return HadError; +} + /// \brief If there is a specific header search directory due the presence /// of an umbrella directory, retrieve that directory. Otherwise, returns null. const DirectoryEntry *ModuleMapParser::getOverriddenHeaderSearchDir() { @@ -1398,6 +1655,7 @@ bool ModuleMapParser::parseModuleMapFile() { break; case MMToken::Comma: + case MMToken::ExcludeKeyword: case MMToken::ExportKeyword: case MMToken::HeaderKeyword: case MMToken::Identifier: @@ -1428,7 +1686,7 @@ bool ModuleMap::parseModuleMapFile(const FileEntry *File) { // Parse this module map file. Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts); Diags->getClient()->BeginSourceFile(MMapLangOpts); - ModuleMapParser Parser(L, *SourceMgr, *Diags, *this, File->getDir(), + ModuleMapParser Parser(L, *SourceMgr, Target, *Diags, *this, File->getDir(), BuiltinIncludeDir); bool Result = Parser.parseModuleMapFile(); Diags->getClient()->EndSourceFile(); diff --git a/lib/Lex/PPDirectives.cpp b/lib/Lex/PPDirectives.cpp index 74b9cbc881ac..b7c1846e82be 100644 --- a/lib/Lex/PPDirectives.cpp +++ b/lib/Lex/PPDirectives.cpp @@ -1296,7 +1296,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, case tok::string_literal: Filename = getSpelling(FilenameTok, FilenameBuffer); End = FilenameTok.getLocation(); - CharEnd = End.getLocWithOffset(Filename.size()); + CharEnd = End.getLocWithOffset(FilenameTok.getLength()); break; case tok::less: @@ -1306,7 +1306,7 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, if (ConcatenateIncludeName(FilenameBuffer, End)) return; // Found <eod> but no ">"? Diagnostic already emitted. Filename = FilenameBuffer.str(); - CharEnd = getLocForEndOfToken(End); + CharEnd = End.getLocWithOffset(1); break; default: Diag(FilenameTok.getLocation(), diag::err_pp_expects_filename); @@ -1314,6 +1314,8 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, return; } + CharSourceRange FilenameRange + = CharSourceRange::getCharRange(FilenameTok.getLocation(), CharEnd); StringRef OriginalFilename = Filename; bool isAngled = GetIncludeFilenameSpelling(FilenameTok.getLocation(), Filename); @@ -1384,9 +1386,13 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, } } - // Notify the callback object that we've seen an inclusion directive. - Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, File, - End, SearchPath, RelativePath); + if (!SuggestedModule) { + // Notify the callback object that we've seen an inclusion directive. + Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, + FilenameRange, File, + SearchPath, RelativePath, + /*ImportedModule=*/0); + } } if (File == 0) { @@ -1480,10 +1486,28 @@ void Preprocessor::HandleIncludeDirective(SourceLocation HashLoc, Module *Imported = TheModuleLoader.loadModule(IncludeTok.getLocation(), Path, Visibility, /*IsIncludeDirective=*/true); + assert((Imported == 0 || Imported == SuggestedModule) && + "the imported module is different than the suggested one"); // If this header isn't part of the module we're building, we're done. - if (!BuildingImportedModule && Imported) + if (!BuildingImportedModule && Imported) { + if (Callbacks) { + Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, + FilenameRange, File, + SearchPath, RelativePath, Imported); + } return; + } + } + + if (Callbacks && SuggestedModule) { + // We didn't notify the callback object that we've seen an inclusion + // directive before. Now that we are parsing the include normally and not + // turning it to a module import, notify the callback object. + Callbacks->InclusionDirective(HashLoc, IncludeTok, Filename, isAngled, + FilenameRange, File, + SearchPath, RelativePath, + /*ImportedModule=*/0); } // The #included file will be considered to be a system header if either it is @@ -1849,7 +1873,7 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { MI->setDefinitionEndLoc(LastTok.getLocation()); // Finally, if this identifier already had a macro defined for it, verify that - // the macro bodies are identical and free the old definition. + // the macro bodies are identical, and issue diagnostics if they are not. if (MacroInfo *OtherMI = getMacroInfo(MacroNameTok.getIdentifierInfo())) { // It is very common for system headers to have tons of macro redefinitions // and for warnings to be disabled in system headers. If this is the case, @@ -1870,7 +1894,6 @@ void Preprocessor::HandleDefineDirective(Token &DefineTok) { } if (OtherMI->isWarnIfUnused()) WarnUnusedMacroLocs.erase(OtherMI->getDefinitionLoc()); - ReleaseMacroInfo(OtherMI); } setMacroInfo(MacroNameTok.getIdentifierInfo(), MI); @@ -1921,9 +1944,20 @@ void Preprocessor::HandleUndefDirective(Token &UndefTok) { if (MI->isWarnIfUnused()) WarnUnusedMacroLocs.erase(MI->getDefinitionLoc()); - // Free macro definition. - ReleaseMacroInfo(MI); - setMacroInfo(MacroNameTok.getIdentifierInfo(), 0); + UndefineMacro(MacroNameTok.getIdentifierInfo(), MI, + MacroNameTok.getLocation()); +} + +void Preprocessor::UndefineMacro(IdentifierInfo *II, MacroInfo *MI, + SourceLocation UndefLoc) { + MI->setUndefLoc(UndefLoc); + if (MI->isFromAST()) { + MI->setChangedAfterLoad(); + if (Listener) + Listener->UndefinedMacro(MI); + } + + clearMacroInfo(II); } diff --git a/lib/Lex/PPExpressions.cpp b/lib/Lex/PPExpressions.cpp index 7cac63eb0f53..d5a88db470d8 100644 --- a/lib/Lex/PPExpressions.cpp +++ b/lib/Lex/PPExpressions.cpp @@ -178,7 +178,9 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, // preprocessor keywords and it wasn't macro expanded, it turns // into a simple 0, unless it is the C++ keyword "true", in which case it // turns into "1". - if (ValueLive) + if (ValueLive && + II->getTokenID() != tok::kw_true && + II->getTokenID() != tok::kw_false) PP.Diag(PeekTok, diag::warn_pp_undef_identifier) << II; Result.Val = II->getTokenID() == tok::kw_true; Result.Val.setIsUnsigned(false); // "0" is signed intmax_t 0. @@ -204,8 +206,7 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, if (NumberInvalid) return true; // a diagnostic was already reported - NumericLiteralParser Literal(Spelling.begin(), Spelling.end(), - PeekTok.getLocation(), PP); + NumericLiteralParser Literal(Spelling, PeekTok.getLocation(), PP); if (Literal.hadError) return true; // a diagnostic was already reported. @@ -219,10 +220,15 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT, if (Literal.hasUDSuffix()) PP.Diag(PeekTok, diag::err_pp_invalid_udl) << /*integer*/1; - // long long is a C99 feature. - if (!PP.getLangOpts().C99 && Literal.isLongLong) - PP.Diag(PeekTok, PP.getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_longlong : diag::ext_longlong); + // 'long long' is a C99 or C++11 feature. + if (!PP.getLangOpts().C99 && Literal.isLongLong) { + if (PP.getLangOpts().CPlusPlus) + PP.Diag(PeekTok, + PP.getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); + else + PP.Diag(PeekTok, diag::ext_c99_longlong); + } // Parse the integer literal into Result. if (Literal.GetIntegerValue(Result.Val)) { diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index e824320cf732..d827f58a485f 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -157,15 +157,15 @@ void Preprocessor::EnterSourceFileWithPTH(PTHLexer *PL, /// EnterMacro - Add a Macro to the top of the include stack and start lexing /// tokens from it instead of the current buffer. void Preprocessor::EnterMacro(Token &Tok, SourceLocation ILEnd, - MacroArgs *Args) { + MacroInfo *Macro, MacroArgs *Args) { PushIncludeMacroStack(); CurDirLookup = 0; if (NumCachedTokenLexers == 0) { - CurTokenLexer.reset(new TokenLexer(Tok, ILEnd, Args, *this)); + CurTokenLexer.reset(new TokenLexer(Tok, ILEnd, Macro, Args, *this)); } else { CurTokenLexer.reset(TokenLexerCache[--NumCachedTokenLexers]); - CurTokenLexer->Init(Tok, ILEnd, Args); + CurTokenLexer->Init(Tok, ILEnd, Macro, Args); } if (CurLexerKind != CLK_LexAfterModuleImport) CurLexerKind = CLK_TokenLexer; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index ebdb6446d167..eee4342e27ca 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -27,39 +27,138 @@ #include "llvm/Config/llvm-config.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" #include <cstdio> #include <ctime> using namespace clang; -MacroInfo *Preprocessor::getInfoForMacro(IdentifierInfo *II) const { - assert(II->hasMacroDefinition() && "Identifier is not a macro!"); - - llvm::DenseMap<IdentifierInfo*, MacroInfo*>::const_iterator Pos - = Macros.find(II); - if (Pos == Macros.end()) { - // Load this macro from the external source. - getExternalSource()->LoadMacroDefinition(II); - Pos = Macros.find(II); - } +MacroInfo *Preprocessor::getMacroInfoHistory(IdentifierInfo *II) const { + assert(II->hadMacroDefinition() && "Identifier has not been not a macro!"); + + macro_iterator Pos = Macros.find(II); assert(Pos != Macros.end() && "Identifier macro info is missing!"); return Pos->second; } /// setMacroInfo - Specify a macro for this identifier. /// -void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI, - bool LoadedFromAST) { - if (MI) { - Macros[II] = MI; - II->setHasMacroDefinition(true); - if (II->isFromAST() && !LoadedFromAST) - II->setChangedSinceDeserialization(); - } else if (II->hasMacroDefinition()) { - Macros.erase(II); - II->setHasMacroDefinition(false); - if (II->isFromAST() && !LoadedFromAST) - II->setChangedSinceDeserialization(); +void Preprocessor::setMacroInfo(IdentifierInfo *II, MacroInfo *MI) { + assert(MI && "MacroInfo should be non-zero!"); + assert(MI->getUndefLoc().isInvalid() && + "Undefined macros cannot be registered"); + + MacroInfo *&StoredMI = Macros[II]; + MI->setPreviousDefinition(StoredMI); + StoredMI = MI; + II->setHasMacroDefinition(MI->getUndefLoc().isInvalid()); + if (II->isFromAST()) + II->setChangedSinceDeserialization(); +} + +void Preprocessor::addLoadedMacroInfo(IdentifierInfo *II, MacroInfo *MI, + MacroInfo *Hint) { + assert(MI && "Missing macro?"); + assert(MI->isFromAST() && "Macro is not from an AST?"); + assert(!MI->getPreviousDefinition() && "Macro already in chain?"); + + MacroInfo *&StoredMI = Macros[II]; + + // Easy case: this is the first macro definition for this macro. + if (!StoredMI) { + StoredMI = MI; + + if (MI->isDefined()) + II->setHasMacroDefinition(true); + return; + } + + // If this macro is a definition and this identifier has been neither + // defined nor undef'd in the current translation unit, add this macro + // to the end of the chain of definitions. + if (MI->isDefined() && StoredMI->isFromAST()) { + // Simple case: if this is the first actual definition, just put it at + // th beginning. + if (!StoredMI->isDefined()) { + MI->setPreviousDefinition(StoredMI); + StoredMI = MI; + + II->setHasMacroDefinition(true); + return; + } + + // Find the end of the definition chain. + MacroInfo *Prev; + MacroInfo *PrevPrev = StoredMI; + bool Ambiguous = StoredMI->isAmbiguous(); + bool MatchedOther = false; + do { + Prev = PrevPrev; + + // If the macros are not identical, we have an ambiguity. + if (!Prev->isIdenticalTo(*MI, *this)) { + if (!Ambiguous) { + Ambiguous = true; + StoredMI->setAmbiguous(true); + } + } else { + MatchedOther = true; + } + } while ((PrevPrev = Prev->getPreviousDefinition()) && + PrevPrev->isDefined()); + + // If there are ambiguous definitions, and we didn't match any other + // definition, then mark us as ambiguous. + if (Ambiguous && !MatchedOther) + MI->setAmbiguous(true); + + // Wire this macro information into the chain. + MI->setPreviousDefinition(Prev->getPreviousDefinition()); + Prev->setPreviousDefinition(MI); + return; + } + + // The macro is not a definition; put it at the end of the list. + MacroInfo *Prev = Hint? Hint : StoredMI; + while (Prev->getPreviousDefinition()) + Prev = Prev->getPreviousDefinition(); + Prev->setPreviousDefinition(MI); +} + +void Preprocessor::makeLoadedMacroInfoVisible(IdentifierInfo *II, + MacroInfo *MI) { + assert(MI->isFromAST() && "Macro must be from the AST"); + + MacroInfo *&StoredMI = Macros[II]; + if (StoredMI == MI) { + // Easy case: this is the first macro anyway. + II->setHasMacroDefinition(MI->isDefined()); + return; } + + // Go find the macro and pull it out of the list. + // FIXME: Yes, this is O(N), and making a pile of macros visible or hidden + // would be quadratic, but it's extremely rare. + MacroInfo *Prev = StoredMI; + while (Prev->getPreviousDefinition() != MI) + Prev = Prev->getPreviousDefinition(); + Prev->setPreviousDefinition(MI->getPreviousDefinition()); + MI->setPreviousDefinition(0); + + // Add the macro back to the list. + addLoadedMacroInfo(II, MI); + + II->setHasMacroDefinition(StoredMI->isDefined()); + if (II->isFromAST()) + II->setChangedSinceDeserialization(); +} + +/// \brief Undefine a macro for this identifier. +void Preprocessor::clearMacroInfo(IdentifierInfo *II) { + assert(II->hasMacroDefinition() && "Macro is not defined!"); + assert(Macros[II]->getUndefLoc().isValid() && "Macro is still defined!"); + II->setHasMacroDefinition(false); + if (II->isFromAST()) + II->setChangedSinceDeserialization(); } /// RegisterBuiltinMacro - Register the specified identifier in the identifier @@ -100,6 +199,20 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); Ident__has_warning = RegisterBuiltinMacro(*this, "__has_warning"); + // Modules. + if (LangOpts.Modules) { + Ident__building_module = RegisterBuiltinMacro(*this, "__building_module"); + + // __MODULE__ + if (!LangOpts.CurrentModule.empty()) + Ident__MODULE__ = RegisterBuiltinMacro(*this, "__MODULE__"); + else + Ident__MODULE__ = 0; + } else { + Ident__building_module = 0; + Ident__MODULE__ = 0; + } + // Microsoft Extensions. if (LangOpts.MicrosoftExt) Ident__pragma = RegisterBuiltinMacro(*this, "__pragma"); @@ -263,7 +376,23 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, } } } - + + // If the macro definition is ambiguous, complain. + if (MI->isAmbiguous()) { + Diag(Identifier, diag::warn_pp_ambiguous_macro) + << Identifier.getIdentifierInfo(); + Diag(MI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_chosen) + << Identifier.getIdentifierInfo(); + for (MacroInfo *PrevMI = MI->getPreviousDefinition(); + PrevMI && PrevMI->isDefined(); + PrevMI = PrevMI->getPreviousDefinition()) { + if (PrevMI->isAmbiguous()) { + Diag(PrevMI->getDefinitionLoc(), diag::note_pp_ambiguous_macro_other) + << Identifier.getIdentifierInfo(); + } + } + } + // If we started lexing a macro, enter the macro expansion body. // If this macro expands to no tokens, don't bother to push it onto the @@ -337,7 +466,7 @@ bool Preprocessor::HandleMacroExpandedIdentifier(Token &Identifier, } // Start expanding the macro. - EnterMacro(Identifier, ExpansionEnd, Args); + EnterMacro(Identifier, ExpansionEnd, MI, Args); // Now that the macro is at the top of the include stack, ask the // preprocessor to read the next token from it. @@ -581,27 +710,27 @@ static void ComputeDATE_TIME(SourceLocation &DATELoc, SourceLocation &TIMELoc, "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" }; - char TmpBuffer[32]; -#ifdef LLVM_ON_WIN32 - sprintf(TmpBuffer, "\"%s %2d %4d\"", Months[TM->tm_mon], TM->tm_mday, - TM->tm_year+1900); -#else - snprintf(TmpBuffer, sizeof(TmpBuffer), "\"%s %2d %4d\"", Months[TM->tm_mon], TM->tm_mday, - TM->tm_year+1900); -#endif - - Token TmpTok; - TmpTok.startToken(); - PP.CreateString(TmpBuffer, strlen(TmpBuffer), TmpTok); - DATELoc = TmpTok.getLocation(); - -#ifdef LLVM_ON_WIN32 - sprintf(TmpBuffer, "\"%02d:%02d:%02d\"", TM->tm_hour, TM->tm_min, TM->tm_sec); -#else - snprintf(TmpBuffer, sizeof(TmpBuffer), "\"%02d:%02d:%02d\"", TM->tm_hour, TM->tm_min, TM->tm_sec); -#endif - PP.CreateString(TmpBuffer, strlen(TmpBuffer), TmpTok); - TIMELoc = TmpTok.getLocation(); + { + SmallString<32> TmpBuffer; + llvm::raw_svector_ostream TmpStream(TmpBuffer); + TmpStream << llvm::format("\"%s %2d %4d\"", Months[TM->tm_mon], + TM->tm_mday, TM->tm_year + 1900); + Token TmpTok; + TmpTok.startToken(); + PP.CreateString(TmpStream.str(), TmpTok); + DATELoc = TmpTok.getLocation(); + } + + { + SmallString<32> TmpBuffer; + llvm::raw_svector_ostream TmpStream(TmpBuffer); + TmpStream << llvm::format("\"%02d:%02d:%02d\"", + TM->tm_hour, TM->tm_min, TM->tm_sec); + Token TmpTok; + TmpTok.startToken(); + PP.CreateString(TmpStream.str(), TmpTok); + TIMELoc = TmpTok.getLocation(); + } } @@ -616,7 +745,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { Feature = Feature.substr(2, Feature.size() - 4); return llvm::StringSwitch<bool>(Feature) - .Case("address_sanitizer", LangOpts.AddressSanitizer) + .Case("address_sanitizer", LangOpts.SanitizeAddress) .Case("attribute_analyzer_noreturn", true) .Case("attribute_availability", true) .Case("attribute_availability_with_message", true) @@ -641,8 +770,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { // Objective-C features .Case("objc_arr", LangOpts.ObjCAutoRefCount) // FIXME: REMOVE? .Case("objc_arc", LangOpts.ObjCAutoRefCount) - .Case("objc_arc_weak", LangOpts.ObjCAutoRefCount && - LangOpts.ObjCRuntimeHasWeak) + .Case("objc_arc_weak", LangOpts.ObjCARCWeak) .Case("objc_default_synthesize_properties", LangOpts.ObjC2) .Case("objc_fixed_enum", LangOpts.ObjC2) .Case("objc_instancetype", LangOpts.ObjC2) @@ -716,22 +844,12 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { // "struct __is_empty" parsing hack hasn't been needed in this // translation unit. If it has, __is_empty reverts to a normal // identifier and __has_feature(is_empty) evaluates false. - .Case("is_empty", - LangOpts.CPlusPlus && - PP.getIdentifierInfo("__is_empty")->getTokenID() - != tok::identifier) + .Case("is_empty", LangOpts.CPlusPlus) .Case("is_enum", LangOpts.CPlusPlus) .Case("is_final", LangOpts.CPlusPlus) .Case("is_literal", LangOpts.CPlusPlus) .Case("is_standard_layout", LangOpts.CPlusPlus) - // __is_pod is available only if the horrible - // "struct __is_pod" parsing hack hasn't been needed in this - // translation unit. If it has, __is_pod reverts to a normal - // identifier and __has_feature(is_pod) evaluates false. - .Case("is_pod", - LangOpts.CPlusPlus && - PP.getIdentifierInfo("__is_pod")->getTokenID() - != tok::identifier) + .Case("is_pod", LangOpts.CPlusPlus) .Case("is_polymorphic", LangOpts.CPlusPlus) .Case("is_trivial", LangOpts.CPlusPlus) .Case("is_trivially_assignable", LangOpts.CPlusPlus) @@ -807,22 +925,30 @@ static bool HasAttribute(const IdentifierInfo *II) { static bool EvaluateHasIncludeCommon(Token &Tok, IdentifierInfo *II, Preprocessor &PP, const DirectoryLookup *LookupFrom) { - SourceLocation LParenLoc; + // Save the location of the current token. If a '(' is later found, use + // that location. If no, use the end of this location instead. + SourceLocation LParenLoc = Tok.getLocation(); // Get '('. PP.LexNonComment(Tok); // Ensure we have a '('. if (Tok.isNot(tok::l_paren)) { - PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName(); - return false; - } - - // Save '(' location for possible missing ')' message. - LParenLoc = Tok.getLocation(); + // No '(', use end of last token. + LParenLoc = PP.getLocForEndOfToken(LParenLoc); + PP.Diag(LParenLoc, diag::err_pp_missing_lparen) << II->getName(); + // If the next token looks like a filename or the start of one, + // assume it is and process it as such. + if (!Tok.is(tok::angle_string_literal) && !Tok.is(tok::string_literal) && + !Tok.is(tok::less)) + return false; + } else { + // Save '(' location for possible missing ')' message. + LParenLoc = Tok.getLocation(); - // Get the file name. - PP.getCurrentLexer()->LexIncludeFilename(Tok); + // Get the file name. + PP.getCurrentLexer()->LexIncludeFilename(Tok); + } // Reserve a buffer to get the spelling. SmallString<128> FilenameBuffer; @@ -847,8 +973,11 @@ static bool EvaluateHasIncludeCommon(Token &Tok, // This could be a <foo/bar.h> file coming from a macro expansion. In this // case, glue the tokens together into FilenameBuffer and interpret those. FilenameBuffer.push_back('<'); - if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc)) + if (PP.ConcatenateIncludeName(FilenameBuffer, EndLoc)) { + // Let the caller know a <eod> was found by changing the Token kind. + Tok.setKind(tok::eod); return false; // Found <eod> but no ">"? Diagnostic already emitted. + } Filename = FilenameBuffer.str(); break; default: @@ -856,12 +985,15 @@ static bool EvaluateHasIncludeCommon(Token &Tok, return false; } + SourceLocation FilenameLoc = Tok.getLocation(); + // Get ')'. PP.LexNonComment(Tok); // Ensure we have a trailing ). if (Tok.isNot(tok::r_paren)) { - PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName(); + PP.Diag(PP.getLocForEndOfToken(FilenameLoc), diag::err_pp_missing_rparen) + << II->getName(); PP.Diag(LParenLoc, diag::note_matching) << "("; return false; } @@ -909,6 +1041,47 @@ static bool EvaluateHasIncludeNext(Token &Tok, return EvaluateHasIncludeCommon(Tok, II, PP, Lookup); } +/// \brief Process __building_module(identifier) expression. +/// \returns true if we are building the named module, false otherwise. +static bool EvaluateBuildingModule(Token &Tok, + IdentifierInfo *II, Preprocessor &PP) { + // Get '('. + PP.LexNonComment(Tok); + + // Ensure we have a '('. + if (Tok.isNot(tok::l_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pp_missing_lparen) << II->getName(); + return false; + } + + // Save '(' location for possible missing ')' message. + SourceLocation LParenLoc = Tok.getLocation(); + + // Get the module name. + PP.LexNonComment(Tok); + + // Ensure that we have an identifier. + if (Tok.isNot(tok::identifier)) { + PP.Diag(Tok.getLocation(), diag::err_expected_id_building_module); + return false; + } + + bool Result + = Tok.getIdentifierInfo()->getName() == PP.getLangOpts().CurrentModule; + + // Get ')'. + PP.LexNonComment(Tok); + + // Ensure we have a trailing ). + if (Tok.isNot(tok::r_paren)) { + PP.Diag(Tok.getLocation(), diag::err_pp_missing_rparen) << II->getName(); + PP.Diag(LParenLoc, diag::note_matching) << "("; + return false; + } + + return Result; +} + /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { @@ -1093,7 +1266,8 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { else Value = EvaluateHasIncludeNext(Tok, II, *this); OS << (int)Value; - Tok.setKind(tok::numeric_constant); + if (Tok.is(tok::r_paren)) + Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_warning) { // The argument should be a parenthesized string literal. // The argument to these builtins should be a parenthesized identifier. @@ -1164,11 +1338,22 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { OS << (int)Value; Tok.setKind(tok::numeric_constant); + } else if (II == Ident__building_module) { + // The argument to this builtin should be an identifier. The + // builtin evaluates to 1 when that identifier names the module we are + // currently building. + OS << (int)EvaluateBuildingModule(Tok, II, *this); + Tok.setKind(tok::numeric_constant); + } else if (II == Ident__MODULE__) { + // The current module as an identifier. + OS << getLangOpts().CurrentModule; + IdentifierInfo *ModuleII = getIdentifierInfo(getLangOpts().CurrentModule); + Tok.setIdentifierInfo(ModuleII); + Tok.setKind(ModuleII->getTokenID()); } else { llvm_unreachable("Unknown identifier!"); } - CreateString(OS.str().data(), OS.str().size(), Tok, - Tok.getLocation(), Tok.getLocation()); + CreateString(OS.str(), Tok, Tok.getLocation(), Tok.getLocation()); } void Preprocessor::markMacroAsUsed(MacroInfo *MI) { diff --git a/lib/Lex/PTHLexer.cpp b/lib/Lex/PTHLexer.cpp index 67738e907516..b1671721b630 100644 --- a/lib/Lex/PTHLexer.cpp +++ b/lib/Lex/PTHLexer.cpp @@ -198,12 +198,11 @@ bool PTHLexer::SkipBlock() { assert(LastHashTokPtr && "No known '#' token."); const unsigned char* HashEntryI = 0; - uint32_t Offset; uint32_t TableIdx; do { // Read the token offset from the side-table. - Offset = ReadLE32(CurPPCondPtr); + uint32_t Offset = ReadLE32(CurPPCondPtr); // Read the target table index from the side-table. TableIdx = ReadLE32(CurPPCondPtr); @@ -223,13 +222,11 @@ bool PTHLexer::SkipBlock() { PPCond + TableIdx*(sizeof(uint32_t)*2); assert(NextPPCondPtr >= CurPPCondPtr); // Read where we should jump to. - uint32_t TmpOffset = ReadLE32(NextPPCondPtr); - const unsigned char* HashEntryJ = TokBuf + TmpOffset; + const unsigned char* HashEntryJ = TokBuf + ReadLE32(NextPPCondPtr); if (HashEntryJ <= LastHashTokPtr) { // Jump directly to the next entry in the side table. HashEntryI = HashEntryJ; - Offset = TmpOffset; TableIdx = ReadLE32(NextPPCondPtr); CurPPCondPtr = NextPPCondPtr; } @@ -448,8 +445,8 @@ PTHManager *PTHManager::Create(const std::string &file, // Get the buffer ranges and check if there are at least three 32-bit // words at the end of the file. - const unsigned char *BufBeg = (unsigned char*)File->getBufferStart(); - const unsigned char *BufEnd = (unsigned char*)File->getBufferEnd(); + const unsigned char *BufBeg = (const unsigned char*)File->getBufferStart(); + const unsigned char *BufEnd = (const unsigned char*)File->getBufferEnd(); // Check the prologue of the file. if ((BufEnd - BufBeg) < (signed)(sizeof("cfe-pth") + 4 + 4) || diff --git a/lib/Lex/Pragma.cpp b/lib/Lex/Pragma.cpp index c9cc4adf4019..e7e6c3705376 100644 --- a/lib/Lex/Pragma.cpp +++ b/lib/Lex/Pragma.cpp @@ -43,7 +43,6 @@ void EmptyPragmaHandler::HandlePragma(Preprocessor &PP, // PragmaNamespace Implementation. //===----------------------------------------------------------------------===// - PragmaNamespace::~PragmaNamespace() { for (llvm::StringMap<PragmaHandler*>::iterator I = Handlers.begin(), E = Handlers.end(); I != E; ++I) @@ -251,7 +250,7 @@ void Preprocessor::Handle_Pragma(Token &Tok) { // where we can lex it. Token TmpTok; TmpTok.startToken(); - CreateString(&StrVal[0], StrVal.size(), TmpTok); + CreateString(StrVal, TmpTok); SourceLocation TokLoc = TmpTok.getLocation(); // Make and enter a lexer object so that we lex and expand the tokens just @@ -683,7 +682,7 @@ IdentifierInfo *Preprocessor::ParsePragmaPushOrPopMacro(Token &Tok) { Token MacroTok; MacroTok.startToken(); MacroTok.setKind(tok::raw_identifier); - CreateString(&StrVal[1], StrVal.size() - 2, MacroTok); + CreateString(StringRef(&StrVal[1], StrVal.size() - 2), MacroTok); // Get the IdentifierInfo of MacroToPushTok. return LookUpIdentifierInfo(MacroTok); @@ -733,19 +732,22 @@ void Preprocessor::HandlePragmaPopMacro(Token &PopMacroTok) { llvm::DenseMap<IdentifierInfo*, std::vector<MacroInfo*> >::iterator iter = PragmaPushMacroInfo.find(IdentInfo); if (iter != PragmaPushMacroInfo.end()) { - // Release the MacroInfo currently associated with IdentInfo. - MacroInfo *CurrentMI = getMacroInfo(IdentInfo); - if (CurrentMI) { + // Forget the MacroInfo currently associated with IdentInfo. + if (MacroInfo *CurrentMI = getMacroInfo(IdentInfo)) { if (CurrentMI->isWarnIfUnused()) WarnUnusedMacroLocs.erase(CurrentMI->getDefinitionLoc()); - ReleaseMacroInfo(CurrentMI); + UndefineMacro(IdentInfo, CurrentMI, MessageLoc); } // Get the MacroInfo we want to reinstall. MacroInfo *MacroToReInstall = iter->second.back(); - // Reinstall the previously pushed macro. - setMacroInfo(IdentInfo, MacroToReInstall); + if (MacroToReInstall) { + // Reinstall the previously pushed macro. + setMacroInfo(IdentInfo, MacroToReInstall); + } else if (IdentInfo->hasMacroDefinition()) { + clearMacroInfo(IdentInfo); + } // Pop PragmaPushMacroInfo stack. iter->second.pop_back(); @@ -1009,7 +1011,7 @@ struct PragmaDebugHandler : public PragmaHandler { if (II->isStr("assert")) { llvm_unreachable("This is an assertion!"); } else if (II->isStr("crash")) { - *(volatile int*) 0x11 = 0; + LLVM_BUILTIN_TRAP; } else if (II->isStr("parser_crash")) { Token Crasher; Crasher.setKind(tok::annot_pragma_parser_crash); diff --git a/lib/Lex/PreprocessingRecord.cpp b/lib/Lex/PreprocessingRecord.cpp index dfdeba3f9cd9..01f3665e76bd 100644 --- a/lib/Lex/PreprocessingRecord.cpp +++ b/lib/Lex/PreprocessingRecord.cpp @@ -25,10 +25,11 @@ ExternalPreprocessingRecordSource::~ExternalPreprocessingRecordSource() { } InclusionDirective::InclusionDirective(PreprocessingRecord &PPRec, InclusionKind Kind, StringRef FileName, - bool InQuotes, const FileEntry *File, + bool InQuotes, bool ImportedModule, + const FileEntry *File, SourceRange Range) : PreprocessingDirective(InclusionDirectiveKind, Range), - InQuotes(InQuotes), Kind(Kind), File(File) + InQuotes(InQuotes), Kind(Kind), ImportedModule(ImportedModule), File(File) { char *Memory = (char*)PPRec.Allocate(FileName.size() + 1, llvm::alignOf<char>()); @@ -59,8 +60,7 @@ PreprocessingRecord::getPreprocessedEntitiesInRange(SourceRange Range) { iterator(this, CachedRangeQuery.Result.second)); } - std::pair<PPEntityID, PPEntityID> - Res = getPreprocessedEntitiesInRangeSlow(Range); + std::pair<int, int> Res = getPreprocessedEntitiesInRangeSlow(Range); CachedRangeQuery.Range = Range; CachedRangeQuery.Result = Res; @@ -95,12 +95,12 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) { if (FID.isInvalid()) return false; - PPEntityID PPID = PPEI.Position; - if (PPID < 0) { - assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() && + int Pos = PPEI.Position; + if (Pos < 0) { + assert(unsigned(-Pos-1) < LoadedPreprocessedEntities.size() && "Out-of bounds loaded preprocessed entity"); assert(ExternalSource && "No external source to load from"); - unsigned LoadedIndex = LoadedPreprocessedEntities.size()+PPID; + unsigned LoadedIndex = LoadedPreprocessedEntities.size()+Pos; if (PreprocessedEntity *PPE = LoadedPreprocessedEntities[LoadedIndex]) return isPreprocessedEntityIfInFileID(PPE, FID, SourceMgr); @@ -118,15 +118,15 @@ bool PreprocessingRecord::isEntityInFileID(iterator PPEI, FileID FID) { FID, SourceMgr); } - assert(unsigned(PPID) < PreprocessedEntities.size() && + assert(unsigned(Pos) < PreprocessedEntities.size() && "Out-of bounds local preprocessed entity"); - return isPreprocessedEntityIfInFileID(PreprocessedEntities[PPID], + return isPreprocessedEntityIfInFileID(PreprocessedEntities[Pos], FID, SourceMgr); } /// \brief Returns a pair of [Begin, End) iterators of preprocessed entities /// that source range \arg R encompasses. -std::pair<PreprocessingRecord::PPEntityID, PreprocessingRecord::PPEntityID> +std::pair<int, int> PreprocessingRecord::getPreprocessedEntitiesInRangeSlow(SourceRange Range) { assert(Range.isValid()); assert(!SourceMgr.isBeforeInTranslationUnit(Range.getEnd(),Range.getBegin())); @@ -319,14 +319,19 @@ void PreprocessingRecord::RegisterMacroDefinition(MacroInfo *Macro, /// \brief Retrieve the preprocessed entity at the given ID. PreprocessedEntity *PreprocessingRecord::getPreprocessedEntity(PPEntityID PPID){ - if (PPID < 0) { - assert(unsigned(-PPID-1) < LoadedPreprocessedEntities.size() && + if (PPID.ID < 0) { + unsigned Index = -PPID.ID - 1; + assert(Index < LoadedPreprocessedEntities.size() && "Out-of bounds loaded preprocessed entity"); - return getLoadedPreprocessedEntity(LoadedPreprocessedEntities.size()+PPID); + return getLoadedPreprocessedEntity(Index); } - assert(unsigned(PPID) < PreprocessedEntities.size() && + + if (PPID.ID == 0) + return 0; + unsigned Index = PPID.ID - 1; + assert(Index < PreprocessedEntities.size() && "Out-of bounds local preprocessed entity"); - return PreprocessedEntities[PPID]; + return PreprocessedEntities[Index]; } /// \brief Retrieve the loaded preprocessed entity at the given index. @@ -389,10 +394,11 @@ void PreprocessingRecord::InclusionDirective( const clang::Token &IncludeTok, StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, - clang::SourceLocation EndLoc, StringRef SearchPath, - StringRef RelativePath) { + StringRef RelativePath, + const Module *Imported) { InclusionDirective::InclusionKind Kind = InclusionDirective::Include; switch (IncludeTok.getIdentifierInfo()->getPPKeywordID()) { @@ -415,9 +421,19 @@ void PreprocessingRecord::InclusionDirective( default: llvm_unreachable("Unknown include directive kind"); } - + + SourceLocation EndLoc; + if (!IsAngled) { + EndLoc = FilenameRange.getBegin(); + } else { + EndLoc = FilenameRange.getEnd(); + if (FilenameRange.isCharRange()) + EndLoc = EndLoc.getLocWithOffset(-1); // the InclusionDirective expects + // a token range. + } clang::InclusionDirective *ID - = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled, + = new (*this) clang::InclusionDirective(*this, Kind, FileName, !IsAngled, + (bool)Imported, File, SourceRange(HashLoc, EndLoc)); addPreprocessedEntity(ID); } diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index 614530cf387f..3b070ce049db 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -26,6 +26,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" #include "MacroArgs.h" #include "clang/Lex/ExternalPreprocessorSource.h" #include "clang/Lex/HeaderSearch.h" @@ -49,21 +50,25 @@ using namespace clang; //===----------------------------------------------------------------------===// ExternalPreprocessorSource::~ExternalPreprocessorSource() { } -Preprocessor::Preprocessor(DiagnosticsEngine &diags, LangOptions &opts, +PPMutationListener::~PPMutationListener() { } + +Preprocessor::Preprocessor(llvm::IntrusiveRefCntPtr<PreprocessorOptions> PPOpts, + DiagnosticsEngine &diags, LangOptions &opts, const TargetInfo *target, SourceManager &SM, HeaderSearch &Headers, ModuleLoader &TheModuleLoader, IdentifierInfoLookup* IILookup, bool OwnsHeaders, bool DelayInitialization, bool IncrProcessing) - : Diags(&diags), LangOpts(opts), Target(target),FileMgr(Headers.getFileMgr()), + : PPOpts(PPOpts), Diags(&diags), LangOpts(opts), Target(target), + FileMgr(Headers.getFileMgr()), SourceMgr(SM), HeaderInfo(Headers), TheModuleLoader(TheModuleLoader), ExternalSource(0), Identifiers(opts, IILookup), IncrementalProcessing(IncrProcessing), CodeComplete(0), CodeCompletionFile(0), CodeCompletionOffset(0), CodeCompletionReached(0), SkipMainFilePreamble(0, true), CurPPLexer(0), - CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), MacroArgCache(0), - Record(0), MIChainHead(0), MICache(0) + CurDirLookup(0), CurLexerKind(CLK_Lexer), Callbacks(0), Listener(0), + MacroArgCache(0), Record(0), MIChainHead(0), MICache(0) { OwnsHeaderSearch = OwnsHeaders; @@ -285,6 +290,39 @@ Preprocessor::macro_end(bool IncludeExternalMacros) const { return Macros.end(); } +/// \brief Compares macro tokens with a specified token value sequence. +static bool MacroDefinitionEquals(const MacroInfo *MI, + llvm::ArrayRef<TokenValue> Tokens) { + return Tokens.size() == MI->getNumTokens() && + std::equal(Tokens.begin(), Tokens.end(), MI->tokens_begin()); +} + +StringRef Preprocessor::getLastMacroWithSpelling( + SourceLocation Loc, + ArrayRef<TokenValue> Tokens) const { + SourceLocation BestLocation; + StringRef BestSpelling; + for (Preprocessor::macro_iterator I = macro_begin(), E = macro_end(); + I != E; ++I) { + if (!I->second->isObjectLike()) + continue; + const MacroInfo *MI = I->second->findDefinitionAtLoc(Loc, SourceMgr); + if (!MI) + continue; + if (!MacroDefinitionEquals(MI, Tokens)) + continue; + SourceLocation Location = I->second->getDefinitionLoc(); + // Choose the macro defined latest. + if (BestLocation.isInvalid() || + (Location.isValid() && + SourceMgr.isBeforeInTranslationUnit(BestLocation, Location))) { + BestLocation = Location; + BestSpelling = I->first->getName(); + } + } + return BestSpelling; +} + void Preprocessor::recomputeCurLexerKind() { if (CurLexer) CurLexerKind = CLK_Lexer; @@ -378,17 +416,17 @@ StringRef Preprocessor::getSpelling(const Token &Tok, /// CreateString - Plop the specified string into a scratch buffer and return a /// location for it. If specified, the source location provides a source /// location for the token. -void Preprocessor::CreateString(const char *Buf, unsigned Len, Token &Tok, +void Preprocessor::CreateString(StringRef Str, Token &Tok, SourceLocation ExpansionLocStart, SourceLocation ExpansionLocEnd) { - Tok.setLength(Len); + Tok.setLength(Str.size()); const char *DestPtr; - SourceLocation Loc = ScratchBuf->getToken(Buf, Len, DestPtr); + SourceLocation Loc = ScratchBuf->getToken(Str.data(), Str.size(), DestPtr); if (ExpansionLocStart.isValid()) Loc = SourceMgr.createExpansionLoc(Loc, ExpansionLocStart, - ExpansionLocEnd, Len); + ExpansionLocEnd, Str.size()); Tok.setLocation(Loc); // If this is a raw identifier or a literal token, set the pointer data. @@ -641,10 +679,14 @@ void Preprocessor::LexAfterModuleImport(Token &Result) { } // If we have a non-empty module path, load the named module. - if (!ModuleImportPath.empty()) - (void)TheModuleLoader.loadModule(ModuleImportLoc, ModuleImportPath, - Module::MacrosVisible, - /*IsIncludeDirective=*/false); + if (!ModuleImportPath.empty()) { + Module *Imported = TheModuleLoader.loadModule(ModuleImportLoc, + ModuleImportPath, + Module::MacrosVisible, + /*IsIncludeDirective=*/false); + if (Callbacks) + Callbacks->moduleImport(ModuleImportLoc, ModuleImportPath, Imported); + } } void Preprocessor::addCommentHandler(CommentHandler *Handler) { diff --git a/lib/Lex/TokenLexer.cpp b/lib/Lex/TokenLexer.cpp index ade40dad77d9..59b747814a51 100644 --- a/lib/Lex/TokenLexer.cpp +++ b/lib/Lex/TokenLexer.cpp @@ -23,12 +23,13 @@ using namespace clang; /// Create a TokenLexer for the specified macro with the specified actual /// arguments. Note that this ctor takes ownership of the ActualArgs pointer. -void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroArgs *Actuals) { +void TokenLexer::Init(Token &Tok, SourceLocation ELEnd, MacroInfo *MI, + MacroArgs *Actuals) { // If the client is reusing a TokenLexer, make sure to free any memory // associated with it. destroy(); - Macro = PP.getMacroInfo(Tok.getIdentifierInfo()); + Macro = MI; ActualArgs = Actuals; CurToken = 0; @@ -118,6 +119,55 @@ void TokenLexer::destroy() { if (ActualArgs) ActualArgs->destroy(PP); } +/// Remove comma ahead of __VA_ARGS__, if present, according to compiler dialect +/// settings. Returns true if the comma is removed. +static bool MaybeRemoveCommaBeforeVaArgs(SmallVector<Token, 128> &ResultToks, + bool &NextTokGetsSpace, + bool HasPasteOperator, + MacroInfo *Macro, unsigned MacroArgNo, + Preprocessor &PP) { + // Is the macro argument __VA_ARGS__? + if (!Macro->isVariadic() || MacroArgNo != Macro->getNumArgs()-1) + return false; + + // In Microsoft-compatibility mode, a comma is removed in the expansion + // of " ... , __VA_ARGS__ " if __VA_ARGS__ is empty. This extension is + // not supported by gcc. + if (!HasPasteOperator && !PP.getLangOpts().MicrosoftMode) + return false; + + // GCC removes the comma in the expansion of " ... , ## __VA_ARGS__ " if + // __VA_ARGS__ is empty, but not in strict C99 mode where there are no + // named arguments, where it remains. In all other modes, including C99 + // with GNU extensions, it is removed regardless of named arguments. + // Microsoft also appears to support this extension, unofficially. + if (PP.getLangOpts().C99 && !PP.getLangOpts().GNUMode + && Macro->getNumArgs() < 2) + return false; + + // Is a comma available to be removed? + if (ResultToks.empty() || !ResultToks.back().is(tok::comma)) + return false; + + // Issue an extension diagnostic for the paste operator. + if (HasPasteOperator) + PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma); + + // Remove the comma. + ResultToks.pop_back(); + + // If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"), + // then removal of the comma should produce a placemarker token (in C99 + // terms) which we model by popping off the previous ##, giving us a plain + // "X" when __VA_ARGS__ is empty. + if (!ResultToks.empty() && ResultToks.back().is(tok::hashhash)) + ResultToks.pop_back(); + + // Never add a space, even if the comma, ##, or arg had a space. + NextTokGetsSpace = false; + return true; +} + /// Expand the arguments of a function-like macro so that we can quickly /// return preexpanded tokens from Tokens. void TokenLexer::ExpandFunctionArguments() { @@ -198,6 +248,14 @@ void TokenLexer::ExpandFunctionArguments() { !ResultToks.empty() && ResultToks.back().is(tok::hashhash); bool PasteAfter = i+1 != e && Tokens[i+1].is(tok::hashhash); + // In Microsoft mode, remove the comma before __VA_ARGS__ to ensure there + // are no trailing commas if __VA_ARGS__ is empty. + if (!PasteBefore && ActualArgs->isVarargsElidedUse() && + MaybeRemoveCommaBeforeVaArgs(ResultToks, NextTokGetsSpace, + /*HasPasteOperator=*/false, + Macro, ArgNo, PP)) + continue; + // If it is not the LHS/RHS of a ## operator, we must pre-expand the // argument and substitute the expanded tokens into the result. This is // C99 6.10.3.1p1. @@ -320,23 +378,13 @@ void TokenLexer::ExpandFunctionArguments() { // If this is the __VA_ARGS__ token, and if the argument wasn't provided, // and if the macro had at least one real argument, and if the token before - // the ## was a comma, remove the comma. - if ((unsigned)ArgNo == Macro->getNumArgs()-1 && // is __VA_ARGS__ - ActualArgs->isVarargsElidedUse() && // Argument elided. - !ResultToks.empty() && ResultToks.back().is(tok::comma)) { - // Never add a space, even if the comma, ##, or arg had a space. - NextTokGetsSpace = false; - // Remove the paste operator, report use of the extension. - PP.Diag(ResultToks.back().getLocation(), diag::ext_paste_comma); - ResultToks.pop_back(); - - // If the comma was right after another paste (e.g. "X##,##__VA_ARGS__"), - // then removal of the comma should produce a placemarker token (in C99 - // terms) which we model by popping off the previous ##, giving us a plain - // "X" when __VA_ARGS__ is empty. - if (!ResultToks.empty() && ResultToks.back().is(tok::hashhash)) - ResultToks.pop_back(); - } + // the ## was a comma, remove the comma. This is a GCC extension which is + // disabled when using -std=c99. + if (ActualArgs->isVarargsElidedUse()) + MaybeRemoveCommaBeforeVaArgs(ResultToks, NextTokGetsSpace, + /*HasPasteOperator=*/true, + Macro, ArgNo, PP); + continue; } @@ -494,7 +542,7 @@ bool TokenLexer::PasteTokens(Token &Tok) { // Claim that the tmp token is a string_literal so that we can get the // character pointer back from CreateString in getLiteralData(). ResultTokTmp.setKind(tok::string_literal); - PP.CreateString(&Buffer[0], Buffer.size(), ResultTokTmp); + PP.CreateString(Buffer, ResultTokTmp); SourceLocation ResultTokLoc = ResultTokTmp.getLocation(); ResultTokStrPtr = ResultTokTmp.getLiteralData(); diff --git a/lib/Parse/ParseAST.cpp b/lib/Parse/ParseAST.cpp index bd4f85952120..7d68e1f37e40 100644 --- a/lib/Parse/ParseAST.cpp +++ b/lib/Parse/ParseAST.cpp @@ -78,7 +78,6 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { S.getPreprocessor().EnterMainSourceFile(); P.Initialize(); - S.Initialize(); // C11 6.9p1 says translation units must have at least one top-level // declaration. C++ doesn't have this restriction. We also don't want to diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index abce27c3f820..9c5c0597eee1 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -34,7 +34,7 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Tok.is(tok::equal)) && "Current token not a '{', ':', '=', or 'try'!"); - MultiTemplateParamsArg TemplateParams(Actions, + MultiTemplateParamsArg TemplateParams( TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0, TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0); @@ -42,10 +42,10 @@ Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, D.setFunctionDefinitionKind(DefinitionKind); if (D.getDeclSpec().isFriendSpecified()) FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, - move(TemplateParams)); + TemplateParams); else { FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D, - move(TemplateParams), 0, + TemplateParams, 0, VS, ICIS_NoInit); if (FnD) { Actions.ProcessDeclAttributeList(getCurScope(), FnD, AccessAttrs, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index cb865cc9c2ba..f73907a7c409 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -143,7 +143,7 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, // Attributes in a class are parsed at the end of the class, along // with other late-parsed declarations. - if (!ClassStack.empty()) + if (!ClassStack.empty() && !LateAttrs->parseSoon()) getCurrentClass().LateParsedDeclarations.push_back(LA); // consume everything up to and including the matching right parens @@ -154,7 +154,8 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, Eof.setLocation(Tok.getLocation()); LA->Toks.push_back(Eof); } else { - ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc); + ParseGNUAttributeArgs(AttrName, AttrNameLoc, attrs, endLoc, + 0, SourceLocation(), AttributeList::AS_GNU); } } else { attrs.addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, @@ -173,11 +174,15 @@ void Parser::ParseGNUAttributes(ParsedAttributes &attrs, } -/// Parse the arguments to a parameterized GNU attribute +/// Parse the arguments to a parameterized GNU attribute or +/// a C++11 attribute in "gnu" namespace. void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, SourceLocation AttrNameLoc, ParsedAttributes &Attrs, - SourceLocation *EndLoc) { + SourceLocation *EndLoc, + IdentifierInfo *ScopeName, + SourceLocation ScopeLoc, + AttributeList::Syntax Syntax) { assert(Tok.is(tok::l_paren) && "Attribute arg list not starting with '('"); @@ -236,7 +241,7 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, break; } - ExprVector ArgExprs(Actions); + ExprVector ArgExprs; if (!BuiltinType && (ParmLoc.isValid() ? Tok.is(tok::comma) : Tok.isNot(tok::r_paren))) { @@ -277,10 +282,11 @@ void Parser::ParseGNUAttributeArgs(IdentifierInfo *AttrName, SourceLocation RParen = Tok.getLocation(); if (!ExpectAndConsume(tok::r_paren, diag::err_expected_rparen)) { + SourceLocation AttrLoc = ScopeLoc.isValid() ? ScopeLoc : AttrNameLoc; AttributeList *attr = - Attrs.addNew(AttrName, SourceRange(AttrNameLoc, RParen), 0, AttrNameLoc, - ParmName, ParmLoc, ArgExprs.take(), ArgExprs.size(), - AttributeList::AS_GNU); + Attrs.addNew(AttrName, SourceRange(AttrLoc, RParen), + ScopeName, ScopeLoc, ParmName, ParmLoc, + ArgExprs.data(), ArgExprs.size(), Syntax); if (BuiltinType && attr->getKind() == AttributeList::AT_IBOutletCollection) Diag(Tok, diag::err_iboutletcollection_builtintype); } @@ -851,10 +857,6 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) { Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate); if (!Class.LateParsedDeclarations.empty()) { - // Allow 'this' within late-parsed attributes. - Sema::CXXThisScopeRAII ThisScope(Actions, Class.TagOrTemplate, - /*TypeQuals=*/0); - for (unsigned i = 0, ni = Class.LateParsedDeclarations.size(); i < ni; ++i){ Class.LateParsedDeclarations[i]->ParseLexedAttributes(); } @@ -869,6 +871,8 @@ void Parser::ParseLexedAttributes(ParsingClass &Class) { /// \brief Parse all attributes in LAs, and attach them to Decl D. void Parser::ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, bool EnterScope, bool OnDefinition) { + assert(LAs.parseSoon() && + "Attribute list should be marked for immediate parsing."); for (unsigned i = 0, ni = LAs.size(); i < ni; ++i) { if (D) LAs[i]->addDecl(D); @@ -904,34 +908,45 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, ParsedAttributes Attrs(AttrFactory); SourceLocation endLoc; - if (LA.Decls.size() == 1) { + if (LA.Decls.size() > 0) { Decl *D = LA.Decls[0]; + NamedDecl *ND = dyn_cast<NamedDecl>(D); + RecordDecl *RD = dyn_cast_or_null<RecordDecl>(D->getDeclContext()); - // If the Decl is templatized, add template parameters to scope. - bool HasTemplateScope = EnterScope && D->isTemplateDecl(); - ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope); - if (HasTemplateScope) - Actions.ActOnReenterTemplateScope(Actions.CurScope, D); - - // If the Decl is on a function, add function parameters to the scope. - bool HasFunctionScope = EnterScope && D->isFunctionOrFunctionTemplate(); - ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunctionScope); - if (HasFunctionScope) - Actions.ActOnReenterFunctionContext(Actions.CurScope, D); - - ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc); - - if (HasFunctionScope) { - Actions.ActOnExitFunctionContext(); - FnScope.Exit(); // Pop scope, and remove Decls from IdResolver - } - if (HasTemplateScope) { - TempScope.Exit(); + // Allow 'this' within late-parsed attributes. + Sema::CXXThisScopeRAII ThisScope(Actions, RD, + /*TypeQuals=*/0, + ND && RD && ND->isCXXInstanceMember()); + + if (LA.Decls.size() == 1) { + // If the Decl is templatized, add template parameters to scope. + bool HasTemplateScope = EnterScope && D->isTemplateDecl(); + ParseScope TempScope(this, Scope::TemplateParamScope, HasTemplateScope); + if (HasTemplateScope) + Actions.ActOnReenterTemplateScope(Actions.CurScope, D); + + // If the Decl is on a function, add function parameters to the scope. + bool HasFunScope = EnterScope && D->isFunctionOrFunctionTemplate(); + ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope, HasFunScope); + if (HasFunScope) + Actions.ActOnReenterFunctionContext(Actions.CurScope, D); + + ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc, + 0, SourceLocation(), AttributeList::AS_GNU); + + if (HasFunScope) { + Actions.ActOnExitFunctionContext(); + FnScope.Exit(); // Pop scope, and remove Decls from IdResolver + } + if (HasTemplateScope) { + TempScope.Exit(); + } + } else { + // If there are multiple decls, then the decl cannot be within the + // function scope. + ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc, + 0, SourceLocation(), AttributeList::AS_GNU); } - } else if (LA.Decls.size() > 0) { - // If there are multiple decls, then the decl cannot be within the - // function scope. - ParseGNUAttributeArgs(&LA.AttrName, LA.AttrNameLoc, Attrs, &endLoc); } else { Diag(Tok, diag::warn_attribute_no_decl) << LA.AttrName.getName(); } @@ -998,7 +1013,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - ExprVector ArgExprs(Actions); + ExprVector ArgExprs; bool ArgExprsOk = true; // now parse the list of expressions @@ -1018,7 +1033,7 @@ void Parser::ParseThreadSafetyAttribute(IdentifierInfo &AttrName, // Match the ')'. if (ArgExprsOk && !T.consumeClose()) { Attrs.addNew(&AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), - ArgExprs.take(), ArgExprs.size(), AttributeList::AS_GNU); + ArgExprs.data(), ArgExprs.size(), AttributeList::AS_GNU); } if (EndLoc) *EndLoc = T.getCloseLocation(); @@ -1127,6 +1142,18 @@ void Parser::DiagnoseProhibitedAttributes(ParsedAttributesWithRange &attrs) { << attrs.Range; } +void Parser::ProhibitCXX11Attributes(ParsedAttributesWithRange &attrs) { + AttributeList *AttrList = attrs.getList(); + while (AttrList) { + if (AttrList->isCXX0XAttribute()) { + Diag(AttrList->getLoc(), diag::warn_attribute_no_decl) + << AttrList->getName(); + AttrList->setInvalid(); + } + AttrList = AttrList->getNext(); + } +} + /// ParseDeclaration - Parse a full 'declaration', which consists of /// declaration-specifiers, some number of declarators, and a semicolon. /// 'Context' should be a Declarator::TheContext value. This returns the @@ -1400,7 +1427,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, // Save late-parsed attributes for now; they need to be parsed in the // appropriate function scope after the function Decl has been constructed. - LateParsedAttrList LateParsedAttrs; + // These will be parsed in ParseFunctionDefinition or ParseLexedAttrList. + LateParsedAttrList LateParsedAttrs(true); if (D.isFunctionDeclarator()) MaybeParseGNUAttributes(D, &LateParsedAttrs); @@ -1587,9 +1615,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, case ParsedTemplateInfo::Template: case ParsedTemplateInfo::ExplicitSpecialization: ThisDecl = Actions.ActOnTemplateDeclarator(getCurScope(), - MultiTemplateParamsArg(Actions, - TemplateInfo.TemplateParams->data(), - TemplateInfo.TemplateParams->size()), + *TemplateInfo.TemplateParams, D); break; @@ -1660,7 +1686,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - ExprVector Exprs(Actions); + ExprVector Exprs; CommaLocsTy CommaLocs; if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { @@ -1669,6 +1695,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, } if (ParseExpressionList(Exprs, CommaLocs)) { + Actions.ActOnInitializerError(ThisDecl); SkipUntil(tok::r_paren); if (getLangOpts().CPlusPlus && D.getCXXScopeSpec().isSet()) { @@ -1689,7 +1716,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes(Declarator &D, ExprResult Initializer = Actions.ActOnParenListExpr(T.getOpenLocation(), T.getCloseLocation(), - move_arg(Exprs)); + Exprs); Actions.AddInitializerToDecl(ThisDecl, Initializer.take(), /*DirectInit=*/true, TypeContainsAuto); } @@ -1872,6 +1899,9 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, TagName="union" ; FixitTagName = "union " ;TagKind=tok::kw_union ;break; case DeclSpec::TST_struct: TagName="struct"; FixitTagName = "struct ";TagKind=tok::kw_struct;break; + case DeclSpec::TST_interface: + TagName="__interface"; FixitTagName = "__interface "; + TagKind=tok::kw___interface;break; case DeclSpec::TST_class: TagName="class" ; FixitTagName = "class " ;TagKind=tok::kw_class ;break; } @@ -2069,13 +2099,13 @@ void Parser::ParseAlignmentSpecifier(ParsedAttributes &Attrs, return; } - ExprVector ArgExprs(Actions); + ExprVector ArgExprs; ArgExprs.push_back(ArgExpr.release()); // FIXME: This should not be GNU, but we since the attribute used is // based on the spelling, and there is no true spelling for // C++11 attributes, this isn't accepted. Attrs.addNew(PP.getIdentifierInfo("aligned"), KWLoc, 0, KWLoc, - 0, T.getOpenLocation(), ArgExprs.take(), 1, + 0, T.getOpenLocation(), ArgExprs.data(), 1, AttributeList::AS_GNU); } @@ -2130,8 +2160,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, DoneWithDeclSpec: if (!AttrsLastTime) ProhibitAttributes(attrs); - else + else { + // Reject C++11 attributes that appertain to decl specifiers as + // we don't support any C++11 attributes that appertain to decl + // specifiers. This also conforms to what g++ 4.8 is doing. + ProhibitCXX11Attributes(attrs); + DS.takeAttributesFrom(attrs); + } // If this is not a declaration specifier token, we're done reading decl // specifiers. First verify that DeclSpec's are consistent. @@ -2271,6 +2307,8 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, isInvalid = DS.SetTypeSpecType(DeclSpec::TST_typename, Tok.getAnnotationEndLoc(), PrevSpec, DiagID, T); + if (isInvalid) + break; } else DS.SetTypeSpecError(); @@ -2476,12 +2514,12 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___forceinline: { isInvalid = DS.SetFunctionSpecInline(Loc, PrevSpec, DiagID); IdentifierInfo *AttrName = Tok.getIdentifierInfo(); - SourceLocation AttrNameLoc = ConsumeToken(); + SourceLocation AttrNameLoc = Tok.getLocation(); // FIXME: This does not work correctly if it is set to be a declspec // attribute, and a GNU attribute is simply incorrect. DS.getAttributes().addNew(AttrName, AttrNameLoc, 0, AttrNameLoc, 0, SourceLocation(), 0, 0, AttributeList::AS_GNU); - continue; + break; } case tok::kw___ptr64: @@ -2706,6 +2744,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // class-specifier: case tok::kw_class: case tok::kw_struct: + case tok::kw___interface: case tok::kw_union: { tok::TokenKind Kind = Tok.getKind(); ConsumeToken(); @@ -2723,15 +2762,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // cv-qualifier: case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const, Loc, PrevSpec, DiagID, - getLangOpts(), /*IsTypeSpec*/true); + getLangOpts()); break; case tok::kw_volatile: isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, - getLangOpts(), /*IsTypeSpec*/true); + getLangOpts()); break; case tok::kw_restrict: isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, - getLangOpts(), /*IsTypeSpec*/true); + getLangOpts()); break; // C++ typename-specifier: @@ -3165,6 +3204,8 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, // anything that's a simple-type-specifier followed by '(' as an // expression. This suffices because function types are not valid // underlying types anyway. + EnterExpressionEvaluationContext Unevaluated(Actions, + Sema::ConstantEvaluated); TPResult TPR = isExpressionOrTypeSpecifierSimple(NextToken().getKind()); // If the next token starts an expression, we know we're parsing a // bit-field. This is the common case. @@ -3213,11 +3254,14 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, SourceRange Range; BaseType = ParseTypeName(&Range); - if (!getLangOpts().CPlusPlus0x && !getLangOpts().ObjC2) - Diag(StartLoc, diag::ext_ms_enum_fixed_underlying_type) - << Range; - if (getLangOpts().CPlusPlus0x) + if (getLangOpts().CPlusPlus0x) { Diag(StartLoc, diag::warn_cxx98_compat_enum_fixed_underlying_type); + } else if (!getLangOpts().ObjC2) { + if (getLangOpts().CPlusPlus) + Diag(StartLoc, diag::ext_cxx11_enum_fixed_underlying_type) << Range; + else + Diag(StartLoc, diag::ext_c_enum_fixed_underlying_type) << Range; + } } } @@ -3526,6 +3570,7 @@ bool Parser::isKnownToBeTypeSpecifier(const Token &Tok) const { // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: + case tok::kw___interface: case tok::kw_union: // enum-specifier case tok::kw_enum: @@ -3597,6 +3642,7 @@ bool Parser::isTypeSpecifierQualifier() { // struct-or-union-specifier (C99) or class-specifier (C++) case tok::kw_class: case tok::kw_struct: + case tok::kw___interface: case tok::kw_union: // enum-specifier case tok::kw_enum: @@ -3735,6 +3781,7 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_class: case tok::kw_struct: case tok::kw_union: + case tok::kw___interface: // enum-specifier case tok::kw_enum: @@ -3748,6 +3795,9 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { case tok::kw_virtual: case tok::kw_explicit: + // friend keyword. + case tok::kw_friend: + // static_assert-declaration case tok::kw__Static_assert: @@ -3756,11 +3806,10 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { // GNU attributes. case tok::kw___attribute: - return true; - // C++0x decltype. + // C++11 decltype and constexpr. case tok::annot_decltype: - return true; + case tok::kw_constexpr: // C11 _Atomic() case tok::kw__Atomic: @@ -3925,15 +3974,15 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS, case tok::kw_const: isInvalid = DS.SetTypeQual(DeclSpec::TQ_const , Loc, PrevSpec, DiagID, - getLangOpts(), /*IsTypeSpec*/false); + getLangOpts()); break; case tok::kw_volatile: isInvalid = DS.SetTypeQual(DeclSpec::TQ_volatile, Loc, PrevSpec, DiagID, - getLangOpts(), /*IsTypeSpec*/false); + getLangOpts()); break; case tok::kw_restrict: isInvalid = DS.SetTypeQual(DeclSpec::TQ_restrict, Loc, PrevSpec, DiagID, - getLangOpts(), /*IsTypeSpec*/false); + getLangOpts()); break; // OpenCL qualifiers: @@ -4344,7 +4393,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { D.SetIdentifier(0, Tok.getLocation()); } else { if (Tok.getKind() == tok::annot_pragma_parser_crash) - *(volatile int*) 0x11 = 0; + LLVM_BUILTIN_TRAP; if (D.getContext() == Declarator::MemberContext) Diag(Tok, diag::err_expected_member_name_or_semi) << D.getDeclSpec().getSourceRange(); @@ -4374,9 +4423,15 @@ void Parser::ParseDirectDeclarator(Declarator &D) { // In such a case, check if we actually have a function declarator; if it // is not, the declarator has been fully parsed. bool IsAmbiguous = false; - if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit() && - !isCXXFunctionDeclarator(&IsAmbiguous)) - break; + if (getLangOpts().CPlusPlus && D.mayBeFollowedByCXXDirectInit()) { + // The name of the declarator, if any, is tentatively declared within + // a possible direct initializer. + TentativelyDeclaredIdentifiers.push_back(D.getIdentifier()); + bool IsFunctionDecl = isCXXFunctionDeclarator(&IsAmbiguous); + TentativelyDeclaredIdentifiers.pop_back(); + if (!IsFunctionDecl) + break; + } ParsedAttributes attrs(AttrFactory); BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); @@ -4553,7 +4608,14 @@ void Parser::ParseFunctionDeclarator(Declarator &D, Actions.ActOnStartFunctionDeclarator(); - SourceLocation EndLoc; + /* LocalEndLoc is the end location for the local FunctionTypeLoc. + EndLoc is the end location for the function declarator. + They differ for trailing return types. */ + SourceLocation StartLoc, LocalEndLoc, EndLoc; + SourceLocation LParenLoc, RParenLoc; + LParenLoc = Tracker.getOpenLocation(); + StartLoc = LParenLoc; + if (isFunctionDeclaratorIdentifierList()) { if (RequiresArg) Diag(Tok, diag::err_argument_required_after_attribute); @@ -4561,7 +4623,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D, ParseFunctionDeclaratorIdentifierList(D, ParamInfo); Tracker.consumeClose(); - EndLoc = Tracker.getCloseLocation(); + RParenLoc = Tracker.getCloseLocation(); + LocalEndLoc = RParenLoc; + EndLoc = RParenLoc; } else { if (Tok.isNot(tok::r_paren)) ParseParameterDeclarationClause(D, FirstArgAttrs, ParamInfo, EllipsisLoc); @@ -4572,7 +4636,9 @@ void Parser::ParseFunctionDeclarator(Declarator &D, // If we have the closing ')', eat it. Tracker.consumeClose(); - EndLoc = Tracker.getCloseLocation(); + RParenLoc = Tracker.getCloseLocation(); + LocalEndLoc = RParenLoc; + EndLoc = RParenLoc; if (getLangOpts().CPlusPlus) { // FIXME: Accept these components in any order, and produce fixits to @@ -4628,21 +4694,25 @@ void Parser::ParseFunctionDeclarator(Declarator &D, MaybeParseCXX0XAttributes(FnAttrs); // Parse trailing-return-type[opt]. + LocalEndLoc = EndLoc; if (getLangOpts().CPlusPlus0x && Tok.is(tok::arrow)) { Diag(Tok, diag::warn_cxx98_compat_trailing_return_type); + if (D.getDeclSpec().getTypeSpecType() == TST_auto) + StartLoc = D.getDeclSpec().getTypeSpecTypeLoc(); + LocalEndLoc = Tok.getLocation(); SourceRange Range; TrailingReturnType = ParseTrailingReturnType(Range); - if (Range.getEnd().isValid()) - EndLoc = Range.getEnd(); + EndLoc = Range.getEnd(); } } } // Remember that we parsed a function type, and remember the attributes. D.AddTypeInfo(DeclaratorChunk::getFunction(HasProto, - /*isVariadic=*/EllipsisLoc.isValid(), - IsAmbiguous, EllipsisLoc, + IsAmbiguous, + LParenLoc, ParamInfo.data(), ParamInfo.size(), + EllipsisLoc, RParenLoc, DS.getTypeQualifiers(), RefQualifierIsLValueRef, RefQualifierLoc, ConstQualifierLoc, @@ -4654,8 +4724,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0, - Tracker.getOpenLocation(), - EndLoc, D, + StartLoc, LocalEndLoc, D, TrailingReturnType), FnAttrs, EndLoc); @@ -5058,7 +5127,8 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { const bool hasParens = Tok.is(tok::l_paren); - EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, + Sema::ReuseLambdaContextDecl); bool isCastExpr; ParsedType CastTy; diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 3dc96cf0d294..4cb14e24f48f 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -18,6 +18,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/PrettyDeclStackTrace.h" +#include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallString.h" #include "RAIIObjectsForParser.h" using namespace clang; @@ -87,6 +88,12 @@ Decl *Parser::ParseNamespace(unsigned Context, } if (Tok.is(tok::equal)) { + if (Ident == 0) { + Diag(Tok, diag::err_expected_ident); + // Skip to end of the definition and eat the ';'. + SkipUntil(tok::semi); + return 0; + } if (!attrs.empty()) Diag(attrTok, diag::err_unexpected_namespace_attributes_alias); if (InlineLoc.isValid()) @@ -581,7 +588,7 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, if (IsAliasDecl) { TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; - MultiTemplateParamsArg TemplateParamsArg(Actions, + MultiTemplateParamsArg TemplateParamsArg( TemplateParams ? TemplateParams->data() : 0, TemplateParams ? TemplateParams->size() : 0); // FIXME: Propagate attributes. @@ -616,12 +623,13 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ BalancedDelimiterTracker T(*this, tok::l_paren); if (T.consumeOpen()) { Diag(Tok, diag::err_expected_lparen); + SkipMalformedDecl(); return 0; } ExprResult AssertExpr(ParseConstantExpression()); if (AssertExpr.isInvalid()) { - SkipUntil(tok::semi); + SkipMalformedDecl(); return 0; } @@ -630,13 +638,13 @@ Decl *Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ if (!isTokenStringLiteral()) { Diag(Tok, diag::err_expected_string_literal); - SkipUntil(tok::semi); + SkipMalformedDecl(); return 0; } ExprResult AssertMessage(ParseStringLiteralExpression()); if (AssertMessage.isInvalid()) { - SkipUntil(tok::semi); + SkipMalformedDecl(); return 0; } @@ -694,9 +702,22 @@ SourceLocation Parser::ParseDecltypeSpecifier(DeclSpec &DS) { 0, /*IsDecltype=*/true); Result = ParseExpression(); if (Result.isInvalid()) { - SkipUntil(tok::r_paren); DS.SetTypeSpecError(); - return StartLoc; + if (SkipUntil(tok::r_paren, /*StopAtSemi=*/true, /*DontConsume=*/true)) { + EndLoc = ConsumeParen(); + } else { + assert(Tok.is(tok::semi)); + if (PP.isBacktrackEnabled()) { + // Backtrack to get the location of the last token before the semi. + PP.RevertCachedTokens(2); + ConsumeToken(); // the semi. + EndLoc = ConsumeAnyToken(); + assert(Tok.is(tok::semi)); + } else { + EndLoc = Tok.getLocation(); + } + } + return EndLoc; } // Match the ')' @@ -1034,6 +1055,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, DeclSpec::TST TagType; if (TagTokKind == tok::kw_struct) TagType = DeclSpec::TST_struct; + else if (TagTokKind == tok::kw___interface) + TagType = DeclSpec::TST_interface; else if (TagTokKind == tok::kw_class) TagType = DeclSpec::TST_class; else { @@ -1151,7 +1174,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, << (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) << (TagType == DeclSpec::TST_class? 0 : TagType == DeclSpec::TST_struct? 1 - : 2) + : TagType == DeclSpec::TST_interface? 2 + : 3) << Name << SourceRange(LAngleLoc, RAngleLoc); @@ -1243,8 +1267,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (Tok.isNot(tok::semi)) { // A semicolon was missing after this declaration. Diagnose and recover. ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, - TagType == DeclSpec::TST_class ? "class" : - TagType == DeclSpec::TST_struct ? "struct" : "union"); + DeclSpec::getSpecifierName(TagType)); PP.EnterToken(Tok); Tok.setKind(tok::semi); } @@ -1279,8 +1302,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TemplateId) { // Explicit specialization, class template partial specialization, // or explicit instantiation. - ASTTemplateArgsPtr TemplateArgsPtr(Actions, - TemplateId->getTemplateArgs(), + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation && TUK == Sema::TUK_Declaration) { @@ -1362,7 +1384,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TemplateArgsPtr, TemplateId->RAngleLoc, attrs.getList(), - MultiTemplateParamsArg(Actions, + MultiTemplateParamsArg( TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); } @@ -1389,7 +1411,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, Actions.ActOnTemplatedFriendTag(getCurScope(), DS.getFriendSpecLoc(), TagType, StartLoc, SS, Name, NameLoc, attrs.getList(), - MultiTemplateParamsArg(Actions, + MultiTemplateParamsArg( TemplateParams? &(*TemplateParams)[0] : 0, TemplateParams? TemplateParams->size() : 0)); } else { @@ -1470,8 +1492,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, if (TUK == Sema::TUK_Definition && (TemplateInfo.Kind || !isValidAfterTypeSpecifier(false))) { ExpectAndConsume(tok::semi, diag::err_expected_semi_after_tagdecl, - TagType == DeclSpec::TST_class ? "class" : - TagType == DeclSpec::TST_struct ? "struct" : "union"); + DeclSpec::getSpecifierName(TagType)); // Push this token back into the preprocessor and change our current token // to ';' so that the rest of the code recovers as though there were an // ';' after the definition. @@ -1667,7 +1688,8 @@ VirtSpecifiers::Specifier Parser::isCXX0XVirtSpecifier(const Token &Tok) const { /// virt-specifier-seq: /// virt-specifier /// virt-specifier-seq virt-specifier -void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { +void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS, + bool IsInterface) { while (true) { VirtSpecifiers::Specifier Specifier = isCXX0XVirtSpecifier(); if (Specifier == VirtSpecifiers::VS_None) @@ -1681,10 +1703,15 @@ void Parser::ParseOptionalCXX0XVirtSpecifierSeq(VirtSpecifiers &VS) { << PrevSpec << FixItHint::CreateRemoval(Tok.getLocation()); - Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_override_control_keyword : - diag::ext_override_control_keyword) - << VirtSpecifiers::getSpecifierName(Specifier); + if (IsInterface && Specifier == VirtSpecifiers::VS_Final) { + Diag(Tok.getLocation(), diag::err_override_control_interface) + << VirtSpecifiers::getSpecifierName(Specifier); + } else { + Diag(Tok.getLocation(), getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_override_control_keyword : + diag::ext_override_control_keyword) + << VirtSpecifiers::getSpecifierName(Specifier); + } ConsumeToken(); } } @@ -1869,7 +1896,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, &CommonLateParsedAttrs); - MultiTemplateParamsArg TemplateParams(Actions, + MultiTemplateParamsArg TemplateParams( TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); @@ -1905,7 +1932,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } - ParseOptionalCXX0XVirtSpecifierSeq(VS); + ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface); // If attributes exist after the declarator, but before an '{', parse them. MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); @@ -2026,7 +2053,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // FIXME: When g++ adds support for this, we'll need to check whether it // goes before or after the GNU attributes and __asm__. - ParseOptionalCXX0XVirtSpecifierSeq(VS); + ParseOptionalCXX0XVirtSpecifierSeq(VS, getCurrentClass().IsInterface); InClassInitStyle HasInClassInit = ICIS_NoInit; if ((Tok.is(tok::equal) || Tok.is(tok::l_brace)) && !HasInitializer) { @@ -2052,11 +2079,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (DS.isFriendSpecified()) { // TODO: handle initializers, bitfields, 'delete' ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, - move(TemplateParams)); + TemplateParams); } else { ThisDecl = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, DeclaratorInfo, - move(TemplateParams), + TemplateParams, BitfieldSize.release(), VS, HasInClassInit); if (AccessAttrs) @@ -2240,6 +2267,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, unsigned TagType, Decl *TagDecl) { assert((TagType == DeclSpec::TST_struct || + TagType == DeclSpec::TST_interface || TagType == DeclSpec::TST_union || TagType == DeclSpec::TST_class) && "Invalid TagType!"); @@ -2254,6 +2282,15 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, if (S->isClassScope()) { // We're inside a class scope, so this is a nested class. NonNestedClass = false; + + // The Microsoft extension __interface does not permit nested classes. + if (getCurrentClass().IsInterface) { + Diag(RecordLoc, diag::err_invalid_member_in_interface) + << /*ErrorType=*/6 + << (isa<NamedDecl>(TagDecl) + ? cast<NamedDecl>(TagDecl)->getQualifiedNameAsString() + : "<anonymous>"); + } break; } @@ -2274,7 +2311,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope); // Note that we are parsing a new (potentially-nested) class definition. - ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass); + ParsingClassDefinition ParsingDef(*this, TagDecl, NonNestedClass, + TagType == DeclSpec::TST_interface); if (TagDecl) Actions.ActOnTagStartDefinition(getCurScope(), TagDecl); @@ -2286,9 +2324,14 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, assert(isCXX0XFinalKeyword() && "not a class definition"); FinalLoc = ConsumeToken(); - Diag(FinalLoc, getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_override_control_keyword : - diag::ext_override_control_keyword) << "final"; + if (TagType == DeclSpec::TST_interface) { + Diag(FinalLoc, diag::err_override_control_interface) + << "final"; + } else { + Diag(FinalLoc, getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_override_control_keyword : + diag::ext_override_control_keyword) << "final"; + } } if (Tok.is(tok::colon)) { @@ -2348,6 +2391,11 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, continue; } + if (Tok.is(tok::annot_pragma_align)) { + HandlePragmaAlign(); + continue; + } + AccessSpecifier AS = getAccessSpecifierIfPresent(); if (AS != AS_none) { // Current token is a C++ access specifier. @@ -2373,6 +2421,13 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, << FixItHint::CreateInsertion(EndLoc, ":"); } + // The Microsoft extension __interface does not permit non-public + // access specifiers. + if (TagType == DeclSpec::TST_interface && CurAS != AS_public) { + Diag(ASLoc, diag::err_access_specifier_interface) + << (CurAS == AS_protected); + } + if (Actions.ActOnAccessSpecifier(AS, ASLoc, EndLoc, AccessAttrs.getList())) { // found another attribute than only annotations @@ -2571,7 +2626,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { T.consumeOpen(); // Parse the optional expression-list. - ExprVector ArgExprs(Actions); + ExprVector ArgExprs; CommaLocsTy CommaLocs; if (Tok.isNot(tok::r_paren) && ParseExpressionList(ArgExprs, CommaLocs)) { SkipUntil(tok::r_paren); @@ -2586,7 +2641,7 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) { return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II, TemplateTypeTy, DS, IdLoc, - T.getOpenLocation(), ArgExprs.take(), + T.getOpenLocation(), ArgExprs.data(), ArgExprs.size(), T.getCloseLocation(), EllipsisLoc); } @@ -2752,10 +2807,11 @@ TypeResult Parser::ParseTrailingReturnType(SourceRange &Range) { /// so push that class onto our stack of classes that is currently /// being parsed. Sema::ParsingClassState -Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass) { +Parser::PushParsingClass(Decl *ClassDecl, bool NonNestedClass, + bool IsInterface) { assert((NonNestedClass || !ClassStack.empty()) && "Nested class without outer class"); - ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass)); + ClassStack.push(new ParsingClass(ClassDecl, NonNestedClass, IsInterface)); return Actions.PushParsingClass(); } @@ -2773,9 +2829,6 @@ void Parser::DeallocateParsedClasses(Parser::ParsingClass *Class) { /// This routine should be called when we have finished parsing the /// definition of a class, but have not yet popped the Scope /// associated with the class's definition. -/// -/// \returns true if the class we've popped is a top-level class, -/// false otherwise. void Parser::PopParsingClass(Sema::ParsingClassState state) { assert(!ClassStack.empty() && "Mismatched push/pop for class parsing"); @@ -2850,6 +2903,21 @@ IdentifierInfo *Parser::TryParseCXX11AttributeIdentifier(SourceLocation &Loc) { } } +static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName, + IdentifierInfo *ScopeName) { + switch (AttributeList::getKind(AttrName, ScopeName, + AttributeList::AS_CXX11)) { + case AttributeList::AT_CarriesDependency: + case AttributeList::AT_FallThrough: + case AttributeList::AT_NoReturn: { + return true; + } + + default: + return false; + } +} + /// ParseCXX11AttributeSpecifier - Parse a C++11 attribute-specifier. Currently /// only parses standard attributes. /// @@ -2934,46 +3002,38 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, } } + bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName,ScopeName); bool AttrParsed = false; - switch (AttributeList::getKind(AttrName, ScopeName, - AttributeList::AS_CXX11)) { - // No arguments - case AttributeList::AT_CarriesDependency: - // FIXME: implement generic support of attributes with C++11 syntax - // see Parse/ParseDecl.cpp: ParseGNUAttributes - case AttributeList::AT_FallThrough: - case AttributeList::AT_NoReturn: { - if (Tok.is(tok::l_paren)) { - Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments) - << AttrName->getName(); - break; + + // Parse attribute arguments + if (Tok.is(tok::l_paren)) { + if (ScopeName && ScopeName->getName() == "gnu") { + ParseGNUAttributeArgs(AttrName, AttrLoc, attrs, endLoc, + ScopeName, ScopeLoc, AttributeList::AS_CXX11); + AttrParsed = true; + } else { + if (StandardAttr) + Diag(Tok.getLocation(), diag::err_cxx11_attribute_forbids_arguments) + << AttrName->getName(); + + // FIXME: handle other formats of c++11 attribute arguments + ConsumeParen(); + SkipUntil(tok::r_paren, false); } + } + if (!AttrParsed) attrs.addNew(AttrName, SourceRange(ScopeLoc.isValid() ? ScopeLoc : AttrLoc, AttrLoc), ScopeName, ScopeLoc, 0, SourceLocation(), 0, 0, AttributeList::AS_CXX11); - AttrParsed = true; - break; - } - - // Silence warnings - default: break; - } - - // Skip the entire parameter clause, if any - if (!AttrParsed && Tok.is(tok::l_paren)) { - ConsumeParen(); - // SkipUntil maintains the balancedness of tokens. - SkipUntil(tok::r_paren, false); - } if (Tok.is(tok::ellipsis)) { - if (AttrParsed) - Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis) - << AttrName->getName(); ConsumeToken(); + + Diag(Tok, diag::err_cxx11_attribute_forbids_ellipsis) + << AttrName->getName(); } } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 8d4668b95481..c7be0d3ff2b9 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -179,7 +179,7 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// \endverbatim ExprResult Parser::ParseExpression(TypeCastState isTypeCast) { ExprResult LHS(ParseAssignmentExpression(isTypeCast)); - return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); + return ParseRHSOfBinaryExpression(LHS, prec::Comma); } /// This routine is called when the '@' is seen and consumed. @@ -190,7 +190,7 @@ ExprResult Parser::ParseExpression(TypeCastState isTypeCast) { ExprResult Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { ExprResult LHS(ParseObjCAtExpression(AtLoc)); - return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); + return ParseRHSOfBinaryExpression(LHS, prec::Comma); } /// This routine is called when a leading '__extension__' is seen and @@ -210,7 +210,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { LHS = Actions.ActOnUnaryOp(getCurScope(), ExtLoc, tok::kw___extension__, LHS.take()); - return ParseRHSOfBinaryExpression(move(LHS), prec::Comma); + return ParseRHSOfBinaryExpression(LHS, prec::Comma); } /// \brief Parse an expr that doesn't include (top-level) commas. @@ -227,7 +227,7 @@ ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false, /*isAddressOfOperand=*/false, isTypeCast); - return ParseRHSOfBinaryExpression(move(LHS), prec::Assignment); + return ParseRHSOfBinaryExpression(LHS, prec::Assignment); } /// \brief Parse an assignment expression where part of an Objective-C message @@ -265,6 +265,17 @@ ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { return Actions.ActOnConstantExpression(Res); } +bool Parser::isNotExpressionStart() { + tok::TokenKind K = Tok.getKind(); + if (K == tok::l_brace || K == tok::r_brace || + K == tok::kw_for || K == tok::kw_while || + K == tok::kw_if || K == tok::kw_else || + K == tok::kw_goto || K == tok::kw_try) + return true; + // If this is a decl-specifier, we can't be at the start of an expression. + return isKnownToBeDeclarationSpecifier(); +} + /// \brief Parse a binary expression that starts with \p LHS and has a /// precedence of at least \p MinPrec. ExprResult @@ -279,12 +290,23 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { // because we are called recursively, or because the token is not a binop), // then we are done! if (NextTokPrec < MinPrec) - return move(LHS); + return LHS; // Consume the operator, saving the operator token for error reporting. Token OpToken = Tok; ConsumeToken(); + // Bail out when encountering a comma followed by a token which can't + // possibly be the start of an expression. For instance: + // int f() { return 1, } + // We can't do this before consuming the comma, because + // isNotExpressionStart() looks at the token stream. + if (OpToken.is(tok::comma) && isNotExpressionStart()) { + PP.EnterToken(Tok); + Tok = OpToken; + return LHS; + } + // Special case handling for the ternary operator. ExprResult TernaryMiddle(true); if (NextTokPrec == prec::Conditional) { @@ -458,7 +480,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, isTypeCast); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); - return move(Res); + return Res; } namespace { @@ -698,7 +720,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case CastExpr: // We have parsed the cast-expression and no postfix-expr pieces are // following. - return move(Res); + return Res; } break; @@ -741,6 +763,53 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // Avoid the unnecessary parse-time lookup in the common case // where the syntax forbids a type. const Token &Next = NextToken(); + + // If this identifier was reverted from a token ID, and the next token + // is a parenthesis, this is likely to be a use of a type trait. Check + // those tokens. + if (Next.is(tok::l_paren) && + Tok.is(tok::identifier) && + Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + // Build up the mapping of revertable type traits, for future use. + if (RevertableTypeTraits.empty()) { +#define RTT_JOIN(X,Y) X##Y +#define REVERTABLE_TYPE_TRAIT(Name) \ + RevertableTypeTraits[PP.getIdentifierInfo(#Name)] \ + = RTT_JOIN(tok::kw_,Name) + + REVERTABLE_TYPE_TRAIT(__is_arithmetic); + REVERTABLE_TYPE_TRAIT(__is_convertible); + REVERTABLE_TYPE_TRAIT(__is_empty); + REVERTABLE_TYPE_TRAIT(__is_floating_point); + REVERTABLE_TYPE_TRAIT(__is_function); + REVERTABLE_TYPE_TRAIT(__is_fundamental); + REVERTABLE_TYPE_TRAIT(__is_integral); + REVERTABLE_TYPE_TRAIT(__is_member_function_pointer); + REVERTABLE_TYPE_TRAIT(__is_member_pointer); + REVERTABLE_TYPE_TRAIT(__is_pod); + REVERTABLE_TYPE_TRAIT(__is_pointer); + REVERTABLE_TYPE_TRAIT(__is_same); + REVERTABLE_TYPE_TRAIT(__is_scalar); + REVERTABLE_TYPE_TRAIT(__is_signed); + REVERTABLE_TYPE_TRAIT(__is_unsigned); + REVERTABLE_TYPE_TRAIT(__is_void); +#undef REVERTABLE_TYPE_TRAIT +#undef RTT_JOIN + } + + // If we find that this is in fact the name of a type trait, + // update the token kind in place and parse again to treat it as + // the appropriate kind of type trait. + llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known + = RevertableTypeTraits.find(II); + if (Known != RevertableTypeTraits.end()) { + Tok.setKind(Known->second); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, isTypeCast); + } + } + if (Next.is(tok::coloncolon) || (!ColonIsSacred && Next.is(tok::colon)) || Next.is(tok::less) || @@ -758,7 +827,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // '.'. IdentifierInfo &II = *Tok.getIdentifierInfo(); SourceLocation ILoc = ConsumeToken(); - + // Support 'Class.property' and 'super.property' notation. if (getLangOpts().ObjC1 && Tok.is(tok::period) && (Actions.getTypeName(II, ILoc, getCurScope()) || @@ -888,7 +957,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = ParseCastExpression(!getLangOpts().CPlusPlus); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); - return move(Res); + return Res; } case tok::amp: { // unary-expression: '&' cast-expression // Special treatment because of member pointers @@ -896,7 +965,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = ParseCastExpression(false, true); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); - return move(Res); + return Res; } case tok::star: // unary-expression: '*' cast-expression @@ -910,7 +979,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = ParseCastExpression(false); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); - return move(Res); + return Res; } case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] @@ -920,7 +989,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Res = ParseCastExpression(false); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); - return move(Res); + return Res; } case tok::kw__Alignof: // unary-expression: '_Alignof' '(' type-name ')' if (!getLangOpts().C11) @@ -946,7 +1015,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Tok.getLocation()); Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), LD); ConsumeToken(); - return move(Res); + return Res; } case tok::kw_const_cast: case tok::kw_dynamic_cast: @@ -1132,13 +1201,14 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (!Result.isInvalid()) Result = Actions.ActOnNoexceptExpr(KeyLoc, T.getOpenLocation(), Result.take(), T.getCloseLocation()); - return move(Result); + return Result; } case tok::kw___is_abstract: // [GNU] unary-type-trait case tok::kw___is_class: case tok::kw___is_empty: case tok::kw___is_enum: + case tok::kw___is_interface_class: case tok::kw___is_literal: case tok::kw___is_arithmetic: case tok::kw___is_integral: @@ -1270,7 +1340,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { switch (Tok.getKind()) { case tok::code_completion: if (InMessageExpression) - return move(LHS); + return LHS; Actions.CodeCompletePostfixExpression(getCurScope(), LHS); cutOffParsing(); @@ -1290,7 +1360,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Fall through; this isn't a message send. default: // Not a postfix-expression suffix. - return move(LHS); + return LHS; case tok::l_square: { // postfix-expression: p-e '[' expression ']' // If we have a array postfix expression that starts on a new line and // Objective-C is enabled, it is highly likely that the user forgot a @@ -1300,7 +1370,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // expression and recover by pretending there is no suffix. if (getLangOpts().ObjC1 && Tok.isAtStartOfLine() && isSimpleObjCMessageExpression()) - return move(LHS); + return LHS; // Reject array indices starting with a lambda-expression. '[[' is // reserved for attributes. @@ -1341,7 +1411,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { BalancedDelimiterTracker PT(*this, tok::l_paren); if (OpKind == tok::lesslessless) { - ExprVector ExecConfigExprs(Actions); + ExprVector ExecConfigExprs; CommaLocsTy ExecConfigCommaLocs; SourceLocation OpenLoc = ConsumeToken(); @@ -1372,7 +1442,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { if (!LHS.isInvalid()) { ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(), OpenLoc, - move_arg(ExecConfigExprs), + ExecConfigExprs, CloseLoc); if (ECResult.isInvalid()) LHS = ExprError(); @@ -1384,7 +1454,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { Loc = PT.getOpenLocation(); } - ExprVector ArgExprs(Actions); + ExprVector ArgExprs; CommaLocsTy CommaLocs; if (Tok.is(tok::code_completion)) { @@ -1414,7 +1484,7 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { ArgExprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); LHS = Actions.ActOnCallExpr(getCurScope(), LHS.take(), Loc, - move_arg(ArgExprs), Tok.getLocation(), + ArgExprs, Tok.getLocation(), ExecConfig); PT.consumeClose(); } @@ -1583,7 +1653,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, // If we get here, the operand to the typeof/sizeof/alignof was an expresion. isCastExpr = false; - return move(Operand); + return Operand; } @@ -1653,7 +1723,8 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { if (OpTok.is(tok::kw_alignof) || OpTok.is(tok::kw__Alignof)) Diag(OpTok, diag::warn_cxx98_compat_alignof); - EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, + Sema::ReuseLambdaContextDecl); bool isCastExpr; ParsedType CastTy; @@ -1684,7 +1755,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { /*isType=*/false, Operand.release(), CastRange); - return move(Operand); + return Operand; } /// ParseBuiltinPrimaryExpression @@ -1796,7 +1867,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { Res = ParseExpression(); if (Res.isInvalid()) { SkipUntil(tok::r_paren); - return move(Res); + return Res; } Comps.back().U.E = Res.release(); @@ -1823,7 +1894,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { ExprResult Cond(ParseAssignmentExpression()); if (Cond.isInvalid()) { SkipUntil(tok::r_paren); - return move(Cond); + return Cond; } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprError(); @@ -1831,7 +1902,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { ExprResult Expr1(ParseAssignmentExpression()); if (Expr1.isInvalid()) { SkipUntil(tok::r_paren); - return move(Expr1); + return Expr1; } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprError(); @@ -1839,7 +1910,7 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { ExprResult Expr2(ParseAssignmentExpression()); if (Expr2.isInvalid()) { SkipUntil(tok::r_paren); - return move(Expr2); + return Expr2; } if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); @@ -2083,7 +2154,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, DeclaratorInfo, CastTy, RParenLoc, Result.take()); } - return move(Result); + return Result; } Diag(Tok, diag::err_expected_lbrace_in_compound_literal); @@ -2093,13 +2164,13 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Parse the expression-list. InMessageExpressionRAIIObject InMessage(*this, false); - ExprVector ArgExprs(Actions); + ExprVector ArgExprs; CommaLocsTy CommaLocs; if (!ParseExpressionList(ArgExprs, CommaLocs)) { ExprType = SimpleExpr; Result = Actions.ActOnParenListExpr(OpenLoc, Tok.getLocation(), - move_arg(ArgExprs)); + ArgExprs); } } else { InMessageExpressionRAIIObject InMessage(*this, false); @@ -2120,7 +2191,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, T.consumeClose(); RParenLoc = T.getCloseLocation(); - return move(Result); + return Result; } /// ParseCompoundLiteralExpression - We have parsed the parenthesized type-name @@ -2141,7 +2212,7 @@ Parser::ParseCompoundLiteralExpression(ParsedType Ty, ExprResult Result = ParseInitializer(); if (!Result.isInvalid() && Ty) return Actions.ActOnCompoundLiteral(LParenLoc, Ty, RParenLoc, Result.take()); - return move(Result); + return Result; } /// ParseStringLiteralExpression - This handles the various token types that @@ -2211,8 +2282,8 @@ ExprResult Parser::ParseGenericSelectionExpression() { } SourceLocation DefaultLoc; - TypeVector Types(Actions); - ExprVector Exprs(Actions); + TypeVector Types; + ExprVector Exprs; while (1) { ParsedType Ty; if (Tok.is(tok::kw_default)) { @@ -2263,7 +2334,7 @@ ExprResult Parser::ParseGenericSelectionExpression() { return Actions.ActOnGenericSelectionExpr(KeyLoc, DefaultLoc, T.getCloseLocation(), ControllingExpr.release(), - move_arg(Types), move_arg(Exprs)); + Types, Exprs); } /// ParseExpressionList - Used for C/C++ (argument-)expression-list. @@ -2415,18 +2486,28 @@ ExprResult Parser::ParseBlockLiteralExpression() { } else { // Otherwise, pretend we saw (void). ParsedAttributes attrs(AttrFactory); - ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(true, false, false, - SourceLocation(), - 0, 0, 0, - true, SourceLocation(), - SourceLocation(), - SourceLocation(), - SourceLocation(), - EST_None, - SourceLocation(), - 0, 0, 0, 0, - CaretLoc, CaretLoc, - ParamInfo), + SourceLocation NoLoc; + ParamInfo.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/true, + /*IsAmbiguous=*/false, + /*RParenLoc=*/NoLoc, + /*ArgInfo=*/0, + /*NumArgs=*/0, + /*EllipsisLoc=*/NoLoc, + /*RParenLoc=*/NoLoc, + /*TypeQuals=*/0, + /*RefQualifierIsLvalueRef=*/true, + /*RefQualifierLoc=*/NoLoc, + /*ConstQualifierLoc=*/NoLoc, + /*VolatileQualifierLoc=*/NoLoc, + /*MutableLoc=*/NoLoc, + EST_None, + /*ESpecLoc=*/NoLoc, + /*Exceptions=*/0, + /*ExceptionRanges=*/0, + /*NumExceptions=*/0, + /*NoexceptExpr=*/0, + CaretLoc, CaretLoc, + ParamInfo), attrs, CaretLoc); MaybeParseGNUAttributes(ParamInfo); @@ -2450,7 +2531,7 @@ ExprResult Parser::ParseBlockLiteralExpression() { Result = Actions.ActOnBlockStmtExpr(CaretLoc, Stmt.take(), getCurScope()); else Actions.ActOnBlockError(CaretLoc, getCurScope()); - return move(Result); + return Result; } /// ParseObjCBoolLiteral - This handles the objective-c Boolean literals. diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index afac25793a73..2f615e150aad 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -96,6 +96,45 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, /*AtDigraph*/false); } +/// \brief Emits an error for a left parentheses after a double colon. +/// +/// When a '(' is found after a '::', emit an error. Attempt to fix the token +/// stream by removing the '(', and the matching ')' if it found. +void Parser::CheckForLParenAfterColonColon() { + if (!Tok.is(tok::l_paren)) + return; + + SourceLocation l_parenLoc = ConsumeParen(), r_parenLoc; + Token Tok1 = getCurToken(); + if (!Tok1.is(tok::identifier) && !Tok1.is(tok::star)) + return; + + if (Tok1.is(tok::identifier)) { + Token Tok2 = GetLookAheadToken(1); + if (Tok2.is(tok::r_paren)) { + ConsumeToken(); + PP.EnterToken(Tok1); + r_parenLoc = ConsumeParen(); + } + } else if (Tok1.is(tok::star)) { + Token Tok2 = GetLookAheadToken(1); + if (Tok2.is(tok::identifier)) { + Token Tok3 = GetLookAheadToken(2); + if (Tok3.is(tok::r_paren)) { + ConsumeToken(); + ConsumeToken(); + PP.EnterToken(Tok2); + PP.EnterToken(Tok1); + r_parenLoc = ConsumeParen(); + } + } + } + + Diag(l_parenLoc, diag::err_paren_after_colon_colon) + << FixItHint::CreateRemoval(l_parenLoc) + << FixItHint::CreateRemoval(r_parenLoc); +} + /// \brief Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which @@ -160,7 +199,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // '::' - Global scope qualifier. if (Actions.ActOnCXXGlobalScopeSpecifier(getCurScope(), ConsumeToken(), SS)) return true; - + + CheckForLParenAfterColonColon(); + HasScopeSpecifier = true; } @@ -301,8 +342,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, HasScopeSpecifier = true; - ASTTemplateArgsPtr TemplateArgsPtr(Actions, - TemplateId->getTemplateArgs(), + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), @@ -372,6 +412,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); + CheckForLParenAfterColonColon(); + HasScopeSpecifier = true; if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc, ObjectType, EnteringContext, SS)) @@ -757,10 +799,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( Scope::FunctionPrototypeScope | Scope::DeclScope); - SourceLocation DeclLoc, DeclEndLoc; + SourceLocation DeclEndLoc; BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - DeclLoc = T.getOpenLocation(); + SourceLocation LParenLoc = T.getOpenLocation(); // Parse parameter-declaration-clause. ParsedAttributes Attr(AttrFactory); @@ -771,7 +813,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( ParseParameterDeclarationClause(D, Attr, ParamInfo, EllipsisLoc); T.consumeClose(); - DeclEndLoc = T.getCloseLocation(); + SourceLocation RParenLoc = T.getCloseLocation(); + DeclEndLoc = RParenLoc; // Parse 'mutable'[opt]. SourceLocation MutableLoc; @@ -797,9 +840,12 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // Parse attribute-specifier[opt]. MaybeParseCXX0XAttributes(Attr, &DeclEndLoc); + SourceLocation FunLocalRangeEnd = DeclEndLoc; + // Parse trailing-return-type[opt]. TypeResult TrailingReturnType; if (Tok.is(tok::arrow)) { + FunLocalRangeEnd = Tok.getLocation(); SourceRange Range; TrailingReturnType = ParseTrailingReturnType(Range); if (Range.getEnd().isValid()) @@ -808,15 +854,17 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( PrototypeScope.Exit(); + SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, - /*isVariadic=*/EllipsisLoc.isValid(), - /*isAmbiguous=*/false, EllipsisLoc, + /*isAmbiguous=*/false, + LParenLoc, ParamInfo.data(), ParamInfo.size(), + EllipsisLoc, RParenLoc, DS.getTypeQualifiers(), /*RefQualifierIsLValueRef=*/true, - /*RefQualifierLoc=*/SourceLocation(), - /*ConstQualifierLoc=*/SourceLocation(), - /*VolatileQualifierLoc=*/SourceLocation(), + /*RefQualifierLoc=*/NoLoc, + /*ConstQualifierLoc=*/NoLoc, + /*VolatileQualifierLoc=*/NoLoc, MutableLoc, ESpecType, ESpecRange.getBegin(), DynamicExceptions.data(), @@ -824,7 +872,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DynamicExceptions.size(), NoexceptExpr.isUsable() ? NoexceptExpr.get() : 0, - DeclLoc, DeclEndLoc, D, + LParenLoc, FunLocalRangeEnd, D, TrailingReturnType), Attr, DeclEndLoc); } else if (Tok.is(tok::kw_mutable) || Tok.is(tok::arrow)) { @@ -853,25 +901,28 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( } ParsedAttributes Attr(AttrFactory); + SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction(/*hasProto=*/true, - /*isVariadic=*/false, - /*isAmbiguous=*/false, - /*EllipsisLoc=*/SourceLocation(), - /*Params=*/0, /*NumParams=*/0, - /*TypeQuals=*/0, - /*RefQualifierIsLValueRef=*/true, - /*RefQualifierLoc=*/SourceLocation(), - /*ConstQualifierLoc=*/SourceLocation(), - /*VolatileQualifierLoc=*/SourceLocation(), - MutableLoc, - EST_None, - /*ESpecLoc=*/SourceLocation(), - /*Exceptions=*/0, - /*ExceptionRanges=*/0, - /*NumExceptions=*/0, - /*NoexceptExpr=*/0, - DeclLoc, DeclEndLoc, D, - TrailingReturnType), + /*isAmbiguous=*/false, + /*LParenLoc=*/NoLoc, + /*Params=*/0, + /*NumParams=*/0, + /*EllipsisLoc=*/NoLoc, + /*RParenLoc=*/NoLoc, + /*TypeQuals=*/0, + /*RefQualifierIsLValueRef=*/true, + /*RefQualifierLoc=*/NoLoc, + /*ConstQualifierLoc=*/NoLoc, + /*VolatileQualifierLoc=*/NoLoc, + MutableLoc, + EST_None, + /*ESpecLoc=*/NoLoc, + /*Exceptions=*/0, + /*ExceptionRanges=*/0, + /*NumExceptions=*/0, + /*NoexceptExpr=*/0, + DeclLoc, DeclEndLoc, D, + TrailingReturnType), Attr, DeclEndLoc); } @@ -926,10 +977,11 @@ ExprResult Parser::ParseCXXCasts() { // Check for "<::" which is parsed as "[:". If found, fix token stream, // diagnose error, suggest fix, and recover parsing. - Token Next = NextToken(); - if (Tok.is(tok::l_square) && Tok.getLength() == 2 && Next.is(tok::colon) && - areTokensAdjacent(Tok, Next)) - FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true); + if (Tok.is(tok::l_square) && Tok.getLength() == 2) { + Token Next = NextToken(); + if (Next.is(tok::colon) && areTokensAdjacent(Tok, Next)) + FixDigraph(*this, PP, Tok, Next, Kind, /*AtDigraph*/true); + } if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName)) return ExprError(); @@ -965,7 +1017,7 @@ ExprResult Parser::ParseCXXCasts() { T.getOpenLocation(), Result.take(), T.getCloseLocation()); - return move(Result); + return Result; } /// ParseCXXTypeid - This handles the C++ typeid expression. @@ -988,6 +1040,22 @@ ExprResult Parser::ParseCXXTypeid() { ExprResult Result; + // C++0x [expr.typeid]p3: + // When typeid is applied to an expression other than an lvalue of a + // polymorphic class type [...] The expression is an unevaluated + // operand (Clause 5). + // + // Note that we can't tell whether the expression is an lvalue of a + // polymorphic class type until after we've parsed the expression; we + // speculatively assume the subexpression is unevaluated, and fix it up + // later. + // + // We enter the unevaluated context before trying to determine whether we + // have a type-id, because the tentative parse logic will try to resolve + // names, and must treat them as unevaluated. + EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated, + Sema::ReuseLambdaContextDecl); + if (isTypeIdInParens()) { TypeResult Ty = ParseTypeName(); @@ -1000,16 +1068,6 @@ ExprResult Parser::ParseCXXTypeid() { Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true, Ty.get().getAsOpaquePtr(), RParenLoc); } else { - // C++0x [expr.typeid]p3: - // When typeid is applied to an expression other than an lvalue of a - // polymorphic class type [...] The expression is an unevaluated - // operand (Clause 5). - // - // Note that we can't tell whether the expression is an lvalue of a - // polymorphic class type until after we've parsed the expression; we - // speculatively assume the subexpression is unevaluated, and fix it up - // later. - EnterExpressionEvaluationContext Unevaluated(Actions, Sema::Unevaluated); Result = ParseExpression(); // Match the ')'. @@ -1026,7 +1084,7 @@ ExprResult Parser::ParseCXXTypeid() { } } - return move(Result); + return Result; } /// ParseCXXUuidof - This handles the Microsoft C++ __uuidof expression. @@ -1074,7 +1132,7 @@ ExprResult Parser::ParseCXXUuidof() { } } - return move(Result); + return Result; } /// \brief Parse a C++ pseudo-destructor expression after the base, @@ -1196,7 +1254,7 @@ ExprResult Parser::ParseThrowExpression() { default: ExprResult Expr(ParseAssignmentExpression()); - if (Expr.isInvalid()) return move(Expr); + if (Expr.isInvalid()) return Expr; return Actions.ActOnCXXThrow(getCurScope(), ThrowLoc, Expr.take()); } } @@ -1245,7 +1303,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - ExprVector Exprs(Actions); + ExprVector Exprs; CommaLocsTy CommaLocs; if (Tok.isNot(tok::r_paren)) { @@ -1265,7 +1323,7 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); return Actions.ActOnCXXTypeConstructExpr(TypeRep, T.getOpenLocation(), - move_arg(Exprs), + Exprs, T.getCloseLocation()); } } @@ -1280,11 +1338,11 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] /// '=' assignment-expression /// -/// \param ExprResult if the condition was parsed as an expression, the -/// parsed expression. +/// \param ExprOut if the condition was parsed as an expression, the parsed +/// expression. /// -/// \param DeclResult if the condition was parsed as a declaration, the -/// parsed declaration. +/// \param DeclOut if the condition was parsed as a declaration, the parsed +/// declaration. /// /// \param Loc The location of the start of the statement that requires this /// condition, e.g., the "for" in a for loop. @@ -1714,8 +1772,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, } // Bundle the template arguments together. - ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), - TemplateArgs.size()); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs); // Constructor and destructor names. TypeResult Type @@ -1762,7 +1819,7 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS, /// ptr-operator conversion-declarator[opt] /// \endcode /// -/// \param The nested-name-specifier that preceded this unqualified-id. If +/// \param SS The nested-name-specifier that preceded this unqualified-id. If /// non-empty, then we are parsing the unqualified-id of a qualified-id. /// /// \param EnteringContext whether we are entering the scope of the @@ -1867,8 +1924,9 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // Parse a literal-operator-id. // - // literal-operator-id: [C++0x 13.5.8] - // operator "" identifier + // literal-operator-id: C++11 [over.literal] + // operator string-literal identifier + // operator user-defined-string-literal if (getLangOpts().CPlusPlus0x && isTokenStringLiteral()) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_literal_operator); @@ -1882,6 +1940,9 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, llvm::SmallVector<SourceLocation, 4> TokLocs; while (isTokenStringLiteral()) { if (!Tok.is(tok::string_literal) && !DiagId) { + // C++11 [over.literal]p1: + // The string-literal or user-defined-string-literal in a + // literal-operator-id shall have no encoding-prefix [...]. DiagLoc = Tok.getLocation(); DiagId = diag::err_literal_operator_string_prefix; } @@ -1903,9 +1964,6 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, Lexer::AdvanceToTokenCharacter(TokLocs[Literal.getUDSuffixToken()], Literal.getUDSuffixOffset(), PP.getSourceManager(), getLangOpts()); - // This form is not permitted by the standard (yet). - DiagLoc = SuffixLoc; - DiagId = diag::err_literal_operator_missing_space; } else if (Tok.is(tok::identifier)) { II = Tok.getIdentifierInfo(); SuffixLoc = ConsumeToken(); @@ -1917,6 +1975,10 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, // The string literal must be empty. if (!Literal.GetString().empty() || Literal.Pascal) { + // C++11 [over.literal]p1: + // The string-literal or user-defined-string-literal in a + // literal-operator-id shall [...] contain no characters + // other than the implicit terminating '\0'. DiagLoc = TokLocs.front(); DiagId = diag::err_literal_operator_string_not_empty; } @@ -1981,7 +2043,7 @@ bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext, /// /// \endcode /// -/// \param The nested-name-specifier that preceded this unqualified-id. If +/// \param SS The nested-name-specifier that preceded this unqualified-id. If /// non-empty, then we are parsing the unqualified-id of a qualified-id. /// /// \param EnteringContext whether we are entering the scope of the @@ -2209,7 +2271,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { // A '(' now can be a new-placement or the '(' wrapping the type-id in the // second form of new-expression. It can't be a new-type-id. - ExprVector PlacementArgs(Actions); + ExprVector PlacementArgs; SourceLocation PlacementLParen, PlacementRParen; SourceRange TypeIdParens; @@ -2279,7 +2341,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { if (Tok.is(tok::l_paren)) { SourceLocation ConstructorLParen, ConstructorRParen; - ExprVector ConstructorArgs(Actions); + ExprVector ConstructorArgs; BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); ConstructorLParen = T.getOpenLocation(); @@ -2298,7 +2360,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { } Initializer = Actions.ActOnParenListExpr(ConstructorLParen, ConstructorRParen, - move_arg(ConstructorArgs)); + ConstructorArgs); } else if (Tok.is(tok::l_brace) && getLangOpts().CPlusPlus0x) { Diag(Tok.getLocation(), diag::warn_cxx98_compat_generalized_initializer_lists); @@ -2308,7 +2370,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { return Initializer; return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen, - move_arg(PlacementArgs), PlacementRParen, + PlacementArgs, PlacementRParen, TypeIdParens, DeclaratorInfo, Initializer.take()); } @@ -2422,7 +2484,7 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { ExprResult Operand(ParseCastExpression(false)); if (Operand.isInvalid()) - return move(Operand); + return Operand; return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.take()); } @@ -2453,6 +2515,7 @@ static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind) { case tok::kw___is_function: return UTT_IsFunction; case tok::kw___is_fundamental: return UTT_IsFundamental; case tok::kw___is_integral: return UTT_IsIntegral; + case tok::kw___is_interface_class: return UTT_IsInterfaceClass; case tok::kw___is_lvalue_reference: return UTT_IsLvalueReference; case tok::kw___is_member_function_pointer: return UTT_IsMemberFunctionPointer; case tok::kw___is_member_object_pointer: return UTT_IsMemberObjectPointer; @@ -2804,7 +2867,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, Result = Actions.ActOnCastExpr(getCurScope(), Tracker.getOpenLocation(), DeclaratorInfo, CastTy, Tracker.getCloseLocation(), Result.take()); - return move(Result); + return Result; } // Not a compound literal, and not followed by a cast-expression. @@ -2823,5 +2886,5 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, } Tracker.consumeClose(); - return move(Result); + return Result; } diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 1c349fddbd57..e47fd9bd24a6 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -313,7 +313,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { Idx = ParseAssignmentExpression(); if (Idx.isInvalid()) { SkipUntil(tok::r_square); - return move(Idx); + return Idx; } } @@ -341,7 +341,7 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { ExprResult RHS(ParseConstantExpression()); if (RHS.isInvalid()) { SkipUntil(tok::r_square); - return move(RHS); + return RHS; } Desig.AddDesignator(Designator::getArrayRange(Idx.release(), RHS.release(), @@ -405,15 +405,14 @@ ExprResult Parser::ParseBraceInitializer() { /// InitExprs - This is the actual list of expressions contained in the /// initializer. - ExprVector InitExprs(Actions); + ExprVector InitExprs; if (Tok.is(tok::r_brace)) { // Empty initializers are a C++ feature and a GNU extension to C. if (!getLangOpts().CPlusPlus) Diag(LBraceLoc, diag::ext_gnu_empty_initializer); // Match the '}'. - return Actions.ActOnInitList(LBraceLoc, MultiExprArg(Actions), - ConsumeBrace()); + return Actions.ActOnInitList(LBraceLoc, MultiExprArg(), ConsumeBrace()); } bool InitExprsOk = true; @@ -476,7 +475,7 @@ ExprResult Parser::ParseBraceInitializer() { bool closed = !T.consumeClose(); if (InitExprsOk && closed) - return Actions.ActOnInitList(LBraceLoc, move_arg(InitExprs), + return Actions.ActOnInitList(LBraceLoc, InitExprs, T.getCloseLocation()); return ExprError(); // an error occurred. diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index db35a386c350..d321baf836bf 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -18,6 +18,7 @@ #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" using namespace clang; @@ -1031,7 +1032,6 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, Scope::FunctionPrototypeScope|Scope::DeclScope); AttributePool allParamAttrs(AttrFactory); - while (1) { ParsedAttributes paramAttrs(AttrFactory); Sema::ObjCArgInfo ArgInfo; @@ -1102,6 +1102,14 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, SelIdent = ParseObjCSelectorPiece(selLoc); if (!SelIdent && Tok.isNot(tok::colon)) break; + if (!SelIdent) { + SourceLocation ColonLoc = Tok.getLocation(); + if (PP.getLocForEndOfToken(ArgInfo.NameLoc) == ColonLoc) { + Diag(ArgInfo.NameLoc, diag::warn_missing_selector_name) << ArgInfo.Name; + Diag(ArgInfo.NameLoc, diag::note_missing_selector_name) << ArgInfo.Name; + Diag(ColonLoc, diag::note_force_empty_selector_name) << ArgInfo.Name; + } + } // We have a selector or a colon, continue parsing. } @@ -1806,7 +1814,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { Diag(Tok, diag::err_expected_lbrace); return StmtError(); } - StmtVector CatchStmts(Actions); + StmtVector CatchStmts; StmtResult FinallyStmt; ParseScope TryScope(this, Scope::DeclScope); StmtResult TryBody(ParseCompoundStatementBody()); @@ -1894,7 +1902,7 @@ StmtResult Parser::ParseObjCTryStmt(SourceLocation atLoc) { } return Actions.ActOnObjCAtTryStmt(atLoc, TryBody.take(), - move_arg(CatchStmts), + CatchStmts, FinallyStmt.take()); } @@ -2061,13 +2069,13 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { ExprResult Lit(Actions.ActOnNumericConstant(Tok)); if (Lit.isInvalid()) { - return move(Lit); + return Lit; } ConsumeToken(); // Consume the literal token. Lit = Actions.ActOnUnaryOp(getCurScope(), OpLoc, Kind, Lit.take()); if (Lit.isInvalid()) - return move(Lit); + return Lit; return ParsePostfixExpressionSuffix( Actions.BuildObjCNumericLiteral(AtLoc, Lit.take())); @@ -2134,7 +2142,7 @@ ExprResult Parser::ParseObjCAtExpression(SourceLocation AtLoc) { } } -/// \brirg Parse the receiver of an Objective-C++ message send. +/// \brief Parse the receiver of an Objective-C++ message send. /// /// This routine parses the receiver of a message send in /// Objective-C++ either as a type or as an expression. Note that this @@ -2346,7 +2354,7 @@ ExprResult Parser::ParseObjCMessageExpression() { ExprResult Res(ParseExpression()); if (Res.isInvalid()) { SkipUntil(tok::r_square); - return move(Res); + return Res; } return ParseObjCMessageExpressionBody(LBracLoc, SourceLocation(), @@ -2418,7 +2426,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, SmallVector<IdentifierInfo *, 12> KeyIdents; SmallVector<SourceLocation, 12> KeyLocs; - ExprVector KeyExprs(Actions); + ExprVector KeyExprs; if (Tok.is(tok::colon)) { while (1) { @@ -2465,7 +2473,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // stop at the ']' when it skips to the ';'. We want it to skip beyond // the enclosing expression. SkipUntil(tok::r_square); - return move(Res); + return Res; } // We have a valid expression. @@ -2512,7 +2520,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, // stop at the ']' when it skips to the ';'. We want it to skip beyond // the enclosing expression. SkipUntil(tok::r_square); - return move(Res); + return Res; } // We have a valid expression. @@ -2551,32 +2559,23 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, if (SuperLoc.isValid()) return Actions.ActOnSuperMessage(getCurScope(), SuperLoc, Sel, - LBracLoc, KeyLocs, RBracLoc, - MultiExprArg(Actions, - KeyExprs.take(), - KeyExprs.size())); + LBracLoc, KeyLocs, RBracLoc, KeyExprs); else if (ReceiverType) return Actions.ActOnClassMessage(getCurScope(), ReceiverType, Sel, - LBracLoc, KeyLocs, RBracLoc, - MultiExprArg(Actions, - KeyExprs.take(), - KeyExprs.size())); + LBracLoc, KeyLocs, RBracLoc, KeyExprs); return Actions.ActOnInstanceMessage(getCurScope(), ReceiverExpr, Sel, - LBracLoc, KeyLocs, RBracLoc, - MultiExprArg(Actions, - KeyExprs.take(), - KeyExprs.size())); + LBracLoc, KeyLocs, RBracLoc, KeyExprs); } ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { ExprResult Res(ParseStringLiteralExpression()); - if (Res.isInvalid()) return move(Res); + if (Res.isInvalid()) return Res; // @"foo" @"bar" is a valid concatenated string. Eat any subsequent string // expressions. At this point, we know that the only valid thing that starts // with '@' is an @"". SmallVector<SourceLocation, 4> AtLocs; - ExprVector AtStrings(Actions); + ExprVector AtStrings; AtLocs.push_back(AtLoc); AtStrings.push_back(Res.release()); @@ -2589,12 +2588,12 @@ ExprResult Parser::ParseObjCStringLiteral(SourceLocation AtLoc) { ExprResult Lit(ParseStringLiteralExpression()); if (Lit.isInvalid()) - return move(Lit); + return Lit; AtStrings.push_back(Lit.release()); } - return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.take(), + return Owned(Actions.ParseObjCStringLiteral(&AtLocs[0], AtStrings.data(), AtStrings.size())); } @@ -2615,7 +2614,7 @@ ExprResult Parser::ParseObjCBooleanLiteral(SourceLocation AtLoc, ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) { ExprResult Lit(Actions.ActOnCharacterConstant(Tok)); if (Lit.isInvalid()) { - return move(Lit); + return Lit; } ConsumeToken(); // Consume the literal token. return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take())); @@ -2629,7 +2628,7 @@ ExprResult Parser::ParseObjCCharacterLiteral(SourceLocation AtLoc) { ExprResult Parser::ParseObjCNumericLiteral(SourceLocation AtLoc) { ExprResult Lit(Actions.ActOnNumericConstant(Tok)); if (Lit.isInvalid()) { - return move(Lit); + return Lit; } ConsumeToken(); // Consume the literal token. return Owned(Actions.BuildObjCNumericLiteral(AtLoc, Lit.take())); @@ -2661,7 +2660,7 @@ Parser::ParseObjCBoxedExpr(SourceLocation AtLoc) { } ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { - ExprVector ElementExprs(Actions); // array elements. + ExprVector ElementExprs; // array elements. ConsumeBracket(); // consume the l_square. while (Tok.isNot(tok::r_square)) { @@ -2672,7 +2671,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { // stop at the ']' when it skips to the ';'. We want it to skip beyond // the enclosing expression. SkipUntil(tok::r_square); - return move(Res); + return Res; } // Parse the ellipsis that indicates a pack expansion. @@ -2689,7 +2688,7 @@ ExprResult Parser::ParseObjCArrayLiteral(SourceLocation AtLoc) { return ExprError(Diag(Tok, diag::err_expected_rsquare_or_comma)); } SourceLocation EndLoc = ConsumeBracket(); // location of ']' - MultiExprArg Args(Actions, ElementExprs.take(), ElementExprs.size()); + MultiExprArg Args(ElementExprs); return Owned(Actions.BuildObjCArrayLiteral(SourceRange(AtLoc, EndLoc), Args)); } @@ -2707,7 +2706,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { // stop at the '}' when it skips to the ';'. We want it to skip beyond // the enclosing expression. SkipUntil(tok::r_brace); - return move(KeyExpr); + return KeyExpr; } } @@ -2723,7 +2722,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { // stop at the '}' when it skips to the ';'. We want it to skip beyond // the enclosing expression. SkipUntil(tok::r_brace); - return move(ValueExpr); + return ValueExpr; } // Parse the ellipsis that designates this as a pack expansion. @@ -2752,7 +2751,7 @@ ExprResult Parser::ParseObjCDictionaryLiteral(SourceLocation AtLoc) { } /// objc-encode-expression: -/// @encode ( type-name ) +/// \@encode ( type-name ) ExprResult Parser::ParseObjCEncodeExpression(SourceLocation AtLoc) { assert(Tok.isObjCAtKeyword(tok::objc_encode) && "Not an @encode expression!"); diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index eb13e0d3574a..a7605f0cf4e0 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -40,7 +40,7 @@ void Parser::HandlePragmaVisibility() { struct PragmaPackInfo { Sema::PragmaPackKind Kind; IdentifierInfo *Name; - Expr *Alignment; + Token Alignment; SourceLocation LParenLoc; SourceLocation RParenLoc; }; @@ -50,10 +50,107 @@ void Parser::HandlePragmaPack() { PragmaPackInfo *Info = static_cast<PragmaPackInfo *>(Tok.getAnnotationValue()); SourceLocation PragmaLoc = ConsumeToken(); - Actions.ActOnPragmaPack(Info->Kind, Info->Name, Info->Alignment, PragmaLoc, + ExprResult Alignment; + if (Info->Alignment.is(tok::numeric_constant)) { + Alignment = Actions.ActOnNumericConstant(Info->Alignment); + if (Alignment.isInvalid()) + return; + } + Actions.ActOnPragmaPack(Info->Kind, Info->Name, Alignment.get(), PragmaLoc, Info->LParenLoc, Info->RParenLoc); } +void Parser::HandlePragmaMSStruct() { + assert(Tok.is(tok::annot_pragma_msstruct)); + Sema::PragmaMSStructKind Kind = + static_cast<Sema::PragmaMSStructKind>( + reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); + Actions.ActOnPragmaMSStruct(Kind); + ConsumeToken(); // The annotation token. +} + +void Parser::HandlePragmaAlign() { + assert(Tok.is(tok::annot_pragma_align)); + Sema::PragmaOptionsAlignKind Kind = + static_cast<Sema::PragmaOptionsAlignKind>( + reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); + SourceLocation PragmaLoc = ConsumeToken(); + Actions.ActOnPragmaOptionsAlign(Kind, PragmaLoc); +} + +void Parser::HandlePragmaWeak() { + assert(Tok.is(tok::annot_pragma_weak)); + SourceLocation PragmaLoc = ConsumeToken(); + Actions.ActOnPragmaWeakID(Tok.getIdentifierInfo(), PragmaLoc, + Tok.getLocation()); + ConsumeToken(); // The weak name. +} + +void Parser::HandlePragmaWeakAlias() { + assert(Tok.is(tok::annot_pragma_weakalias)); + SourceLocation PragmaLoc = ConsumeToken(); + IdentifierInfo *WeakName = Tok.getIdentifierInfo(); + SourceLocation WeakNameLoc = Tok.getLocation(); + ConsumeToken(); + IdentifierInfo *AliasName = Tok.getIdentifierInfo(); + SourceLocation AliasNameLoc = Tok.getLocation(); + ConsumeToken(); + Actions.ActOnPragmaWeakAlias(WeakName, AliasName, PragmaLoc, + WeakNameLoc, AliasNameLoc); + +} + +void Parser::HandlePragmaRedefineExtname() { + assert(Tok.is(tok::annot_pragma_redefine_extname)); + SourceLocation RedefLoc = ConsumeToken(); + IdentifierInfo *RedefName = Tok.getIdentifierInfo(); + SourceLocation RedefNameLoc = Tok.getLocation(); + ConsumeToken(); + IdentifierInfo *AliasName = Tok.getIdentifierInfo(); + SourceLocation AliasNameLoc = Tok.getLocation(); + ConsumeToken(); + Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc, + RedefNameLoc, AliasNameLoc); +} + +void Parser::HandlePragmaFPContract() { + assert(Tok.is(tok::annot_pragma_fp_contract)); + tok::OnOffSwitch OOS = + static_cast<tok::OnOffSwitch>( + reinterpret_cast<uintptr_t>(Tok.getAnnotationValue())); + Actions.ActOnPragmaFPContract(OOS); + ConsumeToken(); // The annotation token. +} + +namespace { + typedef llvm::PointerIntPair<IdentifierInfo *, 1, bool> OpenCLExtData; +} + +void Parser::HandlePragmaOpenCLExtension() { + assert(Tok.is(tok::annot_pragma_opencl_extension)); + OpenCLExtData data = + OpenCLExtData::getFromOpaqueValue(Tok.getAnnotationValue()); + unsigned state = data.getInt(); + IdentifierInfo *ename = data.getPointer(); + SourceLocation NameLoc = Tok.getLocation(); + ConsumeToken(); // The annotation token. + + OpenCLOptions &f = Actions.getOpenCLOptions(); + // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions, + // overriding all previously issued extension directives, but only if the + // behavior is set to disable." + if (state == 0 && ename->isStr("all")) { +#define OPENCLEXT(nm) f.nm = 0; +#include "clang/Basic/OpenCLExtensions.def" + } +#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; } +#include "clang/Basic/OpenCLExtensions.def" + else { + PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename; + return; + } +} + // #pragma GCC visibility comes in two variants: // 'push' '(' [visibility] ')' // 'pop' @@ -130,13 +227,12 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, Sema::PragmaPackKind Kind = Sema::PPK_Default; IdentifierInfo *Name = 0; - ExprResult Alignment; + Token Alignment; + Alignment.startToken(); SourceLocation LParenLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.is(tok::numeric_constant)) { - Alignment = Actions.ActOnNumericConstant(Tok); - if (Alignment.isInvalid()) - return; + Alignment = Tok; PP.Lex(Tok); @@ -165,9 +261,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, PP.Lex(Tok); if (Tok.is(tok::numeric_constant)) { - Alignment = Actions.ActOnNumericConstant(Tok); - if (Alignment.isInvalid()) - return; + Alignment = Tok; PP.Lex(Tok); } else if (Tok.is(tok::identifier)) { @@ -182,9 +276,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, return; } - Alignment = Actions.ActOnNumericConstant(Tok); - if (Alignment.isInvalid()) - return; + Alignment = Tok; PP.Lex(Tok); } @@ -219,7 +311,7 @@ void PragmaPackHandler::HandlePragma(Preprocessor &PP, new (Info) PragmaPackInfo(); Info->Kind = Kind; Info->Name = Name; - Info->Alignment = Alignment.release(); + Info->Alignment = Alignment; Info->LParenLoc = LParenLoc; Info->RParenLoc = RParenLoc; @@ -265,12 +357,23 @@ void PragmaMSStructHandler::HandlePragma(Preprocessor &PP, << "ms_struct"; return; } - Actions.ActOnPragmaMSStruct(Kind); + + Token *Toks = + (Token*) PP.getPreprocessorAllocator().Allocate( + sizeof(Token) * 1, llvm::alignOf<Token>()); + new (Toks) Token(); + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_msstruct); + Toks[0].setLocation(MSStructTok.getLocation()); + Toks[0].setAnnotationValue(reinterpret_cast<void*>( + static_cast<uintptr_t>(Kind))); + PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, + /*OwnsTokens=*/false); } // #pragma 'align' '=' {'native','natural','mac68k','power','reset'} // #pragma 'options 'align' '=' {'native','natural','mac68k','power','reset'} -static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok, +static void ParseAlignPragma(Preprocessor &PP, Token &FirstTok, bool IsOptions) { Token Tok; @@ -317,7 +420,6 @@ static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok, return; } - SourceLocation KindLoc = Tok.getLocation(); PP.Lex(Tok); if (Tok.isNot(tok::eod)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) @@ -325,19 +427,29 @@ static void ParseAlignPragma(Sema &Actions, Preprocessor &PP, Token &FirstTok, return; } - Actions.ActOnPragmaOptionsAlign(Kind, FirstTok.getLocation(), KindLoc); + Token *Toks = + (Token*) PP.getPreprocessorAllocator().Allocate( + sizeof(Token) * 1, llvm::alignOf<Token>()); + new (Toks) Token(); + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_align); + Toks[0].setLocation(FirstTok.getLocation()); + Toks[0].setAnnotationValue(reinterpret_cast<void*>( + static_cast<uintptr_t>(Kind))); + PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, + /*OwnsTokens=*/false); } void PragmaAlignHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &AlignTok) { - ParseAlignPragma(Actions, PP, AlignTok, /*IsOptions=*/false); + ParseAlignPragma(PP, AlignTok, /*IsOptions=*/false); } void PragmaOptionsHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &OptionsTok) { - ParseAlignPragma(Actions, PP, OptionsTok, /*IsOptions=*/true); + ParseAlignPragma(PP, OptionsTok, /*IsOptions=*/true); } // #pragma unused(identifier) @@ -426,7 +538,6 @@ void PragmaUnusedHandler::HandlePragma(Preprocessor &PP, void PragmaWeakHandler::HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &WeakTok) { - // FIXME: Should we be expanding macros here? My guess is no. SourceLocation WeakLoc = WeakTok.getLocation(); Token Tok; @@ -436,19 +547,20 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, return; } - IdentifierInfo *WeakName = Tok.getIdentifierInfo(), *AliasName = 0; - SourceLocation WeakNameLoc = Tok.getLocation(), AliasNameLoc; + Token WeakName = Tok; + bool HasAlias = false; + Token AliasName; PP.Lex(Tok); if (Tok.is(tok::equal)) { + HasAlias = true; PP.Lex(Tok); if (Tok.isNot(tok::identifier)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "weak"; return; } - AliasName = Tok.getIdentifierInfo(); - AliasNameLoc = Tok.getLocation(); + AliasName = Tok; PP.Lex(Tok); } @@ -457,11 +569,29 @@ void PragmaWeakHandler::HandlePragma(Preprocessor &PP, return; } - if (AliasName) { - Actions.ActOnPragmaWeakAlias(WeakName, AliasName, WeakLoc, WeakNameLoc, - AliasNameLoc); + if (HasAlias) { + Token *Toks = + (Token*) PP.getPreprocessorAllocator().Allocate( + sizeof(Token) * 3, llvm::alignOf<Token>()); + Token &pragmaUnusedTok = Toks[0]; + pragmaUnusedTok.startToken(); + pragmaUnusedTok.setKind(tok::annot_pragma_weakalias); + pragmaUnusedTok.setLocation(WeakLoc); + Toks[1] = WeakName; + Toks[2] = AliasName; + PP.EnterTokenStream(Toks, 3, + /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); } else { - Actions.ActOnPragmaWeakID(WeakName, WeakLoc, WeakNameLoc); + Token *Toks = + (Token*) PP.getPreprocessorAllocator().Allocate( + sizeof(Token) * 2, llvm::alignOf<Token>()); + Token &pragmaUnusedTok = Toks[0]; + pragmaUnusedTok.startToken(); + pragmaUnusedTok.setKind(tok::annot_pragma_weak); + pragmaUnusedTok.setLocation(WeakLoc); + Toks[1] = WeakName; + PP.EnterTokenStream(Toks, 2, + /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); } } @@ -479,17 +609,16 @@ void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, return; } - IdentifierInfo *RedefName = Tok.getIdentifierInfo(), *AliasName = 0; - SourceLocation RedefNameLoc = Tok.getLocation(), AliasNameLoc; - + Token RedefName = Tok; PP.Lex(Tok); + if (Tok.isNot(tok::identifier)) { PP.Diag(Tok.getLocation(), diag::warn_pragma_expected_identifier) << "redefine_extname"; return; } - AliasName = Tok.getIdentifierInfo(); - AliasNameLoc = Tok.getLocation(); + + Token AliasName = Tok; PP.Lex(Tok); if (Tok.isNot(tok::eod)) { @@ -498,8 +627,17 @@ void PragmaRedefineExtnameHandler::HandlePragma(Preprocessor &PP, return; } - Actions.ActOnPragmaRedefineExtname(RedefName, AliasName, RedefLoc, - RedefNameLoc, AliasNameLoc); + Token *Toks = + (Token*) PP.getPreprocessorAllocator().Allocate( + sizeof(Token) * 3, llvm::alignOf<Token>()); + Token &pragmaRedefTok = Toks[0]; + pragmaRedefTok.startToken(); + pragmaRedefTok.setKind(tok::annot_pragma_redefine_extname); + pragmaRedefTok.setLocation(RedefLoc); + Toks[1] = RedefName; + Toks[2] = AliasName; + PP.EnterTokenStream(Toks, 3, + /*DisableMacroExpansion=*/true, /*OwnsTokens=*/false); } @@ -511,7 +649,17 @@ PragmaFPContractHandler::HandlePragma(Preprocessor &PP, if (PP.LexOnOffSwitch(OOS)) return; - Actions.ActOnPragmaFPContract(OOS); + Token *Toks = + (Token*) PP.getPreprocessorAllocator().Allocate( + sizeof(Token) * 1, llvm::alignOf<Token>()); + new (Toks) Token(); + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_fp_contract); + Toks[0].setLocation(Tok.getLocation()); + Toks[0].setAnnotationValue(reinterpret_cast<void*>( + static_cast<uintptr_t>(OOS))); + PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, + /*OwnsTokens=*/false); } void @@ -550,19 +698,23 @@ PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, return; } - OpenCLOptions &f = Actions.getOpenCLOptions(); - // OpenCL 1.1 9.1: "The all variant sets the behavior for all extensions, - // overriding all previously issued extension directives, but only if the - // behavior is set to disable." - if (state == 0 && ename->isStr("all")) { -#define OPENCLEXT(nm) f.nm = 0; -#include "clang/Basic/OpenCLExtensions.def" - } -#define OPENCLEXT(nm) else if (ename->isStr(#nm)) { f.nm = state; } -#include "clang/Basic/OpenCLExtensions.def" - else { - PP.Diag(NameLoc, diag::warn_pragma_unknown_extension) << ename; + PP.Lex(Tok); + if (Tok.isNot(tok::eod)) { + PP.Diag(Tok.getLocation(), diag::warn_pragma_extra_tokens_at_eol) << + "OPENCL EXTENSION"; return; } + + OpenCLExtData data(ename, state); + Token *Toks = + (Token*) PP.getPreprocessorAllocator().Allocate( + sizeof(Token) * 1, llvm::alignOf<Token>()); + new (Toks) Token(); + Toks[0].startToken(); + Toks[0].setKind(tok::annot_pragma_opencl_extension); + Toks[0].setLocation(NameLoc); + Toks[0].setAnnotationValue(data.getOpaqueValue()); + PP.EnterTokenStream(Toks, 1, /*DisableMacroExpansion=*/true, + /*OwnsTokens=*/false); } diff --git a/lib/Parse/ParsePragma.h b/lib/Parse/ParsePragma.h index fef6960813d8..b9a2a251fcd4 100644 --- a/lib/Parse/ParsePragma.h +++ b/lib/Parse/ParsePragma.h @@ -21,9 +21,8 @@ namespace clang { class Parser; class PragmaAlignHandler : public PragmaHandler { - Sema &Actions; public: - explicit PragmaAlignHandler(Sema &A) : PragmaHandler("align"), Actions(A) {} + explicit PragmaAlignHandler() : PragmaHandler("align") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); @@ -31,38 +30,31 @@ public: class PragmaGCCVisibilityHandler : public PragmaHandler { public: - explicit PragmaGCCVisibilityHandler(Sema &/*A*/) - : PragmaHandler("visibility") {} + explicit PragmaGCCVisibilityHandler() : PragmaHandler("visibility") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; class PragmaOptionsHandler : public PragmaHandler { - Sema &Actions; public: - explicit PragmaOptionsHandler(Sema &A) : PragmaHandler("options"), - Actions(A) {} + explicit PragmaOptionsHandler() : PragmaHandler("options") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; class PragmaPackHandler : public PragmaHandler { - Sema &Actions; public: - explicit PragmaPackHandler(Sema &A) : PragmaHandler("pack"), - Actions(A) {} + explicit PragmaPackHandler() : PragmaHandler("pack") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; class PragmaMSStructHandler : public PragmaHandler { - Sema &Actions; public: - explicit PragmaMSStructHandler(Sema &A) : PragmaHandler("ms_struct"), - Actions(A) {} + explicit PragmaMSStructHandler() : PragmaHandler("ms_struct") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); @@ -70,48 +62,39 @@ public: class PragmaUnusedHandler : public PragmaHandler { public: - PragmaUnusedHandler(Sema &/*A*/) - : PragmaHandler("unused") {} + PragmaUnusedHandler() : PragmaHandler("unused") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; class PragmaWeakHandler : public PragmaHandler { - Sema &Actions; public: - explicit PragmaWeakHandler(Sema &A) - : PragmaHandler("weak"), Actions(A) {} + explicit PragmaWeakHandler() : PragmaHandler("weak") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; class PragmaRedefineExtnameHandler : public PragmaHandler { - Sema &Actions; public: - explicit PragmaRedefineExtnameHandler(Sema &A) - : PragmaHandler("redefine_extname"), Actions(A) {} + explicit PragmaRedefineExtnameHandler() : PragmaHandler("redefine_extname") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; class PragmaOpenCLExtensionHandler : public PragmaHandler { - Sema &Actions; public: - PragmaOpenCLExtensionHandler(Sema &A) : - PragmaHandler("EXTENSION"), Actions(A) {} + PragmaOpenCLExtensionHandler() : PragmaHandler("EXTENSION") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; class PragmaFPContractHandler : public PragmaHandler { - Sema &Actions; public: - PragmaFPContractHandler(Sema &A) : - PragmaHandler("FP_CONTRACT"), Actions(A) {} + PragmaFPContractHandler() : PragmaHandler("FP_CONTRACT") {} virtual void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer, Token &FirstToken); }; diff --git a/lib/Parse/ParseStmt.cpp b/lib/Parse/ParseStmt.cpp index df9b996aa315..f604e038d2ad 100644 --- a/lib/Parse/ParseStmt.cpp +++ b/lib/Parse/ParseStmt.cpp @@ -17,6 +17,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/TypoCorrection.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Basic/SourceManager.h" @@ -130,96 +131,38 @@ Retry: return ParseLabeledStatement(Attrs); } + // Look up the identifier, and typo-correct it to a keyword if it's not + // found. if (Next.isNot(tok::coloncolon)) { - CXXScopeSpec SS; - IdentifierInfo *Name = Tok.getIdentifierInfo(); - SourceLocation NameLoc = Tok.getLocation(); - - if (getLangOpts().CPlusPlus) - CheckForTemplateAndDigraph(Next, ParsedType(), - /*EnteringContext=*/false, *Name, SS); - - Sema::NameClassification Classification - = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next); - switch (Classification.getKind()) { - case Sema::NC_Keyword: - // The identifier was corrected to a keyword. Update the token - // to this keyword, and try again. - if (Name->getTokenID() != tok::identifier) { - Tok.setIdentifierInfo(Name); - Tok.setKind(Name->getTokenID()); - goto Retry; - } - - // Fall through via the normal error path. - // FIXME: This seems like it could only happen for context-sensitive - // keywords. - - case Sema::NC_Error: + // Try to limit which sets of keywords should be included in typo + // correction based on what the next token is. + // FIXME: Pass the next token into the CorrectionCandidateCallback and + // do this filtering in a more fine-grained manner. + CorrectionCandidateCallback DefaultValidator; + DefaultValidator.WantTypeSpecifiers = + Next.is(tok::l_paren) || Next.is(tok::less) || + Next.is(tok::identifier) || Next.is(tok::star) || + Next.is(tok::amp) || Next.is(tok::l_square); + DefaultValidator.WantExpressionKeywords = + Next.is(tok::l_paren) || Next.is(tok::identifier) || + Next.is(tok::arrow) || Next.is(tok::period); + DefaultValidator.WantRemainingKeywords = + Next.is(tok::l_paren) || Next.is(tok::semi) || + Next.is(tok::identifier) || Next.is(tok::l_brace); + DefaultValidator.WantCXXNamedCasts = false; + if (TryAnnotateName(/*IsAddressOfOperand*/false, &DefaultValidator) + == ANK_Error) { // Handle errors here by skipping up to the next semicolon or '}', and // eat the semicolon if that's what stopped us. SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); if (Tok.is(tok::semi)) ConsumeToken(); return StmtError(); - - case Sema::NC_Unknown: - // Either we don't know anything about this identifier, or we know that - // we're in a syntactic context we haven't handled yet. - break; - - case Sema::NC_Type: - Tok.setKind(tok::annot_typename); - setTypeAnnotation(Tok, Classification.getType()); - Tok.setAnnotationEndLoc(NameLoc); - PP.AnnotateCachedTokens(Tok); - break; - - case Sema::NC_Expression: - Tok.setKind(tok::annot_primary_expr); - setExprAnnotation(Tok, Classification.getExpression()); - Tok.setAnnotationEndLoc(NameLoc); - PP.AnnotateCachedTokens(Tok); - break; - - case Sema::NC_TypeTemplate: - case Sema::NC_FunctionTemplate: { - ConsumeToken(); // the identifier - UnqualifiedId Id; - Id.setIdentifier(Name, NameLoc); - if (AnnotateTemplateIdToken( - TemplateTy::make(Classification.getTemplateName()), - Classification.getTemplateNameKind(), - SS, SourceLocation(), Id, - /*AllowTypeAnnotation=*/false)) { - // Handle errors here by skipping up to the next semicolon or '}', and - // eat the semicolon if that's what stopped us. - SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); - if (Tok.is(tok::semi)) - ConsumeToken(); - return StmtError(); - } - - // If the next token is '::', jump right into parsing a - // nested-name-specifier. We don't want to leave the template-id - // hanging. - if (NextToken().is(tok::coloncolon) && TryAnnotateCXXScopeToken(false)){ - // Handle errors here by skipping up to the next semicolon or '}', and - // eat the semicolon if that's what stopped us. - SkipUntil(tok::r_brace, /*StopAtSemi=*/true, /*DontConsume=*/true); - if (Tok.is(tok::semi)) - ConsumeToken(); - return StmtError(); - } - - // We've annotated a template-id, so try again now. - goto Retry; } - case Sema::NC_NestedNameSpecifier: - // FIXME: Implement this! - break; - } + // If the identifier was typo-corrected, try again. + if (Tok.isNot(tok::identifier)) + goto Retry; } // Fall through @@ -289,7 +232,7 @@ Retry: bool msAsm = false; Res = ParseAsmStatement(msAsm); Res = Actions.ActOnFinishFullStmt(Res.get()); - if (msAsm) return move(Res); + if (msAsm) return Res; SemiError = "asm"; break; } @@ -310,6 +253,41 @@ Retry: ProhibitAttributes(Attrs); HandlePragmaPack(); return StmtEmpty(); + + case tok::annot_pragma_msstruct: + ProhibitAttributes(Attrs); + HandlePragmaMSStruct(); + return StmtEmpty(); + + case tok::annot_pragma_align: + ProhibitAttributes(Attrs); + HandlePragmaAlign(); + return StmtEmpty(); + + case tok::annot_pragma_weak: + ProhibitAttributes(Attrs); + HandlePragmaWeak(); + return StmtEmpty(); + + case tok::annot_pragma_weakalias: + ProhibitAttributes(Attrs); + HandlePragmaWeakAlias(); + return StmtEmpty(); + + case tok::annot_pragma_redefine_extname: + ProhibitAttributes(Attrs); + HandlePragmaRedefineExtname(); + return StmtEmpty(); + + case tok::annot_pragma_fp_contract: + Diag(Tok, diag::err_pragma_fp_contract_scope); + ConsumeToken(); + return StmtError(); + + case tok::annot_pragma_opencl_extension: + ProhibitAttributes(Attrs); + HandlePragmaOpenCLExtension(); + return StmtEmpty(); } // If we reached this code, the statement must end in a semicolon. @@ -324,7 +302,7 @@ Retry: SkipUntil(tok::r_brace, true, true); } - return move(Res); + return Res; } /// \brief Parse an expression statement. @@ -381,7 +359,7 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) { StmtResult TryBlock(ParseCompoundStatement()); if(TryBlock.isInvalid()) - return move(TryBlock); + return TryBlock; StmtResult Handler; if (Tok.is(tok::identifier) && @@ -396,7 +374,7 @@ StmtResult Parser::ParseSEHTryBlockCommon(SourceLocation TryLoc) { } if(Handler.isInvalid()) - return move(Handler); + return Handler; return Actions.ActOnSEHTryBlock(false /* IsCXXTry */, TryLoc, @@ -441,7 +419,7 @@ StmtResult Parser::ParseSEHExceptBlock(SourceLocation ExceptLoc) { StmtResult Block(ParseCompoundStatement()); if(Block.isInvalid()) - return move(Block); + return Block; return Actions.ActOnSEHExceptBlock(ExceptLoc, FilterExpr.take(), Block.take()); } @@ -458,7 +436,7 @@ StmtResult Parser::ParseSEHFinallyBlock(SourceLocation FinallyBlock) { StmtResult Block(ParseCompoundStatement()); if(Block.isInvalid()) - return move(Block); + return Block; return Actions.ActOnSEHFinallyBlock(FinallyBlock,Block.take()); } @@ -603,7 +581,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { // Otherwise we link it into the current chain. Stmt *NextDeepest = Case.get(); if (TopLevelCase.isInvalid()) - TopLevelCase = move(Case); + TopLevelCase = Case; else Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, Case.get()); DeepestParsedCaseStmt = NextDeepest; @@ -636,7 +614,7 @@ StmtResult Parser::ParseCaseStatement(bool MissingCase, ExprResult Expr) { Actions.ActOnCaseStmtBody(DeepestParsedCaseStmt, SubStmt.get()); // Return the top level parsed statement tree. - return move(TopLevelCase); + return TopLevelCase; } /// ParseDefaultStatement @@ -728,6 +706,48 @@ StmtResult Parser::ParseCompoundStatement(bool isStmtExpr, return ParseCompoundStatementBody(isStmtExpr); } +/// Parse any pragmas at the start of the compound expression. We handle these +/// separately since some pragmas (FP_CONTRACT) must appear before any C +/// statement in the compound, but may be intermingled with other pragmas. +void Parser::ParseCompoundStatementLeadingPragmas() { + bool checkForPragmas = true; + while (checkForPragmas) { + switch (Tok.getKind()) { + case tok::annot_pragma_vis: + HandlePragmaVisibility(); + break; + case tok::annot_pragma_pack: + HandlePragmaPack(); + break; + case tok::annot_pragma_msstruct: + HandlePragmaMSStruct(); + break; + case tok::annot_pragma_align: + HandlePragmaAlign(); + break; + case tok::annot_pragma_weak: + HandlePragmaWeak(); + break; + case tok::annot_pragma_weakalias: + HandlePragmaWeakAlias(); + break; + case tok::annot_pragma_redefine_extname: + HandlePragmaRedefineExtname(); + break; + case tok::annot_pragma_opencl_extension: + HandlePragmaOpenCLExtension(); + break; + case tok::annot_pragma_fp_contract: + HandlePragmaFPContract(); + break; + default: + checkForPragmas = false; + break; + } + } + +} + /// ParseCompoundStatementBody - Parse a sequence of statements and invoke the /// ActOnCompoundStmt action. This expects the '{' to be the current token, and /// consume the '}' at the end of the block. It does not manipulate the scope @@ -736,6 +756,11 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), Tok.getLocation(), "in compound statement ('{}')"); + + // Record the state of the FP_CONTRACT pragma, restore on leaving the + // compound statement. + Sema::FPContractStateRAII SaveFPContractState(Actions); + InMessageExpressionRAIIObject InMessage(*this, false); BalancedDelimiterTracker T(*this, tok::l_brace); if (T.consumeOpen()) @@ -743,7 +768,10 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { Sema::CompoundScopeRAII CompoundScope(Actions); - StmtVector Stmts(Actions); + // Parse any pragmas at the beginning of the compound statement. + ParseCompoundStatementLeadingPragmas(); + + StmtVector Stmts; // "__label__ X, Y, Z;" is the GNU "Local Label" extension. These are // only allowed at the start of a compound stmt regardless of the language. @@ -850,7 +878,7 @@ StmtResult Parser::ParseCompoundStatementBody(bool isStmtExpr) { } return Actions.ActOnCompoundStmt(T.getOpenLocation(), CloseLoc, - move_arg(Stmts), isStmtExpr); + Stmts, isStmtExpr); } /// ParseParenExprOrCondition: @@ -1096,7 +1124,7 @@ StmtResult Parser::ParseSwitchStatement(SourceLocation *TrailingElseLoc) { SkipUntil(tok::r_brace, false, false); } else SkipUntil(tok::semi); - return move(Switch); + return Switch; } // C99 6.8.4p3 - In C99, the body of the switch statement is a scope, even if @@ -1375,7 +1403,7 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - StmtVector Stmts(Actions); + StmtVector Stmts; DeclGroupPtrTy DG = ParseSimpleDeclaration(Stmts, Declarator::ForContext, DeclEnd, attrs, false, MightBeForRangeStmt ? @@ -1498,7 +1526,8 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { ForRangeStmt = Actions.ActOnCXXForRangeStmt(ForLoc, FirstPart.take(), ForRangeInit.ColonLoc, ForRangeInit.RangeExpr.get(), - T.getCloseLocation()); + T.getCloseLocation(), + Sema::BFRK_Build); // Similarly, we need to do the semantic analysis for a for-range @@ -1580,7 +1609,7 @@ StmtResult Parser::ParseGotoStatement() { return StmtError(); } - return move(Res); + return Res; } /// ParseContinueStatement @@ -1653,6 +1682,9 @@ StmtResult Parser::ParseReturnStatement() { /// ms-asm-line '\n' ms-asm-instruction-block /// StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { + // MS-style inline assembly is not fully supported, so emit a warning. + Diag(AsmLoc, diag::warn_unsupported_msasm); + SourceManager &SrcMgr = PP.getSourceManager(); SourceLocation EndLoc = AsmLoc; SmallVector<Token, 4> AsmToks; @@ -1745,6 +1777,21 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { return StmtError(); } + // If MS-style inline assembly is disabled, then build an empty asm. + if (!getLangOpts().EmitMicrosoftInlineAsm) { + Token t; + t.setKind(tok::string_literal); + t.setLiteralData("\"/*FIXME: not done*/\""); + t.clearFlag(Token::NeedsCleaning); + t.setLength(21); + ExprResult AsmString(Actions.ActOnStringLiteral(&t, 1)); + ExprVector Constraints; + ExprVector Exprs; + ExprVector Clobbers; + return Actions.ActOnGCCAsmStmt(AsmLoc, true, true, 0, 0, 0, Constraints, + Exprs, AsmString.take(), Clobbers, EndLoc); + } + // FIXME: We should be passing source locations for better diagnostics. return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLoc, llvm::makeArrayRef(AsmToks), EndLoc); @@ -1806,18 +1853,17 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { } SmallVector<IdentifierInfo *, 4> Names; - ExprVector Constraints(Actions); - ExprVector Exprs(Actions); - ExprVector Clobbers(Actions); + ExprVector Constraints; + ExprVector Exprs; + ExprVector Clobbers; if (Tok.is(tok::r_paren)) { // We have a simple asm expression like 'asm("foo")'. T.consumeClose(); - return Actions.ActOnAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, - /*NumOutputs*/ 0, /*NumInputs*/ 0, 0, - move_arg(Constraints), move_arg(Exprs), - AsmString.take(), move_arg(Clobbers), - T.getCloseLocation()); + return Actions.ActOnGCCAsmStmt(AsmLoc, /*isSimple*/ true, isVolatile, + /*NumOutputs*/ 0, /*NumInputs*/ 0, 0, + Constraints, Exprs, AsmString.take(), + Clobbers, T.getCloseLocation()); } // Parse Outputs, if present. @@ -1878,11 +1924,10 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { } T.consumeClose(); - return Actions.ActOnAsmStmt(AsmLoc, false, isVolatile, - NumOutputs, NumInputs, Names.data(), - move_arg(Constraints), move_arg(Exprs), - AsmString.take(), move_arg(Clobbers), - T.getCloseLocation()); + return Actions.ActOnGCCAsmStmt(AsmLoc, false, isVolatile, NumOutputs, + NumInputs, Names.data(), Constraints, Exprs, + AsmString.take(), Clobbers, + T.getCloseLocation()); } /// ParseAsmOperands - Parse the asm-operands production as used by @@ -1975,7 +2020,7 @@ Decl *Parser::ParseFunctionStatementBody(Decl *Decl, ParseScope &BodyScope) { if (FnBody.isInvalid()) { Sema::CompoundScopeRAII CompoundScope(Actions); FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, - MultiStmtArg(Actions), false); + MultiStmtArg(), false); } BodyScope.Exit(); @@ -2006,13 +2051,13 @@ Decl *Parser::ParseFunctionTryBlock(Decl *Decl, ParseScope &BodyScope) { } SourceLocation LBraceLoc = Tok.getLocation(); - StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc)); + StmtResult FnBody(ParseCXXTryBlockCommon(TryLoc, /*FnTry*/true)); // If we failed to parse the try-catch, we just give the function an empty // compound statement as the body. if (FnBody.isInvalid()) { Sema::CompoundScopeRAII CompoundScope(Actions); FnBody = Actions.ActOnCompoundStmt(LBraceLoc, LBraceLoc, - MultiStmtArg(Actions), false); + MultiStmtArg(), false); } BodyScope.Exit(); @@ -2024,12 +2069,18 @@ bool Parser::trySkippingFunctionBody() { assert(SkipFunctionBodies && "Should only be called when SkipFunctionBodies is enabled"); + if (!PP.isCodeCompletionEnabled()) { + ConsumeBrace(); + SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false); + return true; + } + // We're in code-completion mode. Skip parsing for all function bodies unless // the body contains the code-completion point. TentativeParsingAction PA(*this); ConsumeBrace(); if (SkipUntil(tok::r_brace, /*StopAtSemi=*/false, /*DontConsume=*/false, - /*StopAtCodeCompletion=*/PP.isCodeCompletionEnabled())) { + /*StopAtCodeCompletion=*/true)) { PA.Commit(); return true; } @@ -2066,15 +2117,16 @@ StmtResult Parser::ParseCXXTryBlock() { /// 'try' compound-statement seh-except-block /// 'try' compound-statment seh-finally-block /// -StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { +StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc, bool FnTry) { if (Tok.isNot(tok::l_brace)) return StmtError(Diag(Tok, diag::err_expected_lbrace)); // FIXME: Possible draft standard bug: attribute-specifier should be allowed? StmtResult TryBlock(ParseCompoundStatement(/*isStmtExpr=*/false, - Scope::DeclScope|Scope::TryScope)); + Scope::DeclScope | + (FnTry ? Scope::FnTryScope : Scope::TryScope))); if (TryBlock.isInvalid()) - return move(TryBlock); + return TryBlock; // Borland allows SEH-handlers with 'try' @@ -2092,7 +2144,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { Handler = ParseSEHFinallyBlock(Loc); } if(Handler.isInvalid()) - return move(Handler); + return Handler; return Actions.ActOnSEHTryBlock(true /* IsCXXTry */, TryLoc, @@ -2100,7 +2152,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { Handler.take()); } else { - StmtVector Handlers(Actions); + StmtVector Handlers; ParsedAttributesWithRange attrs(AttrFactory); MaybeParseCXX0XAttributes(attrs); ProhibitAttributes(attrs); @@ -2108,7 +2160,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Tok.isNot(tok::kw_catch)) return StmtError(Diag(Tok, diag::err_expected_catch)); while (Tok.is(tok::kw_catch)) { - StmtResult Handler(ParseCXXCatchBlock()); + StmtResult Handler(ParseCXXCatchBlock(FnTry)); if (!Handler.isInvalid()) Handlers.push_back(Handler.release()); } @@ -2117,7 +2169,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { if (Handlers.empty()) return StmtError(); - return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(),move_arg(Handlers)); + return Actions.ActOnCXXTryBlock(TryLoc, TryBlock.take(),Handlers); } } @@ -2132,7 +2184,7 @@ StmtResult Parser::ParseCXXTryBlockCommon(SourceLocation TryLoc) { /// type-specifier-seq /// '...' /// -StmtResult Parser::ParseCXXCatchBlock() { +StmtResult Parser::ParseCXXCatchBlock(bool FnCatch) { assert(Tok.is(tok::kw_catch) && "Expected 'catch'"); SourceLocation CatchLoc = ConsumeToken(); @@ -2144,7 +2196,8 @@ StmtResult Parser::ParseCXXCatchBlock() { // C++ 3.3.2p3: // The name in a catch exception-declaration is local to the handler and // shall not be redeclared in the outermost block of the handler. - ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope); + ParseScope CatchScope(this, Scope::DeclScope | Scope::ControlScope | + (FnCatch ? Scope::FnCatchScope : 0)); // exception-declaration is equivalent to '...' or a parameter-declaration // without default arguments. @@ -2169,7 +2222,7 @@ StmtResult Parser::ParseCXXCatchBlock() { // FIXME: Possible draft standard bug: attribute-specifier should be allowed? StmtResult Block(ParseCompoundStatement()); if (Block.isInvalid()) - return move(Block); + return Block; return Actions.ActOnCXXCatchBlock(CatchLoc, ExceptionDecl, Block.take()); } diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index ade918fb221a..2e0411e8a81c 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -246,7 +246,7 @@ Parser::ParseSingleDeclarationAfterTemplate( return 0; } - LateParsedAttrList LateParsedAttrs; + LateParsedAttrList LateParsedAttrs(true); if (DeclaratorInfo.isFunctionDeclarator()) MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); @@ -889,8 +889,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, return true; } - ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(), - TemplateArgs.size()); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs); // Build the annotation token. if (TNK == TNK_Type_template && AllowTypeAnnotation) { @@ -942,8 +941,6 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, Tok.setLocation(TemplateKWLoc); else Tok.setLocation(TemplateNameLoc); - - TemplateArgsPtr.release(); } // Common fields for the annotation token @@ -969,8 +966,7 @@ void Parser::AnnotateTemplateIdTokenAsType() { TemplateId->Kind == TNK_Dependent_template_name) && "Only works for type and dependent templates"); - ASTTemplateArgsPtr TemplateArgsPtr(Actions, - TemplateId->getTemplateArgs(), + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult Type diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp index 1a4df4791b5f..40c4eee1994b 100644 --- a/lib/Parse/ParseTentative.cpp +++ b/lib/Parse/ParseTentative.cpp @@ -104,16 +104,27 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such // a case. - TPResult TPR = isCXXDeclarationSpecifier(); + bool InvalidAsDeclaration = false; + TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(), + &InvalidAsDeclaration); if (TPR != TPResult::Ambiguous()) return TPR != TPResult::False(); // Returns true for TPResult::True() or // TPResult::Error(). + // FIXME: TryParseSimpleDeclaration doesn't look past the first initializer, + // and so gets some cases wrong. We can't carry on if we've already seen + // something which makes this statement invalid as a declaration in this case, + // since it can cause us to misparse valid code. Revisit this once + // TryParseInitDeclaratorList is fixed. + if (InvalidAsDeclaration) + return false; + // FIXME: Add statistics about the number of ambiguous statements encountered // and how they were resolved (number of declarations+number of expressions). - // Ok, we have a simple-type-specifier/typename-specifier followed by a '('. - // We need tentative parsing... + // Ok, we have a simple-type-specifier/typename-specifier followed by a '(', + // or an identifier which doesn't resolve as anything. We need tentative + // parsing... TentativeParsingAction PA(*this); TPR = TryParseSimpleDeclaration(AllowForRangeDecl); @@ -140,20 +151,28 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) { /// attribute-specifier-seqopt type-specifier-seq declarator /// Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) { - // We know that we have a simple-type-specifier/typename-specifier followed - // by a '('. - assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous()); - if (Tok.is(tok::kw_typeof)) TryParseTypeofSpecifier(); else { + if (Tok.is(tok::annot_cxxscope)) + ConsumeToken(); ConsumeToken(); - + if (getLangOpts().ObjC1 && Tok.is(tok::less)) TryParseProtocolQualifiers(); } - - assert(Tok.is(tok::l_paren) && "Expected '('"); + + // Two decl-specifiers in a row conclusively disambiguate this as being a + // simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the + // overwhelmingly common case that the next token is a '('. + if (Tok.isNot(tok::l_paren)) { + TPResult TPR = isCXXDeclarationSpecifier(); + if (TPR == TPResult::Ambiguous()) + return TPResult::True(); + if (TPR == TPResult::True() || TPR == TPResult::Error()) + return TPR; + assert(TPR == TPResult::False()); + } TPResult TPR = TryParseInitDeclaratorList(); if (TPR != TPResult::Ambiguous()) @@ -623,6 +642,8 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // declarator-id if (Tok.is(tok::annot_cxxscope)) ConsumeToken(); + else + TentativelyDeclaredIdentifiers.push_back(Tok.getIdentifierInfo()); ConsumeToken(); } else if (Tok.is(tok::l_paren)) { ConsumeParen(); @@ -761,6 +782,7 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { case tok::kw___is_convertible_to: case tok::kw___is_empty: case tok::kw___is_enum: + case tok::kw___is_interface_class: case tok::kw___is_final: case tok::kw___is_literal: case tok::kw___is_literal_type: @@ -824,6 +846,12 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { return TPResult::Ambiguous(); } +bool Parser::isTentativelyDeclared(IdentifierInfo *II) { + return std::find(TentativelyDeclaredIdentifiers.begin(), + TentativelyDeclaredIdentifiers.end(), II) + != TentativelyDeclaredIdentifiers.end(); +} + /// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration /// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could /// be either a decl-specifier or a function-style cast, and TPResult::Error() @@ -831,7 +859,10 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) { /// /// If HasMissingTypename is provided, a name with a dependent scope specifier /// will be treated as ambiguous if the 'typename' keyword is missing. If this -/// happens, *HasMissingTypename will be set to 'true'. +/// happens, *HasMissingTypename will be set to 'true'. This will also be used +/// as an indicator that undeclared identifiers (which will trigger a later +/// parse error) should be treated as types. Returns TPResult::Ambiguous() in +/// such cases. /// /// decl-specifier: /// storage-class-specifier @@ -927,22 +958,64 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, bool *HasMissingTypename) { switch (Tok.getKind()) { - case tok::identifier: // foo::bar + case tok::identifier: { // Check for need to substitute AltiVec __vector keyword // for "vector" identifier. if (TryAltiVecVectorToken()) return TPResult::True(); - // Fall through. + + const Token &Next = NextToken(); + // In 'foo bar', 'foo' is always a type name outside of Objective-C. + if (!getLangOpts().ObjC1 && Next.is(tok::identifier)) + return TPResult::True(); + + if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) { + // Determine whether this is a valid expression. If not, we will hit + // a parse error one way or another. In that case, tell the caller that + // this is ambiguous. Typo-correct to type and expression keywords and + // to types and identifiers, in order to try to recover from errors. + CorrectionCandidateCallback TypoCorrection; + TypoCorrection.WantRemainingKeywords = false; + switch (TryAnnotateName(false /* no nested name specifier */, + &TypoCorrection)) { + case ANK_Error: + return TPResult::Error(); + case ANK_TentativeDecl: + return TPResult::False(); + case ANK_TemplateName: + // A bare type template-name which can't be a template template + // argument is an error, and was probably intended to be a type. + return GreaterThanIsOperator ? TPResult::True() : TPResult::False(); + case ANK_Unresolved: + return HasMissingTypename ? TPResult::Ambiguous() : TPResult::False(); + case ANK_Success: + break; + } + assert(Tok.isNot(tok::identifier) && + "TryAnnotateName succeeded without producing an annotation"); + } else { + // This might possibly be a type with a dependent scope specifier and + // a missing 'typename' keyword. Don't use TryAnnotateName in this case, + // since it will annotate as a primary expression, and we want to use the + // "missing 'typename'" logic. + if (TryAnnotateTypeOrScopeToken()) + return TPResult::Error(); + // If annotation failed, assume it's a non-type. + // FIXME: If this happens due to an undeclared identifier, treat it as + // ambiguous. + if (Tok.is(tok::identifier)) + return TPResult::False(); + } + + // We annotated this token as something. Recurse to handle whatever we got. + return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); + } + case tok::kw_typename: // typename T::type // Annotate typenames and C++ scope specifiers. If we get one, just // recurse to handle whatever we get. if (TryAnnotateTypeOrScopeToken()) return TPResult::Error(); - if (Tok.is(tok::identifier)) { - const Token &Next = NextToken(); - return (!getLangOpts().ObjC1 && Next.is(tok::identifier)) ? - TPResult::True() : TPResult::False(); - } return isCXXDeclarationSpecifier(BracedCastResult, HasMissingTypename); case tok::coloncolon: { // ::foo::bar @@ -1073,6 +1146,28 @@ Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult, *HasMissingTypename = true; return TPResult::Ambiguous(); } + } else { + // Try to resolve the name. If it doesn't exist, assume it was + // intended to name a type and keep disambiguating. + switch (TryAnnotateName(false /* SS is not dependent */)) { + case ANK_Error: + return TPResult::Error(); + case ANK_TentativeDecl: + return TPResult::False(); + case ANK_TemplateName: + // A bare type template-name which can't be a template template + // argument is an error, and was probably intended to be a type. + return GreaterThanIsOperator ? TPResult::True() : TPResult::False(); + case ANK_Unresolved: + return HasMissingTypename ? TPResult::Ambiguous() + : TPResult::False(); + case ANK_Success: + // Annotated it, check again. + assert(Tok.isNot(tok::annot_cxxscope) || + NextToken().isNot(tok::identifier)); + return isCXXDeclarationSpecifier(BracedCastResult, + HasMissingTypename); + } } } return TPResult::False(); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 3725e2b84550..f4cdd619cef4 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -23,6 +23,7 @@ #include "clang/AST/ASTConsumer.h" using namespace clang; + namespace { /// \brief A comment handler that passes comments found by the preprocessor /// to the parser action. @@ -47,11 +48,13 @@ IdentifierInfo *Parser::getSEHExceptKeyword() { return Ident__except; } -Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies) +Parser::Parser(Preprocessor &pp, Sema &actions, bool skipFunctionBodies) : PP(pp), Actions(actions), Diags(PP.getDiagnostics()), GreaterThanIsOperator(true), ColonIsSacred(false), InMessageExpression(false), TemplateParameterDepth(0), - ParsingInObjCContainer(false), SkipFunctionBodies(SkipFunctionBodies) { + ParsingInObjCContainer(false) { + SkipFunctionBodies = pp.isCodeCompletionEnabled() || skipFunctionBodies; + Tok.startToken(); Tok.setKind(tok::eof); Actions.CurScope = 0; NumCachedScopes = 0; @@ -60,35 +63,35 @@ Parser::Parser(Preprocessor &pp, Sema &actions, bool SkipFunctionBodies) // Add #pragma handlers. These are removed and destroyed in the // destructor. - AlignHandler.reset(new PragmaAlignHandler(actions)); + AlignHandler.reset(new PragmaAlignHandler()); PP.AddPragmaHandler(AlignHandler.get()); - GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler(actions)); + GCCVisibilityHandler.reset(new PragmaGCCVisibilityHandler()); PP.AddPragmaHandler("GCC", GCCVisibilityHandler.get()); - OptionsHandler.reset(new PragmaOptionsHandler(actions)); + OptionsHandler.reset(new PragmaOptionsHandler()); PP.AddPragmaHandler(OptionsHandler.get()); - PackHandler.reset(new PragmaPackHandler(actions)); + PackHandler.reset(new PragmaPackHandler()); PP.AddPragmaHandler(PackHandler.get()); - MSStructHandler.reset(new PragmaMSStructHandler(actions)); + MSStructHandler.reset(new PragmaMSStructHandler()); PP.AddPragmaHandler(MSStructHandler.get()); - UnusedHandler.reset(new PragmaUnusedHandler(actions)); + UnusedHandler.reset(new PragmaUnusedHandler()); PP.AddPragmaHandler(UnusedHandler.get()); - WeakHandler.reset(new PragmaWeakHandler(actions)); + WeakHandler.reset(new PragmaWeakHandler()); PP.AddPragmaHandler(WeakHandler.get()); - RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler(actions)); + RedefineExtnameHandler.reset(new PragmaRedefineExtnameHandler()); PP.AddPragmaHandler(RedefineExtnameHandler.get()); - FPContractHandler.reset(new PragmaFPContractHandler(actions)); + FPContractHandler.reset(new PragmaFPContractHandler()); PP.AddPragmaHandler("STDC", FPContractHandler.get()); if (getLangOpts().OpenCL) { - OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler(actions)); + OpenCLExtensionHandler.reset(new PragmaOpenCLExtensionHandler()); PP.AddPragmaHandler("OPENCL", OpenCLExtensionHandler.get()); PP.AddPragmaHandler("OPENCL", FPContractHandler.get()); @@ -135,7 +138,7 @@ DiagnosticBuilder Parser::Diag(const Token &Tok, unsigned DiagID) { /// given range. /// /// \param Loc The location where we'll emit the diagnostic. -/// \param Loc The kind of diagnostic to emit. +/// \param DK The kind of diagnostic to emit. /// \param ParenRange Source range enclosing code that should be parenthesized. void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK, SourceRange ParenRange) { @@ -154,7 +157,8 @@ void Parser::SuggestParentheses(SourceLocation Loc, unsigned DK, static bool IsCommonTypo(tok::TokenKind ExpectedTok, const Token &Tok) { switch (ExpectedTok) { - case tok::semi: return Tok.is(tok::colon); // : for ; + case tok::semi: + return Tok.is(tok::colon) || Tok.is(tok::comma); // : or , for ; default: return false; } } @@ -466,9 +470,6 @@ void Parser::Initialize() { EnterScope(Scope::DeclScope); Actions.ActOnTranslationUnitScope(getCurScope()); - // Prime the lexer look-ahead. - ConsumeToken(); - // Initialization for Objective-C context sensitive keywords recognition. // Referenced in Parser::ParseObjCTypeQualifierList. if (getLangOpts().ObjC1) { @@ -523,6 +524,11 @@ void Parser::Initialize() { PP.SetPoisonReason(Ident___abnormal_termination,diag::err_seh___finally_block); PP.SetPoisonReason(Ident_AbnormalTermination,diag::err_seh___finally_block); } + + Actions.Initialize(); + + // Prime the lexer look-ahead. + ConsumeToken(); } namespace { @@ -634,6 +640,27 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, case tok::annot_pragma_pack: HandlePragmaPack(); return DeclGroupPtrTy(); + case tok::annot_pragma_msstruct: + HandlePragmaMSStruct(); + return DeclGroupPtrTy(); + case tok::annot_pragma_align: + HandlePragmaAlign(); + return DeclGroupPtrTy(); + case tok::annot_pragma_weak: + HandlePragmaWeak(); + return DeclGroupPtrTy(); + case tok::annot_pragma_weakalias: + HandlePragmaWeakAlias(); + return DeclGroupPtrTy(); + case tok::annot_pragma_redefine_extname: + HandlePragmaRedefineExtname(); + return DeclGroupPtrTy(); + case tok::annot_pragma_fp_contract: + HandlePragmaFPContract(); + return DeclGroupPtrTy(); + case tok::annot_pragma_opencl_extension: + HandlePragmaOpenCLExtension(); + return DeclGroupPtrTy(); case tok::semi: ConsumeExtraSemi(OutsideFunction); // TODO: Invoke action for top-level semicolon. @@ -693,7 +720,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, // A function definition cannot start with any of these keywords. { SourceLocation DeclEnd; - StmtVector Stmts(Actions); + StmtVector Stmts; return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); } @@ -704,7 +731,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) << 0; SourceLocation DeclEnd; - StmtVector Stmts(Actions); + StmtVector Stmts; return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); } goto dont_know; @@ -716,7 +743,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, // Inline namespaces. Allowed as an extension even in C++03. if (NextKind == tok::kw_namespace) { SourceLocation DeclEnd; - StmtVector Stmts(Actions); + StmtVector Stmts; return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); } @@ -726,7 +753,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) << 1; SourceLocation DeclEnd; - StmtVector Stmts(Actions); + StmtVector Stmts; return ParseDeclaration(Stmts, Declarator::FileContext, DeclEnd, attrs); } } @@ -972,16 +999,14 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, if (getLangOpts().DelayedTemplateParsing && Tok.isNot(tok::equal) && TemplateInfo.Kind == ParsedTemplateInfo::Template) { - MultiTemplateParamsArg TemplateParameterLists(Actions, - TemplateInfo.TemplateParams->data(), - TemplateInfo.TemplateParams->size()); + MultiTemplateParamsArg TemplateParameterLists(*TemplateInfo.TemplateParams); ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); Scope *ParentScope = getCurScope()->getParent(); D.setFunctionDefinitionKind(FDK_Definition); Decl *DP = Actions.HandleDeclarator(ParentScope, D, - move(TemplateParameterLists)); + TemplateParameterLists); D.complete(DP); D.getMutableDeclSpec().abort(); @@ -1009,13 +1034,12 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, (Tok.is(tok::l_brace) || Tok.is(tok::kw_try) || Tok.is(tok::colon)) && Actions.CurContext->isTranslationUnit()) { - MultiTemplateParamsArg TemplateParameterLists(Actions, 0, 0); ParseScope BodyScope(this, Scope::FnScope|Scope::DeclScope); Scope *ParentScope = getCurScope()->getParent(); D.setFunctionDefinitionKind(FDK_Definition); Decl *FuncDecl = Actions.HandleDeclarator(ParentScope, D, - move(TemplateParameterLists)); + MultiTemplateParamsArg()); D.complete(FuncDecl); D.getMutableDeclSpec().abort(); if (FuncDecl) { @@ -1033,10 +1057,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // specified Declarator for the function. Decl *Res = TemplateInfo.TemplateParams? Actions.ActOnStartOfFunctionTemplateDef(getCurScope(), - MultiTemplateParamsArg(Actions, - TemplateInfo.TemplateParams->data(), - TemplateInfo.TemplateParams->size()), - D) + *TemplateInfo.TemplateParams, D) : Actions.ActOnStartOfFunctionDef(getCurScope(), D); // Break out of the ParsingDeclarator context before we parse the body. @@ -1288,7 +1309,7 @@ Parser::ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { *EndLoc = T.getCloseLocation(); } - return move(Result); + return Result; } /// \brief Get the TemplateIdAnnotation from the token and put it in the @@ -1301,6 +1322,143 @@ TemplateIdAnnotation *Parser::takeTemplateIdAnnotation(const Token &tok) { return Id; } +void Parser::AnnotateScopeToken(CXXScopeSpec &SS, bool IsNewAnnotation) { + // Push the current token back into the token stream (or revert it if it is + // cached) and use an annotation scope token for current token. + if (PP.isBacktrackEnabled()) + PP.RevertCachedTokens(1); + else + PP.EnterToken(Tok); + Tok.setKind(tok::annot_cxxscope); + Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS)); + Tok.setAnnotationRange(SS.getRange()); + + // In case the tokens were cached, have Preprocessor replace them + // with the annotation token. We don't need to do this if we've + // just reverted back to a prior state. + if (IsNewAnnotation) + PP.AnnotateCachedTokens(Tok); +} + +/// \brief Attempt to classify the name at the current token position. This may +/// form a type, scope or primary expression annotation, or replace the token +/// with a typo-corrected keyword. This is only appropriate when the current +/// name must refer to an entity which has already been declared. +/// +/// \param IsAddressOfOperand Must be \c true if the name is preceded by an '&' +/// and might possibly have a dependent nested name specifier. +/// \param CCC Indicates how to perform typo-correction for this name. If NULL, +/// no typo correction will be performed. +Parser::AnnotatedNameKind +Parser::TryAnnotateName(bool IsAddressOfOperand, + CorrectionCandidateCallback *CCC) { + assert(Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope)); + + const bool EnteringContext = false; + const bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); + + CXXScopeSpec SS; + if (getLangOpts().CPlusPlus && + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) + return ANK_Error; + + if (Tok.isNot(tok::identifier) || SS.isInvalid()) { + if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(EnteringContext, false, SS, + !WasScopeAnnotation)) + return ANK_Error; + return ANK_Unresolved; + } + + IdentifierInfo *Name = Tok.getIdentifierInfo(); + SourceLocation NameLoc = Tok.getLocation(); + + // FIXME: Move the tentative declaration logic into ClassifyName so we can + // typo-correct to tentatively-declared identifiers. + if (isTentativelyDeclared(Name)) { + // Identifier has been tentatively declared, and thus cannot be resolved as + // an expression. Fall back to annotating it as a type. + if (TryAnnotateTypeOrScopeTokenAfterScopeSpec(EnteringContext, false, SS, + !WasScopeAnnotation)) + return ANK_Error; + return Tok.is(tok::annot_typename) ? ANK_Success : ANK_TentativeDecl; + } + + Token Next = NextToken(); + + // Look up and classify the identifier. We don't perform any typo-correction + // after a scope specifier, because in general we can't recover from typos + // there (eg, after correcting 'A::tempalte B<X>::C', we would need to jump + // back into scope specifier parsing). + Sema::NameClassification Classification + = Actions.ClassifyName(getCurScope(), SS, Name, NameLoc, Next, + IsAddressOfOperand, SS.isEmpty() ? CCC : 0); + + switch (Classification.getKind()) { + case Sema::NC_Error: + return ANK_Error; + + case Sema::NC_Keyword: + // The identifier was typo-corrected to a keyword. + Tok.setIdentifierInfo(Name); + Tok.setKind(Name->getTokenID()); + PP.TypoCorrectToken(Tok); + if (SS.isNotEmpty()) + AnnotateScopeToken(SS, !WasScopeAnnotation); + // We've "annotated" this as a keyword. + return ANK_Success; + + case Sema::NC_Unknown: + // It's not something we know about. Leave it unannotated. + break; + + case Sema::NC_Type: + Tok.setKind(tok::annot_typename); + setTypeAnnotation(Tok, Classification.getType()); + Tok.setAnnotationEndLoc(NameLoc); + if (SS.isNotEmpty()) + Tok.setLocation(SS.getBeginLoc()); + PP.AnnotateCachedTokens(Tok); + return ANK_Success; + + case Sema::NC_Expression: + Tok.setKind(tok::annot_primary_expr); + setExprAnnotation(Tok, Classification.getExpression()); + Tok.setAnnotationEndLoc(NameLoc); + if (SS.isNotEmpty()) + Tok.setLocation(SS.getBeginLoc()); + PP.AnnotateCachedTokens(Tok); + return ANK_Success; + + case Sema::NC_TypeTemplate: + if (Next.isNot(tok::less)) { + // This may be a type template being used as a template template argument. + if (SS.isNotEmpty()) + AnnotateScopeToken(SS, !WasScopeAnnotation); + return ANK_TemplateName; + } + // Fall through. + case Sema::NC_FunctionTemplate: { + // We have a type or function template followed by '<'. + ConsumeToken(); + UnqualifiedId Id; + Id.setIdentifier(Name, NameLoc); + if (AnnotateTemplateIdToken( + TemplateTy::make(Classification.getTemplateName()), + Classification.getTemplateNameKind(), SS, SourceLocation(), Id)) + return ANK_Error; + return ANK_Success; + } + + case Sema::NC_NestedNameSpecifier: + llvm_unreachable("already parsed nested name specifier"); + } + + // Unable to classify the name, but maybe we can annotate a scope specifier. + if (SS.isNotEmpty()) + AnnotateScopeToken(SS, !WasScopeAnnotation); + return ANK_Unresolved; +} + /// TryAnnotateTypeOrScopeToken - If the current token position is on a /// typename (possibly qualified in C++) or a C++ scope specifier not followed /// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens @@ -1377,8 +1535,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { return true; } - ASTTemplateArgsPtr TemplateArgsPtr(Actions, - TemplateId->getTemplateArgs(), + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); Ty = Actions.ActOnTypenameType(getCurScope(), TypenameLoc, SS, @@ -1404,13 +1561,24 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { } // Remembers whether the token was originally a scope annotation. - bool wasScopeAnnotation = Tok.is(tok::annot_cxxscope); + bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); CXXScopeSpec SS; if (getLangOpts().CPlusPlus) if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) return true; + return TryAnnotateTypeOrScopeTokenAfterScopeSpec(EnteringContext, NeedType, + SS, !WasScopeAnnotation); +} + +/// \brief Try to annotate a type or scope token, having already parsed an +/// optional scope specifier. \p IsNewScope should be \c true unless the scope +/// specifier was extracted from an existing tok::annot_cxxscope annotation. +bool Parser::TryAnnotateTypeOrScopeTokenAfterScopeSpec(bool EnteringContext, + bool NeedType, + CXXScopeSpec &SS, + bool IsNewScope) { if (Tok.is(tok::identifier)) { IdentifierInfo *CorrectedII = 0; // Determine whether the identifier is a type name. @@ -1492,21 +1660,7 @@ bool Parser::TryAnnotateTypeOrScopeToken(bool EnteringContext, bool NeedType) { return false; // A C++ scope specifier that isn't followed by a typename. - // Push the current token back into the token stream (or revert it if it is - // cached) and use an annotation scope token for current token. - if (PP.isBacktrackEnabled()) - PP.RevertCachedTokens(1); - else - PP.EnterToken(Tok); - Tok.setKind(tok::annot_cxxscope); - Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS)); - Tok.setAnnotationRange(SS.getRange()); - - // In case the tokens were cached, have Preprocessor replace them - // with the annotation token. We don't need to do this if we've - // just reverted back to the state we were in before being called. - if (!wasScopeAnnotation) - PP.AnnotateCachedTokens(Tok); + AnnotateScopeToken(SS, IsNewScope); return false; } @@ -1529,19 +1683,7 @@ bool Parser::TryAnnotateCXXScopeToken(bool EnteringContext) { if (SS.isEmpty()) return false; - // Push the current token back into the token stream (or revert it if it is - // cached) and use an annotation scope token for current token. - if (PP.isBacktrackEnabled()) - PP.RevertCachedTokens(1); - else - PP.EnterToken(Tok); - Tok.setKind(tok::annot_cxxscope); - Tok.setAnnotationValue(Actions.SaveNestedNameSpecifierAnnotation(SS)); - Tok.setAnnotationRange(SS.getRange()); - - // In case the tokens were cached, have Preprocessor replace them with the - // annotation token. - PP.AnnotateCachedTokens(Tok); + AnnotateScopeToken(SS, true); return false; } @@ -1798,8 +1940,8 @@ bool BalancedDelimiterTracker::diagnoseMissingClose() { } P.Diag(P.Tok, DID); P.Diag(LOpen, diag::note_matching) << LHSName; - if (P.SkipUntil(Close)) - LClose = P.Tok.getLocation(); + if (P.SkipUntil(Close, /*StopAtSemi*/ true, /*DontConsume*/ true)) + LClose = P.ConsumeAnyToken(); return true; } diff --git a/lib/Parse/RAIIObjectsForParser.h b/lib/Parse/RAIIObjectsForParser.h index 455c4af2ffae..060fd206cd71 100644 --- a/lib/Parse/RAIIObjectsForParser.h +++ b/lib/Parse/RAIIObjectsForParser.h @@ -87,9 +87,8 @@ namespace clang { Sema::ParsingDeclState State; bool Popped; - // Do not implement. - ParsingDeclRAIIObject(const ParsingDeclRAIIObject &other); - ParsingDeclRAIIObject &operator=(const ParsingDeclRAIIObject &other); + ParsingDeclRAIIObject(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION; + void operator=(const ParsingDeclRAIIObject &) LLVM_DELETED_FUNCTION; public: enum NoParent_t { NoParent }; @@ -245,8 +244,9 @@ namespace clang { /// the way they used to be. This is used to handle __extension__ in the /// parser. class ExtensionRAIIObject { - void operator=(const ExtensionRAIIObject &); // DO NOT IMPLEMENT - ExtensionRAIIObject(const ExtensionRAIIObject&); // DO NOT IMPLEMENT + ExtensionRAIIObject(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION; + void operator=(const ExtensionRAIIObject &) LLVM_DELETED_FUNCTION; + DiagnosticsEngine &Diags; public: ExtensionRAIIObject(DiagnosticsEngine &diags) : Diags(diags) { diff --git a/lib/Rewrite/CMakeLists.txt b/lib/Rewrite/CMakeLists.txt index af8f6d4f90dd..d3d75430233f 100644 --- a/lib/Rewrite/CMakeLists.txt +++ b/lib/Rewrite/CMakeLists.txt @@ -1,33 +1,2 @@ -add_clang_library(clangRewrite - DeltaTree.cpp - FixItRewriter.cpp - FrontendActions.cpp - HTMLPrint.cpp - HTMLRewrite.cpp - InclusionRewriter.cpp - RewriteMacros.cpp - RewriteModernObjC.cpp - RewriteObjC.cpp - RewriteRope.cpp - RewriteTest.cpp - Rewriter.cpp - TokenRewriter.cpp - ) - -add_dependencies(clangRewrite - ClangAttrClasses - ClangAttrList - ClangAttrParsedAttrList - ClangCommentNodes - ClangDeclNodes - ClangDiagnosticCommon - ClangDiagnosticFrontend - ClangStmtNodes - ) - -target_link_libraries(clangRewrite - clangBasic - clangAST - clangParse - clangFrontend - ) +add_subdirectory(Core) +add_subdirectory(Frontend) diff --git a/lib/Rewrite/Core/CMakeLists.txt b/lib/Rewrite/Core/CMakeLists.txt new file mode 100644 index 000000000000..07978187ff19 --- /dev/null +++ b/lib/Rewrite/Core/CMakeLists.txt @@ -0,0 +1,24 @@ +add_clang_library(clangRewriteCore + DeltaTree.cpp + HTMLRewrite.cpp + RewriteRope.cpp + Rewriter.cpp + TokenRewriter.cpp + ) + +add_dependencies(clangRewriteCore + ClangAttrClasses + ClangAttrList + ClangAttrParsedAttrList + ClangCommentNodes + ClangDeclNodes + ClangDiagnosticCommon + ClangDiagnosticFrontend + ClangStmtNodes + ) + +target_link_libraries(clangRewriteCore + clangBasic + clangAST + clangParse + ) diff --git a/lib/Rewrite/DeltaTree.cpp b/lib/Rewrite/Core/DeltaTree.cpp index 4297dc8de62f..46922772c5a2 100644 --- a/lib/Rewrite/DeltaTree.cpp +++ b/lib/Rewrite/Core/DeltaTree.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/DeltaTree.h" +#include "clang/Rewrite/Core/DeltaTree.h" #include "clang/Basic/LLVM.h" #include <cstring> #include <cstdio> @@ -113,8 +113,6 @@ namespace { void RecomputeFullDeltaLocally(); void Destroy(); - - //static inline bool classof(const DeltaTreeNode *) { return true; } }; } // end anonymous namespace @@ -149,7 +147,6 @@ namespace { return Children[i]; } - //static inline bool classof(const DeltaTreeInteriorNode *) { return true; } static inline bool classof(const DeltaTreeNode *N) { return !N->isLeaf(); } }; } diff --git a/lib/Rewrite/HTMLRewrite.cpp b/lib/Rewrite/Core/HTMLRewrite.cpp index 236b98fc2828..0e8e4fec9f4a 100644 --- a/lib/Rewrite/HTMLRewrite.cpp +++ b/lib/Rewrite/Core/HTMLRewrite.cpp @@ -13,8 +13,8 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Preprocessor.h" -#include "clang/Rewrite/Rewriter.h" -#include "clang/Rewrite/HTMLRewrite.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Rewrite/Core/HTMLRewrite.h" #include "clang/Lex/TokenConcatenation.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/SourceManager.h" @@ -484,6 +484,7 @@ void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { // Temporarily change the diagnostics object so that we ignore any generated // diagnostics from this pass. DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(), + &PP.getDiagnostics().getDiagnosticOptions(), new IgnoringDiagConsumer); // FIXME: This is a huge hack; we reuse the input preprocessor because we want diff --git a/lib/Rewrite/Core/Makefile b/lib/Rewrite/Core/Makefile new file mode 100644 index 000000000000..8c8d2e478135 --- /dev/null +++ b/lib/Rewrite/Core/Makefile @@ -0,0 +1,18 @@ +##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements code transformation / rewriting facilities. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../../.. +LIBRARYNAME := clangRewriteCore + +include $(CLANG_LEVEL)/Makefile + diff --git a/lib/Rewrite/RewriteRope.cpp b/lib/Rewrite/Core/RewriteRope.cpp index cc8de1b11a18..fe7aa2d6477d 100644 --- a/lib/Rewrite/RewriteRope.cpp +++ b/lib/Rewrite/Core/RewriteRope.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/RewriteRope.h" +#include "clang/Rewrite/Core/RewriteRope.h" #include "clang/Basic/LLVM.h" #include <algorithm> using namespace clang; @@ -117,8 +117,6 @@ namespace { /// guaranteed that there is a split at Offset. void erase(unsigned Offset, unsigned NumBytes); - //static inline bool classof(const RopePieceBTreeNode *) { return true; } - }; } // end anonymous namespace @@ -221,7 +219,6 @@ namespace { /// guaranteed that there is a split at Offset. void erase(unsigned Offset, unsigned NumBytes); - //static inline bool classof(const RopePieceBTreeLeaf *) { return true; } static inline bool classof(const RopePieceBTreeNode *N) { return N->isLeaf(); } @@ -458,7 +455,6 @@ namespace { /// guaranteed that there is a split at Offset. void erase(unsigned Offset, unsigned NumBytes); - //static inline bool classof(const RopePieceBTreeInterior *) { return true; } static inline bool classof(const RopePieceBTreeNode *N) { return !N->isLeaf(); } diff --git a/lib/Rewrite/Rewriter.cpp b/lib/Rewrite/Core/Rewriter.cpp index 7c27114f1cfd..4df967f39bc0 100644 --- a/lib/Rewrite/Rewriter.cpp +++ b/lib/Rewrite/Core/Rewriter.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/Rewriter.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "clang/AST/Stmt.h" #include "clang/AST/Decl.h" #include "clang/Basic/DiagnosticIDs.h" diff --git a/lib/Rewrite/TokenRewriter.cpp b/lib/Rewrite/Core/TokenRewriter.cpp index 03ce63ea1174..940ece2f9e03 100644 --- a/lib/Rewrite/TokenRewriter.cpp +++ b/lib/Rewrite/Core/TokenRewriter.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/TokenRewriter.h" +#include "clang/Rewrite/Core/TokenRewriter.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/ScratchBuffer.h" #include "clang/Basic/SourceManager.h" diff --git a/lib/Rewrite/Frontend/CMakeLists.txt b/lib/Rewrite/Frontend/CMakeLists.txt new file mode 100644 index 000000000000..9017e479ab77 --- /dev/null +++ b/lib/Rewrite/Frontend/CMakeLists.txt @@ -0,0 +1,28 @@ +add_clang_library(clangRewriteFrontend + FixItRewriter.cpp + FrontendActions.cpp + HTMLPrint.cpp + InclusionRewriter.cpp + RewriteMacros.cpp + RewriteModernObjC.cpp + RewriteObjC.cpp + RewriteTest.cpp + ) + +add_dependencies(clangRewriteFrontend + ClangAttrClasses + ClangAttrList + ClangAttrParsedAttrList + ClangCommentNodes + ClangDeclNodes + ClangDiagnosticCommon + ClangDiagnosticFrontend + ClangStmtNodes + ) + +target_link_libraries(clangRewriteFrontend + clangBasic + clangAST + clangParse + clangFrontend + ) diff --git a/lib/Rewrite/FixItRewriter.cpp b/lib/Rewrite/Frontend/FixItRewriter.cpp index 3863adb4f162..43a1ab1ac100 100644 --- a/lib/Rewrite/FixItRewriter.cpp +++ b/lib/Rewrite/Frontend/FixItRewriter.cpp @@ -13,7 +13,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/FixItRewriter.h" +#include "clang/Rewrite/Frontend/FixItRewriter.h" #include "clang/Edit/Commit.h" #include "clang/Edit/EditsReceiver.h" #include "clang/Basic/FileManager.h" diff --git a/lib/Rewrite/FrontendActions.cpp b/lib/Rewrite/Frontend/FrontendActions.cpp index 9bc218e994fe..7d29b6d4219d 100644 --- a/lib/Rewrite/FrontendActions.cpp +++ b/lib/Rewrite/Frontend/FrontendActions.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/FrontendActions.h" +#include "clang/Rewrite/Frontend/FrontendActions.h" #include "clang/AST/ASTConsumer.h" #include "clang/Lex/Preprocessor.h" #include "clang/Parse/Parser.h" @@ -16,9 +16,9 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/Utils.h" -#include "clang/Rewrite/ASTConsumers.h" -#include "clang/Rewrite/FixItRewriter.h" -#include "clang/Rewrite/Rewriters.h" +#include "clang/Rewrite/Frontend/ASTConsumers.h" +#include "clang/Rewrite/Frontend/FixItRewriter.h" +#include "clang/Rewrite/Frontend/Rewriters.h" #include "llvm/ADT/OwningPtr.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" diff --git a/lib/Rewrite/HTMLPrint.cpp b/lib/Rewrite/Frontend/HTMLPrint.cpp index 3d190abffcf8..79e44470ada5 100644 --- a/lib/Rewrite/HTMLPrint.cpp +++ b/lib/Rewrite/Frontend/HTMLPrint.cpp @@ -11,7 +11,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/ASTConsumers.h" +#include "clang/Rewrite/Frontend/ASTConsumers.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" @@ -19,8 +19,8 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" -#include "clang/Rewrite/HTMLRewrite.h" -#include "clang/Rewrite/Rewriter.h" +#include "clang/Rewrite/Core/HTMLRewrite.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" using namespace clang; diff --git a/lib/Rewrite/InclusionRewriter.cpp b/lib/Rewrite/Frontend/InclusionRewriter.cpp index 3dfc3b008987..9d1bec957d6d 100644 --- a/lib/Rewrite/InclusionRewriter.cpp +++ b/lib/Rewrite/Frontend/InclusionRewriter.cpp @@ -12,7 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/Rewriters.h" +#include "clang/Rewrite/Frontend/Rewriters.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/PreprocessorOutputOptions.h" @@ -57,10 +57,11 @@ private: const Token &IncludeTok, StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, - SourceLocation EndLoc, StringRef SearchPath, - StringRef RelativePath); + StringRef RelativePath, + const Module *Imported); void WriteLineInfo(const char *Filename, int Line, SrcMgr::CharacteristicKind FileType, StringRef EOL, StringRef Extra = StringRef()); @@ -152,10 +153,11 @@ void InclusionRewriter::InclusionDirective(SourceLocation HashLoc, const Token &/*IncludeTok*/, StringRef /*FileName*/, bool /*IsAngled*/, + CharSourceRange /*FilenameRange*/, const FileEntry * /*File*/, - SourceLocation /*EndLoc*/, StringRef /*SearchPath*/, - StringRef /*RelativePath*/) { + StringRef /*RelativePath*/, + const Module * /*Imported*/) { assert(LastInsertedFileChange == FileChanges.end() && "Another inclusion " "directive was found before the previous one was processed"); std::pair<FileChangeMap::iterator, bool> p = FileChanges.insert( diff --git a/lib/Rewrite/Frontend/Makefile b/lib/Rewrite/Frontend/Makefile new file mode 100644 index 000000000000..ac97d4074ecb --- /dev/null +++ b/lib/Rewrite/Frontend/Makefile @@ -0,0 +1,18 @@ +##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## +# +# This implements code transformation / rewriting facilities. +# +##===----------------------------------------------------------------------===## + +CLANG_LEVEL := ../../.. +LIBRARYNAME := clangRewriteFrontend + +include $(CLANG_LEVEL)/Makefile + diff --git a/lib/Rewrite/RewriteMacros.cpp b/lib/Rewrite/Frontend/RewriteMacros.cpp index 3fa0bdb74534..f399dd5d7ce9 100644 --- a/lib/Rewrite/RewriteMacros.cpp +++ b/lib/Rewrite/Frontend/RewriteMacros.cpp @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/Rewriters.h" -#include "clang/Rewrite/Rewriter.h" +#include "clang/Rewrite/Frontend/Rewriters.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" diff --git a/lib/Rewrite/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp index dcd003f50160..4b56b3720a3f 100644 --- a/lib/Rewrite/RewriteModernObjC.cpp +++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/ASTConsumers.h" -#include "clang/Rewrite/Rewriter.h" +#include "clang/Rewrite/Frontend/ASTConsumers.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ParentMap.h" @@ -278,6 +278,9 @@ namespace { // Syntactic Rewriting. void RewriteRecordBody(RecordDecl *RD); void RewriteInclude(); + void RewriteLineDirective(const Decl *D); + void ConvertSourceLocationToLineDirective(SourceLocation Loc, + std::string &LineString); void RewriteForwardClassDecl(DeclGroupRef D); void RewriteForwardClassDecl(const llvm::SmallVector<Decl*, 8> &DG); void RewriteForwardClassEpilogue(ObjCInterfaceDecl *ClassDecl, @@ -1602,6 +1605,19 @@ Stmt *RewriteModernObjC::RewriteBreakStmt(BreakStmt *S) { return 0; } +void RewriteModernObjC::ConvertSourceLocationToLineDirective( + SourceLocation Loc, + std::string &LineString) { + if (Loc.isFileID()) { + LineString += "\n#line "; + PresumedLoc PLoc = SM->getPresumedLoc(Loc); + LineString += utostr(PLoc.getLine()); + LineString += " \""; + LineString += Lexer::Stringify(PLoc.getFilename()); + LineString += "\"\n"; + } +} + /// RewriteContinueStmt - Rewrite for a continue-stmt inside an ObjC2's foreach /// statement to continue with its inner synthesized loop. /// @@ -1664,7 +1680,10 @@ Stmt *RewriteModernObjC::RewriteObjCForCollectionStmt(ObjCForCollectionStmt *S, StringRef elementName; std::string elementTypeAsString; std::string buf; - buf = "\n{\n\t"; + // line directive first. + SourceLocation ForEachLoc = S->getForLoc(); + ConvertSourceLocationToLineDirective(ForEachLoc, buf); + buf += "{\n\t"; if (DeclStmt *DS = dyn_cast<DeclStmt>(S->getElement())) { // type elem; NamedDecl* D = cast<NamedDecl>(DS->getSingleDecl()); @@ -1836,7 +1855,9 @@ Stmt *RewriteModernObjC::RewriteObjCSynchronizedStmt(ObjCAtSynchronizedStmt *S) assert((*startBuf == '@') && "bogus @synchronized location"); std::string buf; - buf = "{ id _rethrow = 0; id _sync_obj = "; + SourceLocation SynchLoc = S->getAtSynchronizedLoc(); + ConvertSourceLocationToLineDirective(SynchLoc, buf); + buf += "{ id _rethrow = 0; id _sync_obj = "; const char *lparenBuf = startBuf; while (*lparenBuf != '(') lparenBuf++; @@ -1902,12 +1923,14 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { ObjCAtFinallyStmt *finalStmt = S->getFinallyStmt(); bool noCatch = S->getNumCatchStmts() == 0; std::string buf; + SourceLocation TryLocation = S->getAtTryLoc(); + ConvertSourceLocationToLineDirective(TryLocation, buf); if (finalStmt) { if (noCatch) - buf = "{ id volatile _rethrow = 0;\n"; + buf += "{ id volatile _rethrow = 0;\n"; else { - buf = "{ id volatile _rethrow = 0;\ntry {\n"; + buf += "{ id volatile _rethrow = 0;\ntry {\n"; } } // Get the start location and compute the semi location. @@ -1934,13 +1957,15 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { ObjCInterfaceDecl *IDecl = Ptr->getObjectType()->getInterface(); if (IDecl) { std::string Result; + ConvertSourceLocationToLineDirective(Catch->getLocStart(), Result); + startBuf = SM->getCharacterData(startLoc); assert((*startBuf == '@') && "bogus @catch location"); SourceLocation rParenLoc = Catch->getRParenLoc(); const char *rParenBuf = SM->getCharacterData(rParenLoc); // _objc_exc_Foo *_e as argument to catch. - Result = "catch (_objc_exc_"; Result += IDecl->getNameAsString(); + Result += "catch (_objc_exc_"; Result += IDecl->getNameAsString(); Result += " *_"; Result += catchDecl->getNameAsString(); Result += ")"; ReplaceText(startLoc, rParenBuf-startBuf+1, Result); @@ -1966,11 +1991,18 @@ Stmt *RewriteModernObjC::RewriteObjCTryStmt(ObjCAtTryStmt *S) { } if (finalStmt) { buf.clear(); - if (noCatch) - buf = "catch (id e) {_rethrow = e;}\n"; - else - buf = "}\ncatch (id e) {_rethrow = e;}\n"; - + SourceLocation FinallyLoc = finalStmt->getLocStart(); + + if (noCatch) { + ConvertSourceLocationToLineDirective(FinallyLoc, buf); + buf += "catch (id e) {_rethrow = e;}\n"; + } + else { + buf += "}\n"; + ConvertSourceLocationToLineDirective(FinallyLoc, buf); + buf += "catch (id e) {_rethrow = e;}\n"; + } + SourceLocation startFinalLoc = finalStmt->getLocStart(); ReplaceText(startFinalLoc, 8, buf); Stmt *body = finalStmt->getFinallyBody(); @@ -2070,7 +2102,7 @@ CallExpr *RewriteModernObjC::SynthesizeCallToFunctionDecl( const FunctionType *FT = msgSendType->getAs<FunctionType>(); CallExpr *Exp = - new (Context) CallExpr(*Context, ICE, args, nargs, + new (Context) CallExpr(*Context, ICE, llvm::makeArrayRef(args, nargs), FT->getCallResultType(*Context), VK_RValue, EndLoc); return Exp; @@ -2675,8 +2707,7 @@ Stmt *RewriteModernObjC::RewriteObjCBoxedExpr(ObjCBoxedExpr *Exp) { ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), + CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs, FT->getResultType(), VK_RValue, EndLoc); ReplaceStmt(Exp, CE); @@ -2718,7 +2749,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) { for (unsigned i = 0; i < NumElements; i++) InitExprs.push_back(Exp->getElement(i)); Expr *NSArrayCallExpr = - new (Context) CallExpr(*Context, NSArrayDRE, &InitExprs[0], InitExprs.size(), + new (Context) CallExpr(*Context, NSArrayDRE, InitExprs, NSArrayFType, VK_LValue, SourceLocation()); FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(), @@ -2814,8 +2845,7 @@ Stmt *RewriteModernObjC::RewriteObjCArrayLiteralExpr(ObjCArrayLiteral *Exp) { ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), + CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs, FT->getResultType(), VK_RValue, EndLoc); ReplaceStmt(Exp, CE); @@ -2865,7 +2895,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral // (const id [])objects Expr *NSValueCallExpr = - new (Context) CallExpr(*Context, NSDictDRE, &ValueExprs[0], ValueExprs.size(), + new (Context) CallExpr(*Context, NSDictDRE, ValueExprs, NSDictFType, VK_LValue, SourceLocation()); FieldDecl *ARRFD = FieldDecl::Create(*Context, 0, SourceLocation(), @@ -2887,7 +2917,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral DictLiteralValueME); // (const id <NSCopying> [])keys Expr *NSKeyCallExpr = - new (Context) CallExpr(*Context, NSDictDRE, &KeyExprs[0], KeyExprs.size(), + new (Context) CallExpr(*Context, NSDictDRE, KeyExprs, NSDictFType, VK_LValue, SourceLocation()); MemberExpr *DictLiteralKeyME = @@ -2989,8 +3019,7 @@ Stmt *RewriteModernObjC::RewriteObjCDictionaryLiteralExpr(ObjCDictionaryLiteral ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), + CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs, FT->getResultType(), VK_RValue, EndLoc); ReplaceStmt(Exp, CE); @@ -3078,6 +3107,34 @@ static SourceLocation getFunctionSourceLocation (RewriteModernObjC &R, return FD->getTypeSpecStartLoc(); } +void RewriteModernObjC::RewriteLineDirective(const Decl *D) { + + SourceLocation Location = D->getLocation(); + + if (Location.isFileID()) { + std::string LineString("\n#line "); + PresumedLoc PLoc = SM->getPresumedLoc(Location); + LineString += utostr(PLoc.getLine()); + LineString += " \""; + LineString += Lexer::Stringify(PLoc.getFilename()); + if (isa<ObjCMethodDecl>(D)) + LineString += "\""; + else LineString += "\"\n"; + + Location = D->getLocStart(); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isExternC() && !FD->isMain()) { + const DeclContext *DC = FD->getDeclContext(); + if (const LinkageSpecDecl *LSD = dyn_cast<LinkageSpecDecl>(DC)) + // if it is extern "C" {...}, return function decl's own location. + if (!LSD->getRBraceLoc().isValid()) + Location = LSD->getExternLoc(); + } + } + InsertText(Location, LineString); + } +} + /// SynthMsgSendStretCallExpr - This routine translates message expression /// into a call to objc_msgSend_stret() entry point. Tricky part is that /// nil check on receiver must be performed before calling objc_msgSend_stret. @@ -3140,7 +3197,14 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla str += "\t"; str += returnType.getAsString(Context->getPrintingPolicy()); str += " s;\n"; str += "};\n\n"; - SourceLocation FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef); + SourceLocation FunLocStart; + if (CurFunctionDef) + FunLocStart = getFunctionSourceLocation(*this, CurFunctionDef); + else { + assert(CurMethodDef && "SynthMsgSendStretCallExpr - CurMethodDef is null"); + FunLocStart = CurMethodDef->getLocStart(); + } + InsertText(FunLocStart, str); ++stretCount; @@ -3151,7 +3215,7 @@ Expr *RewriteModernObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFla SC_None, false, false); DeclRefExpr *DRE = new (Context) DeclRefExpr(FD, false, castType, VK_RValue, SourceLocation()); - CallExpr *STCE = new (Context) CallExpr(*Context, DRE, &MsgExprs[0], MsgExprs.size(), + CallExpr *STCE = new (Context) CallExpr(*Context, DRE, MsgExprs, castType, VK_LValue, SourceLocation()); FieldDecl *FieldD = FieldDecl::Create(*Context, 0, SourceLocation(), @@ -3260,8 +3324,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, false, superType, VK_LValue, SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], - InitExprs.size(), + SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, superType, VK_LValue, SourceLocation()); // The code for super is a little tricky to prevent collision with @@ -3280,8 +3343,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } else { // (struct __rw_objc_super) { <exprs from above> } InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), - &InitExprs[0], InitExprs.size(), + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, SourceLocation()); TypeSourceInfo *superTInfo = Context->getTrivialTypeSourceInfo(superType); @@ -3370,8 +3432,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, false, superType, VK_LValue, SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], - InitExprs.size(), + SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, superType, VK_LValue, SourceLocation()); // The code for super is a little tricky to prevent collision with // the structure definition in the header. The rewriter has it's own @@ -3389,8 +3450,7 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } else { // (struct __rw_objc_super) { <exprs from above> } InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), - &InitExprs[0], InitExprs.size(), + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, SourceLocation()); TypeSourceInfo *superTInfo = Context->getTrivialTypeSourceInfo(superType); @@ -3544,10 +3604,8 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), - FT->getResultType(), VK_RValue, - EndLoc); + CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs, + FT->getResultType(), VK_RValue, EndLoc); Stmt *ReplacingStmt = CE; if (MsgSendStretFlavor) { // We have the method which returns a struct/union. Must also generate @@ -3578,7 +3636,8 @@ Stmt *RewriteModernObjC::SynthMessageExpr(ObjCMessageExpr *Exp, SourceLocation()); BinaryOperator *lessThanExpr = new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy, - VK_RValue, OK_Ordinary, SourceLocation()); + VK_RValue, OK_Ordinary, SourceLocation(), + false); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) ConditionalOperator *CondExpr = new (Context) ConditionalOperator(lessThanExpr, @@ -3968,8 +4027,12 @@ std::string RewriteModernObjC::SynthesizeBlockFunc(BlockExpr *CE, int i, const FunctionType *AFT = CE->getFunctionType(); QualType RT = AFT->getResultType(); std::string StructRef = "struct " + Tag; - std::string S = "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" + - funcName.str() + "_block_func_" + utostr(i); + SourceLocation BlockLoc = CE->getExprLoc(); + std::string S; + ConvertSourceLocationToLineDirective(BlockLoc, S); + + S += "static " + RT.getAsString(Context->getPrintingPolicy()) + " __" + + funcName.str() + "_block_func_" + utostr(i); BlockDecl *BD = CE->getBlockDecl(); @@ -4585,8 +4648,7 @@ Stmt *RewriteModernObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp E = Exp->arg_end(); I != E; ++I) { BlkExprs.push_back(*I); } - CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0], - BlkExprs.size(), + CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs, Exp->getType(), VK_RValue, SourceLocation()); return CE; @@ -4869,7 +4931,7 @@ void RewriteModernObjC::RewriteBlockPointerDecl(NamedDecl *ND) { else if (*argListBegin == '<') { buf += "/*"; buf += *argListBegin++; - OrigLength++;; + OrigLength++; while (*argListBegin != '>') { buf += *argListBegin++; OrigLength++; @@ -5347,7 +5409,7 @@ Stmt *RewriteModernObjC::SynthBlockInitExpr(BlockExpr *Exp, Context->IntTy, SourceLocation()); InitExprs.push_back(FlagExp); } - NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(), + NewRep = new (Context) CallExpr(*Context, DRE, InitExprs, FType, VK_LValue, SourceLocation()); if (GlobalBlockExpr) { @@ -5666,6 +5728,7 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) { // This synthesizes and inserts the block "impl" struct, invoke function, // and any copy/dispose helper functions. InsertBlockLiteralsWithinFunction(FD); + RewriteLineDirective(D); CurFunctionDef = 0; } break; @@ -5684,6 +5747,7 @@ void RewriteModernObjC::HandleDeclInMainFile(Decl *D) { PropParentMap = 0; } InsertBlockLiteralsWithinMethod(MD); + RewriteLineDirective(D); CurMethodDef = 0; } break; @@ -5894,8 +5958,8 @@ void RewriteModernObjC::Initialize(ASTContext &context) { Preamble += "(const char *);\n"; Preamble += "__OBJC_RW_DLLIMPORT void objc_exception_throw( struct objc_object *);\n"; // @synchronized hooks. - Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter( struct objc_object *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit( struct objc_object *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_enter( struct objc_object *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_exit( struct objc_object *);\n"; Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n"; Preamble += "#ifndef __FASTENUMERATIONSTATE\n"; Preamble += "struct __objcFastEnumerationState {\n\t"; @@ -7476,7 +7540,7 @@ Stmt *RewriteModernObjC::RewriteObjCIvarRefExpr(ObjCIvarRefExpr *IV) { BinaryOperator *addExpr = new (Context) BinaryOperator(castExpr, DRE, BO_Add, Context->getPointerType(Context->CharTy), - VK_RValue, OK_Ordinary, SourceLocation()); + VK_RValue, OK_Ordinary, SourceLocation(), false); // Don't forget the parens to enforce the proper binding. ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), diff --git a/lib/Rewrite/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp index 37c17e63db94..a6dcc6b8d804 100644 --- a/lib/Rewrite/RewriteObjC.cpp +++ b/lib/Rewrite/Frontend/RewriteObjC.cpp @@ -11,8 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/ASTConsumers.h" -#include "clang/Rewrite/Rewriter.h" +#include "clang/Rewrite/Frontend/ASTConsumers.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ParentMap.h" @@ -2059,7 +2059,7 @@ CallExpr *RewriteObjC::SynthesizeCallToFunctionDecl( const FunctionType *FT = msgSendType->getAs<FunctionType>(); CallExpr *Exp = - new (Context) CallExpr(*Context, ICE, args, nargs, + new (Context) CallExpr(*Context, ICE, llvm::makeArrayRef(args, nargs), FT->getCallResultType(*Context), VK_RValue, EndLoc); return Exp; @@ -2661,8 +2661,7 @@ CallExpr *RewriteObjC::SynthMsgSendStretCallExpr(FunctionDecl *MsgSendStretFlavo ParenExpr *PE = new (Context) ParenExpr(SourceLocation(), SourceLocation(), cast); const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *STCE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), + CallExpr *STCE = new (Context) CallExpr(*Context, PE, MsgExprs, FT->getResultType(), VK_RValue, SourceLocation()); return STCE; @@ -2766,8 +2765,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, false, superType, VK_LValue, SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], - InitExprs.size(), + SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, superType, VK_LValue, SourceLocation()); // The code for super is a little tricky to prevent collision with @@ -2786,8 +2784,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } else { // (struct objc_super) { <exprs from above> } InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), - &InitExprs[0], InitExprs.size(), + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, SourceLocation()); TypeSourceInfo *superTInfo = Context->getTrivialTypeSourceInfo(superType); @@ -2876,8 +2873,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, DeclRefExpr *DRE = new (Context) DeclRefExpr(SuperContructorFunctionDecl, false, superType, VK_LValue, SourceLocation()); - SuperRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], - InitExprs.size(), + SuperRep = new (Context) CallExpr(*Context, DRE, InitExprs, superType, VK_LValue, SourceLocation()); // The code for super is a little tricky to prevent collision with // the structure definition in the header. The rewriter has it's own @@ -2895,8 +2891,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, } else { // (struct objc_super) { <exprs from above> } InitListExpr *ILE = - new (Context) InitListExpr(*Context, SourceLocation(), - &InitExprs[0], InitExprs.size(), + new (Context) InitListExpr(*Context, SourceLocation(), InitExprs, SourceLocation()); TypeSourceInfo *superTInfo = Context->getTrivialTypeSourceInfo(superType); @@ -3050,8 +3045,7 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, ParenExpr *PE = new (Context) ParenExpr(StartLoc, EndLoc, cast); const FunctionType *FT = msgSendType->getAs<FunctionType>(); - CallExpr *CE = new (Context) CallExpr(*Context, PE, &MsgExprs[0], - MsgExprs.size(), + CallExpr *CE = new (Context) CallExpr(*Context, PE, MsgExprs, FT->getResultType(), VK_RValue, EndLoc); Stmt *ReplacingStmt = CE; @@ -3084,7 +3078,8 @@ Stmt *RewriteObjC::SynthMessageExpr(ObjCMessageExpr *Exp, SourceLocation()); BinaryOperator *lessThanExpr = new (Context) BinaryOperator(sizeofExpr, limit, BO_LE, Context->IntTy, - VK_RValue, OK_Ordinary, SourceLocation()); + VK_RValue, OK_Ordinary, SourceLocation(), + false); // (sizeof(returnType) <= 8 ? objc_msgSend(...) : objc_msgSend_stret(...)) ConditionalOperator *CondExpr = new (Context) ConditionalOperator(lessThanExpr, @@ -3923,8 +3918,7 @@ Stmt *RewriteObjC::SynthesizeBlockCall(CallExpr *Exp, const Expr *BlockExp) { E = Exp->arg_end(); I != E; ++I) { BlkExprs.push_back(*I); } - CallExpr *CE = new (Context) CallExpr(*Context, PE, &BlkExprs[0], - BlkExprs.size(), + CallExpr *CE = new (Context) CallExpr(*Context, PE, BlkExprs, Exp->getType(), VK_RValue, SourceLocation()); return CE; @@ -4190,7 +4184,7 @@ void RewriteObjC::RewriteBlockPointerDecl(NamedDecl *ND) { else if (*argListBegin == '<') { buf += "/*"; buf += *argListBegin++; - OrigLength++;; + OrigLength++; while (*argListBegin != '>') { buf += *argListBegin++; OrigLength++; @@ -4651,7 +4645,7 @@ Stmt *RewriteObjC::SynthBlockInitExpr(BlockExpr *Exp, Context->IntTy, SourceLocation()); InitExprs.push_back(FlagExp); } - NewRep = new (Context) CallExpr(*Context, DRE, &InitExprs[0], InitExprs.size(), + NewRep = new (Context) CallExpr(*Context, DRE, InitExprs, FType, VK_LValue, SourceLocation()); NewRep = new (Context) UnaryOperator(NewRep, UO_AddrOf, Context->getPointerType(NewRep->getType()), @@ -5119,8 +5113,8 @@ void RewriteObjCFragileABI::Initialize(ASTContext &context) { Preamble += "__OBJC_RW_DLLIMPORT int objc_exception_match"; Preamble += "(struct objc_class *, struct objc_object *);\n"; // @synchronized hooks. - Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_enter(struct objc_object *);\n"; - Preamble += "__OBJC_RW_DLLIMPORT void objc_sync_exit(struct objc_object *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_enter(struct objc_object *);\n"; + Preamble += "__OBJC_RW_DLLIMPORT int objc_sync_exit(struct objc_object *);\n"; Preamble += "__OBJC_RW_DLLIMPORT Protocol *objc_getProtocol(const char *);\n"; Preamble += "#ifndef __FASTENUMERATIONSTATE\n"; Preamble += "struct __objcFastEnumerationState {\n\t"; diff --git a/lib/Rewrite/RewriteTest.cpp b/lib/Rewrite/Frontend/RewriteTest.cpp index 019e5e73120d..722c5e80b443 100644 --- a/lib/Rewrite/RewriteTest.cpp +++ b/lib/Rewrite/Frontend/RewriteTest.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Rewrite/Rewriters.h" +#include "clang/Rewrite/Frontend/Rewriters.h" #include "clang/Lex/Preprocessor.h" -#include "clang/Rewrite/TokenRewriter.h" +#include "clang/Rewrite/Core/TokenRewriter.h" #include "llvm/Support/raw_ostream.h" void clang::DoRewriteTest(Preprocessor &PP, raw_ostream* OS) { diff --git a/lib/Rewrite/Makefile b/lib/Rewrite/Makefile index 5fef9b2c0d38..0be84d406405 100644 --- a/lib/Rewrite/Makefile +++ b/lib/Rewrite/Makefile @@ -1,4 +1,4 @@ -##===- clang/lib/Rewrite/Makefile --------------------------*- Makefile -*-===## +##===- clang/lib/StaticAnalyzer/Makefile -------------------*- Makefile -*-===## # # The LLVM Compiler Infrastructure # @@ -6,13 +6,9 @@ # License. See LICENSE.TXT for details. # ##===----------------------------------------------------------------------===## -# -# This implements code transformation / rewriting facilities. -# -##===----------------------------------------------------------------------===## CLANG_LEVEL := ../.. -LIBRARYNAME := clangRewrite +DIRS := Frontend +PARALLEL_DIRS := Core include $(CLANG_LEVEL)/Makefile - diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 19a7d6f35c8f..801a1b1e0264 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -27,6 +27,7 @@ #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/AST/ParentMap.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Analysis/AnalysisContext.h" @@ -36,10 +37,12 @@ #include "clang/Analysis/Analyses/ThreadSafety.h" #include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/Analyses/UninitializedValues.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" @@ -182,13 +185,6 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { HasFakeEdge = true; continue; } - if (const AsmStmt *AS = dyn_cast<AsmStmt>(S)) { - if (AS->isMSAsm()) { - HasFakeEdge = true; - HasLiveReturn = true; - continue; - } - } if (isa<MSAsmStmt>(S)) { // TODO: Verify this is correct. HasFakeEdge = true; @@ -506,7 +502,7 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, // Information used when building the diagnostic. unsigned DiagKind; - const char *Str; + StringRef Str; SourceRange Range; // FixIts to suppress the diagnosic by removing the dead condition. @@ -822,6 +818,18 @@ namespace { static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, bool PerFunction) { + // Only perform this analysis when using C++11. There is no good workflow + // for this warning when not using C++11. There is no good way to silence + // the warning (no attribute is available) unless we are using C++11's support + // for generalized attributes. Once could use pragmas to silence the warning, + // but as a general solution that is gross and not in the spirit of this + // warning. + // + // NOTE: This an intermediate solution. There are on-going discussions on + // how to properly support this warning outside of C++11 with an annotation. + if (!AC.getASTContext().getLangOpts().CPlusPlus0x) + return; + FallthroughMapper FM(S); FM.TraverseStmt(AC.getBody()); @@ -859,8 +867,21 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, if (S.getLangOpts().CPlusPlus0x) { const Stmt *Term = B.getTerminator(); if (!(B.empty() && Term && isa<BreakStmt>(Term))) { + Preprocessor &PP = S.getPreprocessor(); + TokenValue Tokens[] = { + tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), + tok::coloncolon, PP.getIdentifierInfo("fallthrough"), + tok::r_square, tok::r_square + }; + StringRef AnnotationSpelling = "[[clang::fallthrough]]"; + StringRef MacroName = PP.getLastMacroWithSpelling(L, Tokens); + if (!MacroName.empty()) + AnnotationSpelling = MacroName; + SmallString<64> TextToInsert(AnnotationSpelling); + TextToInsert += "; "; S.Diag(L, diag::note_insert_fallthrough_fixit) << - FixItHint::CreateInsertion(L, "[[clang::fallthrough]]; "); + AnnotationSpelling << + FixItHint::CreateInsertion(L, TextToInsert); } } S.Diag(L, diag::note_insert_break_fixit) << @@ -878,6 +899,199 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, } namespace { +typedef std::pair<const Stmt *, + sema::FunctionScopeInfo::WeakObjectUseMap::const_iterator> + StmtUsesPair; + +class StmtUseSorter { + const SourceManager &SM; + +public: + explicit StmtUseSorter(const SourceManager &SM) : SM(SM) { } + + bool operator()(const StmtUsesPair &LHS, const StmtUsesPair &RHS) { + return SM.isBeforeInTranslationUnit(LHS.first->getLocStart(), + RHS.first->getLocStart()); + } +}; +} + +static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, + const Stmt *S) { + assert(S); + + do { + switch (S->getStmtClass()) { + case Stmt::ForStmtClass: + case Stmt::WhileStmtClass: + case Stmt::CXXForRangeStmtClass: + case Stmt::ObjCForCollectionStmtClass: + return true; + case Stmt::DoStmtClass: { + const Expr *Cond = cast<DoStmt>(S)->getCond(); + llvm::APSInt Val; + if (!Cond->EvaluateAsInt(Val, Ctx)) + return true; + return Val.getBoolValue(); + } + default: + break; + } + } while ((S = PM.getParent(S))); + + return false; +} + + +static void diagnoseRepeatedUseOfWeak(Sema &S, + const sema::FunctionScopeInfo *CurFn, + const Decl *D, + const ParentMap &PM) { + typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy; + typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap; + typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector; + + ASTContext &Ctx = S.getASTContext(); + + const WeakObjectUseMap &WeakMap = CurFn->getWeakObjectUses(); + + // Extract all weak objects that are referenced more than once. + SmallVector<StmtUsesPair, 8> UsesByStmt; + for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end(); + I != E; ++I) { + const WeakUseVector &Uses = I->second; + + // Find the first read of the weak object. + WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end(); + for ( ; UI != UE; ++UI) { + if (UI->isUnsafe()) + break; + } + + // If there were only writes to this object, don't warn. + if (UI == UE) + continue; + + // If there was only one read, followed by any number of writes, and the + // read is not within a loop, don't warn. Additionally, don't warn in a + // loop if the base object is a local variable -- local variables are often + // changed in loops. + if (UI == Uses.begin()) { + WeakUseVector::const_iterator UI2 = UI; + for (++UI2; UI2 != UE; ++UI2) + if (UI2->isUnsafe()) + break; + + if (UI2 == UE) { + if (!isInLoop(Ctx, PM, UI->getUseExpr())) + continue; + + const WeakObjectProfileTy &Profile = I->first; + if (!Profile.isExactProfile()) + continue; + + const NamedDecl *Base = Profile.getBase(); + if (!Base) + Base = Profile.getProperty(); + assert(Base && "A profile always has a base or property."); + + if (const VarDecl *BaseVar = dyn_cast<VarDecl>(Base)) + if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(Base)) + continue; + } + } + + UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I)); + } + + if (UsesByStmt.empty()) + return; + + // Sort by first use so that we emit the warnings in a deterministic order. + std::sort(UsesByStmt.begin(), UsesByStmt.end(), + StmtUseSorter(S.getSourceManager())); + + // Classify the current code body for better warning text. + // This enum should stay in sync with the cases in + // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. + // FIXME: Should we use a common classification enum and the same set of + // possibilities all throughout Sema? + enum { + Function, + Method, + Block, + Lambda + } FunctionKind; + + if (isa<sema::BlockScopeInfo>(CurFn)) + FunctionKind = Block; + else if (isa<sema::LambdaScopeInfo>(CurFn)) + FunctionKind = Lambda; + else if (isa<ObjCMethodDecl>(D)) + FunctionKind = Method; + else + FunctionKind = Function; + + // Iterate through the sorted problems and emit warnings for each. + for (SmallVectorImpl<StmtUsesPair>::const_iterator I = UsesByStmt.begin(), + E = UsesByStmt.end(); + I != E; ++I) { + const Stmt *FirstRead = I->first; + const WeakObjectProfileTy &Key = I->second->first; + const WeakUseVector &Uses = I->second->second; + + // For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy + // may not contain enough information to determine that these are different + // properties. We can only be 100% sure of a repeated use in certain cases, + // and we adjust the diagnostic kind accordingly so that the less certain + // case can be turned off if it is too noisy. + unsigned DiagKind; + if (Key.isExactProfile()) + DiagKind = diag::warn_arc_repeated_use_of_weak; + else + DiagKind = diag::warn_arc_possible_repeated_use_of_weak; + + // Classify the weak object being accessed for better warning text. + // This enum should stay in sync with the cases in + // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. + enum { + Variable, + Property, + ImplicitProperty, + Ivar + } ObjectKind; + + const NamedDecl *D = Key.getProperty(); + if (isa<VarDecl>(D)) + ObjectKind = Variable; + else if (isa<ObjCPropertyDecl>(D)) + ObjectKind = Property; + else if (isa<ObjCMethodDecl>(D)) + ObjectKind = ImplicitProperty; + else if (isa<ObjCIvarDecl>(D)) + ObjectKind = Ivar; + else + llvm_unreachable("Unexpected weak object kind!"); + + // Show the first time the object was read. + S.Diag(FirstRead->getLocStart(), DiagKind) + << ObjectKind << D << FunctionKind + << FirstRead->getSourceRange(); + + // Print all the other accesses as notes. + for (WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end(); + UI != UE; ++UI) { + if (UI->getUseExpr() == FirstRead) + continue; + S.Diag(UI->getUseExpr()->getLocStart(), + diag::note_arc_weak_also_accessed_here) + << UI->getUseExpr()->getSourceRange(); + } + } +} + + +namespace { struct SLocSort { bool operator()(const UninitUse &a, const UninitUse &b) { // Prefer a more confident report over a less confident one. @@ -1091,27 +1305,47 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { diag::warn_variable_requires_any_lock: diag::warn_var_deref_requires_any_lock; PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) - << D->getName() << getLockKindFromAccessKind(AK)); + << D->getNameAsString() << getLockKindFromAccessKind(AK)); Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); } void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK, - Name LockName, LockKind LK, SourceLocation Loc) { + Name LockName, LockKind LK, SourceLocation Loc, + Name *PossibleMatch) { unsigned DiagID = 0; - switch (POK) { - case POK_VarAccess: - DiagID = diag::warn_variable_requires_lock; - break; - case POK_VarDereference: - DiagID = diag::warn_var_deref_requires_lock; - break; - case POK_FunctionCall: - DiagID = diag::warn_fun_requires_lock; - break; + if (PossibleMatch) { + switch (POK) { + case POK_VarAccess: + DiagID = diag::warn_variable_requires_lock_precise; + break; + case POK_VarDereference: + DiagID = diag::warn_var_deref_requires_lock_precise; + break; + case POK_FunctionCall: + DiagID = diag::warn_fun_requires_lock_precise; + break; + } + PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) + << D->getNameAsString() << LockName << LK); + PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match) + << *PossibleMatch); + Warnings.push_back(DelayedDiag(Warning, OptionalNotes(1, Note))); + } else { + switch (POK) { + case POK_VarAccess: + DiagID = diag::warn_variable_requires_lock; + break; + case POK_VarDereference: + DiagID = diag::warn_var_deref_requires_lock; + break; + case POK_FunctionCall: + DiagID = diag::warn_fun_requires_lock; + break; + } + PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) + << D->getNameAsString() << LockName << LK); + Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); } - PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) - << D->getName() << LockName << LK); - Warnings.push_back(DelayedDiag(Warning, OptionalNotes())); } void handleFunExcludesLock(Name FunName, Name LockName, SourceLocation Loc) { @@ -1206,7 +1440,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, AC.getCFGBuildOptions().AddEHEdges = false; AC.getCFGBuildOptions().AddInitializers = true; AC.getCFGBuildOptions().AddImplicitDtors = true; - + AC.getCFGBuildOptions().AddTemporaryDtors = true; + // Force that certain expressions appear as CFGElements in the CFG. This // is used to speed up various analyses. // FIXME: This isn't the right factoring. This is here for initial @@ -1350,6 +1585,11 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull); } + if (S.getLangOpts().ObjCARCWeak && + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, + D->getLocStart()) != DiagnosticsEngine::Ignored) + diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap()); + // Collect statistics about the CFG if it was built. if (S.CollectStats && AC.isCFGBuilt()) { ++NumFunctionsAnalyzed; diff --git a/lib/Sema/CMakeLists.txt b/lib/Sema/CMakeLists.txt index 46dfa05adec1..7cfe3ae8462c 100644 --- a/lib/Sema/CMakeLists.txt +++ b/lib/Sema/CMakeLists.txt @@ -13,7 +13,9 @@ add_clang_library(clangSema DelayedDiagnostic.cpp IdentifierResolver.cpp JumpDiagnostics.cpp + MultiplexExternalSemaSource.cpp Scope.cpp + ScopeInfo.cpp Sema.cpp SemaAccess.cpp SemaAttr.cpp @@ -39,6 +41,7 @@ add_clang_library(clangSema SemaOverload.cpp SemaPseudoObject.cpp SemaStmt.cpp + SemaStmtAsm.cpp SemaStmtAttr.cpp SemaTemplate.cpp SemaTemplateDeduction.cpp diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index a8357255343d..0a236018bdfd 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -193,11 +193,10 @@ CodeCompletionString::CodeCompletionString(const Chunk *Chunks, CXAvailabilityKind Availability, const char **Annotations, unsigned NumAnnotations, - CXCursorKind ParentKind, StringRef ParentName, const char *BriefComment) : NumChunks(NumChunks), NumAnnotations(NumAnnotations), - Priority(Priority), Availability(Availability), ParentKind(ParentKind), + Priority(Priority), Availability(Availability), ParentName(ParentName), BriefComment(BriefComment) { assert(NumChunks <= 0xffff); @@ -339,7 +338,7 @@ CodeCompletionString *CodeCompletionBuilder::TakeString() { = new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(), Priority, Availability, Annotations.data(), Annotations.size(), - ParentKind, ParentName, BriefComment); + ParentName, BriefComment); Chunks.clear(); return Result; } @@ -380,7 +379,6 @@ void CodeCompletionBuilder::AddChunk(CodeCompletionString::ChunkKind CK, void CodeCompletionBuilder::addParentContext(DeclContext *DC) { if (DC->isTranslationUnit()) { - ParentKind = CXCursor_TranslationUnit; return; } @@ -391,7 +389,6 @@ void CodeCompletionBuilder::addParentContext(DeclContext *DC) { if (!ND) return; - ParentKind = getCursorKindForDecl(ND); ParentName = getCodeCompletionTUInfo().getParentName(DC); } diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index d12ca7839095..b3066eb08013 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -144,11 +144,13 @@ CXXScopeSpec::getWithLocInContext(ASTContext &Context) const { /// DeclaratorChunk::getFunction - Return a DeclaratorChunk for a function. /// "TheDeclarator" is the declarator that this will be added to. -DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, +DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isAmbiguous, - SourceLocation EllipsisLoc, + SourceLocation LParenLoc, ParamInfo *ArgInfo, unsigned NumArgs, + SourceLocation EllipsisLoc, + SourceLocation RParenLoc, unsigned TypeQuals, bool RefQualifierIsLvalueRef, SourceLocation RefQualifierLoc, @@ -173,9 +175,11 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, bool isVariadic, I.EndLoc = LocalRangeEnd; I.Fun.AttrList = 0; I.Fun.hasPrototype = hasProto; - I.Fun.isVariadic = isVariadic; + I.Fun.isVariadic = EllipsisLoc.isValid(); I.Fun.isAmbiguous = isAmbiguous; + I.Fun.LParenLoc = LParenLoc.getRawEncoding(); I.Fun.EllipsisLoc = EllipsisLoc.getRawEncoding(); + I.Fun.RParenLoc = RParenLoc.getRawEncoding(); I.Fun.DeleteArgInfo = false; I.Fun.TypeQuals = TypeQuals; I.Fun.NumArgs = NumArgs; @@ -270,6 +274,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_int: case TST_int128: case TST_struct: + case TST_interface: case TST_union: case TST_unknown_anytype: case TST_unspecified: @@ -325,10 +330,14 @@ unsigned DeclSpec::getParsedSpecifiers() const { template <class T> static bool BadSpecifier(T TNew, T TPrev, const char *&PrevSpec, - unsigned &DiagID) { + unsigned &DiagID, + bool IsExtension = true) { PrevSpec = DeclSpec::getSpecifierName(TPrev); - DiagID = (TNew == TPrev ? diag::ext_duplicate_declspec - : diag::err_invalid_decl_spec_combination); + if (TNew != TPrev) + DiagID = diag::err_invalid_decl_spec_combination; + else + DiagID = IsExtension ? diag::ext_duplicate_declspec : + diag::warn_duplicate_declspec; return true; } @@ -396,6 +405,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T) { case DeclSpec::TST_class: return "class"; case DeclSpec::TST_union: return "union"; case DeclSpec::TST_struct: return "struct"; + case DeclSpec::TST_interface: return "__interface"; case DeclSpec::TST_typename: return "type-name"; case DeclSpec::TST_typeofType: case DeclSpec::TST_typeofExpr: return "typeof"; @@ -670,12 +680,16 @@ bool DeclSpec::SetTypeSpecError() { } bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, - unsigned &DiagID, const LangOptions &Lang, - bool IsTypeSpec) { - // Duplicates are permitted in C99, and are permitted in C++11 unless the - // cv-qualifier appears as a type-specifier. - if ((TypeQualifiers & T) && !Lang.C99 && (!Lang.CPlusPlus0x || IsTypeSpec)) - return BadSpecifier(T, T, PrevSpec, DiagID); + unsigned &DiagID, const LangOptions &Lang) { + // Duplicates are permitted in C99, but are not permitted in C++. However, + // since this is likely not what the user intended, we will always warn. We + // do not need to set the qualifier's location since we already have it. + if (TypeQualifiers & T) { + bool IsExtension = true; + if (Lang.C99) + IsExtension = false; + return BadSpecifier(T, T, PrevSpec, DiagID, IsExtension); + } TypeQualifiers |= T; switch (T) { diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp index 876f9d7a9545..310043288554 100644 --- a/lib/Sema/DelayedDiagnostic.cpp +++ b/lib/Sema/DelayedDiagnostic.cpp @@ -22,6 +22,7 @@ using namespace sema; DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc, const NamedDecl *D, const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, StringRef Msg) { DelayedDiagnostic DD; DD.Kind = Deprecation; @@ -29,6 +30,7 @@ DelayedDiagnostic DelayedDiagnostic::makeDeprecation(SourceLocation Loc, DD.Loc = Loc; DD.DeprecationData.Decl = D; DD.DeprecationData.UnknownObjCClass = UnknownObjCClass; + DD.DeprecationData.ObjCProperty = ObjCProperty; char *MessageData = 0; if (Msg.size()) { MessageData = new char [Msg.size()]; diff --git a/lib/Sema/IdentifierResolver.cpp b/lib/Sema/IdentifierResolver.cpp index 4d62cab16765..00939151c673 100644 --- a/lib/Sema/IdentifierResolver.cpp +++ b/lib/Sema/IdentifierResolver.cpp @@ -135,8 +135,16 @@ bool IdentifierResolver::isDeclInScope(Decl *D, DeclContext *Ctx, // of the controlled statement. // assert(S->getParent() && "No TUScope?"); - if (S->getParent()->getFlags() & Scope::ControlScope) + if (S->getFlags() & Scope::FnTryScope) return S->getParent()->isDeclScope(D); + if (S->getParent()->getFlags() & Scope::ControlScope) { + if (S->getParent()->getFlags() & Scope::FnCatchScope) { + S = S->getParent(); + if (S->isDeclScope(D)) + return true; + } + return S->getParent()->isDeclScope(D); + } } return false; } diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index ab786c65aab9..e2ec1ccebdcf 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -123,7 +123,7 @@ typedef std::pair<unsigned,unsigned> ScopePair; /// diagnostic that should be emitted if control goes over it. If not, return 0. static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - unsigned InDiag = 0, OutDiag = 0; + unsigned InDiag = 0; if (VD->getType()->isVariablyModifiedType()) InDiag = diag::note_protected_by_vla; @@ -164,43 +164,53 @@ static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) { // where it is in scope is ill-formed unless the variable has // POD type and is declared without an initializer. - if (const Expr *init = VD->getInit()) { - // We actually give variables of record type (or array thereof) - // an initializer even if that initializer only calls a trivial - // ctor. Detect that case. - // FIXME: With generalized initializer lists, this may - // classify "X x{};" as having no initializer. - unsigned inDiagToUse = diag::note_protected_by_variable_init; - - const CXXRecordDecl *record = 0; - - if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(init)) { - const CXXConstructorDecl *ctor = cce->getConstructor(); - record = ctor->getParent(); - - if (ctor->isTrivial() && ctor->isDefaultConstructor()) { - if (!record->hasTrivialDestructor()) - inDiagToUse = diag::note_protected_by_variable_nontriv_destructor; - else if (!record->isPOD()) - inDiagToUse = diag::note_protected_by_variable_non_pod; - else - inDiagToUse = 0; - } - } else if (VD->getType()->isArrayType()) { - record = VD->getType()->getBaseElementTypeUnsafe() - ->getAsCXXRecordDecl(); + const Expr *Init = VD->getInit(); + if (!Init) + return ScopePair(InDiag, 0); + + const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init); + if (EWC) + Init = EWC->getSubExpr(); + + const MaterializeTemporaryExpr *M = NULL; + Init = Init->findMaterializedTemporary(M); + + SmallVector<SubobjectAdjustment, 2> Adjustments; + Init = Init->skipRValueSubobjectAdjustments(Adjustments); + + QualType QT = Init->getType(); + if (QT.isNull()) + return ScopePair(diag::note_protected_by_variable_init, 0); + + const Type *T = QT.getTypePtr(); + if (T->isArrayType()) + T = T->getBaseElementTypeUnsafe(); + + const CXXRecordDecl *Record = T->getAsCXXRecordDecl(); + if (!Record) + return ScopePair(diag::note_protected_by_variable_init, 0); + + // If we need to call a non trivial destructor for this variable, + // record an out diagnostic. + unsigned OutDiag = 0; + if (!Init->isGLValue() && !Record->hasTrivialDestructor()) + OutDiag = diag::note_exits_dtor; + + if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) { + const CXXConstructorDecl *ctor = cce->getConstructor(); + if (ctor->isTrivial() && ctor->isDefaultConstructor()) { + if (OutDiag) + InDiag = diag::note_protected_by_variable_nontriv_destructor; + else if (!Record->isPOD()) + InDiag = diag::note_protected_by_variable_non_pod; + return ScopePair(InDiag, OutDiag); } - - if (inDiagToUse) - InDiag = inDiagToUse; - - // Also object to indirect jumps which leave scopes with dtors. - if (record && !record->hasTrivialDestructor()) - OutDiag = diag::note_exits_dtor; } + + return ScopePair(diag::note_protected_by_variable_init, OutDiag); } - - return ScopePair(InDiag, OutDiag); + + return ScopePair(InDiag, 0); } if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { @@ -322,6 +332,29 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) Jumps.push_back(S); break; + case Stmt::CXXTryStmtClass: { + CXXTryStmt *TS = cast<CXXTryStmt>(S); + unsigned newParentScope; + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_cxx_try, + diag::note_exits_cxx_try, + TS->getSourceRange().getBegin())); + if (Stmt *TryBlock = TS->getTryBlock()) + BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1)); + + // Jump from the catch into the try is not allowed either. + for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { + CXXCatchStmt *CS = TS->getHandler(I); + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_cxx_catch, + diag::note_exits_cxx_catch, + CS->getSourceRange().getBegin())); + BuildScopeInformation(CS->getHandlerBlock(), + (newParentScope = Scopes.size()-1)); + } + return; + } + default: break; } @@ -418,30 +451,6 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) continue; } - // Disallow jumps into any part of a C++ try statement. This is pretty - // much the same as for Obj-C. - if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) { - Scopes.push_back(GotoScope(ParentScope, - diag::note_protected_by_cxx_try, - diag::note_exits_cxx_try, - TS->getSourceRange().getBegin())); - if (Stmt *TryBlock = TS->getTryBlock()) - BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1)); - - // Jump from the catch into the try is not allowed either. - for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { - CXXCatchStmt *CS = TS->getHandler(I); - Scopes.push_back(GotoScope(ParentScope, - diag::note_protected_by_cxx_catch, - diag::note_exits_cxx_catch, - CS->getSourceRange().getBegin())); - BuildScopeInformation(CS->getHandlerBlock(), - (newParentScope = Scopes.size()-1)); - } - - continue; - } - // Disallow jumps into the protected statement of an @autoreleasepool. if (ObjCAutoreleasePoolStmt *AS = dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)){ // Recursively walk the AST for the @autoreleasepool part, protected by a new @@ -453,14 +462,19 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) BuildScopeInformation(AS->getSubStmt(), (newParentScope = Scopes.size()-1)); continue; } - - if (const BlockExpr *BE = dyn_cast<BlockExpr>(SubStmt)) { - const BlockDecl *BDecl = BE->getBlockDecl(); + + // Disallow jumps past full-expressions that use blocks with + // non-trivial cleanups of their captures. This is theoretically + // implementable but a lot of work which we haven't felt up to doing. + if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(SubStmt)) { + for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) { + const BlockDecl *BDecl = EWC->getObject(i); for (BlockDecl::capture_const_iterator ci = BDecl->capture_begin(), ce = BDecl->capture_end(); ci != ce; ++ci) { VarDecl *variable = ci->getVariable(); BuildScopeInformation(variable, BDecl, ParentScope); } + } } // Recursively walk the AST. diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp new file mode 100644 index 000000000000..f930fb348a25 --- /dev/null +++ b/lib/Sema/MultiplexExternalSemaSource.cpp @@ -0,0 +1,271 @@ +//===--- MultiplexExternalSemaSource.cpp ---------------------------------===// +// +// 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 event dispatching to the subscribed clients. +// +//===----------------------------------------------------------------------===// +#include "clang/Sema/MultiplexExternalSemaSource.h" + +#include "clang/AST/DeclContextInternals.h" +#include "clang/Sema/Lookup.h" + +using namespace clang; + +///\brief Constructs a new multiplexing external sema source and appends the +/// given element to it. +/// +///\param[in] source - An ExternalSemaSource. +/// +MultiplexExternalSemaSource::MultiplexExternalSemaSource(ExternalSemaSource &s1, + ExternalSemaSource &s2){ + Sources.push_back(&s1); + Sources.push_back(&s2); +} + +// pin the vtable here. +MultiplexExternalSemaSource::~MultiplexExternalSemaSource() {} + +///\brief Appends new source to the source list. +/// +///\param[in] source - An ExternalSemaSource. +/// +void MultiplexExternalSemaSource::addSource(ExternalSemaSource &source) { + Sources.push_back(&source); +} + +//===----------------------------------------------------------------------===// +// ExternalASTSource. +//===----------------------------------------------------------------------===// + +Decl *MultiplexExternalSemaSource::GetExternalDecl(uint32_t ID) { + for(size_t i = 0; i < Sources.size(); ++i) + if (Decl *Result = Sources[i]->GetExternalDecl(ID)) + return Result; + return 0; +} + +Selector MultiplexExternalSemaSource::GetExternalSelector(uint32_t ID) { + Selector Sel; + for(size_t i = 0; i < Sources.size(); ++i) { + Sel = Sources[i]->GetExternalSelector(ID); + if (!Sel.isNull()) + return Sel; + } + return Sel; +} + +uint32_t MultiplexExternalSemaSource::GetNumExternalSelectors() { + uint32_t total = 0; + for(size_t i = 0; i < Sources.size(); ++i) + total += Sources[i]->GetNumExternalSelectors(); + return total; +} + +Stmt *MultiplexExternalSemaSource::GetExternalDeclStmt(uint64_t Offset) { + for(size_t i = 0; i < Sources.size(); ++i) + if (Stmt *Result = Sources[i]->GetExternalDeclStmt(Offset)) + return Result; + return 0; +} + +CXXBaseSpecifier *MultiplexExternalSemaSource::GetExternalCXXBaseSpecifiers( + uint64_t Offset){ + for(size_t i = 0; i < Sources.size(); ++i) + if (CXXBaseSpecifier *R = Sources[i]->GetExternalCXXBaseSpecifiers(Offset)) + return R; + return 0; +} + +DeclContextLookupResult MultiplexExternalSemaSource:: +FindExternalVisibleDeclsByName(const DeclContext *DC, DeclarationName Name) { + StoredDeclsList DeclsFound; + DeclContextLookupResult lookup; + for(size_t i = 0; i < Sources.size(); ++i) { + lookup = Sources[i]->FindExternalVisibleDeclsByName(DC, Name); + while(lookup.first != lookup.second) { + if (!DeclsFound.HandleRedeclaration(*lookup.first)) + DeclsFound.AddSubsequentDecl(*lookup.first); + lookup.first++; + } + } + return DeclsFound.getLookupResult(); +} + +void MultiplexExternalSemaSource::completeVisibleDeclsMap(const DeclContext *DC){ + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->completeVisibleDeclsMap(DC); +} + +ExternalLoadResult MultiplexExternalSemaSource:: +FindExternalLexicalDecls(const DeclContext *DC, + bool (*isKindWeWant)(Decl::Kind), + SmallVectorImpl<Decl*> &Result) { + for(size_t i = 0; i < Sources.size(); ++i) + // FIXME: The semantics of the return result is unclear to me... + Sources[i]->FindExternalLexicalDecls(DC, isKindWeWant, Result); + + return ELR_Success; +} + +void MultiplexExternalSemaSource::FindFileRegionDecls(FileID File, + unsigned Offset, + unsigned Length, + SmallVectorImpl<Decl *> &Decls){ + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->FindFileRegionDecls(File, Offset, Length, Decls); +} + +void MultiplexExternalSemaSource::CompleteType(TagDecl *Tag) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->CompleteType(Tag); +} + +void MultiplexExternalSemaSource::CompleteType(ObjCInterfaceDecl *Class) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->CompleteType(Class); +} + +void MultiplexExternalSemaSource::ReadComments() { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadComments(); +} + +void MultiplexExternalSemaSource::StartedDeserializing() { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->StartedDeserializing(); +} + +void MultiplexExternalSemaSource::FinishedDeserializing() { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->FinishedDeserializing(); +} + +void MultiplexExternalSemaSource::StartTranslationUnit(ASTConsumer *Consumer) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->StartTranslationUnit(Consumer); +} + +void MultiplexExternalSemaSource::PrintStats() { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->PrintStats(); +} + +bool MultiplexExternalSemaSource::layoutRecordType(const RecordDecl *Record, + uint64_t &Size, + uint64_t &Alignment, + llvm::DenseMap<const FieldDecl *, uint64_t> &FieldOffsets, + llvm::DenseMap<const CXXRecordDecl *, CharUnits> &BaseOffsets, + llvm::DenseMap<const CXXRecordDecl *, CharUnits> &VirtualBaseOffsets){ + for(size_t i = 0; i < Sources.size(); ++i) + if (Sources[i]->layoutRecordType(Record, Size, Alignment, FieldOffsets, + BaseOffsets, VirtualBaseOffsets)) + return true; + return false; +} + +void MultiplexExternalSemaSource:: +getMemoryBufferSizes(MemoryBufferSizes &sizes) const { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->getMemoryBufferSizes(sizes); + +} + +//===----------------------------------------------------------------------===// +// ExternalSemaSource. +//===----------------------------------------------------------------------===// + + +void MultiplexExternalSemaSource::InitializeSema(Sema &S) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->InitializeSema(S); +} + +void MultiplexExternalSemaSource::ForgetSema() { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ForgetSema(); +} + +void MultiplexExternalSemaSource::ReadMethodPool(Selector Sel) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadMethodPool(Sel); +} + +void MultiplexExternalSemaSource::ReadKnownNamespaces( + SmallVectorImpl<NamespaceDecl*> &Namespaces){ + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadKnownNamespaces(Namespaces); +} + +bool MultiplexExternalSemaSource::LookupUnqualified(LookupResult &R, Scope *S){ + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->LookupUnqualified(R, S); + + return !R.empty(); +} + +void MultiplexExternalSemaSource::ReadTentativeDefinitions( + SmallVectorImpl<VarDecl*> &TentativeDefs) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadTentativeDefinitions(TentativeDefs); +} + +void MultiplexExternalSemaSource::ReadUnusedFileScopedDecls( + SmallVectorImpl<const DeclaratorDecl*> &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadUnusedFileScopedDecls(Decls); +} + +void MultiplexExternalSemaSource::ReadDelegatingConstructors( + SmallVectorImpl<CXXConstructorDecl*> &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadDelegatingConstructors(Decls); +} + +void MultiplexExternalSemaSource::ReadExtVectorDecls( + SmallVectorImpl<TypedefNameDecl*> &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadExtVectorDecls(Decls); +} + +void MultiplexExternalSemaSource::ReadDynamicClasses( + SmallVectorImpl<CXXRecordDecl*> &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadDynamicClasses(Decls); +} + +void MultiplexExternalSemaSource::ReadLocallyScopedExternalDecls( + SmallVectorImpl<NamedDecl*> &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadLocallyScopedExternalDecls(Decls); +} + +void MultiplexExternalSemaSource::ReadReferencedSelectors( + SmallVectorImpl<std::pair<Selector, SourceLocation> > &Sels) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadReferencedSelectors(Sels); +} + +void MultiplexExternalSemaSource::ReadWeakUndeclaredIdentifiers( + SmallVectorImpl<std::pair<IdentifierInfo*, WeakInfo> > &WI) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadWeakUndeclaredIdentifiers(WI); +} + +void MultiplexExternalSemaSource::ReadUsedVTables( + SmallVectorImpl<ExternalVTableUse> &VTables) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadUsedVTables(VTables); +} + +void MultiplexExternalSemaSource::ReadPendingInstantiations( + SmallVectorImpl<std::pair<ValueDecl*, + SourceLocation> > &Pending) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadPendingInstantiations(Pending); +} diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp new file mode 100644 index 000000000000..4d29a34a73ef --- /dev/null +++ b/lib/Sema/ScopeInfo.cpp @@ -0,0 +1,189 @@ +//===--- ScopeInfo.cpp - Information about a semantic context -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements FunctionScopeInfo and its subclasses, which contain +// information about a single function, block, lambda, or method body. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/ScopeInfo.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprObjC.h" + +using namespace clang; +using namespace sema; + +void FunctionScopeInfo::Clear() { + HasBranchProtectedScope = false; + HasBranchIntoScope = false; + HasIndirectGoto = false; + + SwitchStack.clear(); + Returns.clear(); + ErrorTrap.reset(); + PossiblyUnreachableDiags.clear(); + WeakObjectUses.clear(); +} + +static const NamedDecl *getBestPropertyDecl(const ObjCPropertyRefExpr *PropE) { + if (PropE->isExplicitProperty()) + return PropE->getExplicitProperty(); + + return PropE->getImplicitPropertyGetter(); +} + +FunctionScopeInfo::WeakObjectProfileTy::BaseInfoTy +FunctionScopeInfo::WeakObjectProfileTy::getBaseInfo(const Expr *E) { + E = E->IgnoreParenCasts(); + + const NamedDecl *D = 0; + bool IsExact = false; + + switch (E->getStmtClass()) { + case Stmt::DeclRefExprClass: + D = cast<DeclRefExpr>(E)->getDecl(); + IsExact = isa<VarDecl>(D); + break; + case Stmt::MemberExprClass: { + const MemberExpr *ME = cast<MemberExpr>(E); + D = ME->getMemberDecl(); + IsExact = isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()); + break; + } + case Stmt::ObjCIvarRefExprClass: { + const ObjCIvarRefExpr *IE = cast<ObjCIvarRefExpr>(E); + D = IE->getDecl(); + IsExact = IE->getBase()->isObjCSelfExpr(); + break; + } + case Stmt::PseudoObjectExprClass: { + const PseudoObjectExpr *POE = cast<PseudoObjectExpr>(E); + const ObjCPropertyRefExpr *BaseProp = + dyn_cast<ObjCPropertyRefExpr>(POE->getSyntacticForm()); + if (BaseProp) { + D = getBestPropertyDecl(BaseProp); + + const Expr *DoubleBase = BaseProp->getBase(); + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(DoubleBase)) + DoubleBase = OVE->getSourceExpr(); + + IsExact = DoubleBase->isObjCSelfExpr(); + } + break; + } + default: + break; + } + + return BaseInfoTy(D, IsExact); +} + + +FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy( + const ObjCPropertyRefExpr *PropE) + : Base(0, true), Property(getBestPropertyDecl(PropE)) { + + if (PropE->isObjectReceiver()) { + const OpaqueValueExpr *OVE = cast<OpaqueValueExpr>(PropE->getBase()); + const Expr *E = OVE->getSourceExpr(); + Base = getBaseInfo(E); + } else if (PropE->isClassReceiver()) { + Base.setPointer(PropE->getClassReceiver()); + } else { + assert(PropE->isSuperReceiver()); + } +} + +FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy(const Expr *BaseE, + const ObjCPropertyDecl *Prop) + : Base(0, true), Property(Prop) { + if (BaseE) + Base = getBaseInfo(BaseE); + // else, this is a message accessing a property on super. +} + +FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy( + const DeclRefExpr *DRE) + : Base(0, true), Property(DRE->getDecl()) { + assert(isa<VarDecl>(Property)); +} + +FunctionScopeInfo::WeakObjectProfileTy::WeakObjectProfileTy( + const ObjCIvarRefExpr *IvarE) + : Base(getBaseInfo(IvarE->getBase())), Property(IvarE->getDecl()) { +} + +void FunctionScopeInfo::recordUseOfWeak(const ObjCMessageExpr *Msg, + const ObjCPropertyDecl *Prop) { + assert(Msg && Prop); + WeakUseVector &Uses = + WeakObjectUses[WeakObjectProfileTy(Msg->getInstanceReceiver(), Prop)]; + Uses.push_back(WeakUseTy(Msg, Msg->getNumArgs() == 0)); +} + +void FunctionScopeInfo::markSafeWeakUse(const Expr *E) { + E = E->IgnoreParenCasts(); + + if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) { + markSafeWeakUse(POE->getSyntacticForm()); + return; + } + + if (const ConditionalOperator *Cond = dyn_cast<ConditionalOperator>(E)) { + markSafeWeakUse(Cond->getTrueExpr()); + markSafeWeakUse(Cond->getFalseExpr()); + return; + } + + if (const BinaryConditionalOperator *Cond = + dyn_cast<BinaryConditionalOperator>(E)) { + markSafeWeakUse(Cond->getCommon()); + markSafeWeakUse(Cond->getFalseExpr()); + return; + } + + // Has this weak object been seen before? + FunctionScopeInfo::WeakObjectUseMap::iterator Uses; + if (const ObjCPropertyRefExpr *RefExpr = dyn_cast<ObjCPropertyRefExpr>(E)) + Uses = WeakObjectUses.find(WeakObjectProfileTy(RefExpr)); + else if (const ObjCIvarRefExpr *IvarE = dyn_cast<ObjCIvarRefExpr>(E)) + Uses = WeakObjectUses.find(WeakObjectProfileTy(IvarE)); + else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + Uses = WeakObjectUses.find(WeakObjectProfileTy(DRE)); + else if (const ObjCMessageExpr *MsgE = dyn_cast<ObjCMessageExpr>(E)) { + Uses = WeakObjectUses.end(); + if (const ObjCMethodDecl *MD = MsgE->getMethodDecl()) { + if (const ObjCPropertyDecl *Prop = MD->findPropertyDecl()) { + Uses = + WeakObjectUses.find(WeakObjectProfileTy(MsgE->getInstanceReceiver(), + Prop)); + } + } + } + else + return; + + if (Uses == WeakObjectUses.end()) + return; + + // Has there been a read from the object using this Expr? + FunctionScopeInfo::WeakUseVector::reverse_iterator ThisUse = + std::find(Uses->second.rbegin(), Uses->second.rend(), WeakUseTy(E, true)); + if (ThisUse == Uses->second.rend()) + return; + + ThisUse->markSafe(); +} + +FunctionScopeInfo::~FunctionScopeInfo() { } +BlockScopeInfo::~BlockScopeInfo() { } +LambdaScopeInfo::~LambdaScopeInfo() { } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 7f79f0c6d98a..13a33b785b43 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -22,6 +22,7 @@ #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/MultiplexExternalSemaSource.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" @@ -43,22 +44,6 @@ using namespace clang; using namespace sema; -FunctionScopeInfo::~FunctionScopeInfo() { } - -void FunctionScopeInfo::Clear() { - HasBranchProtectedScope = false; - HasBranchIntoScope = false; - HasIndirectGoto = false; - - SwitchStack.clear(); - Returns.clear(); - ErrorTrap.reset(); - PossiblyUnreachableDiags.clear(); -} - -BlockScopeInfo::~BlockScopeInfo() { } -LambdaScopeInfo::~LambdaScopeInfo() { } - PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context, const Preprocessor &PP) { PrintingPolicy Policy = Context.getPrintingPolicy(); @@ -84,12 +69,14 @@ void Sema::ActOnTranslationUnitScope(Scope *S) { Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) - : TheTargetAttributesSema(0), FPFeatures(pp.getLangOpts()), + : TheTargetAttributesSema(0), ExternalSource(0), + isMultiplexExternalSource(false), FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), - CollectStats(false), ExternalSource(0), CodeCompleter(CodeCompleter), + CollectStats(false), CodeCompleter(CodeCompleter), CurContext(0), OriginalLexicalContext(0), PackContext(0), MSStructPragmaOn(false), VisContext(0), + IsBuildingRecoveryCallExpr(false), ExprNeedsCleanups(false), LateTemplateParser(0), OpaqueParser(0), IdResolver(pp), StdInitializerList(0), CXXTypeInfoDecl(0), MSVCGuidDecl(0), NSNumberDecl(0), @@ -203,6 +190,10 @@ Sema::~Sema() { if (ExternalSemaSource *ExternalSema = dyn_cast_or_null<ExternalSemaSource>(Context.getExternalSource())) ExternalSema->ForgetSema(); + + // If Sema's ExternalSource is the multiplexer - we own it. + if (isMultiplexExternalSource) + delete ExternalSource; } /// makeUnavailableInSystemHeader - There is an error in the current @@ -234,6 +225,27 @@ ASTMutationListener *Sema::getASTMutationListener() const { return getASTConsumer().GetASTMutationListener(); } +///\brief Registers an external source. If an external source already exists, +/// creates a multiplex external source and appends to it. +/// +///\param[in] E - A non-null external sema source. +/// +void Sema::addExternalSource(ExternalSemaSource *E) { + assert(E && "Cannot use with NULL ptr"); + + if (!ExternalSource) { + ExternalSource = E; + return; + } + + if (isMultiplexExternalSource) + static_cast<MultiplexExternalSemaSource*>(ExternalSource)->addSource(*E); + else { + ExternalSource = new MultiplexExternalSemaSource(*ExternalSource, *E); + isMultiplexExternalSource = true; + } +} + /// \brief Print out statistics about the semantic analysis. void Sema::PrintStats() const { llvm::errs() << "\n*** Semantic Analysis Stats:\n"; @@ -507,6 +519,11 @@ void Sema::ActOnEndOfTranslationUnit() { assert(DelayedDiagnostics.getCurrentPool() == NULL && "reached end of translation unit with a pool attached?"); + // If code completion is enabled, don't perform any end-of-translation-unit + // work. + if (PP.isCodeCompletionEnabled()) + return; + // Only complete translation units define vtables and perform implicit // instantiations. if (TUKind == TU_Complete) { @@ -648,6 +665,8 @@ void Sema::ActOnEndOfTranslationUnit() { diag::err_tentative_def_incomplete_type)) VD->setInvalidDecl(); + CheckCompleteVariableDeclaration(VD); + // Notify the consumer that we've completed a tentative definition. if (!VD->isInvalidDecl()) Consumer.CompleteTentativeDefinition(VD); @@ -1021,6 +1040,9 @@ LambdaScopeInfo *Sema::getCurLambda() { } void Sema::ActOnComment(SourceRange Comment) { + if (!LangOpts.RetainCommentsFromSystemHeaders && + SourceMgr.isInSystemHeader(Comment.getBegin())) + return; RawComment RC(SourceMgr, Comment); if (RC.isAlmostTrailingComment()) { SourceRange MagicMarkerRange(Comment.getBegin(), @@ -1165,8 +1187,7 @@ static void noteOverloads(Sema &S, const UnresolvedSetImpl &Overloads, DeclsEnd = Overloads.end(); It != DeclsEnd; ++It) { // FIXME: Magic number for max shown overloads stolen from // OverloadCandidateSet::NoteCandidates. - if (ShownOverloads >= 4 && - S.Diags.getShowOverloads() == DiagnosticsEngine::Ovl_Best) { + if (ShownOverloads >= 4 && S.Diags.getShowOverloads() == Ovl_Best) { ++SuppressedOverloads; continue; } @@ -1237,8 +1258,7 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, // FIXME: Try this before emitting the fixit, and suppress diagnostics // while doing so. E = ActOnCallExpr(0, E.take(), ParenInsertionLoc, - MultiExprArg(*this, 0, 0), - ParenInsertionLoc.getLocWithOffset(1)); + MultiExprArg(), ParenInsertionLoc.getLocWithOffset(1)); return true; } diff --git a/lib/Sema/SemaAccess.cpp b/lib/Sema/SemaAccess.cpp index 3481171c7735..58b1a51ae573 100644 --- a/lib/Sema/SemaAccess.cpp +++ b/lib/Sema/SemaAccess.cpp @@ -97,14 +97,19 @@ struct EffectiveContext { // functions (which can gain privileges through friendship), but we // take that as an oversight. while (true) { + // We want to add canonical declarations to the EC lists for + // simplicity of checking, but we need to walk up through the + // actual current DC chain. Otherwise, something like a local + // extern or friend which happens to be the canonical + // declaration will really mess us up. + if (isa<CXXRecordDecl>(DC)) { - CXXRecordDecl *Record = cast<CXXRecordDecl>(DC)->getCanonicalDecl(); - Records.push_back(Record); + CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); + Records.push_back(Record->getCanonicalDecl()); DC = Record->getDeclContext(); } else if (isa<FunctionDecl>(DC)) { - FunctionDecl *Function = cast<FunctionDecl>(DC)->getCanonicalDecl(); - Functions.push_back(Function); - + FunctionDecl *Function = cast<FunctionDecl>(DC); + Functions.push_back(Function->getCanonicalDecl()); if (Function->getFriendObjectKind()) DC = Function->getLexicalDeclContext(); else @@ -1791,7 +1796,7 @@ void Sema::CheckLookupAccess(const LookupResult &R) { /// specifiers into account, but no member access expressions and such. /// /// \param Decl the declaration to check if it can be accessed -/// \param Class the class/context from which to start the search +/// \param Ctx the class/context from which to start the search /// \return true if the Decl is accessible from the Class, false otherwise. bool Sema::IsSimplyAccessible(NamedDecl *Decl, DeclContext *Ctx) { if (CXXRecordDecl *Class = dyn_cast<CXXRecordDecl>(Ctx)) { diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index e935fc735b23..f1154c1a8aeb 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -136,23 +136,12 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) { } void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, - SourceLocation PragmaLoc, - SourceLocation KindLoc) { + SourceLocation PragmaLoc) { if (PackContext == 0) PackContext = new PragmaPackStack(); PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext); - // Reset just pops the top of the stack, or resets the current alignment to - // default. - if (Kind == Sema::POAK_Reset) { - if (!Context->pop(0, /*IsReset=*/true)) { - Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed) - << "stack empty"; - } - return; - } - switch (Kind) { // For all targets we support native and natural are the same. // @@ -181,9 +170,13 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel); break; - default: - Diag(PragmaLoc, diag::warn_pragma_options_align_unsupported_option) - << KindLoc; + case POAK_Reset: + // Reset just pops the top of the stack, or resets the current alignment to + // default. + if (!Context->pop(0, /*IsReset=*/true)) { + Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed) + << "stack empty"; + } break; } } diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 0de9dd5f64c9..15bfd1ce6294 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -520,7 +520,8 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_suggest) << Name << LookupCtx << CorrectedQuotedStr << SS.getRange() - << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr); + << FixItHint::CreateReplacement(Corrected.getCorrectionRange(), + CorrectedStr); else Diag(Found.getNameLoc(), diag::err_undeclared_var_use_suggest) << Name << CorrectedQuotedStr diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index d8d51e77ee24..bf25c6178541 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -227,7 +227,7 @@ Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, CheckExtraCXXDefaultArguments(D); } - return BuildCXXNamedCast(OpLoc, Kind, TInfo, move(E), + return BuildCXXNamedCast(OpLoc, Kind, TInfo, E, SourceRange(LAngleBracketLoc, RAngleBracketLoc), SourceRange(LParenLoc, RParenLoc)); } @@ -1331,8 +1331,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, if (InitSeq.Failed() && (CStyle || !DestType->isReferenceType())) return TC_NotApplicable; - ExprResult Result - = InitSeq.Perform(Self, Entity, InitKind, MultiExprArg(Self, &SrcExprRaw, 1)); + ExprResult Result = InitSeq.Perform(Self, Entity, InitKind, SrcExprRaw); if (Result.isInvalid()) { msg = 0; return TC_Failed; @@ -1343,7 +1342,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, else Kind = CK_NoOp; - SrcExpr = move(Result); + SrcExpr = Result; return TC_Success; } @@ -1492,6 +1491,22 @@ static void DiagnoseCastOfObjCSEL(Sema &Self, const ExprResult &SrcExpr, } } +static void checkIntToPointerCast(bool CStyle, SourceLocation Loc, + const Expr *SrcExpr, QualType DestType, + Sema &Self) { + QualType SrcType = SrcExpr->getType(); + + // Not warning on reinterpret_cast, boolean, constant expressions, etc + // are not explicit design choices, but consistent with GCC's behavior. + // Feel free to modify them if you've reason/evidence for an alternative. + if (CStyle && SrcType->isIntegralType(Self.Context) + && !SrcType->isBooleanType() + && !SrcType->isEnumeralType() + && !SrcExpr->isIntegerConstantExpr(Self.Context) + && Self.Context.getTypeSize(DestType) > Self.Context.getTypeSize(SrcType)) + Self.Diag(Loc, diag::warn_int_to_pointer_cast) << SrcType << DestType; +} + static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, const SourceRange &OpRange, @@ -1513,7 +1528,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, SingleFunctionExpr, Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr ) && SingleFunctionExpr.isUsable()) { - SrcExpr = move(SingleFunctionExpr); + SrcExpr = SingleFunctionExpr; SrcType = SrcExpr.get()->getType(); } else { return TC_NotApplicable; @@ -1690,6 +1705,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, if (SrcType->isIntegralOrEnumerationType()) { assert(destIsPtr && "One type must be a pointer"); + checkIntToPointerCast(CStyle, OpRange.getBegin(), SrcExpr.get(), DestType, + Self); // C++ 5.2.10p5: A value of integral or enumeration type can be explicitly // converted to a pointer. // C++ 5.2.10p9: [Note: ...a null pointer constant of integral type is not @@ -1903,6 +1920,43 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, SrcExpr = ExprError(); } +/// DiagnoseBadFunctionCast - Warn whenever a function call is cast to a +/// non-matching type. Such as enum function call to int, int call to +/// pointer; etc. Cast to 'void' is an exception. +static void DiagnoseBadFunctionCast(Sema &Self, const ExprResult &SrcExpr, + QualType DestType) { + if (Self.Diags.getDiagnosticLevel(diag::warn_bad_function_cast, + SrcExpr.get()->getExprLoc()) + == DiagnosticsEngine::Ignored) + return; + + if (!isa<CallExpr>(SrcExpr.get())) + return; + + QualType SrcType = SrcExpr.get()->getType(); + if (DestType.getUnqualifiedType()->isVoidType()) + return; + if ((SrcType->isAnyPointerType() || SrcType->isBlockPointerType()) + && (DestType->isAnyPointerType() || DestType->isBlockPointerType())) + return; + if (SrcType->isIntegerType() && DestType->isIntegerType() && + (SrcType->isBooleanType() == DestType->isBooleanType()) && + (SrcType->isEnumeralType() == DestType->isEnumeralType())) + return; + if (SrcType->isRealFloatingType() && DestType->isRealFloatingType()) + return; + if (SrcType->isEnumeralType() && DestType->isEnumeralType()) + return; + if (SrcType->isComplexType() && DestType->isComplexType()) + return; + if (SrcType->isComplexIntegerType() && DestType->isComplexIntegerType()) + return; + + Self.Diag(SrcExpr.get()->getExprLoc(), + diag::warn_bad_function_cast) + << SrcType << DestType << SrcExpr.get()->getSourceRange(); +} + /// Check the semantics of a C-style cast operation, in C. void CastOperation::CheckCStyleCast() { assert(!Self.getLangOpts().CPlusPlus); @@ -2035,6 +2089,8 @@ void CastOperation::CheckCStyleCast() { SrcExpr = ExprError(); return; } + checkIntToPointerCast(/* CStyle */ true, OpRange.getBegin(), SrcExpr.get(), + DestType, Self); } else if (!SrcType->isArithmeticType()) { if (!DestType->isIntegralType(Self.Context) && DestType->isArithmeticType()) { @@ -2076,7 +2132,7 @@ void CastOperation::CheckCStyleCast() { } } DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType); - + DiagnoseBadFunctionCast(Self, SrcExpr, DestType); Kind = Self.PrepareScalarCast(SrcExpr, DestType); if (SrcExpr.isInvalid()) return; diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 2559f00f71e0..692a210ef304 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -266,11 +266,11 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__sync_swap_4: case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: - return SemaBuiltinAtomicOverloaded(move(TheCallResult)); + return SemaBuiltinAtomicOverloaded(TheCallResult); #define BUILTIN(ID, TYPE, ATTRS) #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ case Builtin::BI##ID: \ - return SemaAtomicOpsOverloaded(move(TheCallResult), AtomicExpr::AO##ID); + return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID); #include "clang/Basic/Builtins.def" case Builtin::BI__builtin_annotation: if (SemaBuiltinAnnotation(*this, TheCall)) @@ -299,7 +299,7 @@ Sema::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { } } - return move(TheCallResult); + return TheCallResult; } // Get the valid immediate range for the specified NEON type code. @@ -437,6 +437,11 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { default: return false; case Mips::BI__builtin_mips_wrdsp: i = 1; l = 0; u = 63; break; case Mips::BI__builtin_mips_rddsp: i = 0; l = 0; u = 63; break; + case Mips::BI__builtin_mips_append: i = 2; l = 0; u = 31; break; + case Mips::BI__builtin_mips_balign: i = 2; l = 0; u = 3; break; + case Mips::BI__builtin_mips_precr_sra_ph_w: i = 2; l = 0; u = 31; break; + case Mips::BI__builtin_mips_precr_sra_r_ph_w: i = 2; l = 0; u = 31; break; + case Mips::BI__builtin_mips_prepend: i = 2; l = 0; u = 31; break; }; // We can't check the value of a dependent argument. @@ -490,9 +495,8 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args, SourceLocation Loc, SourceRange Range, VariadicCallType CallType) { - // FIXME: This mechanism should be abstracted to be less fragile and - // more efficient. For example, just map function ids to custom - // handlers. + if (CurContext->isDependentContext()) + return; // Printf and scanf checking. bool HandledFormatString = false; @@ -506,8 +510,11 @@ void Sema::checkCall(NamedDecl *FDecl, Expr **Args, // Refuse POD arguments that weren't caught by the format string // checks above. if (!HandledFormatString && CallType != VariadicDoesNotApply) - for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx) - variadicArgumentPODCheck(Args[ArgIdx], CallType); + for (unsigned ArgIdx = NumProtoArgs; ArgIdx < NumArgs; ++ArgIdx) { + // Args[ArgIdx] can be null in malformed code. + if (Expr *Arg = Args[ArgIdx]) + variadicArgumentPODCheck(Arg, CallType); + } for (specific_attr_iterator<NonNullAttr> I = FDecl->specific_attr_begin<NonNullAttr>(), @@ -538,11 +545,23 @@ void Sema::CheckConstructorCall(FunctionDecl *FDecl, Expr **Args, /// and safety properties not strictly enforced by the C type system. bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, const FunctionProtoType *Proto) { - bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall); + bool IsMemberOperatorCall = isa<CXXOperatorCallExpr>(TheCall) && + isa<CXXMethodDecl>(FDecl); + bool IsMemberFunction = isa<CXXMemberCallExpr>(TheCall) || + IsMemberOperatorCall; VariadicCallType CallType = getVariadicCallType(FDecl, Proto, TheCall->getCallee()); unsigned NumProtoArgs = Proto ? Proto->getNumArgs() : 0; - checkCall(FDecl, TheCall->getArgs(), TheCall->getNumArgs(), NumProtoArgs, + Expr** Args = TheCall->getArgs(); + unsigned NumArgs = TheCall->getNumArgs(); + if (IsMemberOperatorCall) { + // If this is a call to a member operator, hide the first argument + // from checkCall. + // FIXME: Our choice of AST representation here is less than ideal. + ++Args; + --NumArgs; + } + checkCall(FDecl, Args, NumArgs, NumProtoArgs, IsMemberFunction, TheCall->getRParenLoc(), TheCall->getCallee()->getSourceRange(), CallType); @@ -737,6 +756,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } + if (AtomTy.isConstQualified()) { + Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_atomic) + << Ptr->getType() << Ptr->getSourceRange(); + return ExprError(); + } ValType = AtomTy->getAs<AtomicType>()->getValueType(); } @@ -885,8 +909,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, } return Owned(new (Context) AtomicExpr(TheCall->getCallee()->getLocStart(), - SubExprs.data(), SubExprs.size(), - ResultType, Op, + SubExprs, ResultType, Op, TheCall->getRParenLoc())); } @@ -1189,10 +1212,19 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // concrete integer type we should convert to is. unsigned NewBuiltinID = BuiltinIndices[BuiltinIndex][SizeIndex]; const char *NewBuiltinName = Context.BuiltinInfo.GetName(NewBuiltinID); - IdentifierInfo *NewBuiltinII = PP.getIdentifierInfo(NewBuiltinName); - FunctionDecl *NewBuiltinDecl = - cast<FunctionDecl>(LazilyCreateBuiltin(NewBuiltinII, NewBuiltinID, - TUScope, false, DRE->getLocStart())); + FunctionDecl *NewBuiltinDecl; + if (NewBuiltinID == BuiltinID) + NewBuiltinDecl = FDecl; + else { + // Perform builtin lookup to avoid redeclaring it. + DeclarationName DN(&Context.Idents.get(NewBuiltinName)); + LookupResult Res(*this, DN, DRE->getLocStart(), LookupOrdinaryName); + LookupName(Res, TUScope, /*AllowBuiltinCreation=*/true); + assert(Res.getFoundDecl()); + NewBuiltinDecl = dyn_cast<FunctionDecl>(Res.getFoundDecl()); + if (NewBuiltinDecl == 0) + return ExprError(); + } // The first argument --- the pointer --- has a fixed type; we // deduce the types of the rest of the arguments accordingly. Walk @@ -1228,14 +1260,14 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { NewBuiltinDecl, /*enclosing*/ false, DRE->getLocation(), - NewBuiltinDecl->getType(), + Context.BuiltinFnTy, DRE->getValueKind()); // Set the callee in the CallExpr. - // FIXME: This leaks the original parens and implicit casts. - ExprResult PromotedCall = UsualUnaryConversions(NewDRE); - if (PromotedCall.isInvalid()) - return ExprError(); + // FIXME: This loses syntactic information. + QualType CalleePtrTy = Context.getPointerType(NewBuiltinDecl->getType()); + ExprResult PromotedCall = ImpCastExprToType(NewDRE, CalleePtrTy, + CK_BuiltinFnToFnPtr); TheCall->setCallee(PromotedCall.take()); // Change the result type of the call to match the original value type. This @@ -1243,7 +1275,7 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // gracefully. TheCall->setType(ResultType); - return move(TheCallResult); + return TheCallResult; } /// CheckObjCString - Checks that the argument to the builtin @@ -1264,7 +1296,7 @@ bool Sema::CheckObjCString(Expr *Arg) { StringRef String = Literal->getString(); unsigned NumBytes = String.size(); SmallVector<UTF16, 128> ToBuf(NumBytes); - const UTF8 *FromPtr = (UTF8 *)String.data(); + const UTF8 *FromPtr = (const UTF8 *)String.data(); UTF16 *ToPtr = &ToBuf[0]; ConversionResult Result = ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, @@ -1503,8 +1535,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { TheCall->setArg(i, 0); } - return Owned(new (Context) ShuffleVectorExpr(Context, exprs.begin(), - exprs.size(), resType, + return Owned(new (Context) ShuffleVectorExpr(Context, exprs, resType, TheCall->getCallee()->getLocStart(), TheCall->getRParenLoc())); } @@ -1935,19 +1966,19 @@ public: void HandleIncompleteSpecifier(const char *startSpecifier, unsigned specifierLen); + void HandleInvalidLengthModifier( + const analyze_format_string::FormatSpecifier &FS, + const analyze_format_string::ConversionSpecifier &CS, + const char *startSpecifier, unsigned specifierLen, unsigned DiagID); + void HandleNonStandardLengthModifier( - const analyze_format_string::LengthModifier &LM, + const analyze_format_string::FormatSpecifier &FS, const char *startSpecifier, unsigned specifierLen); void HandleNonStandardConversionSpecifier( const analyze_format_string::ConversionSpecifier &CS, const char *startSpecifier, unsigned specifierLen); - void HandleNonStandardConversionSpecification( - const analyze_format_string::LengthModifier &LM, - const analyze_format_string::ConversionSpecifier &CS, - const char *startSpecifier, unsigned specifierLen); - virtual void HandlePosition(const char *startPos, unsigned posLen); virtual void HandleInvalidPosition(const char *startSpecifier, @@ -1964,7 +1995,7 @@ public: PartialDiagnostic PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, - FixItHint Fixit = FixItHint()); + ArrayRef<FixItHint> Fixit = ArrayRef<FixItHint>()); protected: bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, @@ -1991,7 +2022,7 @@ protected: template <typename Range> void EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation StringLoc, bool IsStringLocation, Range StringRange, - FixItHint Fixit = FixItHint()); + ArrayRef<FixItHint> Fixit = ArrayRef<FixItHint>()); void CheckPositionalAndNonpositionalArgs( const analyze_format_string::FormatSpecifier *FS); @@ -2025,35 +2056,95 @@ void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier, getSpecifierRange(startSpecifier, specifierLen)); } +void CheckFormatHandler::HandleInvalidLengthModifier( + const analyze_format_string::FormatSpecifier &FS, + const analyze_format_string::ConversionSpecifier &CS, + const char *startSpecifier, unsigned specifierLen, unsigned DiagID) { + using namespace analyze_format_string; + + const LengthModifier &LM = FS.getLengthModifier(); + CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength()); + + // See if we know how to fix this length modifier. + llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier(); + if (FixedLM) { + EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(), + getLocationOfByte(LM.getStart()), + /*IsStringLocation*/true, + getSpecifierRange(startSpecifier, specifierLen)); + + S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier) + << FixedLM->toString() + << FixItHint::CreateReplacement(LMRange, FixedLM->toString()); + + } else { + FixItHint Hint; + if (DiagID == diag::warn_format_nonsensical_length) + Hint = FixItHint::CreateRemoval(LMRange); + + EmitFormatDiagnostic(S.PDiag(DiagID) << LM.toString() << CS.toString(), + getLocationOfByte(LM.getStart()), + /*IsStringLocation*/true, + getSpecifierRange(startSpecifier, specifierLen), + Hint); + } +} + void CheckFormatHandler::HandleNonStandardLengthModifier( - const analyze_format_string::LengthModifier &LM, + const analyze_format_string::FormatSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { - EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << LM.toString() - << 0, - getLocationOfByte(LM.getStart()), - /*IsStringLocation*/true, - getSpecifierRange(startSpecifier, specifierLen)); + using namespace analyze_format_string; + + const LengthModifier &LM = FS.getLengthModifier(); + CharSourceRange LMRange = getSpecifierRange(LM.getStart(), LM.getLength()); + + // See if we know how to fix this length modifier. + llvm::Optional<LengthModifier> FixedLM = FS.getCorrectedLengthModifier(); + if (FixedLM) { + EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) + << LM.toString() << 0, + getLocationOfByte(LM.getStart()), + /*IsStringLocation*/true, + getSpecifierRange(startSpecifier, specifierLen)); + + S.Diag(getLocationOfByte(LM.getStart()), diag::note_format_fix_specifier) + << FixedLM->toString() + << FixItHint::CreateReplacement(LMRange, FixedLM->toString()); + + } else { + EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) + << LM.toString() << 0, + getLocationOfByte(LM.getStart()), + /*IsStringLocation*/true, + getSpecifierRange(startSpecifier, specifierLen)); + } } void CheckFormatHandler::HandleNonStandardConversionSpecifier( const analyze_format_string::ConversionSpecifier &CS, const char *startSpecifier, unsigned specifierLen) { - EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) << CS.toString() - << 1, - getLocationOfByte(CS.getStart()), - /*IsStringLocation*/true, - getSpecifierRange(startSpecifier, specifierLen)); -} + using namespace analyze_format_string; -void CheckFormatHandler::HandleNonStandardConversionSpecification( - const analyze_format_string::LengthModifier &LM, - const analyze_format_string::ConversionSpecifier &CS, - const char *startSpecifier, unsigned specifierLen) { - EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard_conversion_spec) - << LM.toString() << CS.toString(), - getLocationOfByte(LM.getStart()), - /*IsStringLocation*/true, - getSpecifierRange(startSpecifier, specifierLen)); + // See if we know how to fix this conversion specifier. + llvm::Optional<ConversionSpecifier> FixedCS = CS.getStandardSpecifier(); + if (FixedCS) { + EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) + << CS.toString() << /*conversion specifier*/1, + getLocationOfByte(CS.getStart()), + /*IsStringLocation*/true, + getSpecifierRange(startSpecifier, specifierLen)); + + CharSourceRange CSRange = getSpecifierRange(CS.getStart(), CS.getLength()); + S.Diag(getLocationOfByte(CS.getStart()), diag::note_format_fix_specifier) + << FixedCS->toString() + << FixItHint::CreateReplacement(CSRange, FixedCS->toString()); + } else { + EmitFormatDiagnostic(S.PDiag(diag::warn_format_non_standard) + << CS.toString() << /*conversion specifier*/1, + getLocationOfByte(CS.getStart()), + /*IsStringLocation*/true, + getSpecifierRange(startSpecifier, specifierLen)); + } } void CheckFormatHandler::HandlePosition(const char *startPos, @@ -2182,7 +2273,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag, SourceLocation Loc, bool IsStringLocation, Range StringRange, - FixItHint FixIt) { + ArrayRef<FixItHint> FixIt) { EmitFormatDiagnostic(S, inFunctionCall, Args[FormatIdx], PDiag, Loc, IsStringLocation, StringRange, FixIt); } @@ -2190,7 +2281,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag, /// \brief If the format string is not within the funcion call, emit a note /// so that the function call and string are in diagnostic messages. /// -/// \param inFunctionCall if true, the format string is within the function +/// \param InFunctionCall if true, the format string is within the function /// call and only one diagnostic message will be produced. Otherwise, an /// extra note will be emitted pointing to location of the format string. /// @@ -2213,7 +2304,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag, /// \param StringRange some or all of the string to highlight. This is /// templated so it can accept either a CharSourceRange or a SourceRange. /// -/// \param Fixit optional fix it hint for the format string. +/// \param FixIt optional fix it hint for the format string. template<typename Range> void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall, const Expr *ArgumentExpr, @@ -2221,15 +2312,27 @@ void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall, SourceLocation Loc, bool IsStringLocation, Range StringRange, - FixItHint FixIt) { - if (InFunctionCall) - S.Diag(Loc, PDiag) << StringRange << FixIt; - else { + ArrayRef<FixItHint> FixIt) { + if (InFunctionCall) { + const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag); + D << StringRange; + for (ArrayRef<FixItHint>::iterator I = FixIt.begin(), E = FixIt.end(); + I != E; ++I) { + D << *I; + } + } else { S.Diag(IsStringLocation ? ArgumentExpr->getExprLoc() : Loc, PDiag) << ArgumentExpr->getSourceRange(); - S.Diag(IsStringLocation ? Loc : StringRange.getBegin(), - diag::note_format_string_defined) - << StringRange << FixIt; + + const Sema::SemaDiagnosticBuilder &Note = + S.Diag(IsStringLocation ? Loc : StringRange.getBegin(), + diag::note_format_string_defined); + + Note << StringRange; + for (ArrayRef<FixItHint>::iterator I = FixIt.begin(), E = FixIt.end(); + I != E; ++I) { + Note << *I; + } } } @@ -2550,23 +2653,17 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier startSpecifier, specifierLen); // Check the length modifier is valid with the given conversion specifier. - const LengthModifier &LM = FS.getLengthModifier(); - if (!FS.hasValidLengthModifier()) - EmitFormatDiagnostic(S.PDiag(diag::warn_format_nonsensical_length) - << LM.toString() << CS.toString(), - getLocationOfByte(LM.getStart()), - /*IsStringLocation*/true, - getSpecifierRange(startSpecifier, specifierLen), - FixItHint::CreateRemoval( - getSpecifierRange(LM.getStart(), - LM.getLength()))); - if (!FS.hasStandardLengthModifier()) - HandleNonStandardLengthModifier(LM, startSpecifier, specifierLen); + if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo())) + HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, + diag::warn_format_nonsensical_length); + else if (!FS.hasStandardLengthModifier()) + HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen); + else if (!FS.hasStandardLengthConversionCombination()) + HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, + diag::warn_format_non_standard_conversion_spec); + if (!FS.hasStandardConversionSpecifier(S.getLangOpts())) HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen); - if (!FS.hasStandardLengthConversionCombination()) - HandleNonStandardConversionSpecification(LM, CS, startSpecifier, - specifierLen); // The remaining checks depend on the data arguments. if (HasVAListArg) @@ -2582,6 +2679,30 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier return checkFormatExpr(FS, startSpecifier, specifierLen, Arg); } +static bool requiresParensToAddCast(const Expr *E) { + // FIXME: We should have a general way to reason about operator + // precedence and whether parens are actually needed here. + // Take care of a few common cases where they aren't. + const Expr *Inside = E->IgnoreImpCasts(); + if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(Inside)) + Inside = POE->getSyntacticForm()->IgnoreImpCasts(); + + switch (Inside->getStmtClass()) { + case Stmt::ArraySubscriptExprClass: + case Stmt::CallExprClass: + case Stmt::DeclRefExprClass: + case Stmt::MemberExprClass: + case Stmt::ObjCIvarRefExprClass: + case Stmt::ObjCMessageExprClass: + case Stmt::ObjCPropertyRefExprClass: + case Stmt::ParenExprClass: + case Stmt::UnaryOperatorClass: + return false; + default: + return true; + } +} + bool CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier, @@ -2593,81 +2714,151 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // format specifier. const analyze_printf::ArgType &AT = FS.getArgType(S.Context, ObjCContext); - if (AT.isValid() && !AT.matchesType(S.Context, E->getType())) { - // Look through argument promotions for our error message's reported type. - // This includes the integral and floating promotions, but excludes array - // and function pointer decay; seeing that an argument intended to be a - // string has type 'char [6]' is probably more confusing than 'char *'. - if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { - if (ICE->getCastKind() == CK_IntegralCast || - ICE->getCastKind() == CK_FloatingCast) { - E = ICE->getSubExpr(); - - // Check if we didn't match because of an implicit cast from a 'char' - // or 'short' to an 'int'. This is done because printf is a varargs - // function. - if (ICE->getType() == S.Context.IntTy || - ICE->getType() == S.Context.UnsignedIntTy) { - // All further checking is done on the subexpression. - if (AT.matchesType(S.Context, E->getType())) - return true; - } + if (!AT.isValid()) + return true; + + QualType IntendedTy = E->getType(); + if (AT.matchesType(S.Context, IntendedTy)) + return true; + + // Look through argument promotions for our error message's reported type. + // This includes the integral and floating promotions, but excludes array + // and function pointer decay; seeing that an argument intended to be a + // string has type 'char [6]' is probably more confusing than 'char *'. + if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { + if (ICE->getCastKind() == CK_IntegralCast || + ICE->getCastKind() == CK_FloatingCast) { + E = ICE->getSubExpr(); + IntendedTy = E->getType(); + + // Check if we didn't match because of an implicit cast from a 'char' + // or 'short' to an 'int'. This is done because printf is a varargs + // function. + if (ICE->getType() == S.Context.IntTy || + ICE->getType() == S.Context.UnsignedIntTy) { + // All further checking is done on the subexpression. + if (AT.matchesType(S.Context, IntendedTy)) + return true; } } + } - // We may be able to offer a FixItHint if it is a supported type. - PrintfSpecifier fixedFS = FS; - bool success = fixedFS.fixType(E->getType(), S.getLangOpts(), - S.Context, ObjCContext); + if (S.Context.getTargetInfo().getTriple().isOSDarwin()) { + // Special-case some of Darwin's platform-independence types. + if (const TypedefType *UserTy = IntendedTy->getAs<TypedefType>()) { + StringRef Name = UserTy->getDecl()->getName(); + IntendedTy = llvm::StringSwitch<QualType>(Name) + .Case("NSInteger", S.Context.LongTy) + .Case("NSUInteger", S.Context.UnsignedLongTy) + .Case("SInt32", S.Context.IntTy) + .Case("UInt32", S.Context.UnsignedIntTy) + .Default(IntendedTy); + } + } - if (success) { - // Get the fix string from the fixed format specifier - SmallString<16> buf; - llvm::raw_svector_ostream os(buf); - fixedFS.toString(os); + // We may be able to offer a FixItHint if it is a supported type. + PrintfSpecifier fixedFS = FS; + bool success = fixedFS.fixType(IntendedTy, S.getLangOpts(), + S.Context, ObjCContext); + + if (success) { + // Get the fix string from the fixed format specifier + SmallString<16> buf; + llvm::raw_svector_ostream os(buf); + fixedFS.toString(os); + + CharSourceRange SpecRange = getSpecifierRange(StartSpecifier, SpecifierLen); + + if (IntendedTy != E->getType()) { + // The canonical type for formatting this value is different from the + // actual type of the expression. (This occurs, for example, with Darwin's + // NSInteger on 32-bit platforms, where it is typedef'd as 'int', but + // should be printed as 'long' for 64-bit compatibility.) + // Rather than emitting a normal format/argument mismatch, we want to + // add a cast to the recommended type (and correct the format string + // if necessary). + SmallString<16> CastBuf; + llvm::raw_svector_ostream CastFix(CastBuf); + CastFix << "("; + IntendedTy.print(CastFix, S.Context.getPrintingPolicy()); + CastFix << ")"; + + SmallVector<FixItHint,4> Hints; + if (!AT.matchesType(S.Context, IntendedTy)) + Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); + + if (const CStyleCastExpr *CCast = dyn_cast<CStyleCastExpr>(E)) { + // If there's already a cast present, just replace it. + SourceRange CastRange(CCast->getLParenLoc(), CCast->getRParenLoc()); + Hints.push_back(FixItHint::CreateReplacement(CastRange, CastFix.str())); + + } else if (!requiresParensToAddCast(E)) { + // If the expression has high enough precedence, + // just write the C-style cast. + Hints.push_back(FixItHint::CreateInsertion(E->getLocStart(), + CastFix.str())); + } else { + // Otherwise, add parens around the expression as well as the cast. + CastFix << "("; + Hints.push_back(FixItHint::CreateInsertion(E->getLocStart(), + CastFix.str())); + + SourceLocation After = S.PP.getLocForEndOfToken(E->getLocEnd()); + Hints.push_back(FixItHint::CreateInsertion(After, ")")); + } + // We extract the name from the typedef because we don't want to show + // the underlying type in the diagnostic. + const TypedefType *UserTy = cast<TypedefType>(E->getType()); + StringRef Name = UserTy->getDecl()->getName(); + + // Finally, emit the diagnostic. + EmitFormatDiagnostic(S.PDiag(diag::warn_format_argument_needs_cast) + << Name << IntendedTy + << E->getSourceRange(), + E->getLocStart(), /*IsStringLocation=*/false, + SpecRange, Hints); + } else { EmitFormatDiagnostic( S.PDiag(diag::warn_printf_conversion_argument_type_mismatch) - << AT.getRepresentativeTypeName(S.Context) << E->getType() + << AT.getRepresentativeTypeName(S.Context) << IntendedTy << E->getSourceRange(), E->getLocStart(), /*IsStringLocation*/false, - getSpecifierRange(StartSpecifier, SpecifierLen), - FixItHint::CreateReplacement( - getSpecifierRange(StartSpecifier, SpecifierLen), - os.str())); - } else { - const CharSourceRange &CSR = getSpecifierRange(StartSpecifier, - SpecifierLen); - // Since the warning for passing non-POD types to variadic functions - // was deferred until now, we emit a warning for non-POD - // arguments here. - if (S.isValidVarArgType(E->getType()) == Sema::VAK_Invalid) { - unsigned DiagKind; - if (E->getType()->isObjCObjectType()) - DiagKind = diag::err_cannot_pass_objc_interface_to_vararg_format; - else - DiagKind = diag::warn_non_pod_vararg_with_format_string; - - EmitFormatDiagnostic( - S.PDiag(DiagKind) - << S.getLangOpts().CPlusPlus0x - << E->getType() - << CallType - << AT.getRepresentativeTypeName(S.Context) - << CSR - << E->getSourceRange(), - E->getLocStart(), /*IsStringLocation*/false, CSR); - - checkForCStrMembers(AT, E, CSR); - } else - EmitFormatDiagnostic( - S.PDiag(diag::warn_printf_conversion_argument_type_mismatch) - << AT.getRepresentativeTypeName(S.Context) << E->getType() - << CSR - << E->getSourceRange(), - E->getLocStart(), /*IsStringLocation*/false, CSR); + SpecRange, + FixItHint::CreateReplacement(SpecRange, os.str())); } + } else { + const CharSourceRange &CSR = getSpecifierRange(StartSpecifier, + SpecifierLen); + // Since the warning for passing non-POD types to variadic functions + // was deferred until now, we emit a warning for non-POD + // arguments here. + if (S.isValidVarArgType(E->getType()) == Sema::VAK_Invalid) { + unsigned DiagKind; + if (E->getType()->isObjCObjectType()) + DiagKind = diag::err_cannot_pass_objc_interface_to_vararg_format; + else + DiagKind = diag::warn_non_pod_vararg_with_format_string; + + EmitFormatDiagnostic( + S.PDiag(DiagKind) + << S.getLangOpts().CPlusPlus0x + << E->getType() + << CallType + << AT.getRepresentativeTypeName(S.Context) + << CSR + << E->getSourceRange(), + E->getLocStart(), /*IsStringLocation*/false, CSR); + + checkForCStrMembers(AT, E, CSR); + } else + EmitFormatDiagnostic( + S.PDiag(diag::warn_printf_conversion_argument_type_mismatch) + << AT.getRepresentativeTypeName(S.Context) << E->getType() + << CSR + << E->getSourceRange(), + E->getLocStart(), /*IsStringLocation*/false, CSR); } return true; @@ -2776,24 +2967,17 @@ bool CheckScanfHandler::HandleScanfSpecifier( } // Check the length modifier is valid with the given conversion specifier. - const LengthModifier &LM = FS.getLengthModifier(); - if (!FS.hasValidLengthModifier()) { - const CharSourceRange &R = getSpecifierRange(LM.getStart(), LM.getLength()); - EmitFormatDiagnostic(S.PDiag(diag::warn_format_nonsensical_length) - << LM.toString() << CS.toString() - << getSpecifierRange(startSpecifier, specifierLen), - getLocationOfByte(LM.getStart()), - /*IsStringLocation*/true, R, - FixItHint::CreateRemoval(R)); - } + if (!FS.hasValidLengthModifier(S.getASTContext().getTargetInfo())) + HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, + diag::warn_format_nonsensical_length); + else if (!FS.hasStandardLengthModifier()) + HandleNonStandardLengthModifier(FS, startSpecifier, specifierLen); + else if (!FS.hasStandardLengthConversionCombination()) + HandleInvalidLengthModifier(FS, CS, startSpecifier, specifierLen, + diag::warn_format_non_standard_conversion_spec); - if (!FS.hasStandardLengthModifier()) - HandleNonStandardLengthModifier(LM, startSpecifier, specifierLen); if (!FS.hasStandardConversionSpecifier(S.getLangOpts())) HandleNonStandardConversionSpecifier(CS, startSpecifier, specifierLen); - if (!FS.hasStandardLengthConversionCombination()) - HandleNonStandardConversionSpecification(LM, CS, startSpecifier, - specifierLen); // The remaining checks depend on the data arguments. if (HasVAListArg) @@ -2881,7 +3065,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, inFunctionCall, CallType); if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, - getLangOpts())) + getLangOpts(), + Context.getTargetInfo())) H.DoneProcessing(); } else if (Type == FST_Scanf) { CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, @@ -2889,7 +3074,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, inFunctionCall, CallType); if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen, - getLangOpts())) + getLangOpts(), + Context.getTargetInfo())) H.DoneProcessing(); } // TODO: handle other formats } @@ -4138,6 +4324,44 @@ static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { } } +static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, + Expr *Constant, Expr *Other, + llvm::APSInt Value, + bool RhsConstant) { + BinaryOperatorKind op = E->getOpcode(); + QualType OtherT = Other->getType(); + QualType ConstantT = Constant->getType(); + if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT)) + return; + assert((OtherT->isIntegerType() && ConstantT->isIntegerType()) + && "comparison with non-integer type"); + // FIXME. handle cases for signedness to catch (signed char)N == 200 + IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); + IntRange LitRange = GetValueRange(S.Context, Value, Value.getBitWidth()); + if (OtherRange.Width >= LitRange.Width) + return; + bool IsTrue = true; + if (op == BO_EQ) + IsTrue = false; + else if (op == BO_NE) + IsTrue = true; + else if (RhsConstant) { + if (op == BO_GT || op == BO_GE) + IsTrue = !LitRange.NonNegative; + else // op == BO_LT || op == BO_LE + IsTrue = LitRange.NonNegative; + } else { + if (op == BO_LT || op == BO_LE) + IsTrue = !LitRange.NonNegative; + else // op == BO_GT || op == BO_GE + IsTrue = LitRange.NonNegative; + } + SmallString<16> PrettySourceValue(Value.toString(10)); + S.Diag(E->getOperatorLoc(), diag::warn_out_of_range_compare) + << PrettySourceValue << OtherT << IsTrue + << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange(); +} + /// Analyze the operands of the given comparison. Implements the /// fallback case from AnalyzeComparison. static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { @@ -4153,20 +4377,42 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) { QualType T = E->getLHS()->getType(); assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType()) && "comparison with mismatched types"); + if (E->isValueDependent()) + return AnalyzeImpConvsInComparison(S, E); + Expr *LHS = E->getLHS()->IgnoreParenImpCasts(); + Expr *RHS = E->getRHS()->IgnoreParenImpCasts(); + + bool IsComparisonConstant = false; + + // Check whether an integer constant comparison results in a value + // of 'true' or 'false'. + if (T->isIntegralType(S.Context)) { + llvm::APSInt RHSValue; + bool IsRHSIntegralLiteral = + RHS->isIntegerConstantExpr(RHSValue, S.Context); + llvm::APSInt LHSValue; + bool IsLHSIntegralLiteral = + LHS->isIntegerConstantExpr(LHSValue, S.Context); + if (IsRHSIntegralLiteral && !IsLHSIntegralLiteral) + DiagnoseOutOfRangeComparison(S, E, RHS, LHS, RHSValue, true); + else if (!IsRHSIntegralLiteral && IsLHSIntegralLiteral) + DiagnoseOutOfRangeComparison(S, E, LHS, RHS, LHSValue, false); + else + IsComparisonConstant = + (IsRHSIntegralLiteral && IsLHSIntegralLiteral); + } else if (!T->hasUnsignedIntegerRepresentation()) + IsComparisonConstant = E->isIntegerConstantExpr(S.Context); + // We don't do anything special if this isn't an unsigned integral // comparison: we're only interested in integral comparisons, and // signed comparisons only happen in cases we don't care to warn about. // // We also don't care about value-dependent expressions or expressions // whose result is a constant. - if (!T->hasUnsignedIntegerRepresentation() - || E->isValueDependent() || E->isIntegerConstantExpr(S.Context)) + if (!T->hasUnsignedIntegerRepresentation() || IsComparisonConstant) return AnalyzeImpConvsInComparison(S, E); - - Expr *LHS = E->getLHS()->IgnoreParenImpCasts(); - Expr *RHS = E->getRHS()->IgnoreParenImpCasts(); - + // Check to see if one of the (unmodified) operands is of different // signedness. Expr *signedOperand, *unsignedOperand; @@ -4353,6 +4599,46 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { return ValueInRange.toString(10); } +static bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { + if (!isa<ImplicitCastExpr>(Ex)) + return false; + + Expr *InnerE = Ex->IgnoreParenImpCasts(); + const Type *Target = S.Context.getCanonicalType(Ex->getType()).getTypePtr(); + const Type *Source = + S.Context.getCanonicalType(InnerE->getType()).getTypePtr(); + if (Target->isDependentType()) + return false; + + const BuiltinType *FloatCandidateBT = + dyn_cast<BuiltinType>(ToBool ? Source : Target); + const Type *BoolCandidateType = ToBool ? Target : Source; + + return (BoolCandidateType->isSpecificBuiltinType(BuiltinType::Bool) && + FloatCandidateBT && (FloatCandidateBT->isFloatingPoint())); +} + +void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall, + SourceLocation CC) { + unsigned NumArgs = TheCall->getNumArgs(); + for (unsigned i = 0; i < NumArgs; ++i) { + Expr *CurrA = TheCall->getArg(i); + if (!IsImplicitBoolFloatConversion(S, CurrA, true)) + continue; + + bool IsSwapped = ((i > 0) && + IsImplicitBoolFloatConversion(S, TheCall->getArg(i - 1), false)); + IsSwapped |= ((i < (NumArgs - 1)) && + IsImplicitBoolFloatConversion(S, TheCall->getArg(i + 1), false)); + if (IsSwapped) { + // Warn on this floating-point to bool conversion. + DiagnoseImpCast(S, CurrA->IgnoreParenImpCasts(), + CurrA->getType(), CC, + diag::warn_impcast_floating_point_to_bool); + } + } +} + void CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, bool *ICContext = 0) { if (E->isTypeDependent() || E->isValueDependent()) return; @@ -4488,12 +4774,33 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } } + // If the target is bool, warn if expr is a function or method call. + if (Target->isSpecificBuiltinType(BuiltinType::Bool) && + isa<CallExpr>(E)) { + // Check last argument of function call to see if it is an + // implicit cast from a type matching the type the result + // is being cast to. + CallExpr *CEx = cast<CallExpr>(E); + unsigned NumArgs = CEx->getNumArgs(); + if (NumArgs > 0) { + Expr *LastA = CEx->getArg(NumArgs - 1); + Expr *InnerE = LastA->IgnoreParenImpCasts(); + const Type *InnerType = + S.Context.getCanonicalType(InnerE->getType()).getTypePtr(); + if (isa<ImplicitCastExpr>(LastA) && (InnerType == Target)) { + // Warn on this floating-point to bool conversion + DiagnoseImpCast(S, E, T, CC, + diag::warn_impcast_floating_point_to_bool); + } + } + } return; } if ((E->isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) == Expr::NPCK_GNUNull) && !Target->isAnyPointerType() - && !Target->isBlockPointerType() && !Target->isMemberPointerType()) { + && !Target->isBlockPointerType() && !Target->isMemberPointerType() + && Target->isScalarType()) { SourceLocation Loc = E->getSourceRange().getBegin(); if (Loc.isMacroID()) Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first; @@ -4658,6 +4965,10 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { return; } + // Check implicit argument conversions for function calls. + if (CallExpr *Call = dyn_cast<CallExpr>(E)) + CheckImplicitArgumentConversions(S, Call, CC); + // Go ahead and check any implicit conversions we might have skipped. // The non-canonical typecheck is just an optimization; // CheckImplicitConversion will filter out dead implicit conversions. @@ -5077,7 +5388,8 @@ static bool considerVariable(VarDecl *var, Expr *ref, RetainCycleOwner &owner) { return false; owner.Variable = var; - owner.setLocsFrom(ref); + if (ref) + owner.setLocsFrom(ref); return true; } @@ -5186,6 +5498,12 @@ namespace { if (block->getBlockDecl()->capturesVariable(Variable)) Visit(block->getBlockDecl()->getBody()); } + + void VisitOpaqueValueExpr(OpaqueValueExpr *OVE) { + if (Capturer) return; + if (OVE->getSourceExpr()) + Visit(OVE->getSourceExpr()); + } }; } @@ -5195,6 +5513,28 @@ static Expr *findCapturingExpr(Sema &S, Expr *e, RetainCycleOwner &owner) { assert(owner.Variable && owner.Loc.isValid()); e = e->IgnoreParenCasts(); + + // Look through [^{...} copy] and Block_copy(^{...}). + if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(e)) { + Selector Cmd = ME->getSelector(); + if (Cmd.isUnarySelector() && Cmd.getNameForSlot(0) == "copy") { + e = ME->getInstanceReceiver(); + if (!e) + return 0; + e = e->IgnoreParenCasts(); + } + } else if (CallExpr *CE = dyn_cast<CallExpr>(e)) { + if (CE->getNumArgs() == 1) { + FunctionDecl *Fn = dyn_cast_or_null<FunctionDecl>(CE->getCalleeDecl()); + if (Fn) { + const IdentifierInfo *FnI = Fn->getIdentifier(); + if (FnI && FnI->isStr("_Block_copy")) { + e = CE->getArg(0)->IgnoreParenCasts(); + } + } + } + } + BlockExpr *block = dyn_cast<BlockExpr>(e); if (!block || !block->getBlockDecl()->capturesVariable(owner.Variable)) return 0; @@ -5271,6 +5611,20 @@ void Sema::checkRetainCycles(Expr *receiver, Expr *argument) { diagnoseRetainCycle(*this, capturer, owner); } +void Sema::checkRetainCycles(VarDecl *Var, Expr *Init) { + RetainCycleOwner Owner; + if (!considerVariable(Var, /*DeclRefExpr=*/0, Owner)) + return; + + // Because we don't have an expression for the variable, we have to set the + // location explicitly here. + Owner.Loc = Var->getLocation(); + Owner.Range = Var->getSourceRange(); + + if (Expr *Capturer = findCapturingExpr(*this, Init, Owner)) + diagnoseRetainCycle(*this, Capturer, Owner); +} + bool Sema::checkUnsafeAssigns(SourceLocation Loc, QualType LHS, Expr *RHS) { Qualifiers::ObjCLifetime LT = LHS.getObjCLifetime(); @@ -5304,9 +5658,19 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, if (LHSType.isNull()) LHSType = LHS->getType(); + + Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime(); + + if (LT == Qualifiers::OCL_Weak) { + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, Loc); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->markSafeWeakUse(LHS); + } + if (checkUnsafeAssigns(Loc, LHSType, RHS)) return; - Qualifiers::ObjCLifetime LT = LHSType.getObjCLifetime(); + // FIXME. Check for other life times. if (LT != Qualifiers::OCL_None) return; @@ -5826,7 +6190,8 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, if (IsPointerAttr) { // Skip implicit cast of pointer to `void *' (as a function argument). if (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(ArgumentExpr)) - if (ICE->getType()->isVoidPointerType()) + if (ICE->getType()->isVoidPointerType() && + ICE->getCastKind() == CK_BitCast) ArgumentExpr = ICE->getSubExpr(); } QualType ArgumentType = ArgumentExpr->getType(); @@ -5881,4 +6246,3 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, << ArgumentExpr->getSourceRange() << TypeTagExpr->getSourceRange(); } - diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index adf132715738..b1aead8f026d 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -1059,10 +1059,12 @@ bool ResultBuilder::IsClassOrStruct(NamedDecl *ND) const { // Allow us to find class templates, too. if (ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(ND)) ND = ClassTemplate->getTemplatedDecl(); - + + // For purposes of this check, interfaces match too. if (RecordDecl *RD = dyn_cast<RecordDecl>(ND)) return RD->getTagKind() == TTK_Class || - RD->getTagKind() == TTK_Struct; + RD->getTagKind() == TTK_Struct || + RD->getTagKind() == TTK_Interface; return false; } @@ -1422,7 +1424,8 @@ static const char *GetCompletionTypeString(QualType T, if (!Tag->getIdentifier() && !Tag->getTypedefNameForAnonDecl()) { switch (Tag->getTagKind()) { case TTK_Struct: return "struct <anonymous>"; - case TTK_Class: return "class <anonymous>"; + case TTK_Interface: return "__interface <anonymous>"; + case TTK_Class: return "class <anonymous>"; case TTK_Union: return "union <anonymous>"; case TTK_Enum: return "enum <anonymous>"; } @@ -1449,7 +1452,7 @@ static void addThisCompletion(Sema &S, ResultBuilder &Results) { Policy, Allocator)); Builder.AddTypedTextChunk("this"); - Results.AddResult(CodeCompletionResult(Builder.TakeString())); + Results.AddResult(CodeCompletionResult(Builder.TakeString())); } /// \brief Add language constructs that show up for "ordinary" names. @@ -2480,7 +2483,6 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, if (Declaration) { Result.addParentContext(Declaration->getDeclContext()); - Pattern->ParentKind = Result.getParentKind(); Pattern->ParentName = Result.getParentName(); } @@ -2493,7 +2495,7 @@ CodeCompletionResult::CreateCodeCompletionString(ASTContext &Ctx, } if (Kind == RK_Macro) { - MacroInfo *MI = PP.getMacroInfo(Macro); + MacroInfo *MI = PP.getMacroInfoHistory(Macro); assert(MI && "Not a macro?"); Result.AddTypedTextChunk( @@ -2880,10 +2882,14 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) { case ObjCPropertyImplDecl::Synthesize: return CXCursor_ObjCSynthesizeDecl; } + + case Decl::Import: + return CXCursor_ModuleImportDecl; default: if (TagDecl *TD = dyn_cast<TagDecl>(D)) { switch (TD->getTagKind()) { + case TTK_Interface: // fall through case TTK_Struct: return CXCursor_StructDecl; case TTK_Class: return CXCursor_ClassDecl; case TTK_Union: return CXCursor_UnionDecl; @@ -2896,6 +2902,7 @@ CXCursorKind clang::getCursorKindForDecl(Decl *D) { } static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results, + bool IncludeUndefined, bool TargetTypeIsPointer = false) { typedef CodeCompletionResult Result; @@ -2904,7 +2911,8 @@ static void AddMacroResults(Preprocessor &PP, ResultBuilder &Results, for (Preprocessor::macro_iterator M = PP.macro_begin(), MEnd = PP.macro_end(); M != MEnd; ++M) { - Results.AddResult(Result(M->first, + if (IncludeUndefined || M->first->hasMacroDefinition()) + Results.AddResult(Result(M->first, getMacroUsagePriority(M->first->getName(), PP.getLangOpts(), TargetTypeIsPointer))); @@ -3125,7 +3133,6 @@ void Sema::CodeCompleteModuleImport(SourceLocation ImportLoc, void Sema::CodeCompleteOrdinaryName(Scope *S, ParserCompletionContext CompletionContext) { - typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), mapCodeCompletionContext(*this, CompletionContext)); @@ -3204,7 +3211,7 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, } if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); + AddMacroResults(PP, Results, false); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); @@ -3296,7 +3303,6 @@ struct Sema::CodeCompleteExpressionData { /// type we're looking for. void Sema::CodeCompleteExpression(Scope *S, const CodeCompleteExpressionData &Data) { - typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Expression); @@ -3336,7 +3342,7 @@ void Sema::CodeCompleteExpression(Scope *S, AddPrettyFunctionResults(PP.getLangOpts(), Results); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results, PreferredTypeIsPointer); + AddMacroResults(PP, Results, false, PreferredTypeIsPointer); HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext(CodeCompletionContext::CCC_Expression, Data.PreferredType), @@ -3580,7 +3586,6 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { if (!CodeCompleter) return; - typedef CodeCompletionResult Result; ResultBuilder::LookupFilter Filter = 0; enum CodeCompletionContext::Kind ContextKind = CodeCompletionContext::CCC_Other; @@ -3597,6 +3602,7 @@ void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { case DeclSpec::TST_struct: case DeclSpec::TST_class: + case DeclSpec::TST_interface: Filter = &ResultBuilder::IsClassOrStruct; ContextKind = CodeCompletionContext::CCC_ClassOrStructTag; break; @@ -3728,7 +3734,7 @@ void Sema::CodeCompleteCase(Scope *S) { //so only say we include macros if the code completer says we do enum CodeCompletionContext::Kind kind = CodeCompletionContext::CCC_Other; if (CodeCompleter->includeMacros()) { - AddMacroResults(PP, Results); + AddMacroResults(PP, Results, false); kind = CodeCompletionContext::CCC_OtherWithMacros; } @@ -3898,7 +3904,6 @@ void Sema::CodeCompleteReturn(Scope *S) { } void Sema::CodeCompleteAfterIf(Scope *S) { - typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), mapCodeCompletionContext(*this, PCC_Statement)); @@ -3952,7 +3957,7 @@ void Sema::CodeCompleteAfterIf(Scope *S) { AddPrettyFunctionResults(PP.getLangOpts(), Results); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); + AddMacroResults(PP, Results, false); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(),Results.size()); @@ -4408,7 +4413,6 @@ static void AddObjCTopLevelResults(ResultBuilder &Results, bool NeedAt) { } void Sema::CodeCompleteObjCAtDirective(Scope *S) { - typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); @@ -4595,26 +4599,23 @@ static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) { // Check for collisions with "readonly". if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && - (Attributes & (ObjCDeclSpec::DQ_PR_readwrite | - ObjCDeclSpec::DQ_PR_assign | - ObjCDeclSpec::DQ_PR_unsafe_unretained | - ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain | - ObjCDeclSpec::DQ_PR_strong))) + (Attributes & ObjCDeclSpec::DQ_PR_readwrite)) return true; - // Check for more than one of { assign, copy, retain, strong }. + // Check for more than one of { assign, copy, retain, strong, weak }. unsigned AssignCopyRetMask = Attributes & (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_unsafe_unretained | ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain| - ObjCDeclSpec::DQ_PR_strong); + ObjCDeclSpec::DQ_PR_retain | + ObjCDeclSpec::DQ_PR_strong | + ObjCDeclSpec::DQ_PR_weak); if (AssignCopyRetMask && AssignCopyRetMask != ObjCDeclSpec::DQ_PR_assign && AssignCopyRetMask != ObjCDeclSpec::DQ_PR_unsafe_unretained && AssignCopyRetMask != ObjCDeclSpec::DQ_PR_copy && AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain && - AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong) + AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong && + AssignCopyRetMask != ObjCDeclSpec::DQ_PR_weak) return true; return false; @@ -4626,7 +4627,6 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { unsigned Attributes = ODS.getPropertyAttributes(); - typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); @@ -4650,6 +4650,12 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { Results.AddResult(CodeCompletionResult("nonatomic")); if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_atomic)) Results.AddResult(CodeCompletionResult("atomic")); + + // Only suggest "weak" if we're compiling for ARC-with-weak-references or GC. + if (getLangOpts().ObjCARCWeak || getLangOpts().getGC() != LangOptions::NonGC) + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_weak)) + Results.AddResult(CodeCompletionResult("weak")); + if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) { CodeCompletionBuilder Setter(Results.getAllocator(), Results.getCodeCompletionTUInfo()); @@ -4837,8 +4843,6 @@ static void AddObjCMethods(ObjCContainerDecl *Container, void Sema::CodeCompleteObjCPropertyGetter(Scope *S) { - typedef CodeCompletionResult Result; - // Try to find the interface where getters might live. ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurContext); if (!Class) { @@ -4866,8 +4870,6 @@ void Sema::CodeCompleteObjCPropertyGetter(Scope *S) { } void Sema::CodeCompleteObjCPropertySetter(Scope *S) { - typedef CodeCompletionResult Result; - // Try to find the interface where setters might live. ObjCInterfaceDecl *Class = dyn_cast_or_null<ObjCInterfaceDecl>(CurContext); @@ -4898,7 +4900,6 @@ void Sema::CodeCompleteObjCPropertySetter(Scope *S) { void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, bool IsParameter) { - typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Type); @@ -4957,7 +4958,7 @@ void Sema::CodeCompleteObjCPassingType(Scope *S, ObjCDeclSpec &DS, CodeCompleter->includeGlobals()); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); + AddMacroResults(PP, Results, false); HandleCodeCompleteResults(this, CodeCompleter, CodeCompletionContext::CCC_Type, @@ -5041,7 +5042,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { /// /// \param S The semantic analysis object. /// -/// \param S NeedSuperKeyword Whether we need to prefix this completion with +/// \param NeedSuperKeyword Whether we need to prefix this completion with /// the "super" keyword. Otherwise, we just need to provide the arguments. /// /// \param SelIdents The identifiers in the selector that have already been @@ -5187,7 +5188,7 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { Results.ExitScope(); if (CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); + AddMacroResults(PP, Results, false); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); @@ -5339,11 +5340,11 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, // If we have an external source, load the entire class method // pool from the AST file. - if (SemaRef.ExternalSource) { + if (SemaRef.getExternalSource()) { for (uint32_t I = 0, - N = SemaRef.ExternalSource->GetNumExternalSelectors(); + N = SemaRef.getExternalSource()->GetNumExternalSelectors(); I != N; ++I) { - Selector Sel = SemaRef.ExternalSource->GetExternalSelector(I); + Selector Sel = SemaRef.getExternalSource()->GetExternalSelector(I); if (Sel.isNull() || SemaRef.MethodPool.count(Sel)) continue; @@ -5868,7 +5869,6 @@ void Sema::CodeCompleteObjCImplementationCategory(Scope *S, } void Sema::CodeCompleteObjCPropertyDefinition(Scope *S) { - typedef CodeCompletionResult Result; ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); @@ -7169,7 +7169,9 @@ void Sema::CodeCompletePreprocessorMacroName(bool IsDefinition) { M != MEnd; ++M) { Builder.AddTypedTextChunk(Builder.getAllocator().CopyString( M->first->getName())); - Results.AddResult(Builder.TakeString()); + Results.AddResult(CodeCompletionResult(Builder.TakeString(), + CCP_CodePattern, + CXCursor_MacroDefinition)); } Results.ExitScope(); } else if (IsDefinition) { @@ -7186,7 +7188,7 @@ void Sema::CodeCompletePreprocessorExpression() { CodeCompletionContext::CCC_PreprocessorExpression); if (!CodeCompleter || CodeCompleter->includeMacros()) - AddMacroResults(PP, Results); + AddMacroResults(PP, Results, true); // defined (<macro>) Results.EnterNewScope(); @@ -7235,7 +7237,7 @@ void Sema::GatherGlobalCodeCompletions(CodeCompletionAllocator &Allocator, } if (!CodeCompleter || CodeCompleter->includeMacros()) - AddMacroResults(PP, Builder); + AddMacroResults(PP, Builder, true); Results.clear(); Results.insert(Results.end(), diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ea181de00a98..0092d5dab1f4 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -350,8 +350,8 @@ ParsedType Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, /// isTagName() - This method is called *for error recovery purposes only* /// to determine if the specified name is a valid tag name ("struct foo"). If /// so, this returns the TST for the tag corresponding to it (TST_enum, -/// TST_union, TST_struct, TST_class). This is used to diagnose cases in C -/// where the user forgot to specify the tag. +/// TST_union, TST_struct, TST_interface, TST_class). This is used to diagnose +/// cases in C where the user forgot to specify the tag. DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { // Do a tag name lookup in this scope. LookupResult R(*this, &II, SourceLocation(), LookupTagName); @@ -361,6 +361,7 @@ DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { if (const TagDecl *TD = R.getAsSingle<TagDecl>()) { switch (TD->getTagKind()) { case TTK_Struct: return DeclSpec::TST_struct; + case TTK_Interface: return DeclSpec::TST_interface; case TTK_Union: return DeclSpec::TST_union; case TTK_Class: return DeclSpec::TST_class; case TTK_Enum: return DeclSpec::TST_enum; @@ -434,7 +435,8 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, else if (DeclContext *DC = computeDeclContext(*SS, false)) Diag(IILoc, diag::err_unknown_nested_typename_suggest) << II << DC << CorrectedQuotedStr << SS->getRange() - << FixItHint::CreateReplacement(SourceRange(IILoc), CorrectedStr); + << FixItHint::CreateReplacement(Corrected.getCorrectionRange(), + CorrectedStr); else llvm_unreachable("could not have corrected a typo here"); @@ -517,9 +519,9 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc) { - Result.clear(Sema::LookupTagName); - SemaRef.LookupParsedName(Result, S, &SS); - if (TagDecl *Tag = Result.getAsSingle<TagDecl>()) { + LookupResult R(SemaRef, Name, NameLoc, Sema::LookupTagName); + SemaRef.LookupParsedName(R, S, &SS); + if (TagDecl *Tag = R.getAsSingle<TagDecl>()) { const char *TagName = 0; const char *FixItTagName = 0; switch (Tag->getTagKind()) { @@ -538,6 +540,11 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, FixItTagName = "struct "; break; + case TTK_Interface: + TagName = "__interface"; + FixItTagName = "__interface "; + break; + case TTK_Union: TagName = "union"; FixItTagName = "union "; @@ -548,25 +555,42 @@ static bool isTagTypeWithMissingTag(Sema &SemaRef, LookupResult &Result, << Name << TagName << SemaRef.getLangOpts().CPlusPlus << FixItHint::CreateInsertion(NameLoc, FixItTagName); - LookupResult R(SemaRef, Name, NameLoc, Sema::LookupOrdinaryName); - if (SemaRef.LookupParsedName(R, S, &SS)) { - for (LookupResult::iterator I = R.begin(), IEnd = R.end(); - I != IEnd; ++I) - SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type) - << Name << TagName; - } + for (LookupResult::iterator I = Result.begin(), IEnd = Result.end(); + I != IEnd; ++I) + SemaRef.Diag((*I)->getLocation(), diag::note_decl_hiding_tag_type) + << Name << TagName; + + // Replace lookup results with just the tag decl. + Result.clear(Sema::LookupTagName); + SemaRef.LookupParsedName(Result, S, &SS); return true; } - Result.clear(Sema::LookupOrdinaryName); return false; } +/// Build a ParsedType for a simple-type-specifier with a nested-name-specifier. +static ParsedType buildNestedType(Sema &S, CXXScopeSpec &SS, + QualType T, SourceLocation NameLoc) { + ASTContext &Context = S.Context; + + TypeLocBuilder Builder; + Builder.pushTypeSpec(T).setNameLoc(NameLoc); + + T = S.getElaboratedType(ETK_None, SS, T); + ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T); + ElabTL.setElaboratedKeywordLoc(SourceLocation()); + ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); + return S.CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); +} + Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, SourceLocation NameLoc, - const Token &NextToken) { + const Token &NextToken, + bool IsAddressOfOperand, + CorrectionCandidateCallback *CCC) { DeclarationNameInfo NameInfo(Name, NameLoc); ObjCMethodDecl *CurMethod = getCurMethodDecl(); @@ -632,25 +656,11 @@ Corrected: // Perform typo correction to determine if there is another name that is // close to this name. - if (!SecondTry) { + if (!SecondTry && CCC) { SecondTry = true; - CorrectionCandidateCallback DefaultValidator; - // Try to limit which sets of keywords should be included in typo - // correction based on what the next token is. - DefaultValidator.WantTypeSpecifiers = - NextToken.is(tok::l_paren) || NextToken.is(tok::less) || - NextToken.is(tok::identifier) || NextToken.is(tok::star) || - NextToken.is(tok::amp) || NextToken.is(tok::l_square); - DefaultValidator.WantExpressionKeywords = - NextToken.is(tok::l_paren) || NextToken.is(tok::identifier) || - NextToken.is(tok::arrow) || NextToken.is(tok::period); - DefaultValidator.WantRemainingKeywords = - NextToken.is(tok::l_paren) || NextToken.is(tok::semi) || - NextToken.is(tok::identifier) || NextToken.is(tok::l_brace); - DefaultValidator.WantCXXNamedCasts = false; if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S, - &SS, DefaultValidator)) { + &SS, *CCC)) { unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; unsigned QualifiedDiag = diag::err_no_member_suggest; std::string CorrectedStr(Corrected.getAsString(getLangOpts())); @@ -675,11 +685,12 @@ Corrected: Diag(NameLoc, UnqualifiedDiag) << Name << CorrectedQuotedStr << FixItHint::CreateReplacement(NameLoc, CorrectedStr); - else + else // FIXME: is this even reachable? Test it. Diag(NameLoc, QualifiedDiag) << Name << computeDeclContext(SS, false) << CorrectedQuotedStr << SS.getRange() - << FixItHint::CreateReplacement(NameLoc, CorrectedStr); + << FixItHint::CreateReplacement(Corrected.getCorrectionRange(), + CorrectedStr); // Update the name, so that the caller has the new name. Name = Corrected.getCorrectionAsIdentifierInfo(); @@ -705,7 +716,7 @@ Corrected: if (ObjCIvarDecl *Ivar = Result.getAsSingle<ObjCIvarDecl>()) { Result.clear(); ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier())); - return move(E); + return E; } goto Corrected; @@ -731,8 +742,9 @@ Corrected: // perform some heroics to see if we actually have a // template-argument-list, which would indicate a missing 'template' // keyword here. - return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), - NameInfo, /*TemplateArgs=*/0); + return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(), + NameInfo, IsAddressOfOperand, + /*TemplateArgs=*/0); } case LookupResult::Found: @@ -808,14 +820,16 @@ Corrected: return NameClassification::TypeTemplate(Template); } } - + NamedDecl *FirstDecl = (*Result.begin())->getUnderlyingDecl(); if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) { DiagnoseUseOfDecl(Type, NameLoc); QualType T = Context.getTypeDeclType(Type); + if (SS.isNotEmpty()) + return buildNestedType(*this, SS, T, NameLoc); return ParsedType::make(T); } - + ObjCInterfaceDecl *Class = dyn_cast<ObjCInterfaceDecl>(FirstDecl); if (!Class) { // FIXME: It's unfortunate that we don't have a Type node for handling this. @@ -838,24 +852,28 @@ Corrected: return ParsedType::make(T); } + // We can have a type template here if we're classifying a template argument. + if (isa<TemplateDecl>(FirstDecl) && !isa<FunctionTemplateDecl>(FirstDecl)) + return NameClassification::TypeTemplate( + TemplateName(cast<TemplateDecl>(FirstDecl))); + // Check for a tag type hidden by a non-type decl in a few cases where it // seems likely a type is wanted instead of the non-type that was found. - if (!getLangOpts().ObjC1 && FirstDecl && !isa<ClassTemplateDecl>(FirstDecl) && - !isa<TypeAliasTemplateDecl>(FirstDecl)) { + if (!getLangOpts().ObjC1) { bool NextIsOp = NextToken.is(tok::amp) || NextToken.is(tok::star); if ((NextToken.is(tok::identifier) || (NextIsOp && FirstDecl->isFunctionOrFunctionTemplate())) && isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) { - FirstDecl = (*Result.begin())->getUnderlyingDecl(); - if (TypeDecl *Type = dyn_cast<TypeDecl>(FirstDecl)) { - DiagnoseUseOfDecl(Type, NameLoc); - QualType T = Context.getTypeDeclType(Type); - return ParsedType::make(T); - } + TypeDecl *Type = Result.getAsSingle<TypeDecl>(); + DiagnoseUseOfDecl(Type, NameLoc); + QualType T = Context.getTypeDeclType(Type); + if (SS.isNotEmpty()) + return buildNestedType(*this, SS, T, NameLoc); + return ParsedType::make(T); } } - if (!Result.empty() && (*Result.begin())->isCXXClassMember()) + if (FirstDecl->isCXXClassMember()) return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, 0); bool ADL = UseArgumentDependentLookup(SS, Result, NextToken.is(tok::l_paren)); @@ -1186,8 +1204,14 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { Context.DeclMustBeEmitted(FD)) return false; } else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { + // Don't warn on variables of const-qualified or reference type, since their + // values can be used even if though they're not odr-used, and because const + // qualified variables can appear in headers in contexts where they're not + // intended to be used. + // FIXME: Use more principled rules for these exemptions. if (!VD->isFileVarDecl() || - VD->getType().isConstant(Context) || + VD->getType().isConstQualified() || + VD->getType()->isReferenceType() || Context.DeclMustBeEmitted(VD)) return false; @@ -1248,7 +1272,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { QualType Ty = VD->getType(); // Only look at the outermost level of typedef. - if (const TypedefType *TT = dyn_cast<TypedefType>(Ty)) { + if (const TypedefType *TT = Ty->getAs<TypedefType>()) { if (TT->getDecl()->hasAttr<UnusedAttr>()) return false; } @@ -1268,6 +1292,8 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { return false; if (const Expr *Init = VD->getInit()) { + if (const ExprWithCleanups *Cleanups = dyn_cast<ExprWithCleanups>(Init)) + Init = Cleanups->getSubExpr(); const CXXConstructExpr *Construct = dyn_cast<CXXConstructExpr>(Init); if (Construct && !Construct->isElidable()) { @@ -1706,6 +1732,25 @@ DeclHasAttr(const Decl *D, const Attr *A) { if (AA) return false; + // The following thread safety attributes can also be duplicated. + switch (A->getKind()) { + case attr::ExclusiveLocksRequired: + case attr::SharedLocksRequired: + case attr::LocksExcluded: + case attr::ExclusiveLockFunction: + case attr::SharedLockFunction: + case attr::UnlockFunction: + case attr::ExclusiveTrylockFunction: + case attr::SharedTrylockFunction: + case attr::GuardedBy: + case attr::PtGuardedBy: + case attr::AcquiredBefore: + case attr::AcquiredAfter: + return false; + default: + ; + } + const OwnershipAttr *OA = dyn_cast<OwnershipAttr>(A); const AnnotateAttr *Ann = dyn_cast<AnnotateAttr>(A); for (Decl::attr_iterator i = D->attr_begin(), e = D->attr_end(); i != e; ++i) @@ -1908,6 +1953,19 @@ static bool canRedefineFunction(const FunctionDecl *FD, FD->getStorageClass() == SC_Extern); } +/// Is the given calling convention the ABI default for the given +/// declaration? +static bool isABIDefaultCC(Sema &S, CallingConv CC, FunctionDecl *D) { + CallingConv ABIDefaultCC; + if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance()) { + ABIDefaultCC = S.Context.getDefaultCXXMethodCallConv(D->isVariadic()); + } else { + // Free C function or a static method. + ABIDefaultCC = (S.Context.getLangOpts().MRTD ? CC_X86StdCall : CC_C); + } + return ABIDefaultCC == CC; +} + /// MergeFunctionDecl - We just parsed a function 'New' from /// declarator D which has the same name and scope as a previous /// declaration 'Old'. Figure out how to resolve this situation, @@ -1976,6 +2034,9 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { // later declared or defined without one, the second decl assumes the // calling convention of the first. // + // It's OK if a function is first declared without a calling convention, + // but is later declared or defined with the default calling convention. + // // For the new decl, we have to look at the NON-canonical type to tell the // difference between a function that really doesn't have a calling // convention and one that is declared cdecl. That's because in @@ -1989,10 +2050,22 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); bool RequiresAdjustment = false; - if (OldTypeInfo.getCC() != CC_Default && - NewTypeInfo.getCC() == CC_Default) { + if (OldTypeInfo.getCC() == NewTypeInfo.getCC()) { + // Fast path: nothing to do. + + // Inherit the CC from the previous declaration if it was specified + // there but not here. + } else if (NewTypeInfo.getCC() == CC_Default) { NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); RequiresAdjustment = true; + + // Don't complain about mismatches when the default CC is + // effectively the same as the explict one. + } else if (OldTypeInfo.getCC() == CC_Default && + isABIDefaultCC(*this, NewTypeInfo.getCC(), New)) { + NewTypeInfo = NewTypeInfo.withCallingConv(OldTypeInfo.getCC()); + RequiresAdjustment = true; + } else if (!Context.isSameCallConv(OldTypeInfo.getCC(), NewTypeInfo.getCC())) { // Calling conventions really aren't compatible, so complain. @@ -2398,7 +2471,7 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old) { } if (MergedT.isNull()) { Diag(New->getLocation(), diag::err_redefinition_different_type) - << New->getDeclName(); + << New->getDeclName() << New->getType() << Old->getType(); Diag(Old->getLocation(), diag::note_previous_definition); return New->setInvalidDecl(); } @@ -2551,8 +2624,7 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { /// no declarator (e.g. "struct foo;") is parsed. Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS) { - return ParsedFreeStandingDeclSpec(S, AS, DS, - MultiTemplateParamsArg(*this, 0, 0)); + return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg()); } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with @@ -2565,6 +2637,7 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, TagDecl *Tag = 0; if (DS.getTypeSpecType() == DeclSpec::TST_class || DS.getTypeSpecType() == DeclSpec::TST_struct || + DS.getTypeSpecType() == DeclSpec::TST_interface || DS.getTypeSpecType() == DeclSpec::TST_union || DS.getTypeSpecType() == DeclSpec::TST_enum) { TagD = DS.getRepAsDecl(); @@ -2603,7 +2676,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_tag) << (DS.getTypeSpecType() == DeclSpec::TST_class ? 0 : DS.getTypeSpecType() == DeclSpec::TST_struct ? 1 : - DS.getTypeSpecType() == DeclSpec::TST_union ? 2 : 3); + DS.getTypeSpecType() == DeclSpec::TST_interface ? 2 : + DS.getTypeSpecType() == DeclSpec::TST_union ? 3 : 4); else Diag(DS.getConstexprSpecLoc(), diag::err_constexpr_no_declarators); // Don't emit warnings after this error. @@ -2724,16 +2798,17 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec::TST TypeSpecType = DS.getTypeSpecType(); if (TypeSpecType == DeclSpec::TST_class || TypeSpecType == DeclSpec::TST_struct || + TypeSpecType == DeclSpec::TST_interface || TypeSpecType == DeclSpec::TST_union || TypeSpecType == DeclSpec::TST_enum) { AttributeList* attrs = DS.getAttributes().getList(); while (attrs) { - Diag(attrs->getScopeLoc(), - diag::warn_declspec_attribute_ignored) + Diag(attrs->getLoc(), diag::warn_declspec_attribute_ignored) << attrs->getName() << (TypeSpecType == DeclSpec::TST_class ? 0 : TypeSpecType == DeclSpec::TST_struct ? 1 : - TypeSpecType == DeclSpec::TST_union ? 2 : 3); + TypeSpecType == DeclSpec::TST_union ? 2 : + TypeSpecType == DeclSpec::TST_interface ? 3 : 4); attrs = attrs->getNext(); } } @@ -3353,7 +3428,6 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, switch (DS.getTypeSpecType()) { case DeclSpec::TST_typename: case DeclSpec::TST_typeofType: - case DeclSpec::TST_decltype: case DeclSpec::TST_underlyingType: case DeclSpec::TST_atomic: { // Grab the type from the parser. @@ -3377,6 +3451,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, break; } + case DeclSpec::TST_decltype: case DeclSpec::TST_typeofExpr: { Expr *E = DS.getRepAsExpr(); ExprResult Result = S.RebuildExprInCurrentInstantiation(E); @@ -3411,7 +3486,7 @@ static bool RebuildDeclaratorInCurrentInstantiation(Sema &S, Declarator &D, Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { D.setFunctionDefinitionKind(FDK_Declaration); - Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg(*this)); + Decl *Dcl = HandleDeclarator(S, D, MultiTemplateParamsArg()); if (OriginalLexicalContext && OriginalLexicalContext->isObjCContainer() && Dcl && Dcl->getDeclContext()->isFileContext()) @@ -3476,7 +3551,8 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, // void X::f(); // }; if (Cur->Equals(DC)) { - Diag(Loc, diag::warn_member_extra_qualification) + Diag(Loc, LangOpts.MicrosoftExt? diag::warn_member_extra_qualification + : diag::err_member_extra_qualification) << Name << FixItHint::CreateRemoval(SS.getRange()); SS.clear(); return false; @@ -3710,11 +3786,11 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, New = ActOnTypedefDeclarator(S, D, DC, TInfo, Previous); } else if (R->isFunctionType()) { New = ActOnFunctionDeclarator(S, D, DC, TInfo, Previous, - move(TemplateParamLists), + TemplateParamLists, AddToScope); } else { New = ActOnVariableDeclarator(S, D, DC, TInfo, Previous, - move(TemplateParamLists)); + TemplateParamLists); } if (New == 0) @@ -3729,9 +3805,9 @@ Decl *Sema::HandleDeclarator(Scope *S, Declarator &D, return New; } -/// TryToFixInvalidVariablyModifiedType - Helper method to turn variable array -/// types into constant array types in certain situations which would otherwise -/// be errors (for GCC compatibility). +/// Helper method to turn variable array types into constant array +/// types in certain situations which would otherwise be errors (for +/// GCC compatibility). static QualType TryToFixInvalidVariablyModifiedType(QualType T, ASTContext &Context, bool &SizeIsNegative, @@ -3799,6 +3875,52 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, Res, ArrayType::Normal, 0); } +static void +FixInvalidVariablyModifiedTypeLoc(TypeLoc SrcTL, TypeLoc DstTL) { + if (PointerTypeLoc* SrcPTL = dyn_cast<PointerTypeLoc>(&SrcTL)) { + PointerTypeLoc* DstPTL = cast<PointerTypeLoc>(&DstTL); + FixInvalidVariablyModifiedTypeLoc(SrcPTL->getPointeeLoc(), + DstPTL->getPointeeLoc()); + DstPTL->setStarLoc(SrcPTL->getStarLoc()); + return; + } + if (ParenTypeLoc* SrcPTL = dyn_cast<ParenTypeLoc>(&SrcTL)) { + ParenTypeLoc* DstPTL = cast<ParenTypeLoc>(&DstTL); + FixInvalidVariablyModifiedTypeLoc(SrcPTL->getInnerLoc(), + DstPTL->getInnerLoc()); + DstPTL->setLParenLoc(SrcPTL->getLParenLoc()); + DstPTL->setRParenLoc(SrcPTL->getRParenLoc()); + return; + } + ArrayTypeLoc* SrcATL = cast<ArrayTypeLoc>(&SrcTL); + ArrayTypeLoc* DstATL = cast<ArrayTypeLoc>(&DstTL); + TypeLoc SrcElemTL = SrcATL->getElementLoc(); + TypeLoc DstElemTL = DstATL->getElementLoc(); + DstElemTL.initializeFullCopy(SrcElemTL); + DstATL->setLBracketLoc(SrcATL->getLBracketLoc()); + DstATL->setSizeExpr(SrcATL->getSizeExpr()); + DstATL->setRBracketLoc(SrcATL->getRBracketLoc()); +} + +/// Helper method to turn variable array types into constant array +/// types in certain situations which would otherwise be errors (for +/// GCC compatibility). +static TypeSourceInfo* +TryToFixInvalidVariablyModifiedTypeSourceInfo(TypeSourceInfo *TInfo, + ASTContext &Context, + bool &SizeIsNegative, + llvm::APSInt &Oversized) { + QualType FixedTy + = TryToFixInvalidVariablyModifiedType(TInfo->getType(), Context, + SizeIsNegative, Oversized); + if (FixedTy.isNull()) + return 0; + TypeSourceInfo *FixedTInfo = Context.getTrivialTypeSourceInfo(FixedTy); + FixInvalidVariablyModifiedTypeLoc(TInfo->getTypeLoc(), + FixedTInfo->getTypeLoc()); + return FixedTInfo; +} + /// \brief Register the given locally-scoped external C declaration so /// that it can be found later for redeclarations void @@ -3926,19 +4048,21 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) { // then it shall have block scope. // Note that variably modified types must be fixed before merging the decl so // that redeclarations will match. - QualType T = NewTD->getUnderlyingType(); + TypeSourceInfo *TInfo = NewTD->getTypeSourceInfo(); + QualType T = TInfo->getType(); if (T->isVariablyModifiedType()) { getCurFunction()->setHasBranchProtectedScope(); if (S->getFnParent() == 0) { bool SizeIsNegative; llvm::APSInt Oversized; - QualType FixedTy = - TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, - Oversized); - if (!FixedTy.isNull()) { + TypeSourceInfo *FixedTInfo = + TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, + SizeIsNegative, + Oversized); + if (FixedTInfo) { Diag(NewTD->getLocation(), diag::warn_illegal_constant_array_size); - NewTD->setTypeSourceInfo(Context.getTrivialTypeSourceInfo(FixedTy)); + NewTD->setTypeSourceInfo(FixedTInfo); } else { if (SizeIsNegative) Diag(NewTD->getLocation(), diag::err_typecheck_negative_array_size); @@ -4203,7 +4327,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), D.getCXXScopeSpec(), - TemplateParamLists.get(), + TemplateParamLists.data(), TemplateParamLists.size(), /*never a friend*/ false, isExplicitSpecialization, @@ -4244,7 +4368,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (TemplateParamLists.size() > 0 && D.getCXXScopeSpec().isSet()) { NewVD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), - TemplateParamLists.release()); + TemplateParamLists.data()); } if (D.getDeclSpec().isConstexprSpecified()) @@ -4281,6 +4405,14 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); + if (getLangOpts().CUDA) { + // CUDA B.2.5: "__shared__ and __constant__ variables have implied static + // storage [duration]." + if (SC == SC_None && S->getFnParent() != 0 && + (NewVD->hasAttr<CUDASharedAttr>() || NewVD->hasAttr<CUDAConstantAttr>())) + NewVD->setStorageClass(SC_Static); + } + // In auto-retain/release, infer strong retension for variables of // retainable type. if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(NewVD)) @@ -4490,7 +4622,8 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, if (NewVD->isInvalidDecl()) return false; - QualType T = NewVD->getType(); + TypeSourceInfo *TInfo = NewVD->getTypeSourceInfo(); + QualType T = TInfo->getType(); if (T->isObjCObjectType()) { Diag(NewVD->getLocation(), diag::err_statically_allocated_object) @@ -4522,8 +4655,10 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, && !NewVD->hasAttr<BlocksAttr>()) { if (getLangOpts().getGC() != LangOptions::NonGC) Diag(NewVD->getLocation(), diag::warn_gc_attribute_weak_on_local); - else + else { + assert(!getLangOpts().ObjCAutoRefCount); Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); + } } bool isVM = T->isVariablyModifiedType(); @@ -4535,11 +4670,10 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, (T->isVariableArrayType() && NewVD->hasGlobalStorage())) { bool SizeIsNegative; llvm::APSInt Oversized; - QualType FixedTy = - TryToFixInvalidVariablyModifiedType(T, Context, SizeIsNegative, - Oversized); - - if (FixedTy.isNull() && T->isVariableArrayType()) { + TypeSourceInfo *FixedTInfo = + TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, + SizeIsNegative, Oversized); + if (FixedTInfo == 0 && T->isVariableArrayType()) { const VariableArrayType *VAT = Context.getAsVariableArrayType(T); // FIXME: This won't give the correct result for // int a[10][n]; @@ -4558,7 +4692,7 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, return false; } - if (FixedTy.isNull()) { + if (FixedTInfo == 0) { if (NewVD->isFileVarDecl()) Diag(NewVD->getLocation(), diag::err_vm_decl_in_file_scope); else @@ -4568,7 +4702,8 @@ bool Sema::CheckVariableDeclaration(VarDecl *NewVD, } Diag(NewVD->getLocation(), diag::warn_illegal_constant_array_size); - NewVD->setType(FixedTy); + NewVD->setType(FixedTInfo->getType()); + NewVD->setTypeSourceInfo(FixedTInfo); } if (Previous.empty() && NewVD->isExternC()) { @@ -4655,6 +4790,31 @@ static bool FindOverriddenMethod(const CXXBaseSpecifier *Specifier, return false; } +namespace { + enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted }; +} +/// \brief Report an error regarding overriding, along with any relevant +/// overriden methods. +/// +/// \param DiagID the primary error to report. +/// \param MD the overriding method. +/// \param OEK which overrides to include as notes. +static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD, + OverrideErrorKind OEK = OEK_All) { + S.Diag(MD->getLocation(), DiagID) << MD->getDeclName(); + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); + I != E; ++I) { + // This check (& the OEK parameter) could be replaced by a predicate, but + // without lambdas that would be overkill. This is still nicer than writing + // out the diag loop 3 times. + if ((OEK == OEK_All) || + (OEK == OEK_NonDeleted && !(*I)->isDeleted()) || + (OEK == OEK_Deleted && (*I)->isDeleted())) + S.Diag((*I)->getLocation(), diag::note_overridden_virtual_function); + } +} + /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { @@ -4663,6 +4823,8 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { FindOverriddenMethodData Data; Data.Method = MD; Data.S = this; + bool hasDeletedOverridenMethods = false; + bool hasNonDeletedOverridenMethods = false; bool AddedAny = false; if (DC->lookupInBases(&FindOverriddenMethod, &Data, Paths)) { for (CXXBasePaths::decl_iterator I = Paths.found_decls_begin(), @@ -4672,12 +4834,21 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { if (!CheckOverridingFunctionReturnType(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { + hasDeletedOverridenMethods |= OldMD->isDeleted(); + hasNonDeletedOverridenMethods |= !OldMD->isDeleted(); AddedAny = true; } } } } - + + if (hasDeletedOverridenMethods && !MD->isDeleted()) { + ReportOverrides(*this, diag::err_non_deleted_override, MD, OEK_Deleted); + } + if (hasNonDeletedOverridenMethods && MD->isDeleted()) { + ReportOverrides(*this, diag::err_deleted_override, MD, OEK_NonDeleted); + } + return AddedAny; } @@ -4837,6 +5008,10 @@ static NamedDecl* DiagnoseInvalidRedeclaration( } if (Correction) { + // FIXME: use Correction.getCorrectionRange() instead of computing the range + // here. This requires passing in the CXXScopeSpec to CorrectTypo which in + // turn causes the correction to fully qualify the name. If we fix + // CorrectTypo to minimally qualify then this change should be good. SourceRange FixItLoc(NewFD->getLocation()); CXXScopeSpec &SS = ExtraArgs.D.getCXXScopeSpec(); if (Correction.getCorrectionSpecifier() && SS.isValid()) @@ -5072,6 +5247,22 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, } } +void Sema::checkVoidParamDecl(ParmVarDecl *Param) { + // In C++, the empty parameter-type-list must be spelled "void"; a + // typedef of void is not permitted. + if (getLangOpts().CPlusPlus && + Param->getType().getUnqualifiedType() != Context.VoidTy) { + bool IsTypeAlias = false; + if (const TypedefType *TT = Param->getType()->getAs<TypedefType>()) + IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl()); + else if (const TemplateSpecializationType *TST = + Param->getType()->getAs<TemplateSpecializationType>()) + IsTypeAlias = TST->isTypeAlias(); + Diag(Param->getLocation(), diag::err_param_typedef_of_void) + << IsTypeAlias; + } +} + NamedDecl* Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, @@ -5138,6 +5329,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setImplicitlyInline(); } + // If this is a method defined in an __interface, and is not a constructor + // or an overloaded operator, then set the pure flag (isVirtual will already + // return true). + if (const CXXRecordDecl *Parent = + dyn_cast<CXXRecordDecl>(NewFD->getDeclContext())) { + if (Parent->isInterface() && cast<CXXMethodDecl>(NewFD)->isUserProvided()) + NewFD->setPure(true); + } + SetNestedNameSpecifier(NewFD, D); isExplicitSpecialization = false; isFunctionTemplateSpecialization = false; @@ -5157,7 +5357,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.getDeclSpec().getLocStart(), D.getIdentifierLoc(), D.getCXXScopeSpec(), - TemplateParamLists.get(), + TemplateParamLists.data(), TemplateParamLists.size(), isFriend, isExplicitSpecialization, @@ -5196,7 +5396,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (TemplateParamLists.size() > 1) { NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists.size() - 1, - TemplateParamLists.release()); + TemplateParamLists.data()); } } else { // This is a function template specialization. @@ -5204,7 +5404,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // For source fidelity, store all the template param lists. NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), - TemplateParamLists.release()); + TemplateParamLists.data()); // C++0x [temp.expl.spec]p20 forbids "template<> friend void foo(int);". if (isFriend) { @@ -5236,7 +5436,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // For source fidelity, store all the template param lists. NewFD->setTemplateParameterListsInfo(Context, TemplateParamLists.size(), - TemplateParamLists.release()); + TemplateParamLists.data()); } if (Invalid) { @@ -5376,6 +5576,20 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, diag::err_static_out_of_line) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } + + // C++11 [except.spec]p15: + // A deallocation function with no exception-specification is treated + // as if it were specified with noexcept(true). + const FunctionProtoType *FPT = R->getAs<FunctionProtoType>(); + if ((Name.getCXXOverloadedOperator() == OO_Delete || + Name.getCXXOverloadedOperator() == OO_Array_Delete) && + getLangOpts().CPlusPlus0x && FPT && !FPT->hasExceptionSpec()) { + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExceptionSpecType = EST_BasicNoexcept; + NewFD->setType(Context.getFunctionType(FPT->getResultType(), + FPT->arg_type_begin(), + FPT->getNumArgs(), EPI)); + } } // Filter out previous declarations that don't match the scope. @@ -5413,21 +5627,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, FTI.ArgInfo[0].Param && cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) { // Empty arg list, don't push any params. - ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[0].Param); - - // In C++, the empty parameter-type-list must be spelled "void"; a - // typedef of void is not permitted. - if (getLangOpts().CPlusPlus && - Param->getType().getUnqualifiedType() != Context.VoidTy) { - bool IsTypeAlias = false; - if (const TypedefType *TT = Param->getType()->getAs<TypedefType>()) - IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl()); - else if (const TemplateSpecializationType *TST = - Param->getType()->getAs<TemplateSpecializationType>()) - IsTypeAlias = TST->isTypeAlias(); - Diag(Param->getLocation(), diag::err_param_typedef_of_void) - << IsTypeAlias; - } + checkVoidParamDecl(cast<ParmVarDecl>(FTI.ArgInfo[0].Param)); } else if (FTI.NumArgs > 0 && FTI.ArgInfo[0].Param != 0) { for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param); @@ -5500,6 +5700,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.setRedeclaration(CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization)); } + // Make graceful recovery from an invalid redeclaration. + else if (!Previous.empty()) + D.setRedeclaration(true); assert((NewFD->isInvalidDecl() || !D.isRedeclaration() || Previous.getResultKind() != LookupResult::FoundOverloaded) && "previous declaration set still overloaded"); @@ -5510,12 +5713,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TemplateIdAnnotation *TemplateId = D.getName().TemplateId; TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(*this, - TemplateId->getTemplateArgs(), + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, TemplateArgs); - TemplateArgsPtr.release(); HasExplicitTemplateArgs = true; @@ -5969,20 +6170,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // Find any virtual functions that this function overrides. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD)) { if (!Method->isFunctionTemplateSpecialization() && - !Method->getDescribedFunctionTemplate()) { + !Method->getDescribedFunctionTemplate() && + Method->isCanonicalDecl()) { if (AddOverriddenMethods(Method->getParent(), Method)) { // If the function was marked as "static", we have a problem. if (NewFD->getStorageClass() == SC_Static) { - Diag(NewFD->getLocation(), diag::err_static_overrides_virtual) - << NewFD->getDeclName(); - for (CXXMethodDecl::method_iterator - Overridden = Method->begin_overridden_methods(), - OverriddenEnd = Method->end_overridden_methods(); - Overridden != OverriddenEnd; - ++Overridden) { - Diag((*Overridden)->getLocation(), - diag::note_overridden_virtual_function); - } + ReportOverrides(*this, diag::err_static_overrides_virtual, Method); } } } @@ -6191,28 +6384,12 @@ namespace { } } - // Sometimes, the expression passed in lacks the casts that are used - // to determine which DeclRefExpr's to check. Assume that the casts - // are present and continue visiting the expression. - void HandleExpr(Expr *E) { - // Skip checking T a = a where T is not a record or reference type. - // Doing so is a way to silence uninitialized warnings. - if (isRecordType || isReferenceType) - if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - HandleDeclRefExpr(DRE); - - if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { - HandleValue(CO->getTrueExpr()); - HandleValue(CO->getFalseExpr()); - } - - Visit(E); - } - // For most expressions, the cast is directly above the DeclRefExpr. // For conditional operators, the cast can be outside the conditional // operator if both expressions are DeclRefExpr's. void HandleValue(Expr *E) { + if (isReferenceType) + return; E = E->IgnoreParenImpCasts(); if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(E)) { HandleDeclRefExpr(DRE); @@ -6222,11 +6399,32 @@ namespace { if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { HandleValue(CO->getTrueExpr()); HandleValue(CO->getFalseExpr()); + return; + } + + if (isa<MemberExpr>(E)) { + Expr *Base = E->IgnoreParenImpCasts(); + while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) { + // Check for static member variables and don't warn on them. + if (!isa<FieldDecl>(ME->getMemberDecl())) + return; + Base = ME->getBase()->IgnoreParenImpCasts(); + } + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) + HandleDeclRefExpr(DRE); + return; } } + // Reference types are handled here since all uses of references are + // bad, not just r-value uses. + void VisitDeclRefExpr(DeclRefExpr *E) { + if (isReferenceType) + HandleDeclRefExpr(E); + } + void VisitImplicitCastExpr(ImplicitCastExpr *E) { - if ((!isRecordType && E->getCastKind() == CK_LValueToRValue) || + if (E->getCastKind() == CK_LValueToRValue || (isRecordType && E->getCastKind() == CK_NoOp)) HandleValue(E->getSubExpr()); @@ -6237,22 +6435,36 @@ namespace { // Don't warn on arrays since they can be treated as pointers. if (E->getType()->canDecayToPointerType()) return; - ValueDecl *VD = E->getMemberDecl(); - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(VD); - if (isa<FieldDecl>(VD) || (MD && !MD->isStatic())) - if (DeclRefExpr *DRE - = dyn_cast<DeclRefExpr>(E->getBase()->IgnoreParenImpCasts())) { + // Warn when a non-static method call is followed by non-static member + // field accesses, which is followed by a DeclRefExpr. + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(E->getMemberDecl()); + bool Warn = (MD && !MD->isStatic()); + Expr *Base = E->getBase()->IgnoreParenImpCasts(); + while (MemberExpr *ME = dyn_cast<MemberExpr>(Base)) { + if (!isa<FieldDecl>(ME->getMemberDecl())) + Warn = false; + Base = ME->getBase()->IgnoreParenImpCasts(); + } + + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (Warn) HandleDeclRefExpr(DRE); - return; - } + return; + } - Inherited::VisitMemberExpr(E); + // The base of a MemberExpr is not a MemberExpr or a DeclRefExpr. + // Visit that expression. + Visit(Base); } void VisitUnaryOperator(UnaryOperator *E) { // For POD record types, addresses of its own members are well-defined. - if (E->getOpcode() == UO_AddrOf && isRecordType && isPODType && - isa<MemberExpr>(E->getSubExpr()->IgnoreParens())) return; + if (E->getOpcode() == UO_AddrOf && isRecordType && + isa<MemberExpr>(E->getSubExpr()->IgnoreParens())) { + if (!isPODType) + HandleValue(E->getSubExpr()); + return; + } Inherited::VisitUnaryOperator(E); } @@ -6261,20 +6473,38 @@ namespace { void HandleDeclRefExpr(DeclRefExpr *DRE) { Decl* ReferenceDecl = DRE->getDecl(); if (OrigDecl != ReferenceDecl) return; - LookupResult Result(S, DRE->getNameInfo(), Sema::LookupOrdinaryName, - Sema::NotForRedeclaration); + unsigned diag = isReferenceType + ? diag::warn_uninit_self_reference_in_reference_init + : diag::warn_uninit_self_reference_in_init; S.DiagRuntimeBehavior(DRE->getLocStart(), DRE, - S.PDiag(diag::warn_uninit_self_reference_in_init) - << Result.getLookupName() + S.PDiag(diag) + << DRE->getNameInfo().getName() << OrigDecl->getLocation() << DRE->getSourceRange()); } }; -} -/// CheckSelfReference - Warns if OrigDecl is used in expression E. -void Sema::CheckSelfReference(Decl* OrigDecl, Expr *E) { - SelfReferenceChecker(*this, OrigDecl).HandleExpr(E); + /// CheckSelfReference - Warns if OrigDecl is used in expression E. + static void CheckSelfReference(Sema &S, Decl* OrigDecl, Expr *E, + bool DirectInit) { + // Parameters arguments are occassionially constructed with itself, + // for instance, in recursive functions. Skip them. + if (isa<ParmVarDecl>(OrigDecl)) + return; + + E = E->IgnoreParens(); + + // Skip checking T a = a where T is not a record or reference type. + // Doing so is a way to silence uninitialized warnings. + if (!DirectInit && !cast<VarDecl>(OrigDecl)->getType()->isRecordType()) + if (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) + if (ICE->getCastKind() == CK_LValueToRValue) + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr())) + if (DRE->getDecl() == OrigDecl) + return; + + SelfReferenceChecker(S, OrigDecl).Visit(E); + } } /// AddInitializerToDecl - Adds the initializer Init to the @@ -6311,15 +6541,6 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, return; } - // Check for self-references within variable initializers. - // Variables declared within a function/method body (except for references) - // are handled by a dataflow analysis. - // Record types initialized by initializer list are handled here. - // Initialization by constructors are handled in TryConstructorInitialization. - if ((!VDecl->hasLocalStorage() || VDecl->getType()->isReferenceType()) && - (isa<InitListExpr>(Init) || !VDecl->getType()->isRecordType())) - CheckSelfReference(RealDecl, Init); - ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); // C++11 [decl.spec.auto]p6. Deduce the type which 'auto' stands in for. @@ -6495,8 +6716,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } InitializationSequence InitSeq(*this, Entity, Kind, Args, NumArgs); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, Args,NumArgs), - &DclT); + MultiExprArg(Args, NumArgs), &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); return; @@ -6505,6 +6725,14 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, Init = Result.takeAs<Expr>(); } + // Check for self-references within variable initializers. + // Variables declared within a function/method body (except for references) + // are handled by a dataflow analysis. + if (!VDecl->hasLocalStorage() || VDecl->getType()->isRecordType() || + VDecl->getType()->isReferenceType()) { + CheckSelfReference(*this, RealDecl, Init, DirectInit); + } + // If the type changed, it means we had an incomplete type that was // completed by the initializer. For example: // int ary[] = { 1, 3, 5 }; @@ -6515,9 +6743,28 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Check any implicit conversions within the expression. CheckImplicitConversions(Init, VDecl->getLocation()); - if (!VDecl->isInvalidDecl()) + if (!VDecl->isInvalidDecl()) { checkUnsafeAssigns(VDecl->getLocation(), VDecl->getType(), Init); + if (VDecl->hasAttr<BlocksAttr>()) + checkRetainCycles(VDecl, Init); + + // It is safe to assign a weak reference into a strong variable. + // Although this code can still have problems: + // id x = self.weakProp; + // id y = self.weakProp; + // we do not warn to warn spuriously when 'x' and 'y' are on separate + // paths through the function. This should be revisited if + // -Wrepeated-use-of-weak is made flow-sensitive. + if (VDecl->getType().getObjCLifetime() == Qualifiers::OCL_Strong) { + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, + Init->getLocStart()); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->markSafeWeakUse(Init); + } + } + Init = MaybeCreateExprWithCleanups(Init); // Attach the initializer to the decl. VDecl->setInit(Init); @@ -6758,8 +7005,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, AbstractVariableType)) Var->setInvalidDecl(); if (!Type->isDependentType() && !Var->isInvalidDecl() && - Var->getStorageClass() == SC_PrivateExtern) + Var->getStorageClass() == SC_PrivateExtern) { Diag(Var->getLocation(), diag::warn_private_extern); + Diag(Var->getLocation(), diag::note_private_extern); + } return; @@ -6881,8 +7130,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, = InitializationKind::CreateDefault(Var->getLocation()); InitializationSequence InitSeq(*this, Entity, Kind, 0, 0); - ExprResult Init = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, 0, 0)); + ExprResult Init = InitSeq.Perform(*this, Entity, Kind, MultiExprArg()); if (Init.isInvalid()) Var->setInvalidDecl(); else if (Init.get()) { @@ -6957,11 +7205,22 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { } } + if (var->isThisDeclarationADefinition() && + var->getLinkage() == ExternalLinkage) { + // Find a previous declaration that's not a definition. + VarDecl *prev = var->getPreviousDecl(); + while (prev && prev->isThisDeclarationADefinition()) + prev = prev->getPreviousDecl(); + + if (!prev) + Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var; + } + // All the following checks are C++ only. if (!getLangOpts().CPlusPlus) return; - QualType baseType = Context.getBaseElementType(var->getType()); - if (baseType->isDependentType()) return; + QualType type = var->getType(); + if (type->isDependentType()) return; // __block variables might require us to capture a copy-initializer. if (var->hasAttr<BlocksAttr>()) { @@ -6970,8 +7229,6 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // Regardless, we don't want to ignore array nesting when // constructing this copy. - QualType type = var->getType(); - if (type->isStructureOrClassType()) { SourceLocation poi = var->getLocation(); Expr *varRef =new (Context) DeclRefExpr(var, false, type, VK_LValue, poi); @@ -6989,8 +7246,10 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Expr *Init = var->getInit(); bool IsGlobal = var->hasGlobalStorage() && !var->isStaticLocal(); + QualType baseType = Context.getBaseElementType(type); - if (!var->getDeclContext()->isDependentContext() && Init) { + if (!var->getDeclContext()->isDependentContext() && + Init && !Init->isValueDependent()) { if (IsGlobal && !var->isConstexpr() && getDiagnostics().getDiagnosticLevel(diag::warn_global_constructor, var->getLocation()) @@ -7178,7 +7437,7 @@ void Sema::ActOnDocumentableDecls(Decl **Group, unsigned NumDecls) { // the lookahead in the lexer: we've consumed the semicolon and looked // ahead through comments. for (unsigned i = 0; i != NumDecls; ++i) - Context.getCommentForDecl(Group[i]); + Context.getCommentForDecl(Group[i], &PP); } } @@ -7450,6 +7709,9 @@ void Sema::ActOnFinishKNRParamDeclarations(Scope *S, Declarator &D, unsigned DiagID; // unused DS.SetTypeSpecType(DeclSpec::TST_int, FTI.ArgInfo[i].IdentLoc, PrevSpec, DiagID); + // Use the identifier location for the type source range. + DS.SetRangeStart(FTI.ArgInfo[i].IdentLoc); + DS.SetRangeEnd(FTI.ArgInfo[i].IdentLoc); Declarator ParamD(DS, Declarator::KNRTypeListContext); ParamD.SetIdentifier(FTI.ArgInfo[i].Ident, FTI.ArgInfo[i].IdentLoc); FTI.ArgInfo[i].Param = ActOnParamDeclarator(S, ParamD); @@ -7464,8 +7726,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D) { Scope *ParentScope = FnBodyScope->getParent(); D.setFunctionDefinitionKind(FDK_Definition); - Decl *DP = HandleDeclarator(ParentScope, D, - MultiTemplateParamsArg(*this)); + Decl *DP = HandleDeclarator(ParentScope, D, MultiTemplateParamsArg()); return ActOnStartOfFunctionDef(FnBodyScope, DP); } @@ -7707,7 +7968,7 @@ void Sema::computeNRVO(Stmt *Body, FunctionScopeInfo *Scope) { } Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) { - return ActOnFinishFunctionBody(D, move(BodyArg), false); + return ActOnFinishFunctionBody(D, BodyArg, false); } Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, @@ -7765,22 +8026,16 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (Body) computeNRVO(Body, getCurFunction()); } - if (getCurFunction()->ObjCShouldCallSuperDealloc) { - Diag(MD->getLocEnd(), diag::warn_objc_missing_super_dealloc); - getCurFunction()->ObjCShouldCallSuperDealloc = false; - } - if (getCurFunction()->ObjCShouldCallSuperFinalize) { - Diag(MD->getLocEnd(), diag::warn_objc_missing_super_finalize); - getCurFunction()->ObjCShouldCallSuperFinalize = false; + if (getCurFunction()->ObjCShouldCallSuper) { + Diag(MD->getLocEnd(), diag::warn_objc_missing_super_call) + << MD->getSelector().getAsString(); + getCurFunction()->ObjCShouldCallSuper = false; } } else { return 0; } - assert(!getCurFunction()->ObjCShouldCallSuperDealloc && - "This should only be set for ObjC methods, which should have been " - "handled in the block above."); - assert(!getCurFunction()->ObjCShouldCallSuperFinalize && + assert(!getCurFunction()->ObjCShouldCallSuper && "This should only be set for ObjC methods, which should have been " "handled in the block above."); @@ -7916,13 +8171,28 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, bool Error = DS.SetTypeSpecType(DeclSpec::TST_int, Loc, Dummy, DiagID); (void)Error; // Silence warning. assert(!Error && "Error setting up implicit decl!"); + SourceLocation NoLoc; Declarator D(DS, Declarator::BlockContext); - D.AddTypeInfo(DeclaratorChunk::getFunction(false, false, false, - SourceLocation(), 0, 0, 0, true, - SourceLocation(), SourceLocation(), - SourceLocation(), SourceLocation(), - EST_None, SourceLocation(), - 0, 0, 0, 0, Loc, Loc, D), + D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false, + /*IsAmbiguous=*/false, + /*RParenLoc=*/NoLoc, + /*ArgInfo=*/0, + /*NumArgs=*/0, + /*EllipsisLoc=*/NoLoc, + /*RParenLoc=*/NoLoc, + /*TypeQuals=*/0, + /*RefQualifierIsLvalueRef=*/true, + /*RefQualifierLoc=*/NoLoc, + /*ConstQualifierLoc=*/NoLoc, + /*VolatileQualifierLoc=*/NoLoc, + /*MutableLoc=*/NoLoc, + EST_None, + /*ESpecLoc=*/NoLoc, + /*Exceptions=*/0, + /*ExceptionRanges=*/0, + /*NumExceptions=*/0, + /*NoexceptExpr=*/0, + Loc, Loc, D), DS.getAttributes(), SourceLocation()); D.SetIdentifier(&II, Loc); @@ -8071,6 +8341,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, switch (D.getDeclSpec().getTypeSpecType()) { case TST_enum: case TST_struct: + case TST_interface: case TST_union: case TST_class: { TagDecl *tagFromDeclSpec = cast<TagDecl>(D.getDeclSpec().getRepAsDecl()); @@ -8146,6 +8417,29 @@ bool Sema::CheckEnumRedeclaration(SourceLocation EnumLoc, bool IsScoped, return false; } +/// \brief Get diagnostic %select index for tag kind for +/// redeclaration diagnostic message. +/// WARNING: Indexes apply to particular diagnostics only! +/// +/// \returns diagnostic %select index. +static unsigned getRedeclDiagFromTagKind(TagTypeKind Tag) { + switch (Tag) { + case TTK_Struct: return 0; + case TTK_Interface: return 1; + case TTK_Class: return 2; + default: llvm_unreachable("Invalid tag kind for redecl diagnostic!"); + } +} + +/// \brief Determine if tag kind is a class-key compatible with +/// class for redeclaration (class, struct, or __interface). +/// +/// \returns true iff the tag kind is compatible. +static bool isClassCompatTagKind(TagTypeKind Tag) +{ + return Tag == TTK_Struct || Tag == TTK_Class || Tag == TTK_Interface; +} + /// \brief Determine whether a tag with a given kind is acceptable /// as a redeclaration of the given tag declaration. /// @@ -8168,12 +8462,11 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, // struct class-key shall be used to refer to a class (clause 9) // declared using the class or struct class-key. TagTypeKind OldTag = Previous->getTagKind(); - if (!isDefinition || (NewTag != TTK_Class && NewTag != TTK_Struct)) + if (!isDefinition || !isClassCompatTagKind(NewTag)) if (OldTag == NewTag) return true; - if ((OldTag == TTK_Struct || OldTag == TTK_Class) && - (NewTag == TTK_Struct || NewTag == TTK_Class)) { + if (isClassCompatTagKind(OldTag) && isClassCompatTagKind(NewTag)) { // Warn about the struct/class tag mismatch. bool isTemplate = false; if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Previous)) @@ -8183,7 +8476,8 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, // In a template instantiation, do not offer fix-its for tag mismatches // since they usually mess up the template instead of fixing the problem. Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << (NewTag == TTK_Class) << isTemplate << &Name; + << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(OldTag); return true; } @@ -8202,13 +8496,13 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, if (!previousMismatch) { previousMismatch = true; Diag(NewTagLoc, diag::warn_struct_class_previous_tag_mismatch) - << (NewTag == TTK_Class) << isTemplate << &Name; + << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(I->getTagKind()); } Diag(I->getInnerLocStart(), diag::note_struct_class_suggestion) - << (NewTag == TTK_Class) + << getRedeclDiagFromTagKind(NewTag) << FixItHint::CreateReplacement(I->getInnerLocStart(), - NewTag == TTK_Class? - "class" : "struct"); + TypeWithKeyword::getTagTypeKindName(NewTag)); } } return true; @@ -8224,16 +8518,16 @@ bool Sema::isAcceptableTagRedeclaration(const TagDecl *Previous, } Diag(NewTagLoc, diag::warn_struct_class_tag_mismatch) - << (NewTag == TTK_Class) - << isTemplate << &Name; + << getRedeclDiagFromTagKind(NewTag) << isTemplate << &Name + << getRedeclDiagFromTagKind(OldTag); Diag(Redecl->getLocation(), diag::note_previous_use); // If there is a previous defintion, suggest a fix-it. if (Previous->getDefinition()) { Diag(NewTagLoc, diag::note_struct_class_suggestion) - << (Redecl->getTagKind() == TTK_Class) + << getRedeclDiagFromTagKind(Redecl->getTagKind()) << FixItHint::CreateReplacement(SourceRange(NewTagLoc), - Redecl->getTagKind() == TTK_Class? "class" : "struct"); + TypeWithKeyword::getTagTypeKindName(Redecl->getTagKind())); } return true; @@ -8276,7 +8570,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, (SS.isNotEmpty() && TUK != TUK_Reference)) { if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier(KWLoc, NameLoc, SS, - TemplateParameterLists.get(), + TemplateParameterLists.data(), TemplateParameterLists.size(), TUK == TUK_Friend, isExplicitSpecialization, @@ -8293,8 +8587,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, SS, Name, NameLoc, Attr, TemplateParams, AS, ModulePrivateLoc, - TemplateParameterLists.size() - 1, - (TemplateParameterList**) TemplateParameterLists.release()); + TemplateParameterLists.size()-1, + TemplateParameterLists.data()); return Result.get(); } else { // The "template<>" header is extraneous. @@ -8843,7 +9137,7 @@ CreateNewDecl: if (TemplateParameterLists.size() > 0) { New->setTemplateParameterListsInfo(Context, TemplateParameterLists.size(), - (TemplateParameterList**) TemplateParameterLists.release()); + TemplateParameterLists.data()); } } else @@ -9298,12 +9592,15 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, if (!InvalidDecl && T->isVariablyModifiedType()) { bool SizeIsNegative; llvm::APSInt Oversized; - QualType FixedTy = TryToFixInvalidVariablyModifiedType(T, Context, - SizeIsNegative, - Oversized); - if (!FixedTy.isNull()) { + + TypeSourceInfo *FixedTInfo = + TryToFixInvalidVariablyModifiedTypeSourceInfo(TInfo, Context, + SizeIsNegative, + Oversized); + if (FixedTInfo) { Diag(Loc, diag::warn_illegal_constant_array_size); - T = FixedTy; + TInfo = FixedTInfo; + T = FixedTInfo->getType(); } else { if (SizeIsNegative) Diag(Loc, diag::err_typecheck_negative_array_size); @@ -9460,12 +9757,12 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { return false; } -/// If the given constructor is user-provided, produce a diagnostic explaining +/// If the given constructor is user-declared, produce a diagnostic explaining /// that it makes the class non-trivial. -static bool DiagnoseNontrivialUserProvidedCtor(Sema &S, QualType QT, +static bool diagnoseNonTrivialUserDeclaredCtor(Sema &S, QualType QT, CXXConstructorDecl *CD, Sema::CXXSpecialMember CSM) { - if (!CD->isUserProvided()) + if (CD->isImplicit()) return false; SourceLocation CtorLoc = CD->getLocation(); @@ -9488,17 +9785,17 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { if (RD->hasUserDeclaredConstructor()) { typedef CXXRecordDecl::ctor_iterator ctor_iter; for (ctor_iter CI = RD->ctor_begin(), CE = RD->ctor_end(); CI != CE; ++CI) - if (DiagnoseNontrivialUserProvidedCtor(*this, QT, *CI, member)) + if (diagnoseNonTrivialUserDeclaredCtor(*this, QT, *CI, member)) return; - // No user-provided constructors; look for constructor templates. + // No user-delcared constructors; look for constructor templates. typedef CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl> tmpl_iter; for (tmpl_iter TI(RD->decls_begin()), TE(RD->decls_end()); TI != TE; ++TI) { CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(TI->getTemplatedDecl()); - if (CD && DiagnoseNontrivialUserProvidedCtor(*this, QT, CD, member)) + if (CD && diagnoseNonTrivialUserDeclaredCtor(*this, QT, CD, member)) return; } } @@ -10025,42 +10322,6 @@ void Sema::ActOnFields(Scope* S, Convs->setAccess(I, (*I)->getAccess()); if (!CXXRecord->isDependentType()) { - // Objective-C Automatic Reference Counting: - // If a class has a non-static data member of Objective-C pointer - // type (or array thereof), it is a non-POD type and its - // default constructor (if any), copy constructor, copy assignment - // operator, and destructor are non-trivial. - // - // This rule is also handled by CXXRecordDecl::completeDefinition(). - // However, here we check whether this particular class is only - // non-POD because of the presence of an Objective-C pointer member. - // If so, objects of this type cannot be shared between code compiled - // with ARC and code compiled with manual retain/release. - if (getLangOpts().ObjCAutoRefCount && - CXXRecord->hasObjectMember() && - CXXRecord->getLinkage() == ExternalLinkage) { - if (CXXRecord->isPOD()) { - Diag(CXXRecord->getLocation(), - diag::warn_arc_non_pod_class_with_object_member) - << CXXRecord; - } else { - // FIXME: Fix-Its would be nice here, but finding a good location - // for them is going to be tricky. - if (CXXRecord->hasTrivialCopyConstructor()) - Diag(CXXRecord->getLocation(), - diag::warn_arc_trivial_member_function_with_object_member) - << CXXRecord << 0; - if (CXXRecord->hasTrivialCopyAssignment()) - Diag(CXXRecord->getLocation(), - diag::warn_arc_trivial_member_function_with_object_member) - << CXXRecord << 1; - if (CXXRecord->hasTrivialDestructor()) - Diag(CXXRecord->getLocation(), - diag::warn_arc_trivial_member_function_with_object_member) - << CXXRecord << 2; - } - } - // Adjust user-defined destructor exception spec. if (getLangOpts().CPlusPlus0x && CXXRecord->hasUserDeclaredDestructor()) @@ -10092,7 +10353,7 @@ void Sema::ActOnFields(Scope* S, // class subobject has more than one final overrider the // program is ill-formed. Diag(Record->getLocation(), diag::err_multiple_final_overriders) - << (NamedDecl *)M->first << Record; + << (const NamedDecl *)M->first << Record; Diag(M->first->getLocation(), diag::note_overridden_virtual_function); for (OverridingMethods::overriding_iterator @@ -10100,7 +10361,7 @@ void Sema::ActOnFields(Scope* S, OMEnd = SO->second.end(); OM != OMEnd; ++OM) Diag(OM->Method->getLocation(), diag::note_final_overrider) - << (NamedDecl *)M->first << OM->Method->getParent(); + << (const NamedDecl *)M->first << OM->Method->getParent(); Record->setInvalidDecl(); } @@ -10461,57 +10722,6 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, return New; } -// Emits a warning if every element in the enum is the same value and if -// every element is initialized with a integer or boolean literal. -static void CheckForUniqueEnumValues(Sema &S, Decl **Elements, - unsigned NumElements, EnumDecl *Enum, - QualType EnumType) { - if (S.Diags.getDiagnosticLevel(diag::warn_identical_enum_values, - Enum->getLocation()) == - DiagnosticsEngine::Ignored) - return; - - if (NumElements < 2) - return; - - if (!Enum->getIdentifier()) - return; - - llvm::APSInt FirstVal; - - for (unsigned i = 0; i != NumElements; ++i) { - EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]); - if (!ECD) - return; - - Expr *InitExpr = ECD->getInitExpr(); - if (!InitExpr) - return; - InitExpr = InitExpr->IgnoreImpCasts(); - if (!isa<IntegerLiteral>(InitExpr) && !isa<CXXBoolLiteralExpr>(InitExpr)) - return; - - if (i == 0) { - FirstVal = ECD->getInitVal(); - continue; - } - - if (!llvm::APSInt::isSameValue(FirstVal, ECD->getInitVal())) - return; - } - - S.Diag(Enum->getLocation(), diag::warn_identical_enum_values) - << EnumType << FirstVal.toString(10) - << Enum->getSourceRange(); - - EnumConstantDecl *Last = cast<EnumConstantDecl>(Elements[NumElements - 1]), - *Next = cast<EnumConstantDecl>(Elements[NumElements - 2]); - - S.Diag(Last->getLocation(), diag::note_identical_enum_values) - << FixItHint::CreateReplacement(Last->getInitExpr()->getSourceRange(), - Next->getName()); -} - void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, SourceLocation RBraceLoc, Decl *EnumDeclX, Decl **Elements, unsigned NumElements, @@ -10734,8 +10944,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // it needs to go into the function scope. if (InFunctionDeclarator) DeclsInPrototypeScope.push_back(Enum); - - CheckForUniqueEnumValues(*this, Elements, NumElements, Enum, EnumType); } Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr, @@ -10834,10 +11042,6 @@ Decl *Sema::getObjCDeclContext() const { } AvailabilityResult Sema::getCurContextAvailability() const { - const Decl *D = cast<Decl>(getCurLexicalContext()); - // A category implicitly has the availability of the interface. - if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) - D = CatD->getClassInterface(); - + const Decl *D = cast<Decl>(getCurObjCLexicalContext()); return D->getAvailability(); } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index caa7b2f65a9d..e326a20c87d0 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -415,14 +415,19 @@ static void checkAttrArgsAreLockableObjs(Sema &S, Decl *D, } if (StringLiteral *StrLit = dyn_cast<StringLiteral>(ArgExp)) { - // Ignore empty strings without warnings - if (StrLit->getLength() == 0) + if (StrLit->getLength() == 0 || + StrLit->getString() == StringRef("*")) { + // Pass empty strings to the analyzer without warnings. + // Treat "*" as the universal lock. + Args.push_back(ArgExp); continue; + } // We allow constant strings to be used as a placeholder for expressions // that are not valid C++ syntax, but warn that they are ignored. S.Diag(Attr.getLoc(), diag::warn_thread_attribute_ignored) << Attr.getName(); + Args.push_back(ArgExp); continue; } @@ -859,7 +864,6 @@ static void handleLockReturnedAttr(Sema &S, Decl *D, if (!checkAttributeNumArgs(S, Attr, 1)) return; - Expr *Arg = Attr.getArg(0); if (!isa<FunctionDecl>(D) && !isa<FunctionTemplateDecl>(D)) { S.Diag(Attr.getLoc(), diag::warn_thread_attribute_wrong_decl_type) @@ -867,9 +871,6 @@ static void handleLockReturnedAttr(Sema &S, Decl *D, return; } - if (Arg->isTypeDependent()) - return; - // check that the argument is lockable object SmallVector<Expr*, 1> Args; checkAttrArgsAreLockableObjs(S, D, Attr, Args); @@ -962,7 +963,8 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { else if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { // If the alignment is less than or equal to 8 bits, the packed attribute // has no effect. - if (!FD->getType()->isIncompleteType() && + if (!FD->getType()->isDependentType() && + !FD->getType()->isIncompleteType() && S.Context.getTypeAlign(FD->getType()) <= 8) S.Diag(Attr.getLoc(), diag::warn_attribute_ignored_for_field_of_type) << Attr.getName() << FD->getType(); @@ -973,8 +975,8 @@ static void handlePackedAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleMsStructAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (TagDecl *TD = dyn_cast<TagDecl>(D)) - TD->addAttr(::new (S.Context) MsStructAttr(Attr.getRange(), S.Context)); + if (RecordDecl *RD = dyn_cast<RecordDecl>(D)) + RD->addAttr(::new (S.Context) MsStructAttr(Attr.getRange(), S.Context)); else S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); } @@ -1522,6 +1524,20 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { Str->getString())); } +static void handleMinSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { + // Check the attribute arguments. + if (!checkAttributeNumArgs(S, Attr, 0)) + return; + + if (!isa<FunctionDecl>(D) && !isa<ObjCMethodDecl>(D)) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + D->addAttr(::new (S.Context) MinSizeAttr(Attr.getRange(), S.Context)); +} + static void handleColdAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Check the attribute arguments. if (!checkAttributeNumArgs(S, Attr, 0)) @@ -2268,16 +2284,14 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { } if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { QualType T = TD->getUnderlyingType(); - if (!T->isPointerType() || - !T->getAs<PointerType>()->getPointeeType()->isRecordType()) { + if (!T->isCARCBridgableType()) { S.Diag(TD->getLocation(), diag::err_nsobject_attribute); return; } } else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) { QualType T = PD->getType(); - if (!T->isPointerType() || - !T->getAs<PointerType>()->getPointeeType()->isRecordType()) { + if (!T->isCARCBridgableType()) { S.Diag(PD->getLocation(), diag::err_nsobject_attribute); return; } @@ -3583,7 +3597,12 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { } D->addAttr(::new (S.Context) PcsAttr(Attr.getRange(), S.Context, PCS)); + return; } + case AttributeList::AT_PnaclCall: + D->addAttr(::new (S.Context) PnaclCallAttr(Attr.getRange(), S.Context)); + return; + default: llvm_unreachable("unexpected attribute kind"); } @@ -3636,9 +3655,17 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC) { Diag(attr.getLoc(), diag::err_invalid_pcs); return true; } + case AttributeList::AT_PnaclCall: CC = CC_PnaclCall; break; default: llvm_unreachable("unexpected attribute kind"); } + const TargetInfo &TI = Context.getTargetInfo(); + TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC); + if (A == TargetInfo::CCCR_Warning) { + Diag(attr.getLoc(), diag::warn_cconv_ignored) << attr.getName(); + CC = TI.getDefaultCallingConv(); + } + return false; } @@ -3878,11 +3905,11 @@ static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) returnType = MD->getResultType(); - else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) - returnType = PD->getType(); else if (S.getLangOpts().ObjCAutoRefCount && hasDeclarator(D) && (Attr.getKind() == AttributeList::AT_NSReturnsRetained)) return; // ignore: was handled as a type attribute + else if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(D)) + returnType = PD->getType(); else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) returnType = FD->getResultType(); else { @@ -3971,6 +3998,33 @@ static void handleObjCReturnsInnerPointerAttr(Sema &S, Decl *D, ::new (S.Context) ObjCReturnsInnerPointerAttr(attr.getRange(), S.Context)); } +static void handleObjCRequiresSuperAttr(Sema &S, Decl *D, + const AttributeList &attr) { + SourceLocation loc = attr.getLoc(); + ObjCMethodDecl *method = dyn_cast<ObjCMethodDecl>(D); + + if (!method) { + S.Diag(D->getLocStart(), diag::err_attribute_wrong_decl_type) + << SourceRange(loc, loc) << attr.getName() << ExpectedMethod; + return; + } + DeclContext *DC = method->getDeclContext(); + if (const ObjCProtocolDecl *PDecl = dyn_cast_or_null<ObjCProtocolDecl>(DC)) { + S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) + << attr.getName() << 0; + S.Diag(PDecl->getLocation(), diag::note_protocol_decl); + return; + } + if (method->getMethodFamily() == OMF_dealloc) { + S.Diag(D->getLocStart(), diag::warn_objc_requires_super_protocol) + << attr.getName() << 1; + return; + } + + method->addAttr( + ::new (S.Context) ObjCRequiresSuperAttr(attr.getRange(), S.Context)); +} + /// Handle cf_audited_transfer and cf_unknown_transfer. static void handleCFTransferAttr(Sema &S, Decl *D, const AttributeList &A) { if (!isa<FunctionDecl>(D)) { @@ -4149,19 +4203,21 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { } static void handleInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (S.LangOpts.MicrosoftExt) { - AttributeList::Kind Kind = Attr.getKind(); - if (Kind == AttributeList::AT_SingleInheritance) - D->addAttr( - ::new (S.Context) SingleInheritanceAttr(Attr.getRange(), S.Context)); - else if (Kind == AttributeList::AT_MultipleInheritance) - D->addAttr( - ::new (S.Context) MultipleInheritanceAttr(Attr.getRange(), S.Context)); - else if (Kind == AttributeList::AT_VirtualInheritance) - D->addAttr( - ::new (S.Context) VirtualInheritanceAttr(Attr.getRange(), S.Context)); - } else + if (!S.LangOpts.MicrosoftExt) { S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + return; + } + + AttributeList::Kind Kind = Attr.getKind(); + if (Kind == AttributeList::AT_SingleInheritance) + D->addAttr( + ::new (S.Context) SingleInheritanceAttr(Attr.getRange(), S.Context)); + else if (Kind == AttributeList::AT_MultipleInheritance) + D->addAttr( + ::new (S.Context) MultipleInheritanceAttr(Attr.getRange(), S.Context)); + else if (Kind == AttributeList::AT_VirtualInheritance) + D->addAttr( + ::new (S.Context) VirtualInheritanceAttr(Attr.getRange(), S.Context)); } static void handlePortabilityAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -4246,6 +4302,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ExtVectorType: handleExtVectorTypeAttr(S, scope, D, Attr); break; + case AttributeList::AT_MinSize: + handleMinSizeAttr(S, D, Attr); + break; case AttributeList::AT_Format: handleFormatAttr (S, D, Attr); break; case AttributeList::AT_FormatArg: handleFormatArgAttr (S, D, Attr); break; case AttributeList::AT_CUDAGlobal: handleGlobalAttr (S, D, Attr); break; @@ -4278,6 +4337,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ObjCReturnsInnerPointer: handleObjCReturnsInnerPointerAttr(S, D, Attr); break; + case AttributeList::AT_ObjCRequiresSuper: + handleObjCRequiresSuperAttr(S, D, Attr); break; + case AttributeList::AT_NSBridged: handleNSBridgedAttr(S, scope, D, Attr); break; @@ -4360,6 +4422,7 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ThisCall: case AttributeList::AT_Pascal: case AttributeList::AT_Pcs: + case AttributeList::AT_PnaclCall: handleCallConvAttr(S, D, Attr); break; case AttributeList::AT_OpenCLKernel: @@ -4774,18 +4837,25 @@ static bool isDeclDeprecated(Decl *D) { static void DoEmitDeprecationWarning(Sema &S, const NamedDecl *D, StringRef Message, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass) { + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCPropery) { DeclarationName Name = D->getDeclName(); if (!Message.empty()) { S.Diag(Loc, diag::warn_deprecated_message) << Name << Message; S.Diag(D->getLocation(), isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at : diag::note_previous_decl) << Name; + if (ObjCPropery) + S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute) + << ObjCPropery->getDeclName() << 0; } else if (!UnknownObjCClass) { S.Diag(Loc, diag::warn_deprecated) << D->getDeclName(); S.Diag(D->getLocation(), isa<ObjCMethodDecl>(D) ? diag::note_method_declared_at : diag::note_previous_decl) << Name; + if (ObjCPropery) + S.Diag(ObjCPropery->getLocation(), diag::note_property_attribute) + << ObjCPropery->getDeclName() << 0; } else { S.Diag(Loc, diag::warn_deprecated_fwdclass_message) << Name; S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); @@ -4800,16 +4870,19 @@ void Sema::HandleDelayedDeprecationCheck(DelayedDiagnostic &DD, DD.Triggered = true; DoEmitDeprecationWarning(*this, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc, - DD.getUnknownObjCClass()); + DD.getUnknownObjCClass(), + DD.getObjCProperty()); } void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass) { + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty) { // Delay if we're currently parsing a declaration. if (DelayedDiagnostics.shouldDelayDiagnostics()) { DelayedDiagnostics.add(DelayedDiagnostic::makeDeprecation(Loc, D, UnknownObjCClass, + ObjCProperty, Message)); return; } @@ -4817,5 +4890,5 @@ void Sema::EmitDeprecationWarning(NamedDecl *D, StringRef Message, // Otherwise, don't warn if our current context is deprecated. if (isDeclDeprecated(cast<Decl>(getCurLexicalContext()))) return; - DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass); + DoEmitDeprecationWarning(*this, D, Message, Loc, UnknownObjCClass, ObjCProperty); } diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index eeac9b8e8d70..16eddf80ae5b 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -246,8 +246,7 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, InitializationKind Kind = InitializationKind::CreateCopy(Param->getLocation(), EqualLoc); InitializationSequence InitSeq(*this, Entity, Kind, &Arg, 1); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, &Arg, 1)); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Arg); if (Result.isInvalid()) return true; Arg = Result.takeAs<Expr>(); @@ -374,10 +373,10 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { } } -// MergeCXXFunctionDecl - Merge two declarations of the same C++ -// function, once we already know that they have the same -// type. Subroutine of MergeFunctionDecl. Returns true if there was an -// error, false otherwise. +/// MergeCXXFunctionDecl - Merge two declarations of the same C++ +/// function, once we already know that they have the same +/// type. Subroutine of MergeFunctionDecl. Returns true if there was an +/// error, false otherwise. bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Scope *S) { bool Invalid = false; @@ -676,6 +675,20 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, return true; } +/// \brief Get diagnostic %select index for tag kind for +/// record diagnostic message. +/// WARNING: Indexes apply to particular diagnostics only! +/// +/// \returns diagnostic %select index. +static unsigned getRecordDiagFromTagKind(TagTypeKind Tag) { + switch (Tag) { + case TTK_Struct: return 0; + case TTK_Interface: return 1; + case TTK_Class: return 2; + default: llvm_unreachable("Invalid tag kind for record diagnostic!"); + } +} + // CheckConstexprFunctionDecl - Check whether a function declaration satisfies // the requirements of a constexpr function definition or a constexpr // constructor definition. If so, return true. If not, produce appropriate @@ -692,8 +705,8 @@ bool Sema::CheckConstexprFunctionDecl(const FunctionDecl *NewFD) { const CXXRecordDecl *RD = MD->getParent(); if (RD->getNumVBases()) { Diag(NewFD->getLocation(), diag::err_constexpr_virtual_base) - << isa<CXXConstructorDecl>(NewFD) << RD->isStruct() - << RD->getNumVBases(); + << isa<CXXConstructorDecl>(NewFD) + << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases(); for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) Diag(I->getLocStart(), @@ -1005,6 +1018,41 @@ bool Sema::isCurrentClassName(const IdentifierInfo &II, Scope *, return false; } +/// \brief Determine whether the given class is a base class of the given +/// class, including looking at dependent bases. +static bool findCircularInheritance(const CXXRecordDecl *Class, + const CXXRecordDecl *Current) { + SmallVector<const CXXRecordDecl*, 8> Queue; + + Class = Class->getCanonicalDecl(); + while (true) { + for (CXXRecordDecl::base_class_const_iterator I = Current->bases_begin(), + E = Current->bases_end(); + I != E; ++I) { + CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl(); + if (!Base) + continue; + + Base = Base->getDefinition(); + if (!Base) + continue; + + if (Base->getCanonicalDecl() == Class) + return true; + + Queue.push_back(Base); + } + + if (Queue.empty()) + return false; + + Current = Queue.back(); + Queue.pop_back(); + } + + return false; +} + /// \brief Check the validity of a C++ base class specifier. /// /// \returns a new CXXBaseSpecifier if well-formed, emits diagnostics @@ -1031,13 +1079,32 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, << TInfo->getTypeLoc().getSourceRange(); EllipsisLoc = SourceLocation(); } - - if (BaseType->isDependentType()) + + SourceLocation BaseLoc = TInfo->getTypeLoc().getBeginLoc(); + + if (BaseType->isDependentType()) { + // Make sure that we don't have circular inheritance among our dependent + // bases. For non-dependent bases, the check for completeness below handles + // this. + if (CXXRecordDecl *BaseDecl = BaseType->getAsCXXRecordDecl()) { + if (BaseDecl->getCanonicalDecl() == Class->getCanonicalDecl() || + ((BaseDecl = BaseDecl->getDefinition()) && + findCircularInheritance(Class, BaseDecl))) { + Diag(BaseLoc, diag::err_circular_inheritance) + << BaseType << Context.getTypeDeclType(Class); + + if (BaseDecl->getCanonicalDecl() != Class->getCanonicalDecl()) + Diag(BaseDecl->getLocation(), diag::note_previous_decl) + << BaseType; + + return 0; + } + } + return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, Class->getTagKind() == TTK_Class, Access, TInfo, EllipsisLoc); - - SourceLocation BaseLoc = TInfo->getTypeLoc().getBeginLoc(); + } // Base specifiers must be record types. if (!BaseType->isRecordType()) { @@ -1165,10 +1232,21 @@ bool Sema::AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, // Okay, add this new base class. KnownBase = Bases[idx]; Bases[NumGoodBases++] = Bases[idx]; - if (const RecordType *Record = NewBaseType->getAs<RecordType>()) - if (const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl())) - if (RD->hasAttr<WeakAttr>()) - Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context)); + if (const RecordType *Record = NewBaseType->getAs<RecordType>()) { + const CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl()); + if (Class->isInterface() && + (!RD->isInterface() || + KnownBase->getAccessSpecifier() != AS_public)) { + // The Microsoft extension __interface does not permit bases that + // are not themselves public interfaces. + Diag(KnownBase->getLocStart(), diag::err_invalid_base_in_interface) + << getRecordDiagFromTagKind(RD->getTagKind()) << RD->getName() + << RD->getSourceRange(); + Invalid = true; + } + if (RD->hasAttr<WeakAttr>()) + Class->addAttr(::new (Context) WeakAttr(SourceRange(), Context)); + } } } @@ -1407,6 +1485,9 @@ bool Sema::ActOnAccessSpecifier(AccessSpecifier Access, /// CheckOverrideControl - Check C++11 override control semantics. void Sema::CheckOverrideControl(Decl *D) { + if (D->isInvalidDecl()) + return; + const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D); // Do we know which functions this declaration might be overriding? @@ -1496,6 +1577,50 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, bool isFunc = D.isDeclarationOfFunction(); + if (cast<CXXRecordDecl>(CurContext)->isInterface()) { + // The Microsoft extension __interface only permits public member functions + // and prohibits constructors, destructors, operators, non-public member + // functions, static methods and data members. + unsigned InvalidDecl; + bool ShowDeclName = true; + if (!isFunc) + InvalidDecl = (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) ? 0 : 1; + else if (AS != AS_public) + InvalidDecl = 2; + else if (DS.getStorageClassSpec() == DeclSpec::SCS_static) + InvalidDecl = 3; + else switch (Name.getNameKind()) { + case DeclarationName::CXXConstructorName: + InvalidDecl = 4; + ShowDeclName = false; + break; + + case DeclarationName::CXXDestructorName: + InvalidDecl = 5; + ShowDeclName = false; + break; + + case DeclarationName::CXXOperatorName: + case DeclarationName::CXXConversionFunctionName: + InvalidDecl = 6; + break; + + default: + InvalidDecl = 0; + break; + } + + if (InvalidDecl) { + if (ShowDeclName) + Diag(Loc, diag::err_invalid_member_in_interface) + << (InvalidDecl-1) << Name; + else + Diag(Loc, diag::err_invalid_member_in_interface) + << (InvalidDecl-1) << ""; + return 0; + } + } + // C++ 9.2p6: A member shall not be declared to have automatic storage // duration (auto, register) or with the extern storage-class-specifier. // C++ 7.1.1p8: The mutable specifier can be applied only to names of class @@ -1548,7 +1673,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, // Member field could not be with "template" keyword. // So TemplateParameterLists should be empty in this case. if (TemplateParameterLists.size()) { - TemplateParameterList* TemplateParams = TemplateParameterLists.get()[0]; + TemplateParameterList* TemplateParams = TemplateParameterLists[0]; if (TemplateParams->size()) { // There is no such thing as a member field template. Diag(D.getIdentifierLoc(), diag::err_template_member) @@ -1588,7 +1713,7 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } else { assert(InitStyle == ICIS_NoInit); - Member = HandleDeclarator(S, D, move(TemplateParameterLists)); + Member = HandleDeclarator(S, D, TemplateParameterLists); if (!Member) { return 0; } @@ -1662,6 +1787,99 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, return Member; } +namespace { + class UninitializedFieldVisitor + : public EvaluatedExprVisitor<UninitializedFieldVisitor> { + Sema &S; + ValueDecl *VD; + public: + typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited; + UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context), + S(S), VD(VD) { + } + + void HandleExpr(Expr *E) { + if (!E) return; + + // Expressions like x(x) sometimes lack the surrounding expressions + // but need to be checked anyways. + HandleValue(E); + Visit(E); + } + + void HandleValue(Expr *E) { + E = E->IgnoreParens(); + + if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + if (isa<EnumConstantDecl>(ME->getMemberDecl())) + return; + Expr *Base = E; + while (isa<MemberExpr>(Base)) { + ME = dyn_cast<MemberExpr>(Base); + if (VarDecl *VarD = dyn_cast<VarDecl>(ME->getMemberDecl())) + if (VarD->hasGlobalStorage()) + return; + Base = ME->getBase(); + } + + if (VD == ME->getMemberDecl() && isa<CXXThisExpr>(Base)) { + unsigned diag = VD->getType()->isReferenceType() + ? diag::warn_reference_field_is_uninit + : diag::warn_field_is_uninit; + S.Diag(ME->getExprLoc(), diag) << ME->getMemberNameInfo().getName(); + return; + } + } + + if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { + HandleValue(CO->getTrueExpr()); + HandleValue(CO->getFalseExpr()); + return; + } + + if (BinaryConditionalOperator *BCO = + dyn_cast<BinaryConditionalOperator>(E)) { + HandleValue(BCO->getCommon()); + HandleValue(BCO->getFalseExpr()); + return; + } + + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + switch (BO->getOpcode()) { + default: + return; + case(BO_PtrMemD): + case(BO_PtrMemI): + HandleValue(BO->getLHS()); + return; + case(BO_Comma): + HandleValue(BO->getRHS()); + return; + } + } + } + + void VisitImplicitCastExpr(ImplicitCastExpr *E) { + if (E->getCastKind() == CK_LValueToRValue) + HandleValue(E->getSubExpr()); + + Inherited::VisitImplicitCastExpr(E); + } + + void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { + Expr *Callee = E->getCallee(); + if (isa<MemberExpr>(Callee)) + HandleValue(Callee); + + Inherited::VisitCXXMemberCallExpr(E); + } + }; + static void CheckInitExprContainsUninitializedFields(Sema &S, Expr *E, + ValueDecl *VD) { + UninitializedFieldVisitor(S, VD).HandleExpr(E); + } +} // namespace + /// ActOnCXXInClassMemberInitializer - This is invoked after parsing an /// in-class initializer for a non-static C++ class member, and after /// instantiating an in-class initializer in a class template. Such actions @@ -1685,8 +1903,17 @@ Sema::ActOnCXXInClassMemberInitializer(Decl *D, SourceLocation InitLoc, return; } + if (getDiagnostics().getDiagnosticLevel(diag::warn_field_is_uninit, InitLoc) + != DiagnosticsEngine::Ignored) { + CheckInitExprContainsUninitializedFields(*this, InitExpr, FD); + } + ExprResult Init = InitExpr; - if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent()) { + if (!FD->getType()->isDependentType() && !InitExpr->isTypeDependent() && + !FD->getDeclContext()->isDependentContext()) { + // Note: We don't type-check when we're in a dependent context, because + // the initialization-substitution code does not properly handle direct + // list initialization. We have the same hackaround for ctor-initializers. if (isa<InitListExpr>(InitExpr) && isStdInitializerList(FD->getType(), 0)) { Diag(FD->getLocation(), diag::warn_dangling_std_initializer_list) << /*at end of ctor*/1 << InitExpr->getSourceRange(); @@ -1795,7 +2022,8 @@ Sema::ActOnMemInitializer(Decl *ConstructorD, Expr **Args, unsigned NumArgs, SourceLocation RParenLoc, SourceLocation EllipsisLoc) { - Expr *List = new (Context) ParenListExpr(Context, LParenLoc, Args, NumArgs, + Expr *List = new (Context) ParenListExpr(Context, LParenLoc, + llvm::makeArrayRef(Args, NumArgs), RParenLoc); return BuildMemInitializer(ConstructorD, S, SS, MemberOrBase, TemplateTypeTy, DS, IdLoc, List, EllipsisLoc); @@ -2044,96 +2272,6 @@ static void CheckForDanglingReferenceOrPointer(Sema &S, ValueDecl *Member, << (unsigned)IsPointer; } -namespace { - class UninitializedFieldVisitor - : public EvaluatedExprVisitor<UninitializedFieldVisitor> { - Sema &S; - ValueDecl *VD; - public: - typedef EvaluatedExprVisitor<UninitializedFieldVisitor> Inherited; - UninitializedFieldVisitor(Sema &S, ValueDecl *VD) : Inherited(S.Context), - S(S), VD(VD) { - } - - void HandleExpr(Expr *E) { - if (!E) return; - - // Expressions like x(x) sometimes lack the surrounding expressions - // but need to be checked anyways. - HandleValue(E); - Visit(E); - } - - void HandleValue(Expr *E) { - E = E->IgnoreParens(); - - if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { - if (isa<EnumConstantDecl>(ME->getMemberDecl())) - return; - Expr *Base = E; - while (isa<MemberExpr>(Base)) { - ME = dyn_cast<MemberExpr>(Base); - if (VarDecl *VarD = dyn_cast<VarDecl>(ME->getMemberDecl())) - if (VarD->hasGlobalStorage()) - return; - Base = ME->getBase(); - } - - if (VD == ME->getMemberDecl() && isa<CXXThisExpr>(Base)) { - S.Diag(ME->getExprLoc(), diag::warn_field_is_uninit); - return; - } - } - - if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { - HandleValue(CO->getTrueExpr()); - HandleValue(CO->getFalseExpr()); - return; - } - - if (BinaryConditionalOperator *BCO = - dyn_cast<BinaryConditionalOperator>(E)) { - HandleValue(BCO->getCommon()); - HandleValue(BCO->getFalseExpr()); - return; - } - - if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { - switch (BO->getOpcode()) { - default: - return; - case(BO_PtrMemD): - case(BO_PtrMemI): - HandleValue(BO->getLHS()); - return; - case(BO_Comma): - HandleValue(BO->getRHS()); - return; - } - } - } - - void VisitImplicitCastExpr(ImplicitCastExpr *E) { - if (E->getCastKind() == CK_LValueToRValue) - HandleValue(E->getSubExpr()); - - Inherited::VisitImplicitCastExpr(E); - } - - void VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { - Expr *Callee = E->getCallee(); - if (isa<MemberExpr>(Callee)) - HandleValue(Callee); - - Inherited::VisitCXXMemberCallExpr(E); - } - }; - static void CheckInitExprContainsUninitializedFields(Sema &S, Expr *E, - ValueDecl *VD) { - UninitializedFieldVisitor(S, VD).HandleExpr(E); - } -} // namespace - MemInitResult Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, SourceLocation IdLoc) { @@ -2167,11 +2305,13 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, != DiagnosticsEngine::Ignored) for (unsigned i = 0; i < NumArgs; ++i) // FIXME: Warn about the case when other fields are used before being - // uninitialized. For example, let this field be the i'th field. When + // initialized. For example, let this field be the i'th field. When // initializing the i'th field, throw a warning if any of the >= i'th // fields are used, as they are not yet initialized. // Right now we are only handling the case where the i'th field uses // itself in its initializer. + // Also need to take into account that some fields may be initialized by + // in-class initializers, see C++11 [class.base.init]p9. CheckInitExprContainsUninitializedFields(*this, Args[i], Member); SourceRange InitRange = Init->getSourceRange(); @@ -2204,7 +2344,7 @@ Sema::BuildMemberInitializer(ValueDecl *Member, Expr *Init, InitializationSequence InitSeq(*this, MemberEntity, Kind, Args, NumArgs); ExprResult MemberInit = InitSeq.Perform(*this, MemberEntity, Kind, - MultiExprArg(*this, Args, NumArgs), + MultiExprArg(Args, NumArgs), 0); if (MemberInit.isInvalid()) return true; @@ -2273,7 +2413,7 @@ Sema::BuildDelegatingInitializer(TypeSourceInfo *TInfo, Expr *Init, InitRange.getEnd()); InitializationSequence InitSeq(*this, DelegationEntity, Kind, Args, NumArgs); ExprResult DelegationInit = InitSeq.Perform(*this, DelegationEntity, Kind, - MultiExprArg(*this, Args,NumArgs), + MultiExprArg(Args, NumArgs), 0); if (DelegationInit.isInvalid()) return true; @@ -2411,8 +2551,7 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo, InitRange.getEnd()); InitializationSequence InitSeq(*this, BaseEntity, Kind, Args, NumArgs); ExprResult BaseInit = InitSeq.Perform(*this, BaseEntity, Kind, - MultiExprArg(*this, Args, NumArgs), - 0); + MultiExprArg(Args, NumArgs), 0); if (BaseInit.isInvalid()) return true; @@ -2480,8 +2619,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, InitializationKind InitKind = InitializationKind::CreateDefault(Constructor->getLocation()); InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, 0, 0); - BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, - MultiExprArg(SemaRef, 0, 0)); + BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, MultiExprArg()); break; } @@ -2936,7 +3074,11 @@ bool Sema::SetCtorInitializers(CXXConstructorDecl *Constructor, NumInitializers * sizeof(CXXCtorInitializer*)); Constructor->setCtorInitializers(baseOrMemberInitializers); } - + + // Let template instantiation know whether we had errors. + if (AnyErrors) + Constructor->setInvalidDecl(); + return false; } @@ -3324,11 +3466,10 @@ void Sema::ActOnMemInitializers(Decl *ConstructorDecl, } else { assert(Init->isDelegatingInitializer()); // This must be the only initializer - if (i != 0 || NumMemInits > 1) { - Diag(MemInits[0]->getSourceLocation(), + if (NumMemInits != 1) { + Diag(Init->getSourceLocation(), diag::err_delegating_initializer_alone) - << MemInits[0]->getSourceRange(); - HadError = true; + << Init->getSourceRange() << MemInits[i ? 0 : 1]->getSourceRange(); // We will treat this as being the only initializer. } SetDelegatingInitializer(Constructor, MemInits[i]); @@ -3812,6 +3953,11 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { diag::warn_non_virtual_dtor) << Context.getRecordType(Record); } + if (Record->isAbstract() && Record->hasAttr<FinalAttr>()) { + Diag(Record->getLocation(), diag::warn_abstract_final_class); + DiagnoseAbstractType(Record); + } + // See if a method overloads virtual methods in a base /// class without overriding any. if (!Record->isDependentType()) { @@ -4065,7 +4211,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { // Compute argument constness, constexpr, and triviality. bool CanHaveConstParam = false; - bool Trivial; + bool Trivial = false; switch (CSM) { case CXXDefaultConstructor: Trivial = RD->hasTrivialDefaultConstructor(); @@ -4304,7 +4450,7 @@ bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj, /// If we're operating on a base class, the object type is the /// type of this special member. QualType objectTy; - AccessSpecifier access = target->getAccess();; + AccessSpecifier access = target->getAccess(); if (CXXBaseSpecifier *base = Subobj.dyn_cast<CXXBaseSpecifier*>()) { objectTy = S.Context.getTypeDeclType(MD->getParent()); access = CXXRecordDecl::MergeAccess(base->getAccessSpecifier(), access); @@ -4647,6 +4793,19 @@ namespace { }; } +/// \brief Check whether any most overriden method from MD in Methods +static bool CheckMostOverridenMethods(const CXXMethodDecl *MD, + const llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) { + if (MD->size_overridden_methods() == 0) + return Methods.count(MD->getCanonicalDecl()); + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); + I != E; ++I) + if (CheckMostOverridenMethods(*I, Methods)) + return true; + return false; +} + /// \brief Member lookup function that determines whether a given C++ /// method overloads virtual methods in a base class without overriding any, /// to be used with CXXRecordDecl::lookupInBases(). @@ -4678,7 +4837,7 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier, if (!Data.S->IsOverload(Data.Method, MD, false)) return true; // Collect the overload only if its hidden. - if (!Data.OverridenAndUsingBaseMethods.count(MD)) + if (!CheckMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods)) overloadedMethods.push_back(MD); } } @@ -4689,6 +4848,17 @@ static bool FindHiddenVirtualMethod(const CXXBaseSpecifier *Specifier, return foundSameNameMethod; } +/// \brief Add the most overriden methods from MD to Methods +static void AddMostOverridenMethods(const CXXMethodDecl *MD, + llvm::SmallPtrSet<const CXXMethodDecl *, 8>& Methods) { + if (MD->size_overridden_methods() == 0) + Methods.insert(MD->getCanonicalDecl()); + for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), + E = MD->end_overridden_methods(); + I != E; ++I) + AddMostOverridenMethods(*I, Methods); +} + /// \brief See if a method overloads virtual methods in a base class without /// overriding any. void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { @@ -4709,14 +4879,11 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { // by 'using' in a set. A base method not in this set is hidden. for (DeclContext::lookup_result res = DC->lookup(MD->getDeclName()); res.first != res.second; ++res.first) { - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*res.first)) - for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), - E = MD->end_overridden_methods(); - I != E; ++I) - Data.OverridenAndUsingBaseMethods.insert((*I)->getCanonicalDecl()); + NamedDecl *ND = *res.first; if (UsingShadowDecl *shad = dyn_cast<UsingShadowDecl>(*res.first)) - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(shad->getTargetDecl())) - Data.OverridenAndUsingBaseMethods.insert(MD->getCanonicalDecl()); + ND = shad->getTargetDecl(); + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND)) + AddMostOverridenMethods(MD, Data.OverridenAndUsingBaseMethods); } if (DC->lookupInBases(&FindHiddenVirtualMethod, &Data, Paths) && @@ -5307,7 +5474,47 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { // Namespace Handling //===----------------------------------------------------------------------===// +/// \brief Diagnose a mismatch in 'inline' qualifiers when a namespace is +/// reopened. +static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc, + SourceLocation Loc, + IdentifierInfo *II, bool *IsInline, + NamespaceDecl *PrevNS) { + assert(*IsInline != PrevNS->isInline()); + + // HACK: Work around a bug in libstdc++4.6's <atomic>, where + // std::__atomic[0,1,2] are defined as non-inline namespaces, then reopened as + // inline namespaces, with the intention of bringing names into namespace std. + // + // We support this just well enough to get that case working; this is not + // sufficient to support reopening namespaces as inline in general. + if (*IsInline && II && II->getName().startswith("__atomic") && + S.getSourceManager().isInSystemHeader(Loc)) { + // Mark all prior declarations of the namespace as inline. + for (NamespaceDecl *NS = PrevNS->getMostRecentDecl(); NS; + NS = NS->getPreviousDecl()) + NS->setInline(*IsInline); + // Patch up the lookup table for the containing namespace. This isn't really + // correct, but it's good enough for this particular case. + for (DeclContext::decl_iterator I = PrevNS->decls_begin(), + E = PrevNS->decls_end(); I != E; ++I) + if (NamedDecl *ND = dyn_cast<NamedDecl>(*I)) + PrevNS->getParent()->makeDeclVisibleInContext(ND); + return; + } + + if (PrevNS->isInline()) + // The user probably just forgot the 'inline', so suggest that it + // be added back. + S.Diag(Loc, diag::warn_inline_namespace_reopened_noninline) + << FixItHint::CreateInsertion(KeywordLoc, "inline "); + else + S.Diag(Loc, diag::err_inline_namespace_mismatch) + << IsInline; + S.Diag(PrevNS->getLocation(), diag::note_previous_definition); + *IsInline = PrevNS->isInline(); +} /// ActOnStartNamespaceDef - This is called at the start of a namespace /// definition. @@ -5357,21 +5564,9 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, if (PrevNS) { // This is an extended namespace definition. - if (IsInline != PrevNS->isInline()) { - // inline-ness must match - if (PrevNS->isInline()) { - // The user probably just forgot the 'inline', so suggest that it - // be added back. - Diag(Loc, diag::warn_inline_namespace_reopened_noninline) - << FixItHint::CreateInsertion(NamespaceLoc, "inline "); - } else { - Diag(Loc, diag::err_inline_namespace_mismatch) - << IsInline; - } - Diag(PrevNS->getLocation(), diag::note_previous_definition); - - IsInline = PrevNS->isInline(); - } + if (IsInline != PrevNS->isInline()) + DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, Loc, II, + &IsInline, PrevNS); } else if (PrevDecl) { // This is an invalid name redefinition. Diag(Loc, diag::err_redefinition_different_kind) @@ -5402,15 +5597,9 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, PrevNS = ND->getAnonymousNamespace(); } - if (PrevNS && IsInline != PrevNS->isInline()) { - // inline-ness must match - Diag(Loc, diag::err_inline_namespace_mismatch) - << IsInline; - Diag(PrevNS->getLocation(), diag::note_previous_definition); - - // Recover by ignoring the new namespace's inline status. - IsInline = PrevNS->isInline(); - } + if (PrevNS && IsInline != PrevNS->isInline()) + DiagnoseNamespaceInlineMismatch(*this, NamespaceLoc, NamespaceLoc, II, + &IsInline, PrevNS); } NamespaceDecl *Namespc = NamespaceDecl::Create(Context, CurContext, IsInline, @@ -5460,15 +5649,15 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope, if (!PrevNS) { UsingDirectiveDecl* UD - = UsingDirectiveDecl::Create(Context, CurContext, + = UsingDirectiveDecl::Create(Context, Parent, /* 'using' */ LBrace, /* 'namespace' */ SourceLocation(), /* qualifier */ NestedNameSpecifierLoc(), /* identifier */ SourceLocation(), Namespc, - /* Ancestor */ CurContext); + /* Ancestor */ Parent); UD->setImplicit(); - CurContext->addDecl(UD); + Parent->addDecl(UD); } } @@ -5697,7 +5886,8 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc, if (DeclContext *DC = S.computeDeclContext(SS, false)) S.Diag(IdentLoc, diag::err_using_directive_member_suggest) << Ident << DC << CorrectedQuotedStr << SS.getRange() - << FixItHint::CreateReplacement(IdentLoc, CorrectedStr); + << FixItHint::CreateReplacement(Corrected.getCorrectionRange(), + CorrectedStr); else S.Diag(IdentLoc, diag::err_using_directive_suggest) << Ident << CorrectedQuotedStr @@ -6562,10 +6752,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, if (TemplateParamLists.size() != 1) { Diag(UsingLoc, diag::err_alias_template_extra_headers) - << SourceRange(TemplateParamLists.get()[1]->getTemplateLoc(), - TemplateParamLists.get()[TemplateParamLists.size()-1]->getRAngleLoc()); + << SourceRange(TemplateParamLists[1]->getTemplateLoc(), + TemplateParamLists[TemplateParamLists.size()-1]->getRAngleLoc()); } - TemplateParameterList *TemplateParams = TemplateParamLists.get()[0]; + TemplateParameterList *TemplateParams = TemplateParamLists[0]; // Only consider previous declarations in the same scope. FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false, @@ -6696,28 +6886,6 @@ Decl *Sema::ActOnNamespaceAliasDef(Scope *S, return AliasDecl; } -namespace { - /// \brief Scoped object used to handle the state changes required in Sema - /// to implicitly define the body of a C++ member function; - class ImplicitlyDefinedFunctionScope { - Sema &S; - Sema::ContextRAII SavedContext; - - public: - ImplicitlyDefinedFunctionScope(Sema &S, CXXMethodDecl *Method) - : S(S), SavedContext(S, Method) - { - S.PushFunctionScope(); - S.PushExpressionEvaluationContext(Sema::PotentiallyEvaluated); - } - - ~ImplicitlyDefinedFunctionScope() { - S.PopExpressionEvaluationContext(); - S.PopFunctionScopeInfo(); - } - }; -} - Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) { @@ -6861,7 +7029,7 @@ void Sema::DefineImplicitDefaultConstructor(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = Constructor->getParent(); assert(ClassDecl && "DefineImplicitDefaultConstructor - invalid constructor"); - ImplicitlyDefinedFunctionScope Scope(*this, Constructor); + SynthesizedFunctionScope Scope(*this, Constructor); DiagnosticErrorTrap Trap(Diags); if (SetCtorInitializers(Constructor, 0, 0, /*AnyErrors=*/false) || Trap.hasErrorOccurred()) { @@ -7173,7 +7341,7 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, if (Destructor->isInvalidDecl()) return; - ImplicitlyDefinedFunctionScope Scope(*this, Destructor); + SynthesizedFunctionScope Scope(*this, Destructor); DiagnosticErrorTrap Trap(Diags); MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), @@ -7412,7 +7580,7 @@ BuildSingleCopyAssign(Sema &S, SourceLocation Loc, QualType T, = new (S.Context) BinaryOperator(IterationVarRefRVal, IntegerLiteral::Create(S.Context, Upper, SizeType, Loc), BO_NE, S.Context.BoolTy, - VK_RValue, OK_Ordinary, Loc); + VK_RValue, OK_Ordinary, Loc, false); // Create the pre-increment of the iteration variable. Expr *Increment @@ -7654,7 +7822,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CopyAssignOperator->setUsed(); - ImplicitlyDefinedFunctionScope Scope(*this, CopyAssignOperator); + SynthesizedFunctionScope Scope(*this, CopyAssignOperator); DiagnosticErrorTrap Trap(Diags); // C++0x [class.copy]p30: @@ -7666,7 +7834,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, // which they were declared in the class definition. // The statements that form the synthesized function body. - ASTOwningVector<Stmt*> Statements(*this); + SmallVector<Stmt*, 8> Statements; // The parameter for the "other" object, which we are copying from. ParmVarDecl *Other = CopyAssignOperator->getParamDecl(0); @@ -7846,8 +8014,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy, - CollectableMemCpy->getType(), - VK_LValue, Loc, 0).take(); + Context.BuiltinFnTy, + VK_RValue, Loc, 0).take(); assert(CollectableMemCpyRef && "Builtin reference cannot fail"); } } @@ -7866,12 +8034,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, } BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, - BuiltinMemCpy->getType(), - VK_LValue, Loc, 0).take(); + Context.BuiltinFnTy, + VK_RValue, Loc, 0).take(); assert(BuiltinMemCpyRef && "Builtin reference cannot fail"); } - ASTOwningVector<Expr*> CallArgs(*this); + SmallVector<Expr*, 8> CallArgs; CallArgs.push_back(To.takeAs<Expr>()); CallArgs.push_back(From.takeAs<Expr>()); CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc)); @@ -7879,12 +8047,12 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, if (NeedsCollectableMemCpy) Call = ActOnCallExpr(/*Scope=*/0, CollectableMemCpyRef, - Loc, move_arg(CallArgs), + Loc, CallArgs, Loc); else Call = ActOnCallExpr(/*Scope=*/0, BuiltinMemCpyRef, - Loc, move_arg(CallArgs), + Loc, CallArgs, Loc); assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!"); @@ -7934,7 +8102,7 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, StmtResult Body; { CompoundScopeRAII CompoundScope(*this); - Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements), + Body = ActOnCompoundStmt(Loc, Loc, Statements, /*isStmtExpr=*/false); assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } @@ -8040,7 +8208,7 @@ hasMoveOrIsTriviallyCopyable(Sema &S, QualType Type, bool IsConstructor) { // reference types, are supposed to return false here, but that appears // to be a standard defect. CXXRecordDecl *ClassDecl = Type->getAsCXXRecordDecl(); - if (!ClassDecl || !ClassDecl->getDefinition()) + if (!ClassDecl || !ClassDecl->getDefinition() || ClassDecl->isInvalidDecl()) return true; if (Type.isTriviallyCopyableType(S.Context)) @@ -8195,7 +8363,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, MoveAssignOperator->setUsed(); - ImplicitlyDefinedFunctionScope Scope(*this, MoveAssignOperator); + SynthesizedFunctionScope Scope(*this, MoveAssignOperator); DiagnosticErrorTrap Trap(Diags); // C++0x [class.copy]p28: @@ -8207,7 +8375,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, // definition. // The statements that form the synthesized function body. - ASTOwningVector<Stmt*> Statements(*this); + SmallVector<Stmt*, 8> Statements; // The parameter for the "other" object, which we are move from. ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0); @@ -8395,8 +8563,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, } CollectableMemCpyRef = BuildDeclRefExpr(CollectableMemCpy, - CollectableMemCpy->getType(), - VK_LValue, Loc, 0).take(); + Context.BuiltinFnTy, + VK_RValue, Loc, 0).take(); assert(CollectableMemCpyRef && "Builtin reference cannot fail"); } } @@ -8415,12 +8583,12 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, } BuiltinMemCpyRef = BuildDeclRefExpr(BuiltinMemCpy, - BuiltinMemCpy->getType(), - VK_LValue, Loc, 0).take(); + Context.BuiltinFnTy, + VK_RValue, Loc, 0).take(); assert(BuiltinMemCpyRef && "Builtin reference cannot fail"); } - ASTOwningVector<Expr*> CallArgs(*this); + SmallVector<Expr*, 8> CallArgs; CallArgs.push_back(To.takeAs<Expr>()); CallArgs.push_back(From.takeAs<Expr>()); CallArgs.push_back(IntegerLiteral::Create(Context, Size, SizeType, Loc)); @@ -8428,12 +8596,12 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, if (NeedsCollectableMemCpy) Call = ActOnCallExpr(/*Scope=*/0, CollectableMemCpyRef, - Loc, move_arg(CallArgs), + Loc, CallArgs, Loc); else Call = ActOnCallExpr(/*Scope=*/0, BuiltinMemCpyRef, - Loc, move_arg(CallArgs), + Loc, CallArgs, Loc); assert(!Call.isInvalid() && "Call to __builtin_memcpy cannot fail!"); @@ -8483,7 +8651,7 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, StmtResult Body; { CompoundScopeRAII CompoundScope(*this); - Body = ActOnCompoundStmt(Loc, Loc, move_arg(Statements), + Body = ActOnCompoundStmt(Loc, Loc, Statements, /*isStmtExpr=*/false); assert(!Body.isInvalid() && "Compound statement creation cannot fail"); } @@ -8691,7 +8859,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = CopyConstructor->getParent(); assert(ClassDecl && "DefineImplicitCopyConstructor - invalid constructor"); - ImplicitlyDefinedFunctionScope Scope(*this, CopyConstructor); + SynthesizedFunctionScope Scope(*this, CopyConstructor); DiagnosticErrorTrap Trap(Diags); if (SetCtorInitializers(CopyConstructor, 0, 0, /*AnyErrors=*/false) || @@ -8703,7 +8871,7 @@ void Sema::DefineImplicitCopyConstructor(SourceLocation CurrentLocation, Sema::CompoundScopeRAII CompoundScope(*this); CopyConstructor->setBody(ActOnCompoundStmt(CopyConstructor->getLocation(), CopyConstructor->getLocation(), - MultiStmtArg(*this, 0, 0), + MultiStmtArg(), /*isStmtExpr=*/false) .takeAs<Stmt>()); CopyConstructor->setImplicitlyDefined(true); @@ -8874,7 +9042,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, CXXRecordDecl *ClassDecl = MoveConstructor->getParent(); assert(ClassDecl && "DefineImplicitMoveConstructor - invalid constructor"); - ImplicitlyDefinedFunctionScope Scope(*this, MoveConstructor); + SynthesizedFunctionScope Scope(*this, MoveConstructor); DiagnosticErrorTrap Trap(Diags); if (SetCtorInitializers(MoveConstructor, 0, 0, /*AnyErrors=*/false) || @@ -8886,7 +9054,7 @@ void Sema::DefineImplicitMoveConstructor(SourceLocation CurrentLocation, Sema::CompoundScopeRAII CompoundScope(*this); MoveConstructor->setBody(ActOnCompoundStmt(MoveConstructor->getLocation(), MoveConstructor->getLocation(), - MultiStmtArg(*this, 0, 0), + MultiStmtArg(), /*isStmtExpr=*/false) .takeAs<Stmt>()); MoveConstructor->setImplicitlyDefined(true); @@ -8926,7 +9094,7 @@ void Sema::DefineImplicitLambdaToFunctionPointerConversion( Conv->setUsed(); - ImplicitlyDefinedFunctionScope Scope(*this, Conv); + SynthesizedFunctionScope Scope(*this, Conv); DiagnosticErrorTrap Trap(Diags); // Return the address of the __invoke function. @@ -8959,7 +9127,7 @@ void Sema::DefineImplicitLambdaToBlockPointerConversion( { Conv->setUsed(); - ImplicitlyDefinedFunctionScope Scope(*this, Conv); + SynthesizedFunctionScope Scope(*this, Conv); DiagnosticErrorTrap Trap(Diags); // Copy-initialize the lambda object as needed to capture it. @@ -9014,12 +9182,12 @@ static bool hasOneRealArgument(MultiExprArg Args) { return false; default: - if (!Args.get()[1]->isDefaultArgument()) + if (!Args[1]->isDefaultArgument()) return false; // fall through case 1: - return !Args.get()[0]->isDefaultArgument(); + return !Args[0]->isDefaultArgument(); } return false; @@ -9047,12 +9215,12 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, // directly into the target of the omitted copy/move if (ConstructKind == CXXConstructExpr::CK_Complete && Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) { - Expr *SubExpr = ((Expr **)ExprArgs.get())[0]; + Expr *SubExpr = ExprArgs[0]; Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent()); } return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, - Elidable, move(ExprArgs), HadMultipleCandidates, + Elidable, ExprArgs, HadMultipleCandidates, RequiresZeroInit, ConstructKind, ParenRange); } @@ -9066,12 +9234,9 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange) { - unsigned NumExprs = ExprArgs.size(); - Expr **Exprs = (Expr **)ExprArgs.release(); - MarkFunctionReferenced(ConstructLoc, Constructor); return Owned(CXXConstructExpr::Create(Context, DeclInitType, ConstructLoc, - Constructor, Elidable, Exprs, NumExprs, + Constructor, Elidable, ExprArgs, HadMultipleCandidates, /*FIXME*/false, RequiresZeroInit, static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind), @@ -9085,7 +9250,7 @@ bool Sema::InitializeVarWithConstructor(VarDecl *VD, // FIXME: Provide the correct paren SourceRange when available. ExprResult TempResult = BuildCXXConstructExpr(VD->getLocation(), VD->getType(), Constructor, - move(Exprs), HadMultipleCandidates, false, + Exprs, HadMultipleCandidates, false, CXXConstructExpr::CK_Complete, SourceRange()); if (TempResult.isInvalid()) return true; @@ -9135,11 +9300,11 @@ bool Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, MultiExprArg ArgsPtr, SourceLocation Loc, - ASTOwningVector<Expr*> &ConvertedArgs, + SmallVectorImpl<Expr*> &ConvertedArgs, bool AllowExplicit) { // FIXME: This duplicates a lot of code from Sema::ConvertArgumentsForCall. unsigned NumArgs = ArgsPtr.size(); - Expr **Args = (Expr **)ArgsPtr.get(); + Expr **Args = ArgsPtr.data(); const FunctionProtoType *Proto = Constructor->getType()->getAs<FunctionProtoType>(); @@ -9268,7 +9433,7 @@ CheckOperatorNewDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) { } static bool -CheckOperatorDeleteDeclaration(Sema &SemaRef, const FunctionDecl *FnDecl) { +CheckOperatorDeleteDeclaration(Sema &SemaRef, FunctionDecl *FnDecl) { // C++ [basic.stc.dynamic.deallocation]p1: // A program is ill-formed if deallocation functions are declared in a // namespace scope other than global scope or declared static in global @@ -9825,7 +9990,7 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, /// \brief Perform semantic analysis of the given friend type declaration. /// /// \returns A friend declaration that. -FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc, +FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation LocStart, SourceLocation FriendLoc, TypeSourceInfo *TSInfo) { assert(TSInfo && "NULL TypeSourceInfo for friend type declaration"); @@ -9864,7 +10029,7 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc, diag::warn_cxx98_compat_nonclass_type_friend : diag::ext_nonclass_type_friend) << T - << SourceRange(FriendLoc, TypeRange.getEnd()); + << TypeRange; } } else if (T->getAs<EnumType>()) { Diag(FriendLoc, @@ -9872,18 +10037,22 @@ FriendDecl *Sema::CheckFriendTypeDecl(SourceLocation Loc, diag::warn_cxx98_compat_enum_friend : diag::ext_enum_friend) << T - << SourceRange(FriendLoc, TypeRange.getEnd()); + << TypeRange; } - // C++0x [class.friend]p3: + // C++11 [class.friend]p3: + // A friend declaration that does not declare a function shall have one + // of the following forms: + // friend elaborated-type-specifier ; + // friend simple-type-specifier ; + // friend typename-specifier ; + if (getLangOpts().CPlusPlus0x && LocStart != FriendLoc) + Diag(FriendLoc, diag::err_friend_not_first_in_declaration) << T; + // If the type specifier in a friend declaration designates a (possibly - // cv-qualified) class type, that class is declared as a friend; otherwise, + // cv-qualified) class type, that class is declared as a friend; otherwise, // the friend declaration is ignored. - - // FIXME: C++0x has some syntactic restrictions on friend type declarations - // in [class.friend]p3 that we do not implement. - - return FriendDecl::Create(Context, CurContext, Loc, TSInfo, FriendLoc); + return FriendDecl::Create(Context, CurContext, LocStart, TSInfo, FriendLoc); } /// Handle a friend tag declaration where the scope specifier was @@ -9901,7 +10070,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, if (TemplateParameterList *TemplateParams = MatchTemplateParametersToScopeSpecifier(TagLoc, NameLoc, SS, - TempParamLists.get(), + TempParamLists.data(), TempParamLists.size(), /*friend*/ true, isExplicitSpecialization, @@ -9916,7 +10085,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, TemplateParams, AS_public, /*ModulePrivateLoc=*/SourceLocation(), TempParamLists.size() - 1, - (TemplateParameterList**) TempParamLists.release()).take(); + TempParamLists.data()).take(); } else { // The "template<>" header is extraneous. Diag(TemplateParams->getTemplateLoc(), diag::err_template_tag_noparams) @@ -9929,7 +10098,7 @@ Decl *Sema::ActOnTemplatedFriendTag(Scope *S, SourceLocation FriendLoc, bool isAllExplicitSpecializations = true; for (unsigned I = TempParamLists.size(); I-- > 0; ) { - if (TempParamLists.get()[I]->size()) { + if (TempParamLists[I]->size()) { isAllExplicitSpecializations = false; break; } @@ -10076,7 +10245,7 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, if (unsigned NumTempParamLists = TempParams.size()) D = FriendTemplateDecl::Create(Context, CurContext, Loc, NumTempParamLists, - TempParams.release(), + TempParams.data(), TSI, DS.getFriendSpecLoc()); else @@ -10318,7 +10487,7 @@ Decl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, bool AddToScope = true; NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, TInfo, Previous, - move(TemplateParams), AddToScope); + TemplateParams, AddToScope); if (!ND) return 0; assert(ND->getDeclContext() == DC); @@ -10435,10 +10604,10 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { // If this definition appears within the record, do the checking when // the record is complete. const FunctionDecl *Primary = MD; - if (MD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) + if (const FunctionDecl *Pattern = MD->getTemplateInstantiationPattern()) // Find the uninstantiated declaration that actually had the '= default' // on it. - MD->getTemplateInstantiationPattern()->isDefined(Primary); + Pattern->isDefined(Primary); if (Primary == Primary->getCanonicalDecl()) return; @@ -10963,14 +11132,16 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor, if (Ctor->isInvalidDecl()) return; - const FunctionDecl *FNTarget = 0; - CXXConstructorDecl *Target; - - // We ignore the result here since if we don't have a body, Target will be - // null below. - (void)Ctor->getTargetConstructor()->hasBody(FNTarget); - Target -= const_cast<CXXConstructorDecl*>(cast_or_null<CXXConstructorDecl>(FNTarget)); + CXXConstructorDecl *Target = Ctor->getTargetConstructor(); + + // Target may not be determinable yet, for instance if this is a dependent + // call in an uninstantiated template. + if (Target) { + const FunctionDecl *FNTarget = 0; + (void)Target->hasBody(FNTarget); + Target = const_cast<CXXConstructorDecl*>( + cast_or_null<CXXConstructorDecl>(FNTarget)); + } CXXConstructorDecl *Canonical = Ctor->getCanonicalDecl(), // Avoid dereferencing a null pointer here. @@ -10994,17 +11165,18 @@ void DelegatingCycleHelper(CXXConstructorDecl* Ctor, diag::warn_delegating_ctor_cycle) << Ctor; - // Don't add a note for a function delegating directo to itself. + // Don't add a note for a function delegating directly to itself. if (TCanonical != Canonical) S.Diag(Target->getLocation(), diag::note_it_delegates_to); CXXConstructorDecl *C = Target; while (C->getCanonicalDecl() != Canonical) { + const FunctionDecl *FNTarget = 0; (void)C->getTargetConstructor()->hasBody(FNTarget); assert(FNTarget && "Ctor cycle through bodiless function"); - C - = const_cast<CXXConstructorDecl*>(cast<CXXConstructorDecl>(FNTarget)); + C = const_cast<CXXConstructorDecl*>( + cast<CXXConstructorDecl>(FNTarget)); S.Diag(C->getLocation(), diag::note_which_delegates_to); } } @@ -11027,9 +11199,8 @@ void Sema::CheckDelegatingCtorCycles() { for (DelegatingCtorDeclsType::iterator I = DelegatingCtorDecls.begin(ExternalSource), E = DelegatingCtorDecls.end(); - I != E; ++I) { - DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); - } + I != E; ++I) + DelegatingCycleHelper(*I, Valid, Invalid, Current, *this); for (CI = Invalid.begin(), CE = Invalid.end(); CI != CE; ++CI) (*CI)->setInvalidDecl(); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 9da4d69382ef..c4e91e85015f 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -282,6 +282,25 @@ void Sema::AddAnyMethodToGlobalPool(Decl *D) { AddFactoryMethodToGlobalPool(MDecl, true); } +/// HasExplicitOwnershipAttr - returns true when pointer to ObjC pointer +/// has explicit ownership attribute; false otherwise. +static bool +HasExplicitOwnershipAttr(Sema &S, ParmVarDecl *Param) { + QualType T = Param->getType(); + + if (const PointerType *PT = T->getAs<PointerType>()) { + T = PT->getPointeeType(); + } else if (const ReferenceType *RT = T->getAs<ReferenceType>()) { + T = RT->getPointeeType(); + } else { + return true; + } + + // If we have a lifetime qualifier, but it's local, we must have + // inferred it. So, it is implicit. + return !T.getLocalQualifiers().hasObjCLifetime(); +} + /// ActOnStartOfObjCMethodDef - This routine sets up parameters; invisible /// and user declared, in the method definition's AST. void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { @@ -313,6 +332,12 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { RequireCompleteType(Param->getLocation(), Param->getType(), diag::err_typecheck_decl_incomplete_type)) Param->setInvalidDecl(); + if (!Param->isInvalidDecl() && + getLangOpts().ObjCAutoRefCount && + !HasExplicitOwnershipAttr(*this, Param)) + Diag(Param->getLocation(), diag::warn_arc_strong_pointer_objc_pointer) << + Param->getType(); + if ((*PI)->getIdentifier()) PushOnScopeChains(*PI, FnBodyScope); } @@ -345,8 +370,10 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { // Warn on deprecated methods under -Wdeprecated-implementations, // and prepare for warning on missing super calls. if (ObjCInterfaceDecl *IC = MDecl->getClassInterface()) { - if (ObjCMethodDecl *IMD = - IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod())) + ObjCMethodDecl *IMD = + IC->lookupMethod(MDecl->getSelector(), MDecl->isInstanceMethod()); + + if (IMD) DiagnoseObjCImplementedDeprecations(*this, dyn_cast<NamedDecl>(IMD), MDecl->getLocation(), 0); @@ -356,13 +383,23 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { // Finally, in ActOnFinishFunctionBody() (SemaDecl), warn if flag is set. // Only do this if the current class actually has a superclass. if (IC->getSuperClass()) { - getCurFunction()->ObjCShouldCallSuperDealloc = - !(Context.getLangOpts().ObjCAutoRefCount || - Context.getLangOpts().getGC() == LangOptions::GCOnly) && - MDecl->getMethodFamily() == OMF_dealloc; - getCurFunction()->ObjCShouldCallSuperFinalize = - Context.getLangOpts().getGC() != LangOptions::NonGC && - MDecl->getMethodFamily() == OMF_finalize; + ObjCMethodFamily Family = MDecl->getMethodFamily(); + if (Family == OMF_dealloc) { + if (!(getLangOpts().ObjCAutoRefCount || + getLangOpts().getGC() == LangOptions::GCOnly)) + getCurFunction()->ObjCShouldCallSuper = true; + + } else if (Family == OMF_finalize) { + if (Context.getLangOpts().getGC() != LangOptions::NonGC) + getCurFunction()->ObjCShouldCallSuper = true; + + } else { + const ObjCMethodDecl *SuperMethod = + IC->getSuperClass()->lookupMethod(MDecl->getSelector(), + MDecl->isInstanceMethod()); + getCurFunction()->ObjCShouldCallSuper = + (SuperMethod && SuperMethod->hasAttr<ObjCRequiresSuperAttr>()); + } } } } @@ -510,7 +547,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc, // Check then save referenced protocols. if (NumProtoRefs) { - IDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, + IDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs, ProtoLocs, Context); IDecl->setEndOfDefinitionLoc(EndProtoLoc); } @@ -652,7 +689,7 @@ Sema::ActOnStartProtocolInterface(SourceLocation AtProtoInterfaceLoc, if (!err && NumProtoRefs ) { /// Check then save referenced protocols. - PDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, + PDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs, ProtoLocs, Context); } @@ -819,11 +856,11 @@ ActOnStartCategoryInterface(SourceLocation AtInterfaceLoc, CurContext->addDecl(CDecl); if (NumProtoRefs) { - CDecl->setProtocolList((ObjCProtocolDecl**)ProtoRefs, NumProtoRefs, + CDecl->setProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs, ProtoLocs, Context); // Protocols in the class extension belong to the class. if (CDecl->IsClassExtension()) - IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl**)ProtoRefs, + IDecl->mergeClassExtensionProtocolList((ObjCProtocolDecl*const*)ProtoRefs, NumProtoRefs, Context); } @@ -1545,9 +1582,9 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, E = PDecl->instmeth_end(); I != E; ++I) { ObjCMethodDecl *method = *I; if (method->getImplementationControl() != ObjCMethodDecl::Optional && - !method->isSynthesized() && !InsMap.count(method->getSelector()) && - (!Super || - !Super->lookupInstanceMethod(method->getSelector()))) { + !method->isPropertyAccessor() && + !InsMap.count(method->getSelector()) && + (!Super || !Super->lookupInstanceMethod(method->getSelector()))) { // If a method is not implemented in the category implementation but // has been declared in its primary class, superclass, // or in one of their protocols, no need to issue the warning. @@ -1560,7 +1597,7 @@ void Sema::CheckProtocolMethodDefs(SourceLocation ImpLoc, if (ObjCMethodDecl *MethodInClass = IDecl->lookupInstanceMethod(method->getSelector(), true /*shallowCategoryLookup*/)) - if (C || MethodInClass->isSynthesized()) + if (C || MethodInClass->isPropertyAccessor()) continue; unsigned DIAG = diag::warn_unimplemented_protocol_method; if (Diags.getDiagnosticLevel(DIAG, ImpLoc) @@ -1621,7 +1658,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, if (InsMapSeen.count((*I)->getSelector())) continue; InsMapSeen.insert((*I)->getSelector()); - if (!(*I)->isSynthesized() && + if (!(*I)->isPropertyAccessor() && !InsMap.count((*I)->getSelector())) { if (ImmediateClass) WarnUndefinedMethod(IMPDecl->getLocation(), *I, IncompleteImpl, @@ -1638,7 +1675,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, if (!WarnCategoryMethodImpl) WarnConflictingTypedMethods(ImpMethodDecl, MethodDecl, isa<ObjCProtocolDecl>(CDecl)); - else if (!MethodDecl->isSynthesized()) + else if (!MethodDecl->isPropertyAccessor()) WarnExactTypedMethods(ImpMethodDecl, MethodDecl, isa<ObjCProtocolDecl>(CDecl)); } @@ -1672,14 +1709,26 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, } if (ObjCInterfaceDecl *I = dyn_cast<ObjCInterfaceDecl> (CDecl)) { - // Also methods in class extensions need be looked at next. - for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension(); - ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) - MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, - IMPDecl, - const_cast<ObjCCategoryDecl *>(ClsExtDecl), - IncompleteImpl, false, - WarnCategoryMethodImpl); + // when checking that methods in implementation match their declaration, + // i.e. when WarnCategoryMethodImpl is false, check declarations in class + // extension; as well as those in categories. + if (!WarnCategoryMethodImpl) + for (const ObjCCategoryDecl *CDeclChain = I->getCategoryList(); + CDeclChain; CDeclChain = CDeclChain->getNextClassCategory()) + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + IMPDecl, + const_cast<ObjCCategoryDecl *>(CDeclChain), + IncompleteImpl, false, + WarnCategoryMethodImpl); + else + // Also methods in class extensions need be looked at next. + for (const ObjCCategoryDecl *ClsExtDecl = I->getFirstClassExtension(); + ClsExtDecl; ClsExtDecl = ClsExtDecl->getNextClassExtension()) + MatchAllMethodDeclarations(InsMap, ClsMap, InsMapSeen, ClsMapSeen, + IMPDecl, + const_cast<ObjCCategoryDecl *>(ClsExtDecl), + IncompleteImpl, false, + WarnCategoryMethodImpl); // Check for any implementation of a methods declared in protocol. for (ObjCInterfaceDecl::all_protocol_iterator @@ -2339,11 +2388,11 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, CExtDecl; CExtDecl = CExtDecl->getNextClassExtension()) { if (ObjCMethodDecl *GetterMethod = CExtDecl->getInstanceMethod(Property->getGetterName())) - GetterMethod->setSynthesized(true); + GetterMethod->setPropertyAccessor(true); if (!Property->isReadOnly()) if (ObjCMethodDecl *SetterMethod = CExtDecl->getInstanceMethod(Property->getSetterName())) - SetterMethod->setSynthesized(true); + SetterMethod->setPropertyAccessor(true); } } } @@ -2435,26 +2484,49 @@ CvtQTToAstBitMask(ObjCDeclSpec::ObjCDeclQualifier PQTVal) { } static inline +unsigned countAlignAttr(const AttrVec &A) { + unsigned count=0; + for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i) + if ((*i)->getKind() == attr::Aligned) + ++count; + return count; +} + +static inline bool containsInvalidMethodImplAttribute(ObjCMethodDecl *IMD, const AttrVec &A) { // If method is only declared in implementation (private method), // No need to issue any diagnostics on method definition with attributes. if (!IMD) return false; - + // method declared in interface has no attribute. - // But implementation has attributes. This is invalid + // But implementation has attributes. This is invalid. + // Except when implementation has 'Align' attribute which is + // immaterial to method declared in interface. if (!IMD->hasAttrs()) - return true; + return (A.size() > countAlignAttr(A)); const AttrVec &D = IMD->getAttrs(); - if (D.size() != A.size()) - return true; + unsigned countAlignOnImpl = countAlignAttr(A); + if (!countAlignOnImpl && (A.size() != D.size())) + return true; + else if (countAlignOnImpl) { + unsigned countAlignOnDecl = countAlignAttr(D); + if (countAlignOnDecl && (A.size() != D.size())) + return true; + else if (!countAlignOnDecl && + ((A.size()-countAlignOnImpl) != D.size())) + return true; + } + // attributes on method declaration and definition must match exactly. // Note that we have at most a couple of attributes on methods, so this // n*n search is good enough. for (AttrVec::const_iterator i = A.begin(), e = A.end(); i != e; ++i) { + if ((*i)->getKind() == attr::Aligned) + continue; bool match = false; for (AttrVec::const_iterator i1 = D.begin(), e1 = D.end(); i1 != e1; ++i1) { if ((*i)->getKind() == (*i1)->getKind()) { @@ -2465,6 +2537,7 @@ bool containsInvalidMethodImplAttribute(ObjCMethodDecl *IMD, if (!match) return true; } + return false; } @@ -2525,7 +2598,7 @@ public: // with this selector before. Sema::GlobalMethodPool::iterator it = S.MethodPool.find(selector); if (it == S.MethodPool.end()) { - if (!S.ExternalSource) return; + if (!S.getExternalSource()) return; S.ReadMethodPool(selector); it = S.MethodPool.find(selector); @@ -2767,7 +2840,7 @@ Decl *Sema::ActOnMethodDeclaration( ResultTInfo, CurContext, MethodType == tok::minus, isVariadic, - /*isSynthesized=*/false, + /*isPropertyAccessor=*/false, /*isImplicitlyDeclared=*/false, /*isDefined=*/false, MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index e6266fb0863a..e1f4888d632f 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -120,6 +120,24 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { return SourceDecl->getType()->castAs<FunctionProtoType>(); } +/// Determine whether a function has an implicitly-generated exception +/// specification. +static bool hasImplicitExceptionSpec(FunctionDecl *Decl) { + if (!isa<CXXDestructorDecl>(Decl) && + Decl->getDeclName().getCXXOverloadedOperator() != OO_Delete && + Decl->getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) + return false; + + // If the user didn't declare the function, its exception specification must + // be implicit. + if (!Decl->getTypeSourceInfo()) + return true; + + const FunctionProtoType *Ty = + Decl->getTypeSourceInfo()->getType()->getAs<FunctionProtoType>(); + return !Ty->hasExceptionSpec(); +} + bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; @@ -129,25 +147,35 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { if (getLangOpts().MicrosoftExt) DiagID = diag::warn_mismatched_exception_spec; - if (!CheckEquivalentExceptionSpec(PDiag(DiagID), - PDiag(diag::note_previous_declaration), - Old->getType()->getAs<FunctionProtoType>(), - Old->getLocation(), - New->getType()->getAs<FunctionProtoType>(), - New->getLocation(), - &MissingExceptionSpecification, - &MissingEmptyExceptionSpecification, - /*AllowNoexceptAllMatchWithNoSpec=*/true, - IsOperatorNew)) + // Check the types as written: they must match before any exception + // specification adjustment is applied. + if (!CheckEquivalentExceptionSpec( + PDiag(DiagID), PDiag(diag::note_previous_declaration), + Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), + New->getType()->getAs<FunctionProtoType>(), New->getLocation(), + &MissingExceptionSpecification, &MissingEmptyExceptionSpecification, + /*AllowNoexceptAllMatchWithNoSpec=*/true, IsOperatorNew)) { + // C++11 [except.spec]p4 [DR1492]: + // If a declaration of a function has an implicit + // exception-specification, other declarations of the function shall + // not specify an exception-specification. + if (getLangOpts().CPlusPlus0x && + hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) { + Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch) + << hasImplicitExceptionSpec(Old); + if (!Old->getLocation().isInvalid()) + Diag(Old->getLocation(), diag::note_previous_declaration); + } return false; + } // The failure was something other than an empty exception // specification; return an error. if (!MissingExceptionSpecification && !MissingEmptyExceptionSpecification) return true; - const FunctionProtoType *NewProto - = New->getType()->getAs<FunctionProtoType>(); + const FunctionProtoType *NewProto = + New->getType()->getAs<FunctionProtoType>(); // The new function declaration is only missing an empty exception // specification "throw()". If the throw() specification came from a @@ -172,8 +200,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { } if (MissingExceptionSpecification && NewProto) { - const FunctionProtoType *OldProto - = Old->getType()->getAs<FunctionProtoType>(); + const FunctionProtoType *OldProto = + Old->getType()->getAs<FunctionProtoType>(); FunctionProtoType::ExtProtoInfo EPI = NewProto->getExtProtoInfo(); EPI.ExceptionSpecType = OldProto->getExceptionSpecType(); @@ -290,14 +318,17 @@ bool Sema::CheckEquivalentExceptionSpec( unsigned DiagID = diag::err_mismatched_exception_spec; if (getLangOpts().MicrosoftExt) DiagID = diag::warn_mismatched_exception_spec; - return CheckEquivalentExceptionSpec( - PDiag(DiagID), + return CheckEquivalentExceptionSpec(PDiag(DiagID), PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc); } /// CheckEquivalentExceptionSpec - Check if the two types have compatible /// exception specifications. See C++ [except.spec]p3. +/// +/// \return \c false if the exception specifications match, \c true if there is +/// a problem. If \c true is returned, either a diagnostic has already been +/// produced or \c *MissingExceptionSpecification is set to \c true. bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, const FunctionProtoType *Old, @@ -1029,6 +1060,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::PseudoObjectExprClass: case Expr::SubstNonTypeTemplateParmExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::FunctionParmPackExprClass: case Expr::UnaryExprOrTypeTraitExprClass: case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 3875ba171366..bf4abfcb7460 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -66,6 +66,15 @@ bool Sema::CanUseDecl(NamedDecl *D) { return true; } +static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { + // Warn if this is used but marked unused. + if (D->hasAttr<UnusedAttr>()) { + const Decl *DC = cast<Decl>(S.getCurObjCLexicalContext()); + if (!DC->hasAttr<UnusedAttr>()) + S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName(); + } +} + static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass) { @@ -78,6 +87,17 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC)) Result = TheEnumDecl->getAvailability(&Message); } + + const ObjCPropertyDecl *ObjCPDecl = 0; + if (Result == AR_Deprecated || Result == AR_Unavailable) { + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { + AvailabilityResult PDeclResult = PD->getAvailability(0); + if (PDeclResult == Result) + ObjCPDecl = PD; + } + } + } switch (Result) { case AR_Available: @@ -85,23 +105,30 @@ static AvailabilityResult DiagnoseAvailabilityOfDecl(Sema &S, break; case AR_Deprecated: - S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass); + S.EmitDeprecationWarning(D, Message, Loc, UnknownObjCClass, ObjCPDecl); break; case AR_Unavailable: if (S.getCurContextAvailability() != AR_Unavailable) { if (Message.empty()) { - if (!UnknownObjCClass) + if (!UnknownObjCClass) { S.Diag(Loc, diag::err_unavailable) << D->getDeclName(); + if (ObjCPDecl) + S.Diag(ObjCPDecl->getLocation(), diag::note_property_attribute) + << ObjCPDecl->getDeclName() << 1; + } else S.Diag(Loc, diag::warn_unavailable_fwdclass_message) << D->getDeclName(); } - else + else S.Diag(Loc, diag::err_unavailable_message) << D->getDeclName() << Message; - S.Diag(D->getLocation(), diag::note_unavailable_here) - << isa<FunctionDecl>(D) << false; + S.Diag(D->getLocation(), diag::note_unavailable_here) + << isa<FunctionDecl>(D) << false; + if (ObjCPDecl) + S.Diag(ObjCPDecl->getLocation(), diag::note_property_attribute) + << ObjCPDecl->getDeclName() << 1; } break; } @@ -250,9 +277,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, } DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass); - // Warn if this is used but marked unused. - if (D->hasAttr<UnusedAttr>()) - Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName(); + DiagnoseUnusedOfDecl(*this, D, Loc); diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc); @@ -502,7 +527,7 @@ ExprResult Sema::DefaultFunctionArrayLvalueConversion(Expr *E) { Res = DefaultLvalueConversion(Res.take()); if (Res.isInvalid()) return ExprError(); - return move(Res); + return Res; } @@ -1098,8 +1123,8 @@ Sema::ActOnGenericSelectionExpr(SourceLocation KeyLoc, unsigned NumAssocs = ArgTypes.size(); assert(NumAssocs == ArgExprs.size()); - ParsedType *ParsedTypes = ArgTypes.release(); - Expr **Exprs = ArgExprs.release(); + ParsedType *ParsedTypes = ArgTypes.data(); + Expr **Exprs = ArgExprs.data(); TypeSourceInfo **Types = new TypeSourceInfo*[NumAssocs]; for (unsigned i = 0; i < NumAssocs; ++i) { @@ -1185,8 +1210,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, if (IsResultDependent) return Owned(new (Context) GenericSelectionExpr( Context, KeyLoc, ControllingExpr, - Types, Exprs, NumAssocs, DefaultLoc, - RParenLoc, ContainsUnexpandedParameterPack)); + llvm::makeArrayRef(Types, NumAssocs), + llvm::makeArrayRef(Exprs, NumAssocs), + DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack)); SmallVector<unsigned, 1> CompatIndices; unsigned DefaultIndex = -1U; @@ -1240,8 +1266,9 @@ Sema::CreateGenericSelectionExpr(SourceLocation KeyLoc, return Owned(new (Context) GenericSelectionExpr( Context, KeyLoc, ControllingExpr, - Types, Exprs, NumAssocs, DefaultLoc, - RParenLoc, ContainsUnexpandedParameterPack, + llvm::makeArrayRef(Types, NumAssocs), + llvm::makeArrayRef(Exprs, NumAssocs), + DefaultLoc, RParenLoc, ContainsUnexpandedParameterPack, ResultIndex)); } @@ -1402,6 +1429,15 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, MarkDeclRefReferenced(E); + if (getLangOpts().ObjCARCWeak && isa<VarDecl>(D) && + Ty.getObjCLifetime() == Qualifiers::OCL_Weak) { + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, + E->getLocStart()); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->recordUseOfWeak(E); + } + // Just in case we're building an illegal pointer-to-member. FieldDecl *FD = dyn_cast<FieldDecl>(D); if (FD && FD->isBitField()) @@ -1428,11 +1464,9 @@ Sema::DecomposeUnqualifiedId(const UnqualifiedId &Id, Buffer.setLAngleLoc(Id.TemplateId->LAngleLoc); Buffer.setRAngleLoc(Id.TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(*this, - Id.TemplateId->getTemplateArgs(), + ASTTemplateArgsPtr TemplateArgsPtr(Id.TemplateId->getTemplateArgs(), Id.TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, Buffer); - TemplateArgsPtr.release(); TemplateName TName = Id.TemplateId->Template.get(); SourceLocation TNameLoc = Id.TemplateId->TemplateNameLoc; @@ -1606,7 +1640,8 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R, Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << computeDeclContext(SS, false) << CorrectedQuotedStr << SS.getRange() - << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); + << FixItHint::CreateReplacement(Corrected.getCorrectionRange(), + CorrectedStr); if (ND) Diag(ND->getLocation(), diag::note_previous_decl) << CorrectedQuotedStr; @@ -1797,7 +1832,7 @@ ExprResult Sema::ActOnIdExpression(Scope *S, // lookup fails and no expression will be built to reference it. if (!E.isInvalid() && !E.get()) return ExprError(); - return move(E); + return E; } } } @@ -1860,9 +1895,10 @@ ExprResult Sema::ActOnIdExpression(Scope *S, /// this path. ExprResult Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, - const DeclarationNameInfo &NameInfo) { - DeclContext *DC; - if (!(DC = computeDeclContext(SS, false)) || DC->isDependentContext()) + const DeclarationNameInfo &NameInfo, + bool IsAddressOfOperand) { + DeclContext *DC = computeDeclContext(SS, false); + if (!DC) return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*TemplateArgs=*/0); @@ -1875,13 +1911,26 @@ Sema::BuildQualifiedDeclarationNameExpr(CXXScopeSpec &SS, if (R.isAmbiguous()) return ExprError(); + if (R.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) + return BuildDependentDeclRefExpr(SS, /*TemplateKWLoc=*/SourceLocation(), + NameInfo, /*TemplateArgs=*/0); + if (R.empty()) { Diag(NameInfo.getLoc(), diag::err_no_member) << NameInfo.getName() << DC << SS.getRange(); return ExprError(); } - return BuildDeclarationNameExpr(SS, R, /*ADL*/ false); + // Defend against this resolving to an implicit member access. We usually + // won't get here if this might be a legitimate a class member (we end up in + // BuildMemberReferenceExpr instead), but this can be valid if we're forming + // a pointer-to-member or in an unevaluated context in C++11. + if (!R.empty() && (*R.begin())->isCXXClassMember() && !IsAddressOfOperand) + return BuildPossibleImplicitMemberExpr(SS, + /*TemplateKWLoc=*/SourceLocation(), + R, /*TemplateArgs=*/0); + + return BuildDeclarationNameExpr(SS, R, /* ADL */ false); } /// LookupInObjCMethod - The parser has read a name in, and Sema has @@ -1965,9 +2014,25 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, ObjCMethodFamily MF = CurMethod->getMethodFamily(); if (MF != OMF_init && MF != OMF_dealloc && MF != OMF_finalize) Diag(Loc, diag::warn_direct_ivar_access) << IV->getDeclName(); - return Owned(new (Context) - ObjCIvarRefExpr(IV, IV->getType(), Loc, - SelfExpr.take(), true, true)); + + ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(), + Loc, + SelfExpr.take(), + true, true); + + if (getLangOpts().ObjCAutoRefCount) { + if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, Loc); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->recordUseOfWeak(Result); + } + if (CurContext->isClosure()) + Diag(Loc, diag::warn_implicitly_retains_self) + << FixItHint::CreateInsertion(Loc, "self->"); + } + + return Owned(Result); } } else if (CurMethod->isInstanceMethod()) { // We should warn if a local variable hides an ivar. @@ -2416,6 +2481,14 @@ Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, } case Decl::Function: { + if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) { + if (!Context.BuiltinInfo.isPredefinedLibFunction(BID)) { + type = Context.BuiltinFnTy; + valueKind = VK_RValue; + break; + } + } + const FunctionType *fty = type->castAs<FunctionType>(); // If we're referring to a function with an __unknown_anytype @@ -2615,19 +2688,20 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { return ActOnIntegerConstant(Tok.getLocation(), Val-'0'); } - SmallString<512> IntegerBuffer; - // Add padding so that NumericLiteralParser can overread by one character. - IntegerBuffer.resize(Tok.getLength()+1); - const char *ThisTokBegin = &IntegerBuffer[0]; + SmallString<128> SpellingBuffer; + // NumericLiteralParser wants to overread by one character. Add padding to + // the buffer in case the token is copied to the buffer. If getSpelling() + // returns a StringRef to the memory buffer, it should have a null char at + // the EOF, so it is also safe. + SpellingBuffer.resize(Tok.getLength() + 1); // Get the spelling of the token, which eliminates trigraphs, etc. bool Invalid = false; - unsigned ActualLength = PP.getSpelling(Tok, ThisTokBegin, &Invalid); + StringRef TokSpelling = PP.getSpelling(Tok, SpellingBuffer, &Invalid); if (Invalid) return ExprError(); - NumericLiteralParser Literal(ThisTokBegin, ThisTokBegin+ActualLength, - Tok.getLocation(), PP); + NumericLiteralParser Literal(TokSpelling, Tok.getLocation(), PP); if (Literal.hadError) return ExprError(); @@ -2693,7 +2767,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { Context.CharTy, llvm::APInt(32, Length + 1), ArrayType::Normal, 0); Expr *Lit = StringLiteral::Create( - Context, StringRef(ThisTokBegin, Length), StringLiteral::Ascii, + Context, StringRef(TokSpelling.data(), Length), StringLiteral::Ascii, /*Pascal*/false, StrTy, &TokLoc, 1); return BuildLiteralOperatorCall(R, OpNameInfo, llvm::makeArrayRef(&Lit, 1), TokLoc); @@ -2709,7 +2783,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { bool CharIsUnsigned = Context.CharTy->isUnsignedIntegerType(); llvm::APSInt Value(CharBits, CharIsUnsigned); for (unsigned I = 0, N = Literal.getUDSuffixOffset(); I != N; ++I) { - Value = ThisTokBegin[I]; + Value = TokSpelling[I]; TemplateArgument Arg(Context, Value, Context.CharTy); TemplateArgumentLocInfo ArgInfo; ExplicitArgs.addArgument(TemplateArgumentLoc(Arg, ArgInfo)); @@ -2747,11 +2821,15 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } else { QualType Ty; - // long long is a C99 feature. - if (!getLangOpts().C99 && Literal.isLongLong) - Diag(Tok.getLocation(), - getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_longlong : diag::ext_longlong); + // 'long long' is a C99 or C++11 feature. + if (!getLangOpts().C99 && Literal.isLongLong) { + if (getLangOpts().CPlusPlus) + Diag(Tok.getLocation(), + getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); + else + Diag(Tok.getLocation(), diag::ext_c99_longlong); + } // Get the value in the widest-possible width. unsigned MaxWidth = Context.getTargetInfo().getIntMaxTWidth(); @@ -3140,7 +3218,7 @@ Sema::ActOnUnaryExprOrTypeTraitExpr(SourceLocation OpLoc, Expr *ArgEx = (Expr *)TyOrEx; ExprResult Result = CreateUnaryExprOrTypeTraitExpr(ArgEx, OpLoc, ExprKind); - return move(Result); + return Result; } static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc, @@ -3167,7 +3245,7 @@ static QualType CheckRealImagOperand(Sema &S, ExprResult &V, SourceLocation Loc, ExprResult PR = S.CheckPlaceholderExpr(V.get()); if (PR.isInvalid()) return QualType(); if (PR.get() != V.get()) { - V = move(PR); + V = PR; return CheckRealImagOperand(S, V, Loc, IsReal); } @@ -3442,8 +3520,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, Expr *ResultE = Result.takeAs<Expr>(); InitializationSequence InitSeq(*this, Entity, Kind, &ResultE, 1); - Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, &ResultE, 1)); + Result = InitSeq.Perform(*this, Entity, Kind, ResultE); if (Result.isInvalid()) return ExprError(); @@ -3776,28 +3853,25 @@ ExprResult Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, MultiExprArg ArgExprs, SourceLocation RParenLoc, Expr *ExecConfig, bool IsExecConfig) { - unsigned NumArgs = ArgExprs.size(); - // Since this might be a postfix expression, get rid of ParenListExprs. ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Fn); if (Result.isInvalid()) return ExprError(); Fn = Result.take(); - Expr **Args = ArgExprs.release(); - if (getLangOpts().CPlusPlus) { // If this is a pseudo-destructor expression, build the call immediately. if (isa<CXXPseudoDestructorExpr>(Fn)) { - if (NumArgs > 0) { + if (!ArgExprs.empty()) { // Pseudo-destructor calls should not have any arguments. Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args) << FixItHint::CreateRemoval( - SourceRange(Args[0]->getLocStart(), - Args[NumArgs-1]->getLocEnd())); + SourceRange(ArgExprs[0]->getLocStart(), + ArgExprs.back()->getLocEnd())); } - return Owned(new (Context) CallExpr(Context, Fn, 0, 0, Context.VoidTy, - VK_RValue, RParenLoc)); + return Owned(new (Context) CallExpr(Context, Fn, MultiExprArg(), + Context.VoidTy, VK_RValue, + RParenLoc)); } // Determine whether this is a dependent call inside a C++ template, @@ -3807,17 +3881,16 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, bool Dependent = false; if (Fn->isTypeDependent()) Dependent = true; - else if (Expr::hasAnyTypeDependentArguments( - llvm::makeArrayRef(Args, NumArgs))) + else if (Expr::hasAnyTypeDependentArguments(ArgExprs)) Dependent = true; if (Dependent) { if (ExecConfig) { return Owned(new (Context) CUDAKernelCallExpr( - Context, Fn, cast<CallExpr>(ExecConfig), Args, NumArgs, + Context, Fn, cast<CallExpr>(ExecConfig), ArgExprs, Context.DependentTy, VK_RValue, RParenLoc)); } else { - return Owned(new (Context) CallExpr(Context, Fn, Args, NumArgs, + return Owned(new (Context) CallExpr(Context, Fn, ArgExprs, Context.DependentTy, VK_RValue, RParenLoc)); } @@ -3825,8 +3898,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, // Determine whether this is a call to an object (C++ [over.call.object]). if (Fn->getType()->isRecordType()) - return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, Args, NumArgs, - RParenLoc)); + return Owned(BuildCallToObjectOfClassType(S, Fn, LParenLoc, + ArgExprs.data(), + ArgExprs.size(), RParenLoc)); if (Fn->getType() == Context.UnknownAnyTy) { ExprResult result = rebuildUnknownAnyFunction(*this, Fn); @@ -3835,8 +3909,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, } if (Fn->getType() == Context.BoundMemberTy) { - return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, - RParenLoc); + return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs.data(), + ArgExprs.size(), RParenLoc); } } @@ -3849,11 +3923,11 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, OverloadExpr *ovl = find.Expression; if (isa<UnresolvedLookupExpr>(ovl)) { UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(ovl); - return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, Args, NumArgs, - RParenLoc, ExecConfig); + return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, ArgExprs.data(), + ArgExprs.size(), RParenLoc, ExecConfig); } else { - return BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs, - RParenLoc); + return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs.data(), + ArgExprs.size(), RParenLoc); } } } @@ -3877,8 +3951,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, else if (isa<MemberExpr>(NakedFn)) NDecl = cast<MemberExpr>(NakedFn)->getMemberDecl(); - return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, Args, NumArgs, RParenLoc, - ExecConfig, IsExecConfig); + return BuildResolvedCallExpr(Fn, NDecl, LParenLoc, ArgExprs.data(), + ArgExprs.size(), RParenLoc, ExecConfig, + IsExecConfig); } ExprResult @@ -3932,9 +4007,19 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, SourceLocation RParenLoc, Expr *Config, bool IsExecConfig) { FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl); + unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0); // Promote the function operand. - ExprResult Result = UsualUnaryConversions(Fn); + // We special-case function promotion here because we only allow promoting + // builtin functions to function pointers in the callee of a call. + ExprResult Result; + if (BuiltinID && + Fn->getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)) { + Result = ImpCastExprToType(Fn, Context.getPointerType(FDecl->getType()), + CK_BuiltinFnToFnPtr).take(); + } else { + Result = UsualUnaryConversions(Fn); + } if (Result.isInvalid()) return ExprError(); Fn = Result.take(); @@ -3945,19 +4030,17 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (Config) TheCall = new (Context) CUDAKernelCallExpr(Context, Fn, cast<CallExpr>(Config), - Args, NumArgs, + llvm::makeArrayRef(Args,NumArgs), Context.BoolTy, VK_RValue, RParenLoc); else TheCall = new (Context) CallExpr(Context, Fn, - Args, NumArgs, + llvm::makeArrayRef(Args, NumArgs), Context.BoolTy, VK_RValue, RParenLoc); - unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0); - // Bail out early if calling a builtin with custom typechecking. if (BuiltinID && Context.BuiltinInfo.hasCustomTypechecking(BuiltinID)) return CheckBuiltinFunctionCall(BuiltinID, TheCall); @@ -4143,9 +4226,8 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, SourceRange(LParenLoc, RParenLoc), /*InitList=*/true); InitializationSequence InitSeq(*this, Entity, Kind, &LiteralExpr, 1); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(*this, &LiteralExpr, 1), - &literalType); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, LiteralExpr, + &literalType); if (Result.isInvalid()) return ExprError(); LiteralExpr = Result.get(); @@ -4167,28 +4249,25 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, ExprResult Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, SourceLocation RBraceLoc) { - unsigned NumInit = InitArgList.size(); - Expr **InitList = InitArgList.release(); - // Immediately handle non-overload placeholders. Overloads can be // resolved contextually, but everything else here can't. - for (unsigned I = 0; I != NumInit; ++I) { - if (InitList[I]->getType()->isNonOverloadPlaceholderType()) { - ExprResult result = CheckPlaceholderExpr(InitList[I]); + for (unsigned I = 0, E = InitArgList.size(); I != E; ++I) { + if (InitArgList[I]->getType()->isNonOverloadPlaceholderType()) { + ExprResult result = CheckPlaceholderExpr(InitArgList[I]); // Ignore failures; dropping the entire initializer list because // of one failure would be terrible for indexing/etc. if (result.isInvalid()) continue; - InitList[I] = result.take(); + InitArgList[I] = result.take(); } } // Semantic analysis for initializers is done by ActOnDeclarator() and // CheckInitializer() - it requires knowledge of the object being intialized. - InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitList, - NumInit, RBraceLoc); + InitListExpr *E = new (Context) InitListExpr(Context, LBraceLoc, InitArgList, + RBraceLoc); E->setType(Context.VoidTy); // FIXME: just a place holder for now. return Owned(E); } @@ -4575,8 +4654,7 @@ ExprResult Sema::BuildVectorLiteral(SourceLocation LParenLoc, // FIXME: This means that pretty-printing the final AST will produce curly // braces instead of the original commas. InitListExpr *initE = new (Context) InitListExpr(Context, LParenLoc, - &initExprs[0], - initExprs.size(), RParenLoc); + initExprs, RParenLoc); initE->setType(Ty); return BuildCompoundLiteralExpr(LParenLoc, TInfo, RParenLoc, initE); } @@ -4603,10 +4681,8 @@ Sema::MaybeConvertParenListExprToParenExpr(Scope *S, Expr *OrigExpr) { ExprResult Sema::ActOnParenListExpr(SourceLocation L, SourceLocation R, MultiExprArg Val) { - unsigned nexprs = Val.size(); - Expr **exprs = reinterpret_cast<Expr**>(Val.release()); - assert((exprs != 0) && "ActOnParenOrParenListExpr() missing expr list"); - Expr *expr = new (Context) ParenListExpr(Context, L, exprs, nexprs, R); + assert(Val.data() != 0 && "ActOnParenOrParenListExpr() missing expr list"); + Expr *expr = new (Context) ParenListExpr(Context, L, Val, R); return Owned(expr); } @@ -4884,11 +4960,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult LHSResult = CheckPlaceholderExpr(LHS.get()); if (!LHSResult.isUsable()) return QualType(); - LHS = move(LHSResult); + LHS = LHSResult; ExprResult RHSResult = CheckPlaceholderExpr(RHS.get()); if (!RHSResult.isUsable()) return QualType(); - RHS = move(RHSResult); + RHS = RHSResult; // C++ is sufficiently different to merit its own checker. if (getLangOpts().CPlusPlus) @@ -5247,7 +5323,7 @@ static void DiagnoseConditionalPrecedence(Sema &Self, << BinaryOperator::getOpcodeStr(CondOpcode); SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::note_precedence_conditional_silence) + Self.PDiag(diag::note_precedence_silence) << BinaryOperator::getOpcodeStr(CondOpcode), SourceRange(Condition->getLocStart(), Condition->getLocEnd())); @@ -5811,8 +5887,7 @@ static void ConstructTransparentUnion(Sema &S, ASTContext &C, // of the transparent union. Expr *E = EResult.take(); InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(), - &E, 1, - SourceLocation()); + E, SourceLocation()); Initializer->setType(UnionType); Initializer->setInitializedFieldInUnion(Field); @@ -5910,7 +5985,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS, !CheckObjCARCUnavailableWeakConversion(LHSType, RHS.get()->getType())) result = IncompatibleObjCWeakRef; - RHS = move(Res); + RHS = Res; return result; } @@ -6708,7 +6783,7 @@ static void diagnoseFunctionPointerToVoidComparison(Sema &S, SourceLocation Loc, } static bool isObjCObjectLiteral(ExprResult &E) { - switch (E.get()->getStmtClass()) { + switch (E.get()->IgnoreParenImpCasts()->getStmtClass()) { case Stmt::ObjCArrayLiteralClass: case Stmt::ObjCDictionaryLiteralClass: case Stmt::ObjCStringLiteralClass: @@ -6800,6 +6875,7 @@ static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc, LK_String } LiteralKind; + Literal = Literal->IgnoreParenImpCasts(); switch (Literal->getStmtClass()) { case Stmt::ObjCStringLiteralClass: // "string literal" @@ -7202,7 +7278,10 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, (LHSType->isIntegerType() && RHSType->isAnyPointerType())) { unsigned DiagID = 0; bool isError = false; - if ((LHSIsNull && LHSType->isIntegerType()) || + if (LangOpts.DebuggerSupport) { + // Under a debugger, allow the comparison of pointers to integers, + // since users tend to want to compare addresses. + } else if ((LHSIsNull && LHSType->isIntegerType()) || (RHSIsNull && RHSType->isIntegerType())) { if (IsRelational && !getLangOpts().CPlusPlus) DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero; @@ -7419,12 +7498,12 @@ inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14] ExprResult LHSRes = PerformContextuallyConvertToBool(LHS.get()); if (LHSRes.isInvalid()) return InvalidOperands(Loc, LHS, RHS); - LHS = move(LHSRes); + LHS = LHSRes; ExprResult RHSRes = PerformContextuallyConvertToBool(RHS.get()); if (RHSRes.isInvalid()) return InvalidOperands(Loc, LHS, RHS); - RHS = move(RHSRes); + RHS = RHSRes; // C++ [expr.log.and]p2 // C++ [expr.log.or]p2 @@ -7683,10 +7762,31 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, } if (ConvTy == Compatible) { - if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) - checkRetainCycles(LHSExpr, RHS.get()); - else if (getLangOpts().ObjCAutoRefCount) + if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) { + // Warn about retain cycles where a block captures the LHS, but + // not if the LHS is a simple variable into which the block is + // being stored...unless that variable can be captured by reference! + const Expr *InnerLHS = LHSExpr->IgnoreParenCasts(); + const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InnerLHS); + if (!DRE || DRE->getDecl()->hasAttr<BlocksAttr>()) + checkRetainCycles(LHSExpr, RHS.get()); + + // It is safe to assign a weak reference into a strong variable. + // Although this code can still have problems: + // id x = self.weakProp; + // id y = self.weakProp; + // we do not warn to warn spuriously when 'x' and 'y' are on separate + // paths through the function. This should be revisited if + // -Wrepeated-use-of-weak is made flow-sensitive. + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, + RHS.get()->getLocStart()); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->markSafeWeakUse(RHS.get()); + + } else if (getLangOpts().ObjCAutoRefCount) { checkUnsafeExprAssigns(Loc, LHSExpr, RHS.get()); + } } } else { // Compound assignment "x += y" @@ -7972,8 +8072,16 @@ static QualType CheckAddressOfOperand(Sema &S, ExprResult &OrigOp, // The method was named without a qualifier. } else if (!DRE->getQualifier()) { - S.Diag(OpLoc, diag::err_unqualified_pointer_member_function) - << op->getSourceRange(); + if (MD->getParent()->getName().empty()) + S.Diag(OpLoc, diag::err_unqualified_pointer_member_function) + << op->getSourceRange(); + else { + SmallString<32> Str; + StringRef Qual = (MD->getParent()->getName() + "::").toStringRef(Str); + S.Diag(OpLoc, diag::err_unqualified_pointer_member_function) + << op->getSourceRange() + << FixItHint::CreateInsertion(op->getSourceRange().getBegin(), Qual); + } } return S.Context.getMemberPointerType(op->getType(), @@ -8216,8 +8324,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, InitializedEntity Entity = InitializedEntity::InitializeTemporary(LHSExpr->getType()); InitializationSequence InitSeq(*this, Entity, Kind, &RHSExpr, 1); - ExprResult Init = InitSeq.Perform(*this, Entity, Kind, - MultiExprArg(&RHSExpr, 1)); + ExprResult Init = InitSeq.Perform(*this, Entity, Kind, RHSExpr); if (Init.isInvalid()) return Init; RHSExpr = Init.take(); @@ -8340,7 +8447,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, if (CompResultTy.isNull()) return Owned(new (Context) BinaryOperator(LHS.take(), RHS.take(), Opc, - ResultTy, VK, OK, OpLoc)); + ResultTy, VK, OK, OpLoc, + FPFeatures.fp_contract)); if (getLangOpts().CPlusPlus && LHS.get()->getObjectKind() != OK_ObjCProperty) { VK = VK_LValue; @@ -8348,7 +8456,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, } return Owned(new (Context) CompoundAssignOperator(LHS.take(), RHS.take(), Opc, ResultTy, VK, OK, CompLHSTy, - CompResultTy, OpLoc)); + CompResultTy, OpLoc, + FPFeatures.fp_contract)); } /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison @@ -8383,8 +8492,8 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, SourceRange DiagRange = isLeftComp ? SourceRange(LHSExpr->getLocStart(), OpLoc) : SourceRange(OpLoc, RHSExpr->getLocEnd()); - std::string OpStr = isLeftComp ? BinOp::getOpcodeStr(LHSopc) - : BinOp::getOpcodeStr(RHSopc); + StringRef OpStr = isLeftComp ? BinOp::getOpcodeStr(LHSopc) + : BinOp::getOpcodeStr(RHSopc); SourceRange ParensRange = isLeftComp ? SourceRange(cast<BinOp>(LHSExpr)->getRHS()->getLocStart(), RHSExpr->getLocEnd()) @@ -8394,7 +8503,7 @@ static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperatorKind Opc, Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) << DiagRange << BinOp::getOpcodeStr(Opc) << OpStr; SuggestParentheses(Self, OpLoc, - Self.PDiag(diag::note_precedence_bitwise_silence) << OpStr, + Self.PDiag(diag::note_precedence_silence) << OpStr, (isLeftComp ? LHSExpr : RHSExpr)->getSourceRange()); SuggestParentheses(Self, OpLoc, Self.PDiag(diag::note_precedence_bitwise_first) << BinOp::getOpcodeStr(Opc), @@ -8411,7 +8520,8 @@ EmitDiagnosticForBitwiseAndInBitwiseOr(Sema &Self, SourceLocation OpLoc, Self.Diag(Bop->getOperatorLoc(), diag::warn_bitwise_and_in_bitwise_or) << Bop->getSourceRange() << OpLoc; SuggestParentheses(Self, Bop->getOperatorLoc(), - Self.PDiag(diag::note_bitwise_and_in_bitwise_or_silence), + Self.PDiag(diag::note_precedence_silence) + << Bop->getOpcodeStr(), Bop->getSourceRange()); } @@ -8425,7 +8535,8 @@ EmitDiagnosticForLogicalAndInLogicalOr(Sema &Self, SourceLocation OpLoc, Self.Diag(Bop->getOperatorLoc(), diag::warn_logical_and_in_logical_or) << Bop->getSourceRange() << OpLoc; SuggestParentheses(Self, Bop->getOperatorLoc(), - Self.PDiag(diag::note_logical_and_in_logical_or_silence), + Self.PDiag(diag::note_precedence_silence) + << Bop->getOpcodeStr(), Bop->getSourceRange()); } @@ -8489,6 +8600,20 @@ static void DiagnoseBitwiseAndInBitwiseOr(Sema &S, SourceLocation OpLoc, } } +static void DiagnoseAdditionInShift(Sema &S, SourceLocation OpLoc, + Expr *SubExpr, StringRef Shift) { + if (BinaryOperator *Bop = dyn_cast<BinaryOperator>(SubExpr)) { + if (Bop->getOpcode() == BO_Add || Bop->getOpcode() == BO_Sub) { + StringRef Op = Bop->getOpcodeStr(); + S.Diag(Bop->getOperatorLoc(), diag::warn_addition_in_bitshift) + << Bop->getSourceRange() << OpLoc << Shift << Op; + SuggestParentheses(S, Bop->getOperatorLoc(), + S.PDiag(diag::note_precedence_silence) << Op, + Bop->getSourceRange()); + } + } +} + /// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky /// precedence. static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, @@ -8510,6 +8635,13 @@ static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperatorKind Opc, DiagnoseLogicalAndInLogicalOrLHS(Self, OpLoc, LHSExpr, RHSExpr); DiagnoseLogicalAndInLogicalOrRHS(Self, OpLoc, LHSExpr, RHSExpr); } + + if ((Opc == BO_Shl && LHSExpr->getType()->isIntegralType(Self.getASTContext())) + || Opc == BO_Shr) { + StringRef Shift = BinaryOperator::getOpcodeStr(Opc); + DiagnoseAdditionInShift(Self, OpLoc, LHSExpr, Shift); + DiagnoseAdditionInShift(Self, OpLoc, RHSExpr, Shift); + } } // Binary Operators. 'Tok' is the token for the operator. @@ -8647,6 +8779,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, break; case UO_Deref: { Input = DefaultFunctionArrayLvalueConversion(Input.take()); + if (Input.isInvalid()) return ExprError(); resultType = CheckIndirectionOperand(*this, Input.get(), VK, OpLoc); break; } @@ -9147,8 +9280,7 @@ ExprResult Sema::BuildBuiltinOffsetOf(SourceLocation BuiltinLoc, } return Owned(OffsetOfExpr::Create(Context, Context.getSizeType(), BuiltinLoc, - TInfo, Comps.data(), Comps.size(), - Exprs.data(), Exprs.size(), RParenLoc)); + TInfo, Comps, Exprs, RParenLoc)); } ExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, @@ -9526,6 +9658,16 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, if (Result.isInvalid()) return ExprError(); E = Result.take(); + } else if (VaListType->isRecordType() && getLangOpts().CPlusPlus) { + // If va_list is a record type and we are compiling in C++ mode, + // check the argument using reference binding. + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Context, + Context.getLValueReferenceType(VaListType), false); + ExprResult Init = PerformCopyInitialization(Entity, SourceLocation(), E); + if (Init.isInvalid()) + return ExprError(); + E = Init.takeAs<Expr>(); } else { // Otherwise, the va_list argument must be an l-value because // it is modified by va_arg. @@ -10094,6 +10236,14 @@ Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); } +void +Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, + ReuseLambdaContextDecl_t, + bool IsDecltype) { + Decl *LambdaContextDecl = ExprEvalContexts.back().LambdaContextDecl; + PushExpressionEvaluationContext(NewContext, LambdaContextDecl, IsDecltype); +} + void Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back(); @@ -10191,15 +10341,44 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func) { Func->setReferenced(); - // Don't mark this function as used multiple times, unless it's a constexpr - // function which we need to instantiate. - if (Func->isUsed(false) && - !(Func->isConstexpr() && !Func->getBody() && - Func->isImplicitlyInstantiable())) - return; - - if (!IsPotentiallyEvaluatedContext(*this)) - return; + // C++11 [basic.def.odr]p3: + // A function whose name appears as a potentially-evaluated expression is + // odr-used if it is the unique lookup result or the selected member of a + // set of overloaded functions [...]. + // + // We (incorrectly) mark overload resolution as an unevaluated context, so we + // can just check that here. Skip the rest of this function if we've already + // marked the function as used. + if (Func->isUsed(false) || !IsPotentiallyEvaluatedContext(*this)) { + // C++11 [temp.inst]p3: + // Unless a function template specialization has been explicitly + // instantiated or explicitly specialized, the function template + // specialization is implicitly instantiated when the specialization is + // referenced in a context that requires a function definition to exist. + // + // We consider constexpr function templates to be referenced in a context + // that requires a definition to exist whenever they are referenced. + // + // FIXME: This instantiates constexpr functions too frequently. If this is + // really an unevaluated context (and we're not just in the definition of a + // function template or overload resolution or other cases which we + // incorrectly consider to be unevaluated contexts), and we're not in a + // subexpression which we actually need to evaluate (for instance, a + // template argument, array bound or an expression in a braced-init-list), + // we are not permitted to instantiate this constexpr function definition. + // + // FIXME: This also implicitly defines special members too frequently. They + // are only supposed to be implicitly defined if they are odr-used, but they + // are not odr-used from constant expressions in unevaluated contexts. + // However, they cannot be referenced if they are deleted, and they are + // deleted whenever the implicit definition of the special member would + // fail. + if (!Func->isConstexpr() || Func->getBody()) + return; + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func); + if (!Func->isImplicitlyInstantiable() && (!MD || MD->isUserProvided())) + return; + } // Note that this declaration has been used. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) { @@ -10469,8 +10648,7 @@ static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, InitializationSequence Init(S, Entities.back(), InitKind, &Ref, 1); ExprResult Result(true); if (!Init.Diagnose(S, Entities.back(), InitKind, &Ref, 1)) - Result = Init.Perform(S, Entities.back(), InitKind, - MultiExprArg(S, &Ref, 1)); + Result = Init.Perform(S, Entities.back(), InitKind, Ref); // If this initialization requires any cleanups (e.g., due to a // default argument to a copy constructor), note that for the @@ -10886,20 +11064,21 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, } } - // Per C++11 [basic.def.odr], a variable is odr-used "unless it is - // an object that satisfies the requirements for appearing in a - // constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) + // Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies + // the requirements for appearing in a constant expression (5.19) and, if + // it is an object, the lvalue-to-rvalue conversion (4.1) // is immediately applied." We check the first part here, and // Sema::UpdateMarkingForLValueToRValue deals with the second part. // Note that we use the C++11 definition everywhere because nothing in - // C++03 depends on whether we get the C++03 version correct. This does not - // apply to references, since they are not objects. + // C++03 depends on whether we get the C++03 version correct. The second + // part does not apply to references, since they are not objects. const VarDecl *DefVD; - if (E && !isa<ParmVarDecl>(Var) && !Var->getType()->isReferenceType() && + if (E && !isa<ParmVarDecl>(Var) && Var->isUsableInConstantExpressions(SemaRef.Context) && - Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE()) - SemaRef.MaybeODRUseExprs.insert(E); - else + Var->getAnyInitializer(DefVD) && DefVD->checkInitIsICE()) { + if (!Var->getType()->isReferenceType()) + SemaRef.MaybeODRUseExprs.insert(E); + } else MarkVarDeclODRUsed(SemaRef, Var, Loc); } @@ -11205,7 +11384,9 @@ void Sema::DiagnoseAssignmentAsCondition(Expr *E) { IsOrAssign = Op->getOperator() == OO_PipeEqual; Loc = Op->getOperatorLoc(); - } else { + } else if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) + return DiagnoseAssignmentAsCondition(POE->getSyntacticForm()); + else { // Not an assignment. return; } @@ -11759,6 +11940,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { case BuiltinType::PseudoObject: return checkPseudoObjectRValue(E); + case BuiltinType::BuiltinFn: + Diag(E->getLocStart(), diag::err_builtin_fn_use); + return ExprError(); + // Everything else should be impossible. #define BUILTIN_TYPE(Id, SingletonId) \ case BuiltinType::Id: @@ -11783,6 +11968,18 @@ ExprResult Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { assert((Kind == tok::kw___objc_yes || Kind == tok::kw___objc_no) && "Unknown Objective-C Boolean value!"); + QualType BoolT = Context.ObjCBuiltinBoolTy; + if (!Context.getBOOLDecl()) { + LookupResult Result(*this, &Context.Idents.get("BOOL"), OpLoc, + Sema::LookupOrdinaryName); + if (LookupName(Result, getCurScope()) && Result.isSingleResult()) { + NamedDecl *ND = Result.getFoundDecl(); + if (TypedefDecl *TD = dyn_cast<TypedefDecl>(ND)) + Context.setBOOLDecl(TD); + } + } + if (Context.getBOOLDecl()) + BoolT = Context.getBOOLType(); return Owned(new (Context) ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes, - Context.ObjCBuiltinBoolTy, OpLoc)); + BoolT, OpLoc)); } diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 27402599a401..0919bc5b6fa4 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -410,33 +410,13 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } -/// Retrieve the UuidAttr associated with QT. -static UuidAttr *GetUuidAttrOfType(QualType QT) { - // Optionally remove one level of pointer, reference or array indirection. - const Type *Ty = QT.getTypePtr();; - if (QT->isPointerType() || QT->isReferenceType()) - Ty = QT->getPointeeType().getTypePtr(); - else if (QT->isArrayType()) - Ty = cast<ArrayType>(QT)->getElementType().getTypePtr(); - - // Loop all record redeclaration looking for an uuid attribute. - CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); - for (CXXRecordDecl::redecl_iterator I = RD->redecls_begin(), - E = RD->redecls_end(); I != E; ++I) { - if (UuidAttr *Uuid = I->getAttr<UuidAttr>()) - return Uuid; - } - - return 0; -} - /// \brief Build a Microsoft __uuidof expression with a type operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { if (!Operand->getType()->isDependentType()) { - if (!GetUuidAttrOfType(Operand->getType())) + if (!CXXUuidofExpr::GetUuidAttrOfType(Operand->getType())) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); } @@ -452,7 +432,7 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, Expr *E, SourceLocation RParenLoc) { if (!E->getType()->isDependentType()) { - if (!GetUuidAttrOfType(E->getType()) && + if (!CXXUuidofExpr::GetUuidAttrOfType(E->getType()) && !E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); } @@ -808,21 +788,18 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, MultiExprArg exprs, SourceLocation RParenLoc) { QualType Ty = TInfo->getType(); - unsigned NumExprs = exprs.size(); - Expr **Exprs = (Expr**)exprs.get(); SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc(); - if (Ty->isDependentType() || - CallExpr::hasAnyTypeDependentArguments( - llvm::makeArrayRef(Exprs, NumExprs))) { - exprs.release(); - + if (Ty->isDependentType() || CallExpr::hasAnyTypeDependentArguments(exprs)) { return Owned(CXXUnresolvedConstructExpr::Create(Context, TInfo, LParenLoc, - Exprs, NumExprs, + exprs, RParenLoc)); } + unsigned NumExprs = exprs.size(); + Expr **Exprs = exprs.data(); + bool ListInitialization = LParenLoc.isInvalid(); assert((!ListInitialization || (NumExprs == 1 && isa<InitListExpr>(Exprs[0]))) && "List initialization must have initializer list as expression."); @@ -835,7 +812,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, // corresponding cast expression. if (NumExprs == 1 && !ListInitialization) { Expr *Arg = Exprs[0]; - exprs.release(); return BuildCXXFunctionalCastExpr(TInfo, LParenLoc, Arg, RParenLoc); } @@ -865,7 +841,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, : InitializationKind::CreateValue(TyBeginLoc, LParenLoc, RParenLoc); InitializationSequence InitSeq(*this, Entity, Kind, Exprs, NumExprs); - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, move(exprs)); + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, exprs); if (!Result.isInvalid() && ListInitialization && isa<InitListExpr>(Result.get())) { @@ -881,7 +857,7 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, } // FIXME: Improve AST representation? - return move(Result); + return Result; } /// doesUsualArrayDeleteWantSize - Answers whether the usual @@ -1011,9 +987,9 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) DirectInitRange = List->getSourceRange(); - return BuildCXXNew(StartLoc, UseGlobal, + return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal, PlacementLParen, - move(PlacementArgs), + PlacementArgs, PlacementRParen, TypeIdParens, AllocType, @@ -1044,7 +1020,7 @@ static bool isLegalArrayNewInitializer(CXXNewExpr::InitializationStyle Style, } ExprResult -Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, +Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, SourceLocation PlacementLParen, MultiExprArg PlacementArgs, SourceLocation PlacementRParen, @@ -1056,6 +1032,7 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, Expr *Initializer, bool TypeMayContainAuto) { SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange(); + SourceLocation StartLoc = Range.getBegin(); CXXNewExpr::InitializationStyle initStyle; if (DirectInitRange.isValid()) { @@ -1279,21 +1256,13 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - // ARC: warn about ABI issues. - if (getLangOpts().ObjCAutoRefCount) { - QualType BaseAllocType = Context.getBaseElementType(AllocType); - if (BaseAllocType.hasStrongOrWeakObjCLifetime()) - Diag(StartLoc, diag::warn_err_new_delete_object_array) - << 0 << BaseAllocType; - } - // Note that we do *not* convert the argument in any way. It can // be signed, larger than size_t, whatever. } FunctionDecl *OperatorNew = 0; FunctionDecl *OperatorDelete = 0; - Expr **PlaceArgs = (Expr**)PlacementArgs.get(); + Expr **PlaceArgs = PlacementArgs.data(); unsigned NumPlaceArgs = PlacementArgs.size(); if (!AllocType->isDependentType() && @@ -1432,15 +1401,14 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal, } } - PlacementArgs.release(); - return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew, OperatorDelete, UsualArrayDeleteWantsSize, - PlaceArgs, NumPlaceArgs, TypeIdParens, + llvm::makeArrayRef(PlaceArgs, NumPlaceArgs), + TypeIdParens, ArraySize, initStyle, Initializer, ResultType, AllocTypeInfo, - StartLoc, DirectInitRange)); + Range, DirectInitRange)); } /// \brief Checks that a type is suitable as the allocated type @@ -1638,7 +1606,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, = dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) { // Perform template argument deduction to try to match the // expected function type. - TemplateDeductionInfo Info(Context, StartLoc); + TemplateDeductionInfo Info(StartLoc); if (DeduceTemplateArguments(FnTmpl, 0, ExpectedFunctionType, Fn, Info)) continue; } else @@ -2100,7 +2068,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, ObjectPtrConversions.front()->getConversionType(), AA_Converting); if (Res.isUsable()) { - Ex = move(Res); + Ex = Res; Type = Ex.get()->getType(); } } @@ -2211,13 +2179,6 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, } } - } else if (getLangOpts().ObjCAutoRefCount && - PointeeElem->isObjCLifetimeType() && - (PointeeElem.getObjCLifetime() == Qualifiers::OCL_Strong || - PointeeElem.getObjCLifetime() == Qualifiers::OCL_Weak) && - ArrayForm) { - Diag(StartLoc, diag::warn_err_new_delete_object_array) - << 1 << PointeeElem; } if (!OperatorDelete) { @@ -2287,7 +2248,7 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, return ExprError(); } - return move(Condition); + return Condition; } /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid. @@ -2354,11 +2315,9 @@ static ExprResult BuildCXXCastArgument(Sema &S, default: llvm_unreachable("Unhandled cast kind!"); case CK_ConstructorConversion: { CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Method); - ASTOwningVector<Expr*> ConstructorArgs(S); + SmallVector<Expr*, 8> ConstructorArgs; - if (S.CompleteConstructorCall(Constructor, - MultiExprArg(&From, 1), - CastLoc, ConstructorArgs)) + if (S.CompleteConstructorCall(Constructor, From, CastLoc, ConstructorArgs)) return ExprError(); S.CheckConstructorAccess(CastLoc, Constructor, @@ -2367,7 +2326,7 @@ static ExprResult BuildCXXCastArgument(Sema &S, ExprResult Result = S.BuildCXXConstructExpr(CastLoc, Ty, cast<CXXConstructorDecl>(Method), - move_arg(ConstructorArgs), + ConstructorArgs, HadMultipleCandidates, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); if (Result.isInvalid()) @@ -2511,15 +2470,14 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // FIXME: When can ToType be a reference type? assert(!ToType->isReferenceType()); if (SCS.Second == ICK_Derived_To_Base) { - ASTOwningVector<Expr*> ConstructorArgs(*this); + SmallVector<Expr*, 8> ConstructorArgs; if (CompleteConstructorCall(cast<CXXConstructorDecl>(SCS.CopyConstructor), - MultiExprArg(*this, &From, 1), - /*FIXME:ConstructLoc*/SourceLocation(), + From, /*FIXME:ConstructLoc*/SourceLocation(), ConstructorArgs)) return ExprError(); return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), ToType, SCS.CopyConstructor, - move_arg(ConstructorArgs), + ConstructorArgs, /*HadMultipleCandidates*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, @@ -2527,8 +2485,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } return BuildCXXConstructExpr(/*FIXME:ConstructLoc*/SourceLocation(), ToType, SCS.CopyConstructor, - MultiExprArg(*this, &From, 1), - /*HadMultipleCandidates*/ false, + From, /*HadMultipleCandidates*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -2602,8 +2559,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Integral_Promotion: case ICK_Integral_Conversion: - From = ImpCastExprToType(From, ToType, CK_IntegralCast, - VK_RValue, /*BasePath=*/0, CCK).take(); + if (ToType->isBooleanType()) { + assert(FromType->castAs<EnumType>()->getDecl()->isFixed() && + SCS.Second == ICK_Integral_Promotion && + "only enums with fixed underlying type can promote to bool"); + From = ImpCastExprToType(From, ToType, CK_IntegralToBoolean, + VK_RValue, /*BasePath=*/0, CCK).take(); + } else { + From = ImpCastExprToType(From, ToType, CK_IntegralCast, + VK_RValue, /*BasePath=*/0, CCK).take(); + } break; case ICK_Floating_Promotion: @@ -2943,6 +2908,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, case UTT_IsEmpty: case UTT_IsPolymorphic: case UTT_IsAbstract: + case UTT_IsInterfaceClass: // Fall-through // These traits require a complete type. @@ -3007,7 +2973,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, case UTT_IsUnion: return T->isUnionType(); case UTT_IsClass: - return T->isClassType() || T->isStructureType(); + return T->isClassType() || T->isStructureType() || T->isInterfaceType(); case UTT_IsFunction: return T->isFunctionType(); @@ -3073,6 +3039,10 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, UnaryTypeTrait UTT, if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->isAbstract(); return false; + case UTT_IsInterfaceClass: + if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) + return RD->isInterface(); + return false; case UTT_IsFinal: if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return RD->hasAttr<FinalAttr>(); @@ -3417,9 +3387,7 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, if (Init.Failed()) return false; - ExprResult Result = Init.Perform(S, To, InitKind, - MultiExprArg(ArgExprs.data(), - ArgExprs.size())); + ExprResult Result = Init.Perform(S, To, InitKind, ArgExprs); if (Result.isInvalid() || SFINAE.hasErrorOccurred()) return false; @@ -3577,7 +3545,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, BinaryTypeTrait BTT, if (Init.Failed()) return false; - ExprResult Result = Init.Perform(Self, To, Kind, MultiExprArg(&FromPtr, 1)); + ExprResult Result = Init.Perform(Self, To, Kind, FromPtr); return !Result.isInvalid() && !SFINAE.hasErrorOccurred(); } @@ -3774,7 +3742,7 @@ ExprResult Sema::ActOnExpressionTrait(ExpressionTrait ET, ExprResult Result = BuildExpressionTrait(ET, KWLoc, Queried, RParen); - return move(Result); + return Result; } static bool EvaluateExpressionTrait(ExpressionTrait ET, Expr *E) { @@ -4056,14 +4024,14 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS Best->Conversions[0], Sema::AA_Converting); if (LHSRes.isInvalid()) break; - LHS = move(LHSRes); + LHS = LHSRes; ExprResult RHSRes = Self.PerformImplicitConversion(RHS.get(), Best->BuiltinTypes.ParamTypes[1], Best->Conversions[1], Sema::AA_Converting); if (RHSRes.isInvalid()) break; - RHS = move(RHSRes); + RHS = RHSRes; if (Best->Function) Self.MarkFunctionReferenced(QuestionLoc, Best->Function); return false; @@ -4104,7 +4072,7 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { SourceLocation()); Expr *Arg = E.take(); InitializationSequence InitSeq(Self, Entity, Kind, &Arg, 1); - ExprResult Result = InitSeq.Perform(Self, Entity, Kind, MultiExprArg(&Arg, 1)); + ExprResult Result = InitSeq.Perform(Self, Entity, Kind, Arg); if (Result.isInvalid()) return true; @@ -4129,7 +4097,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult CondRes = CheckCXXBooleanCondition(Cond.take()); if (CondRes.isInvalid()) return QualType(); - Cond = move(CondRes); + Cond = CondRes; } // Assume r-value. @@ -4160,6 +4128,9 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &NonVoid = LVoid ? RHS : LHS; if (NonVoid.get()->getType()->isRecordType() && NonVoid.get()->isGLValue()) { + if (RequireNonAbstractType(QuestionLoc, NonVoid.get()->getType(), + diag::err_allocation_of_abstract_type)) + return QualType(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(NonVoid.get()->getType()); NonVoid = PerformCopyInitialization(Entity, SourceLocation(), NonVoid); @@ -4302,7 +4273,11 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. + if (RequireNonAbstractType(QuestionLoc, LTy, + diag::err_allocation_of_abstract_type)) + return QualType(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); + ExprResult LHSCopy = PerformCopyInitialization(Entity, SourceLocation(), LHS); @@ -4566,14 +4541,14 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // Convert E1 to Composite1 ExprResult E1Result - = E1ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,&E1,1)); + = E1ToC1.Perform(*this, Entity1, Kind, E1); if (E1Result.isInvalid()) return QualType(); E1 = E1Result.takeAs<Expr>(); // Convert E2 to Composite1 ExprResult E2Result - = E2ToC1.Perform(*this, Entity1, Kind, MultiExprArg(*this,&E2,1)); + = E2ToC1.Perform(*this, Entity1, Kind, E2); if (E2Result.isInvalid()) return QualType(); E2 = E2Result.takeAs<Expr>(); @@ -4591,14 +4566,14 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // Convert E1 to Composite2 ExprResult E1Result - = E1ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E1, 1)); + = E1ToC2.Perform(*this, Entity2, Kind, E1); if (E1Result.isInvalid()) return QualType(); E1 = E1Result.takeAs<Expr>(); // Convert E2 to Composite2 ExprResult E2Result - = E2ToC2.Perform(*this, Entity2, Kind, MultiExprArg(*this, &E2, 1)); + = E2ToC2.Perform(*this, Entity2, Kind, E2); if (E2Result.isInvalid()) return QualType(); E2 = E2Result.takeAs<Expr>(); @@ -4839,7 +4814,8 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) { BO_Comma, BO->getType(), BO->getValueKind(), BO->getObjectKind(), - BO->getOperatorLoc())); + BO->getOperatorLoc(), + BO->isFPContractable())); } } @@ -4991,7 +4967,7 @@ Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, SourceLocation OpLoc, // type C (or of pointer to a class type C), the unqualified-id is looked // up in the scope of class C. [...] ObjectType = ParsedType::make(BaseType); - return move(Base); + return Base; } ExprResult Sema::DiagnoseDtorReference(SourceLocation NameLoc, @@ -5056,7 +5032,8 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) return ExprError(); - if (!ObjectType->isDependentType() && !ObjectType->isScalarType()) { + if (!ObjectType->isDependentType() && !ObjectType->isScalarType() && + !ObjectType->isVectorType()) { if (getLangOpts().MicrosoftMode && ObjectType->isVoidType()) Diag(OpLoc, diag::ext_pseudo_dtor_on_void) << Base->getSourceRange(); else @@ -5203,8 +5180,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, } else { // Resolve the template-id to a type. TemplateIdAnnotation *TemplateId = SecondTypeName.TemplateId; - ASTTemplateArgsPtr TemplateArgsPtr(*this, - TemplateId->getTemplateArgs(), + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(TemplateId->SS, TemplateId->TemplateKWLoc, @@ -5253,8 +5229,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, } else { // Resolve the template-id to a type. TemplateIdAnnotation *TemplateId = FirstTypeName.TemplateId; - ASTTemplateArgsPtr TemplateArgsPtr(*this, - TemplateId->getTemplateArgs(), + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(TemplateId->SS, TemplateId->TemplateKWLoc, @@ -5353,7 +5328,7 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, MarkFunctionReferenced(Exp.get()->getLocStart(), Method); CXXMemberCallExpr *CE = - new (Context) CXXMemberCallExpr(Context, ME, 0, 0, ResultType, VK, + new (Context) CXXMemberCallExpr(Context, ME, MultiExprArg(), ResultType, VK, Exp.get()->getLocEnd()); return CE; } diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index 8f445e28648d..a7fd47183a16 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -13,6 +13,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -353,7 +354,7 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, // Now look up the TypeDefDecl from the vector type. Without this, // diagostics look bad. We want extended vector types to appear built-in. for (Sema::ExtVectorDeclsType::iterator - I = S.ExtVectorDecls.begin(S.ExternalSource), + I = S.ExtVectorDecls.begin(S.getExternalSource()), E = S.ExtVectorDecls.end(); I != E; ++I) { if ((*I)->getUnderlyingType() == VT) @@ -605,7 +606,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R, R.addDecl(ND); SemaRef.Diag(R.getNameLoc(), diag::err_no_member_suggest) << Name << DC << CorrectedQuotedStr << SS.getRange() - << FixItHint::CreateReplacement(R.getNameLoc(), CorrectedStr); + << FixItHint::CreateReplacement(Corrected.getCorrectionRange(), + CorrectedStr); SemaRef.Diag(ND->getLocation(), diag::note_previous_decl) << ND->getDeclName(); } @@ -656,7 +658,7 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, } if (Result.get()) - return move(Result); + return Result; // LookupMemberExpr can modify Base, and thus change BaseType BaseType = Base->getType(); @@ -1021,7 +1023,7 @@ static bool ShouldTryAgainWithRedefinitionType(Sema &S, ExprResult &base) { // Do the substitution as long as the redefinition type isn't just a // possibly-qualified pointer to builtin-id or builtin-Class again. opty = redef->getAs<ObjCObjectPointerType>(); - if (opty && !opty->getObjectType()->getInterface() != 0) + if (opty && !opty->getObjectType()->getInterface()) return false; base = S.ImpCastExprToType(base.take(), redef, CK_BitCast); @@ -1272,9 +1274,23 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr, if (warn) Diag(MemberLoc, diag::warn_direct_ivar_access) << IV->getDeclName(); } - return Owned(new (Context) ObjCIvarRefExpr(IV, IV->getType(), - MemberLoc, BaseExpr.take(), - IsArrow)); + + ObjCIvarRefExpr *Result = new (Context) ObjCIvarRefExpr(IV, IV->getType(), + MemberLoc, + BaseExpr.take(), + IsArrow); + + if (getLangOpts().ObjCAutoRefCount) { + if (IV->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, + MemberLoc); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->recordUseOfWeak(Result); + } + } + + return Owned(Result); } // Objective-C property access. @@ -1550,7 +1566,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, Id.getKind() == UnqualifiedId::IK_DestructorName) return DiagnoseDtorReference(NameInfo.getLoc(), Result.get()); - return move(Result); + return Result; } ActOnMemberAccessExtraArgs ExtraArgs = {S, Id, ObjCImpDecl, HasTrailingLParen}; @@ -1560,7 +1576,7 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, false, &ExtraArgs); } - return move(Result); + return Result; } static ExprResult diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 0aabf8b634d1..e43b6bff5586 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -229,7 +229,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, S.NSNumberPointer, ResultTInfo, S.NSNumberDecl, /*isInstance=*/false, /*isVariadic=*/false, - /*isSynthesized=*/false, + /*isPropertyAccessor=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, @@ -345,7 +345,7 @@ static ExprResult CheckObjCCollectionLiteralElement(Sema &S, Expr *Element, SourceLocation()); InitializationSequence Seq(S, Entity, Kind, &Element, 1); if (!Seq.Failed()) - return Seq.Perform(S, Entity, Kind, MultiExprArg(S, &Element, 1)); + return Seq.Perform(S, Entity, Kind, Element); } Expr *OrigElement = Element; @@ -477,7 +477,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { stringWithUTF8String, NSStringPointer, ResultTInfo, NSStringDecl, /*isInstance=*/false, /*isVariadic=*/false, - /*isSynthesized=*/false, + /*isPropertyAccessor=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, @@ -646,7 +646,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { ResultTInfo, Context.getTranslationUnitDecl(), false /*Instance*/, false/*isVariadic*/, - /*isSynthesized=*/false, + /*isPropertyAccessor=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, false); @@ -708,7 +708,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { // Check that each of the elements provided is valid in a collection literal, // performing conversions as necessary. - Expr **ElementsBuffer = Elements.get(); + Expr **ElementsBuffer = Elements.data(); for (unsigned I = 0, N = Elements.size(); I != N; ++I) { ExprResult Converted = CheckObjCCollectionLiteralElement(*this, ElementsBuffer[I], @@ -724,10 +724,8 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { Context.getObjCInterfaceType(NSArrayDecl)); return MaybeBindToTemporary( - ObjCArrayLiteral::Create(Context, - llvm::makeArrayRef(Elements.get(), - Elements.size()), - Ty, ArrayWithObjectsMethod, SR)); + ObjCArrayLiteral::Create(Context, Elements, Ty, + ArrayWithObjectsMethod, SR)); } ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, @@ -766,7 +764,7 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, 0 /*TypeSourceInfo */, Context.getTranslationUnitDecl(), false /*Instance*/, false/*isVariadic*/, - /*isSynthesized=*/false, + /*isPropertyAccessor=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, false); @@ -1125,7 +1123,9 @@ void Sema::EmitRelatedResultTypeNote(const Expr *E) { bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, Expr **Args, unsigned NumArgs, - Selector Sel, ObjCMethodDecl *Method, + Selector Sel, + ArrayRef<SourceLocation> SelectorLocs, + ObjCMethodDecl *Method, bool isClassMessage, bool isSuperMessage, SourceLocation lbrac, SourceLocation rbrac, QualType &ReturnType, ExprValueKind &VK) { @@ -1149,7 +1149,8 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, : diag::warn_inst_method_not_found; if (!getLangOpts().DebuggerSupport) Diag(lbrac, DiagID) - << Sel << isClassMessage << SourceRange(lbrac, rbrac); + << Sel << isClassMessage << SourceRange(SelectorLocs.front(), + SelectorLocs.back()); // In debuggers, we want to use __unknown_anytype for these // results so that clients can cast them. @@ -1304,8 +1305,8 @@ static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) { Expr *RExpr = Receiver->IgnoreParenImpCasts(); SourceLocation Loc = RExpr->getLocStart(); QualType T = RExpr->getType(); - ObjCPropertyDecl *PDecl = 0; - ObjCMethodDecl *GDecl = 0; + const ObjCPropertyDecl *PDecl = 0; + const ObjCMethodDecl *GDecl = 0; if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(RExpr)) { RExpr = POE->getSyntacticForm(); if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(RExpr)) { @@ -1327,34 +1328,29 @@ static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) { // See if receiver is a method which envokes a synthesized getter // backing a 'weak' property. ObjCMethodDecl *Method = ME->getMethodDecl(); - if (Method && Method->isSynthesized()) { - Selector Sel = Method->getSelector(); - if (Sel.getNumArgs() == 0) { - const DeclContext *Container = Method->getDeclContext(); - PDecl = - S.LookupPropertyDecl(cast<ObjCContainerDecl>(Container), - Sel.getIdentifierInfoForSlot(0)); - } + if (Method && Method->getSelector().getNumArgs() == 0) { + PDecl = Method->findPropertyDecl(); if (PDecl) T = PDecl->getType(); } } - if (T.getObjCLifetime() == Qualifiers::OCL_Weak) { - S.Diag(Loc, diag::warn_receiver_is_weak) - << ((!PDecl && !GDecl) ? 0 : (PDecl ? 1 : 2)); - if (PDecl) - S.Diag(PDecl->getLocation(), diag::note_property_declare); - else if (GDecl) - S.Diag(GDecl->getLocation(), diag::note_method_declared_at) << GDecl; - return; + if (T.getObjCLifetime() != Qualifiers::OCL_Weak) { + if (!PDecl) + return; + if (!(PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)) + return; } - - if (PDecl && - (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)) { - S.Diag(Loc, diag::warn_receiver_is_weak) << 1; + + S.Diag(Loc, diag::warn_receiver_is_weak) + << ((!PDecl && !GDecl) ? 0 : (PDecl ? 1 : 2)); + + if (PDecl) S.Diag(PDecl->getLocation(), diag::note_property_declare); - } + else if (GDecl) + S.Diag(GDecl->getLocation(), diag::note_method_declared_at) << GDecl; + + S.Diag(Loc, diag::note_arc_assign_to_strong); } /// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an @@ -1776,19 +1772,17 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, // We are in a method whose class has a superclass, so 'super' // is acting as a keyword. - if (Method->isInstanceMethod()) { - if (Sel.getMethodFamily() == OMF_dealloc) - getCurFunction()->ObjCShouldCallSuperDealloc = false; - if (Sel.getMethodFamily() == OMF_finalize) - getCurFunction()->ObjCShouldCallSuperFinalize = false; + if (Method->getSelector() == Sel) + getCurFunction()->ObjCShouldCallSuper = false; + if (Method->isInstanceMethod()) { // Since we are in an instance method, this is an instance // message to the superclass instance. QualType SuperTy = Context.getObjCInterfaceType(Super); SuperTy = Context.getObjCObjectPointerType(SuperTy); return BuildInstanceMessage(0, SuperTy, SuperLoc, Sel, /*Method=*/0, - LBracLoc, SelectorLocs, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, Args); } // Since we are in a class method, this is a class message to @@ -1796,7 +1790,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, return BuildClassMessage(/*ReceiverTypeInfo=*/0, Context.getObjCInterfaceType(Super), SuperLoc, Sel, /*Method=*/0, - LBracLoc, SelectorLocs, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, Args); } @@ -1911,7 +1905,7 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, // If the receiver type is dependent, we can't type-check anything // at this point. Build a dependent expression. unsigned NumArgs = ArgsIn.size(); - Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); + Expr **Args = ArgsIn.data(); assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return Owned(ObjCMessageExpr::Create(Context, ReceiverType, VK_RValue, LBracLoc, ReceiverTypeInfo, @@ -1965,8 +1959,9 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, ExprValueKind VK = VK_RValue; unsigned NumArgs = ArgsIn.size(); - Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); - if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, true, + Expr **Args = ArgsIn.data(); + if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, SelectorLocs, + Method, true, SuperLoc.isValid(), LBracLoc, RBracLoc, ReturnType, VK)) return ExprError(); @@ -2016,7 +2011,7 @@ ExprResult Sema::ActOnClassMessage(Scope *S, return BuildClassMessage(ReceiverTypeInfo, ReceiverType, /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, - LBracLoc, SelectorLocs, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, Args); } ExprResult Sema::BuildInstanceMessageImplicit(Expr *Receiver, @@ -2095,7 +2090,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // If the receiver is type-dependent, we can't type-check anything // at this point. Build a dependent expression. unsigned NumArgs = ArgsIn.size(); - Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); + Expr **Args = ArgsIn.data(); assert(SuperLoc.isInvalid() && "Message to super with dependent type"); return Owned(ObjCMessageExpr::Create(Context, Context.DependentTy, VK_RValue, LBracLoc, Receiver, Sel, @@ -2282,7 +2277,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, LBracLoc, SelectorLocs, RBracLoc, - move(ArgsIn)); + ArgsIn); } else { // Reject other random receiver types (e.g. structs). Diag(Loc, diag::err_bad_receiver_type) @@ -2295,12 +2290,13 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // Check the message arguments. unsigned NumArgs = ArgsIn.size(); - Expr **Args = reinterpret_cast<Expr **>(ArgsIn.release()); + Expr **Args = ArgsIn.data(); QualType ReturnType; ExprValueKind VK = VK_RValue; bool ClassMessage = (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()); - if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, Method, + if (CheckMessageArgumentTypes(ReceiverType, Args, NumArgs, Sel, + SelectorLocs, Method, ClassMessage, SuperLoc.isValid(), LBracLoc, RBracLoc, ReturnType, VK)) return ExprError(); @@ -2428,6 +2424,24 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // In ARC, check for message sends which are likely to introduce // retain cycles. checkRetainCycles(Result); + + if (!isImplicit && Method) { + if (const ObjCPropertyDecl *Prop = Method->findPropertyDecl()) { + bool IsWeak = + Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak; + if (!IsWeak && Sel.isUnarySelector()) + IsWeak = ReturnType.getObjCLifetime() & Qualifiers::OCL_Weak; + + if (IsWeak) { + DiagnosticsEngine::Level Level = + Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, + LBracLoc); + if (Level != DiagnosticsEngine::Ignored) + getCurFunction()->recordUseOfWeak(Result, Prop); + + } + } + } } return MaybeBindToTemporary(Result); @@ -2448,7 +2462,7 @@ ExprResult Sema::ActOnInstanceMessage(Scope *S, return BuildInstanceMessage(Receiver, Receiver->getType(), /*SuperLoc=*/SourceLocation(), Sel, /*Method=*/0, - LBracLoc, SelectorLocs, RBracLoc, move(Args)); + LBracLoc, SelectorLocs, RBracLoc, Args); } enum ARCConversionTypeClass { @@ -3079,8 +3093,8 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) { return new (Context) GenericSelectionExpr(Context, gse->getGenericLoc(), gse->getControllingExpr(), - subTypes.data(), subExprs.data(), - n, gse->getDefaultLoc(), + subTypes, subExprs, + gse->getDefaultLoc(), gse->getRParenLoc(), gse->containsUnexpandedParameterPack(), gse->getResultIndex()); @@ -3101,8 +3115,8 @@ bool Sema::CheckObjCARCUnavailableWeakConversion(QualType castType, canExprType->isObjCObjectPointerType()) { if (const ObjCObjectPointerType *ObjT = canExprType->getAs<ObjCObjectPointerType>()) - if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable()) - return false; + if (const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl()) + return !ObjI->isArcWeakrefUnavailable(); } return true; } diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 62ab1e645089..3596bbfc725a 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -1316,6 +1316,8 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, // If the record is invalid, some of it's members are invalid. To avoid // confusion, we forgo checking the intializer for the entire record. if (structDecl->isInvalidDecl()) { + // Assume it was supposed to consume a single initializer. + ++Index; hadError = true; return; } @@ -1503,11 +1505,14 @@ static void ExpandAnonymousFieldDesignator(Sema &SemaRef, /// corresponds to FieldName. static IndirectFieldDecl *FindIndirectFieldDesignator(FieldDecl *AnonField, IdentifierInfo *FieldName) { + if (!FieldName) + return 0; + assert(AnonField->isAnonymousStructOrUnion()); Decl *NextDecl = AnonField->getNextDeclInContext(); while (IndirectFieldDecl *IF = dyn_cast_or_null<IndirectFieldDecl>(NextDecl)) { - if (FieldName && FieldName == IF->getAnonField()->getIdentifier()) + if (FieldName == IF->getAnonField()->getIdentifier()) return IF; NextDecl = NextDecl->getNextDeclInContext(); } @@ -1521,8 +1526,8 @@ static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef, for (unsigned I = 0; I < NumIndexExprs; ++I) IndexExprs[I] = DIE->getSubExpr(I + 1); return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators_begin(), - DIE->size(), IndexExprs.data(), - NumIndexExprs, DIE->getEqualOrColonLoc(), + DIE->size(), IndexExprs, + DIE->getEqualOrColonLoc(), DIE->usesGNUSyntax(), DIE->getInit()); } @@ -1562,7 +1567,7 @@ class FieldInitializerValidatorCCC : public CorrectionCandidateCallback { /// /// @param DesigIdx The index of the current designator. /// -/// @param DeclType The type of the "current object" (C99 6.7.8p17), +/// @param CurrentObjectType The type of the "current object" (C99 6.7.8p17), /// into which the designation in @p DIE should refer. /// /// @param NextField If non-NULL and the first designator in @p DIE is @@ -2068,7 +2073,7 @@ InitListChecker::getStructuredSubobjectInit(InitListExpr *IList, unsigned Index, InitListExpr *Result = new (SemaRef.Context) InitListExpr(SemaRef.Context, - InitRange.getBegin(), 0, 0, + InitRange.getBegin(), MultiExprArg(), InitRange.getEnd()); QualType ResultType = CurrentObjectType; @@ -2261,8 +2266,8 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, DesignatedInitExpr *DIE = DesignatedInitExpr::Create(Context, Designators.data(), Designators.size(), - InitExpressions.data(), InitExpressions.size(), - Loc, GNUSyntax, Init.takeAs<Expr>()); + InitExpressions, Loc, GNUSyntax, + Init.takeAs<Expr>()); if (!getLangOpts().C99) Diag(DIE->getLocStart(), diag::ext_designated_init) @@ -2814,14 +2819,6 @@ static void TryConstructorInitialization(Sema &S, assert((!InitListSyntax || (NumArgs == 1 && isa<InitListExpr>(Args[0]))) && "InitListSyntax must come with a single initializer list argument."); - // Check constructor arguments for self reference. - if (DeclaratorDecl *DD = Entity.getDecl()) - // Parameters arguments are occassionially constructed with itself, - // for instance, in recursive functions. Skip them. - if (!isa<ParmVarDecl>(DD)) - for (unsigned i = 0; i < NumArgs; ++i) - S.CheckSelfReference(DD, Args[i]); - // The type we're constructing needs to be complete. if (S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { Sequence.setIncompleteTypeFailure(DestType); @@ -3614,8 +3611,8 @@ static void TryValueInitialization(Sema &S, // user-provided or deleted default constructor, then the object is // zero-initialized and, if T has a non-trivial default constructor, // default-initialized; - // FIXME: The 'non-union' here is a defect (not yet assigned an issue - // number). Update the quotation when the defect is resolved. + // The 'non-union' here was removed by DR1502. The 'non-trivial default + // constructor' part was removed by DR1507. if (NeedZeroInitialization) Sequence.AddZeroInitializationStep(Entity.getType()); @@ -3703,8 +3700,14 @@ static void TryUserDefinedConversion(Sema &S, // Try to complete the type we're converting to. if (!S.RequireCompleteType(Kind.getLocation(), DestType, 0)) { - DeclContext::lookup_iterator Con, ConEnd; - for (llvm::tie(Con, ConEnd) = S.LookupConstructors(DestRecordDecl); + DeclContext::lookup_iterator ConOrig, ConEndOrig; + llvm::tie(ConOrig, ConEndOrig) = S.LookupConstructors(DestRecordDecl); + // The container holding the constructors can under certain conditions + // be changed while iterating. To be safe we copy the lookup results + // to a new container. + SmallVector<NamedDecl*, 8> CopyOfCon(ConOrig, ConEndOrig); + for (SmallVector<NamedDecl*, 8>::iterator + Con = CopyOfCon.begin(), ConEnd = CopyOfCon.end(); Con != ConEnd; ++Con) { NamedDecl *D = *Con; DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); @@ -4413,7 +4416,7 @@ static ExprResult CopyObject(Sema &S, if (const RecordType *Record = T->getAs<RecordType>()) Class = cast<CXXRecordDecl>(Record->getDecl()); if (!Class) - return move(CurInit); + return CurInit; // C++0x [class.copy]p32: // When certain criteria are met, an implementation is allowed to @@ -4435,7 +4438,7 @@ static ExprResult CopyObject(Sema &S, // Make sure that the type we are copying is complete. if (S.RequireCompleteType(Loc, T, diag::err_temp_copy_incomplete)) - return move(CurInit); + return CurInit; // Perform overload resolution using the class's copy/move constructors. // Only consider constructors and constructor templates. Per @@ -4460,7 +4463,7 @@ static ExprResult CopyObject(Sema &S, CandidateSet.NoteCandidates(S, OCD_AllCandidates, CurInitExpr); if (!IsExtraneousCopy || S.isSFINAEContext()) return ExprError(); - return move(CurInit); + return CurInit; case OR_Ambiguous: S.Diag(Loc, diag::err_temp_copy_ambiguous) @@ -4478,7 +4481,7 @@ static ExprResult CopyObject(Sema &S, } CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function); - ASTOwningVector<Expr*> ConstructorArgs(S); + SmallVector<Expr*, 8> ConstructorArgs; CurInit.release(); // Ownership transferred into MultiExprArg, below. S.CheckConstructorAccess(Loc, Constructor, Entity, @@ -4521,7 +4524,7 @@ static ExprResult CopyObject(Sema &S, // Actually perform the constructor call. CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable, - move_arg(ConstructorArgs), + ConstructorArgs, HadMultipleCandidates, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, @@ -4530,7 +4533,7 @@ static ExprResult CopyObject(Sema &S, // If we're supposed to bind temporaries, do so. if (!CurInit.isInvalid() && shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); - return move(CurInit); + return CurInit; } /// \brief Check whether elidable copy construction for binding a reference to @@ -4619,7 +4622,7 @@ PerformConstructorInitialization(Sema &S, bool HadMultipleCandidates = Step.Function.HadMultipleCandidates; // Build a call to the selected constructor. - ASTOwningVector<Expr*> ConstructorArgs(S); + SmallVector<Expr*, 8> ConstructorArgs; SourceLocation Loc = (Kind.isCopyInit() && Kind.getEqualLoc().isValid()) ? Kind.getEqualLoc() : Kind.getLocation(); @@ -4648,7 +4651,7 @@ PerformConstructorInitialization(Sema &S, // Determine the arguments required to actually perform the constructor // call. - if (S.CompleteConstructorCall(Constructor, move(Args), + if (S.CompleteConstructorCall(Constructor, Args, Loc, ConstructorArgs, AllowExplicitConv)) return ExprError(); @@ -4660,8 +4663,6 @@ PerformConstructorInitialization(Sema &S, (Kind.getKind() == InitializationKind::IK_Direct || Kind.getKind() == InitializationKind::IK_Value)))) { // An explicitly-constructed temporary, e.g., X(1, 2). - unsigned NumExprs = ConstructorArgs.size(); - Expr **Exprs = (Expr **)ConstructorArgs.take(); S.MarkFunctionReferenced(Loc, Constructor); S.DiagnoseUseOfDecl(Constructor, Loc); @@ -4675,8 +4676,7 @@ PerformConstructorInitialization(Sema &S, CurInit = S.Owned(new (S.Context) CXXTemporaryObjectExpr(S.Context, Constructor, TSInfo, - Exprs, - NumExprs, + ConstructorArgs, ParenRange, HadMultipleCandidates, ConstructorInitRequiresZeroInit)); @@ -4702,7 +4702,7 @@ PerformConstructorInitialization(Sema &S, if (Entity.allowsNRVO()) CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), Constructor, /*Elidable=*/true, - move_arg(ConstructorArgs), + ConstructorArgs, HadMultipleCandidates, ConstructorInitRequiresZeroInit, ConstructKind, @@ -4710,7 +4710,7 @@ PerformConstructorInitialization(Sema &S, else CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), Constructor, - move_arg(ConstructorArgs), + ConstructorArgs, HadMultipleCandidates, ConstructorInitRequiresZeroInit, ConstructKind, @@ -4727,7 +4727,7 @@ PerformConstructorInitialization(Sema &S, if (shouldBindAsTemporary(Entity)) CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); - return move(CurInit); + return CurInit; } /// Determine whether the specified InitializedEntity definitely has a lifetime @@ -4775,7 +4775,7 @@ InitializationSequence::Perform(Sema &S, QualType *ResultType) { if (Failed()) { unsigned NumArgs = Args.size(); - Diagnose(S, Entity, Kind, (Expr **)Args.release(), NumArgs); + Diagnose(S, Entity, Kind, Args.data(), NumArgs); return ExprError(); } @@ -4795,7 +4795,7 @@ InitializationSequence::Perform(Sema &S, // introduced and such). So, we fall back to making the array // type a dependently-sized array type with no specified // bound. - if (isa<InitListExpr>((Expr *)Args.get()[0])) { + if (isa<InitListExpr>((Expr *)Args[0])) { SourceRange Brackets; // Scavange the location of the brackets from the entity, if we can. @@ -4823,12 +4823,12 @@ InitializationSequence::Perform(Sema &S, // Rebuild the ParenListExpr. SourceRange ParenRange = Kind.getParenRange(); return S.ActOnParenListExpr(ParenRange.getBegin(), ParenRange.getEnd(), - move(Args)); + Args); } assert(Kind.getKind() == InitializationKind::IK_Copy || Kind.isExplicitCast() || Kind.getKind() == InitializationKind::IK_DirectList); - return ExprResult(Args.release()[0]); + return ExprResult(Args[0]); } // No steps means no initialization. @@ -4836,22 +4836,22 @@ InitializationSequence::Perform(Sema &S, return S.Owned((Expr *)0); if (S.getLangOpts().CPlusPlus0x && Entity.getType()->isReferenceType() && - Args.size() == 1 && isa<InitListExpr>(Args.get()[0]) && + Args.size() == 1 && isa<InitListExpr>(Args[0]) && Entity.getKind() != InitializedEntity::EK_Parameter) { // Produce a C++98 compatibility warning if we are initializing a reference // from an initializer list. For parameters, we produce a better warning // elsewhere. - Expr *Init = Args.get()[0]; + Expr *Init = Args[0]; S.Diag(Init->getLocStart(), diag::warn_cxx98_compat_reference_list_init) << Init->getSourceRange(); } // Diagnose cases where we initialize a pointer to an array temporary, and the // pointer obviously outlives the temporary. - if (Args.size() == 1 && Args.get()[0]->getType()->isArrayType() && + if (Args.size() == 1 && Args[0]->getType()->isArrayType() && Entity.getType()->isPointerType() && InitializedEntityOutlivesFullExpression(Entity)) { - Expr *Init = Args.get()[0]; + Expr *Init = Args[0]; Expr::LValueClassification Kind = Init->ClassifyLValue(S.Context); if (Kind == Expr::LV_ClassTemporary || Kind == Expr::LV_ArrayTemporary) S.Diag(Init->getLocStart(), diag::warn_temporary_array_to_pointer_decay) @@ -4897,7 +4897,7 @@ InitializationSequence::Perform(Sema &S, case SK_ProduceObjCObject: case SK_StdInitializerList: { assert(Args.size() == 1); - CurInit = Args.get()[0]; + CurInit = Args[0]; if (!CurInit.get()) return ExprError(); break; } @@ -4924,7 +4924,7 @@ InitializationSequence::Perform(Sema &S, // initializer to reflect that choice. S.CheckAddressOfMemberAccess(CurInit.get(), Step->Function.FoundDecl); S.DiagnoseUseOfDecl(Step->Function.FoundDecl, Kind.getLocation()); - CurInit = S.FixOverloadedFunctionReference(move(CurInit), + CurInit = S.FixOverloadedFunctionReference(CurInit, Step->Function.FoundDecl, Step->Function.Function); break; @@ -5016,7 +5016,7 @@ InitializationSequence::Perform(Sema &S, break; case SK_ExtraneousCopyToTemporary: - CurInit = CopyObject(S, Step->Type, Entity, move(CurInit), + CurInit = CopyObject(S, Step->Type, Entity, CurInit, /*IsExtraneousCopy=*/true); break; @@ -5031,7 +5031,7 @@ InitializationSequence::Perform(Sema &S, bool CreatedObject = false; if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Fn)) { // Build a call to the selected constructor. - ASTOwningVector<Expr*> ConstructorArgs(S); + SmallVector<Expr*, 8> ConstructorArgs; SourceLocation Loc = CurInit.get()->getLocStart(); CurInit.release(); // Ownership transferred into MultiExprArg, below. @@ -5045,7 +5045,7 @@ InitializationSequence::Perform(Sema &S, // Build an expression that constructs a temporary. CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, - move_arg(ConstructorArgs), + ConstructorArgs, HadMultipleCandidates, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, @@ -5079,7 +5079,7 @@ InitializationSequence::Perform(Sema &S, FoundFn, Conversion); if(CurInitExprRes.isInvalid()) return ExprError(); - CurInit = move(CurInitExprRes); + CurInit = CurInitExprRes; // Build the actual call to the conversion function. CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion, @@ -5115,7 +5115,7 @@ InitializationSequence::Perform(Sema &S, CurInit = S.MaybeBindToTemporary(CurInit.takeAs<Expr>()); if (RequiresCopy) CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, - move(CurInit), /*IsExtraneousCopy=*/false); + CurInit, /*IsExtraneousCopy=*/false); break; } @@ -5144,7 +5144,7 @@ InitializationSequence::Perform(Sema &S, getAssignmentAction(Entity), CCK); if (CurInitExprRes.isInvalid()) return ExprError(); - CurInit = move(CurInitExprRes); + CurInit = CurInitExprRes; break; } @@ -5195,13 +5195,13 @@ InitializationSequence::Perform(Sema &S, Entity.getType().getNonReferenceType()); bool UseTemporary = Entity.getType()->isReferenceType(); assert(Args.size() == 1 && "expected a single argument for list init"); - InitListExpr *InitList = cast<InitListExpr>(Args.get()[0]); + InitListExpr *InitList = cast<InitListExpr>(Args[0]); S.Diag(InitList->getExprLoc(), diag::warn_cxx98_compat_ctor_list_init) << InitList->getSourceRange(); MultiExprArg Arg(InitList->getInits(), InitList->getNumInits()); CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity : Entity, - Kind, move(Arg), *Step, + Kind, Arg, *Step, ConstructorInitRequiresZeroInit); break; } @@ -5214,7 +5214,7 @@ InitializationSequence::Perform(Sema &S, Expr *E = CurInit.take(); InitListExpr *Syntactic = Step->WrappingSyntacticList; InitListExpr *ILE = new (S.Context) InitListExpr(S.Context, - Syntactic->getLBraceLoc(), &E, 1, Syntactic->getRBraceLoc()); + Syntactic->getLBraceLoc(), E, Syntactic->getRBraceLoc()); ILE->setSyntacticForm(Syntactic); ILE->setType(E->getType()); ILE->setValueKind(E->getValueKind()); @@ -5234,7 +5234,7 @@ InitializationSequence::Perform(Sema &S, bool UseTemporary = Entity.getType()->isReferenceType(); CurInit = PerformConstructorInitialization(S, UseTemporary ? TempEntity : Entity, - Kind, move(Args), *Step, + Kind, Args, *Step, ConstructorInitRequiresZeroInit); break; } @@ -5268,15 +5268,15 @@ InitializationSequence::Perform(Sema &S, case SK_CAssignment: { QualType SourceType = CurInit.get()->getType(); - ExprResult Result = move(CurInit); + ExprResult Result = CurInit; Sema::AssignConvertType ConvTy = S.CheckSingleAssignmentConstraints(Step->Type, Result); if (Result.isInvalid()) return ExprError(); - CurInit = move(Result); + CurInit = Result; // If this is a call, allow conversion to a transparent union. - ExprResult CurInitExprRes = move(CurInit); + ExprResult CurInitExprRes = CurInit; if (ConvTy != Sema::Compatible && Entity.getKind() == InitializedEntity::EK_Parameter && S.CheckTransparentUnionArgumentConstraints(Step->Type, CurInitExprRes) @@ -5284,7 +5284,7 @@ InitializationSequence::Perform(Sema &S, ConvTy = Sema::Compatible; if (CurInitExprRes.isInvalid()) return ExprError(); - CurInit = move(CurInitExprRes); + CurInit = CurInitExprRes; bool Complained; if (S.DiagnoseAssignmentResult(ConvTy, Kind.getLocation(), @@ -5398,7 +5398,7 @@ InitializationSequence::Perform(Sema &S, } InitListExpr *Semantic = new (S.Context) InitListExpr(S.Context, ILE->getLBraceLoc(), - Converted.data(), NumInits, ILE->getRBraceLoc()); + Converted, ILE->getRBraceLoc()); Semantic->setSyntacticForm(ILE); Semantic->setType(Dest); Semantic->setInitializesStdInitializerList(); @@ -5415,7 +5415,7 @@ InitializationSequence::Perform(Sema &S, cast<FieldDecl>(Entity.getDecl()), CurInit.get()); - return move(CurInit); + return CurInit; } //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 6414c6fbac97..15cd2a73e7f7 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -22,13 +22,14 @@ using namespace clang; using namespace sema; CXXRecordDecl *Sema::createLambdaClosureType(SourceRange IntroducerRange, + TypeSourceInfo *Info, bool KnownDependent) { DeclContext *DC = CurContext; while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext())) DC = DC->getParent(); // Start constructing the lambda class. - CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, + CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, Info, IntroducerRange.getBegin(), KnownDependent); DC->addDecl(Class); @@ -369,15 +370,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, if (!TmplScope->decl_empty()) KnownDependent = true; - CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, KnownDependent); - // Determine the signature of the call operator. TypeSourceInfo *MethodTyInfo; bool ExplicitParams = true; bool ExplicitResultType = true; bool ContainsUnexpandedParameterPack = false; SourceLocation EndLoc; - llvm::ArrayRef<ParmVarDecl *> Params; + llvm::SmallVector<ParmVarDecl *, 8> Params; if (ParamInfo.getNumTypeObjects() == 0) { // C++11 [expr.prim.lambda]p4: // If a lambda-expression does not include a lambda-declarator, it is as @@ -410,17 +409,25 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, ExplicitResultType = MethodTyInfo->getType()->getAs<FunctionType>()->getResultType() != Context.DependentTy; - - TypeLoc TL = MethodTyInfo->getTypeLoc(); - FunctionProtoTypeLoc Proto = cast<FunctionProtoTypeLoc>(TL); - Params = llvm::ArrayRef<ParmVarDecl *>(Proto.getParmArray(), - Proto.getNumArgs()); + + if (FTI.NumArgs == 1 && !FTI.isVariadic && FTI.ArgInfo[0].Ident == 0 && + cast<ParmVarDecl>(FTI.ArgInfo[0].Param)->getType()->isVoidType()) { + // Empty arg list, don't push any params. + checkVoidParamDecl(cast<ParmVarDecl>(FTI.ArgInfo[0].Param)); + } else { + Params.reserve(FTI.NumArgs); + for (unsigned i = 0, e = FTI.NumArgs; i != e; ++i) + Params.push_back(cast<ParmVarDecl>(FTI.ArgInfo[i].Param)); + } // Check for unexpanded parameter packs in the method type. if (MethodTyInfo->getType()->containsUnexpandedParameterPack()) ContainsUnexpandedParameterPack = true; } - + + CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo, + KnownDependent); + CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params); @@ -528,6 +535,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } + // Ignore invalid decls; they'll just confuse the code later. + if (Var->isInvalidDecl()) + continue; + if (!Var->hasLocalStorage()) { Diag(C->Loc, diag::err_capture_non_automatic_variable) << C->Id; Diag(Var->getLocation(), diag::note_previous_decl) << C->Id; diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index dad196b410c4..f6987e7bfbe0 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -707,7 +707,7 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // result), perform template argument deduction and place the // specialization into the result set. We do this to avoid forcing all // callers to perform special deduction for conversion functions. - TemplateDeductionInfo Info(R.getSema().Context, R.getNameLoc()); + TemplateDeductionInfo Info(R.getNameLoc()); FunctionDecl *Specialization = 0; const FunctionProtoType *ConvProto @@ -1725,15 +1725,17 @@ bool Sema::DiagnoseAmbiguousLookup(LookupResult &Result) { namespace { struct AssociatedLookup { - AssociatedLookup(Sema &S, + AssociatedLookup(Sema &S, SourceLocation InstantiationLoc, Sema::AssociatedNamespaceSet &Namespaces, Sema::AssociatedClassSet &Classes) - : S(S), Namespaces(Namespaces), Classes(Classes) { + : S(S), Namespaces(Namespaces), Classes(Classes), + InstantiationLoc(InstantiationLoc) { } Sema &S; Sema::AssociatedNamespaceSet &Namespaces; Sema::AssociatedClassSet &Classes; + SourceLocation InstantiationLoc; }; } @@ -1796,6 +1798,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::Expression: + case TemplateArgument::NullPtr: // [Note: non-type template arguments do not contribute to the set of // associated namespaces. ] break; @@ -1864,8 +1867,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, // Only recurse into base classes for complete types. if (!Class->hasDefinition()) { - // FIXME: we might need to instantiate templates here - return; + QualType type = Result.S.Context.getTypeDeclType(Class); + if (Result.S.RequireCompleteType(Result.InstantiationLoc, type, + /*no diagnostic*/ 0)) + return; } // Add direct and indirect base classes along with their associated @@ -2069,13 +2074,15 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { /// namespaces searched by argument-dependent lookup /// (C++ [basic.lookup.argdep]) for a given set of arguments. void -Sema::FindAssociatedClassesAndNamespaces(llvm::ArrayRef<Expr *> Args, +Sema::FindAssociatedClassesAndNamespaces(SourceLocation InstantiationLoc, + llvm::ArrayRef<Expr *> Args, AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses) { AssociatedNamespaces.clear(); AssociatedClasses.clear(); - AssociatedLookup Result(*this, AssociatedNamespaces, AssociatedClasses); + AssociatedLookup Result(*this, InstantiationLoc, + AssociatedNamespaces, AssociatedClasses); // C++ [basic.lookup.koenig]p2: // For each argument type T in the function call, there is a set @@ -2642,17 +2649,14 @@ void ADLResult::insert(NamedDecl *New) { void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, SourceLocation Loc, llvm::ArrayRef<Expr *> Args, - ADLResult &Result, - bool StdNamespaceIsAssociated) { + ADLResult &Result) { // Find all of the associated namespaces and classes based on the // arguments we have. AssociatedNamespaceSet AssociatedNamespaces; AssociatedClassSet AssociatedClasses; - FindAssociatedClassesAndNamespaces(Args, + FindAssociatedClassesAndNamespaces(Loc, Args, AssociatedNamespaces, AssociatedClasses); - if (StdNamespaceIsAssociated && StdNamespace) - AssociatedNamespaces.insert(getStdNamespace()); QualType T1, T2; if (Operator) { @@ -2661,13 +2665,6 @@ void Sema::ArgumentDependentLookup(DeclarationName Name, bool Operator, T2 = Args[1]->getType(); } - // Try to complete all associated classes, in case they contain a - // declaration of a friend function. - for (AssociatedClassSet::iterator C = AssociatedClasses.begin(), - CEnd = AssociatedClasses.end(); - C != CEnd; ++C) - RequireCompleteType(Loc, Context.getRecordType(*C), 0); - // C++ [basic.lookup.argdep]p3: // Let X be the lookup set produced by unqualified lookup (3.4.1) // and let Y be the lookup set produced by argument dependent @@ -4056,7 +4053,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, if (IsUnqualifiedLookup) UnqualifiedTyposCorrected[Typo] = Result; - return Result; + TypoCorrection TC = Result; + TC.setCorrectionRange(SS, TypoName); + return TC; } else if (BestResults.size() > 1 // Ugly hack equivalent to CTC == CTC_ObjCMessageReceiver; @@ -4076,7 +4075,9 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName, if (IsUnqualifiedLookup) UnqualifiedTyposCorrected[Typo] = BestResults["super"].front(); - return BestResults["super"].front(); + TypoCorrection TC = BestResults["super"].front(); + TC.setCorrectionRange(SS, TypoName); + return TC; } // If this was an unqualified lookup and we believe the callback object did diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 27deab226f91..8d708607f6eb 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -22,6 +22,7 @@ #include "clang/Basic/SourceManager.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallString.h" +#include "clang/Lex/Preprocessor.h" using namespace clang; @@ -43,7 +44,7 @@ static Qualifiers::ObjCLifetime getImpliedARCOwnership( if (attrs & (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong | ObjCPropertyDecl::OBJC_PR_copy)) { - return type->getObjCARCImplicitLifetime(); + return Qualifiers::OCL_Strong; } else if (attrs & ObjCPropertyDecl::OBJC_PR_weak) { return Qualifiers::OCL_Weak; } else if (attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) { @@ -102,6 +103,15 @@ static void checkARCPropertyDecl(Sema &S, ObjCPropertyDecl *property) { << propertyLifetime; } +static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) { + if ((S.getLangOpts().getGC() != LangOptions::NonGC && + T.isObjCGCWeak()) || + (S.getLangOpts().ObjCAutoRefCount && + T.getObjCLifetime() == Qualifiers::OCL_Weak)) + return ObjCDeclSpec::DQ_PR_weak; + return 0; +} + Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, SourceLocation LParenLoc, FieldDeclarator &FD, @@ -114,12 +124,8 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, unsigned Attributes = ODS.getPropertyAttributes(); TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); QualType T = TSI->getType(); - if ((getLangOpts().getGC() != LangOptions::NonGC && - T.isObjCGCWeak()) || - (getLangOpts().ObjCAutoRefCount && - T.getObjCLifetime() == Qualifiers::OCL_Weak)) - Attributes |= ObjCDeclSpec::DQ_PR_weak; - + Attributes |= deduceWeakPropertyFromType(*this, T); + bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || // default is readwrite! !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); @@ -236,6 +242,15 @@ static bool LocPropertyAttribute( ASTContext &Context, const char *attrName, } +static unsigned getOwnershipRule(unsigned attr) { + return attr & (ObjCPropertyDecl::OBJC_PR_assign | + ObjCPropertyDecl::OBJC_PR_retain | + ObjCPropertyDecl::OBJC_PR_copy | + ObjCPropertyDecl::OBJC_PR_weak | + ObjCPropertyDecl::OBJC_PR_strong | + ObjCPropertyDecl::OBJC_PR_unsafe_unretained); +} + Decl * Sema::HandlePropertyInClassExtension(Scope *S, SourceLocation AtLoc, @@ -335,6 +350,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, Diag(AtLoc, diag::err_type_mismatch_continuation_class) << PDecl->getType(); Diag(PIDecl->getLocation(), diag::note_property_declare); + return 0; } } @@ -342,13 +358,11 @@ Sema::HandlePropertyInClassExtension(Scope *S, // with continuation class's readwrite property attribute! unsigned PIkind = PIDecl->getPropertyAttributesAsWritten(); if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) { - unsigned retainCopyNonatomic = - (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong | - ObjCPropertyDecl::OBJC_PR_copy | - ObjCPropertyDecl::OBJC_PR_nonatomic); - if ((Attributes & retainCopyNonatomic) != - (PIkind & retainCopyNonatomic)) { + PIkind |= deduceWeakPropertyFromType(*this, PIDecl->getType()); + unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes); + unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind); + if (PrimaryClassMemoryModel && ClassExtensionMemoryModel && + (PrimaryClassMemoryModel != ClassExtensionMemoryModel)) { Diag(AtLoc, diag::warn_property_attr_mismatch); Diag(PIDecl->getLocation(), diag::note_property_declare); } @@ -397,6 +411,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, Diag(AtLoc, diag) << CCPrimary->getDeclName(); Diag(PIDecl->getLocation(), diag::note_property_declare); + return 0; } *isOverridingProperty = true; // Make sure setter decl is synthesized, and added to primary class's list. @@ -405,7 +420,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, PDecl->setSetterMethodDecl(PIDecl->getSetterMethodDecl()); if (ASTMutationListener *L = Context.getASTMutationListener()) L->AddedObjCPropertyInClassExtension(PDecl, PIDecl, CDecl); - return 0; + return PDecl; } ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, @@ -543,6 +558,23 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc, ivarLifetime == Qualifiers::OCL_Autoreleasing) return; + // If the ivar is private, and it's implicitly __unsafe_unretained + // becaues of its type, then pretend it was actually implicitly + // __strong. This is only sound because we're processing the + // property implementation before parsing any method bodies. + if (ivarLifetime == Qualifiers::OCL_ExplicitNone && + propertyLifetime == Qualifiers::OCL_Strong && + ivar->getAccessControl() == ObjCIvarDecl::Private) { + SplitQualType split = ivarType.split(); + if (split.Quals.hasObjCLifetime()) { + assert(ivarType->isObjCARCImplicitlyUnretainedType()); + split.Quals.setObjCLifetime(Qualifiers::OCL_Strong); + ivarType = S.Context.getQualifiedType(split); + ivar->setType(ivarType); + return; + } + } + switch (propertyLifetime) { case Qualifiers::OCL_Strong: S.Diag(propertyImplLoc, diag::err_arc_strong_property_ownership) @@ -632,7 +664,13 @@ DiagnoseClassAndClassExtPropertyMismatch(Sema &S, ObjCInterfaceDecl *ClassDecl, // property. if (Attributes & ObjCDeclSpec::DQ_PR_readonly) { if (!classExtPropertyAttr || - (classExtPropertyAttr & ObjCDeclSpec::DQ_PR_readwrite)) + (classExtPropertyAttr & + (ObjCDeclSpec::DQ_PR_readwrite| + ObjCDeclSpec::DQ_PR_assign | + ObjCDeclSpec::DQ_PR_unsafe_unretained | + ObjCDeclSpec::DQ_PR_copy | + ObjCDeclSpec::DQ_PR_retain | + ObjCDeclSpec::DQ_PR_strong))) continue; warn = true; break; @@ -857,13 +895,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (lifetime == Qualifiers::OCL_Weak) { bool err = false; if (const ObjCObjectPointerType *ObjT = - PropertyIvarType->getAs<ObjCObjectPointerType>()) - if (ObjT->getInterfaceDecl()->isArcWeakrefUnavailable()) { + PropertyIvarType->getAs<ObjCObjectPointerType>()) { + const ObjCInterfaceDecl *ObjI = ObjT->getInterfaceDecl(); + if (ObjI && ObjI->isArcWeakrefUnavailable()) { Diag(PropertyDiagLoc, diag::err_arc_weak_unavailable_property); Diag(property->getLocation(), diag::note_property_declare); err = true; } - if (!err && !getLangOpts().ObjCRuntimeHasWeak) { + } + if (!err && !getLangOpts().ObjCARCWeak) { Diag(PropertyDiagLoc, diag::err_arc_weak_no_runtime); Diag(property->getLocation(), diag::note_property_declare); } @@ -891,7 +931,6 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, Ivar->setInvalidDecl(); ClassImpDecl->addDecl(Ivar); IDecl->makeDeclVisibleInContext(Ivar); - property->setPropertyIvarDecl(Ivar); if (getLangOpts().ObjCRuntime.isFragile()) Diag(PropertyDiagLoc, diag::error_missing_property_ivar_decl) @@ -907,14 +946,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, << Ivar << Ivar->getName(); // Note! I deliberately want it to fall thru so more errors are caught. } + property->setPropertyIvarDecl(Ivar); + QualType IvarType = Context.getCanonicalType(Ivar->getType()); // Check that type of property and its ivar are type compatible. if (!Context.hasSameType(PropertyIvarType, IvarType)) { - compat = false; if (isa<ObjCObjectPointerType>(PropertyIvarType) && isa<ObjCObjectPointerType>(IvarType)) - compat = + compat = Context.canAssignObjCInterfaces( PropertyIvarType->getAs<ObjCObjectPointerType>(), IvarType->getAs<ObjCObjectPointerType>()); @@ -988,19 +1028,21 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // For Objective-C++, need to synthesize the AST for the IVAR object to be // returned by the getter as it must conform to C++'s copy-return rules. // FIXME. Eventually we want to do this for Objective-C as well. + SynthesizedFunctionScope Scope(*this, getterMethod); ImplicitParamDecl *SelfDecl = getterMethod->getSelfDecl(); DeclRefExpr *SelfExpr = new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(), - VK_RValue, SourceLocation()); + VK_RValue, PropertyDiagLoc); + MarkDeclRefReferenced(SelfExpr); Expr *IvarRefExpr = - new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, + new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, SelfExpr, true, true); ExprResult Res = PerformCopyInitialization(InitializedEntity::InitializeResult( - SourceLocation(), + PropertyDiagLoc, getterMethod->getResultType(), /*NRVO=*/false), - SourceLocation(), + PropertyDiagLoc, Owned(IvarRefExpr)); if (!Res.isInvalid()) { Expr *ResExpr = Res.takeAs<Expr>(); @@ -1021,19 +1063,22 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr && Ivar->getType()->isRecordType()) { // FIXME. Eventually we want to do this for Objective-C as well. + SynthesizedFunctionScope Scope(*this, setterMethod); ImplicitParamDecl *SelfDecl = setterMethod->getSelfDecl(); DeclRefExpr *SelfExpr = new (Context) DeclRefExpr(SelfDecl, false, SelfDecl->getType(), - VK_RValue, SourceLocation()); + VK_RValue, PropertyDiagLoc); + MarkDeclRefReferenced(SelfExpr); Expr *lhs = - new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), AtLoc, + new (Context) ObjCIvarRefExpr(Ivar, Ivar->getType(), PropertyDiagLoc, SelfExpr, true, true); ObjCMethodDecl::param_iterator P = setterMethod->param_begin(); ParmVarDecl *Param = (*P); QualType T = Param->getType().getNonReferenceType(); - Expr *rhs = new (Context) DeclRefExpr(Param, false, T, - VK_LValue, SourceLocation()); - ExprResult Res = BuildBinOp(S, lhs->getLocEnd(), + DeclRefExpr *rhs = new (Context) DeclRefExpr(Param, false, T, + VK_LValue, PropertyDiagLoc); + MarkDeclRefReferenced(rhs); + ExprResult Res = BuildBinOp(S, PropertyDiagLoc, BO_Assign, lhs, rhs); if (property->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_atomic) { @@ -1043,7 +1088,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (const FunctionDecl *FuncDecl = CXXCE->getDirectCallee()) if (!FuncDecl->isTrivial()) if (property->getType()->isReferenceType()) { - Diag(PropertyLoc, + Diag(PropertyDiagLoc, diag::err_atomic_property_nontrivial_assign_op) << property->getType(); Diag(FuncDecl->getLocStart(), @@ -1395,8 +1440,8 @@ bool Sema::isPropertyReadonly(ObjCPropertyDecl *PDecl, /// CollectImmediateProperties - This routine collects all properties in /// the class and its conforming protocols; but not those it its super class. void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap, - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& SuperPropMap) { + ObjCContainerDecl::PropertyMap &PropMap, + ObjCContainerDecl::PropertyMap &SuperPropMap) { if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) { for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), E = IDecl->prop_end(); P != E; ++P) { @@ -1442,118 +1487,38 @@ void Sema::CollectImmediateProperties(ObjCContainerDecl *CDecl, } } -/// CollectClassPropertyImplementations - This routine collects list of -/// properties to be implemented in the class. This includes, class's -/// and its conforming protocols' properties. -static void CollectClassPropertyImplementations(ObjCContainerDecl *CDecl, - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) { - if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) { - for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), - E = IDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = *P; - PropMap[Prop->getIdentifier()] = Prop; - } - for (ObjCInterfaceDecl::all_protocol_iterator - PI = IDecl->all_referenced_protocol_begin(), - E = IDecl->all_referenced_protocol_end(); PI != E; ++PI) - CollectClassPropertyImplementations((*PI), PropMap); - } - else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) { - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = *P; - if (!PropMap.count(Prop->getIdentifier())) - PropMap[Prop->getIdentifier()] = Prop; - } - // scan through protocol's protocols. - for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), - E = PDecl->protocol_end(); PI != E; ++PI) - CollectClassPropertyImplementations((*PI), PropMap); - } -} - /// CollectSuperClassPropertyImplementations - This routine collects list of /// properties to be implemented in super class(s) and also coming from their /// conforming protocols. static void CollectSuperClassPropertyImplementations(ObjCInterfaceDecl *CDecl, - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>& PropMap) { + ObjCInterfaceDecl::PropertyMap &PropMap) { if (ObjCInterfaceDecl *SDecl = CDecl->getSuperClass()) { while (SDecl) { - CollectClassPropertyImplementations(SDecl, PropMap); + SDecl->collectPropertiesToImplement(PropMap); SDecl = SDecl->getSuperClass(); } } } -/// LookupPropertyDecl - Looks up a property in the current class and all -/// its protocols. -ObjCPropertyDecl *Sema::LookupPropertyDecl(const ObjCContainerDecl *CDecl, - IdentifierInfo *II) { - if (const ObjCInterfaceDecl *IDecl = - dyn_cast<ObjCInterfaceDecl>(CDecl)) { - for (ObjCContainerDecl::prop_iterator P = IDecl->prop_begin(), - E = IDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = *P; - if (Prop->getIdentifier() == II) - return Prop; - } - // scan through class's protocols. - for (ObjCInterfaceDecl::all_protocol_iterator - PI = IDecl->all_referenced_protocol_begin(), - E = IDecl->all_referenced_protocol_end(); PI != E; ++PI) { - ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); - if (Prop) - return Prop; - } - } - else if (const ObjCProtocolDecl *PDecl = - dyn_cast<ObjCProtocolDecl>(CDecl)) { - for (ObjCProtocolDecl::prop_iterator P = PDecl->prop_begin(), - E = PDecl->prop_end(); P != E; ++P) { - ObjCPropertyDecl *Prop = *P; - if (Prop->getIdentifier() == II) - return Prop; - } - // scan through protocol's protocols. - for (ObjCProtocolDecl::protocol_iterator PI = PDecl->protocol_begin(), - E = PDecl->protocol_end(); PI != E; ++PI) { - ObjCPropertyDecl *Prop = LookupPropertyDecl((*PI), II); - if (Prop) - return Prop; - } - } - return 0; -} - -static IdentifierInfo * getDefaultSynthIvarName(ObjCPropertyDecl *Prop, - ASTContext &Ctx) { - SmallString<128> ivarName; - { - llvm::raw_svector_ostream os(ivarName); - os << '_' << Prop->getIdentifier()->getName(); - } - return &Ctx.Idents.get(ivarName.str()); -} - /// \brief Default synthesizes all properties which must be synthesized /// in class's \@implementation. void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCInterfaceDecl *IDecl) { - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; - CollectClassPropertyImplementations(IDecl, PropMap); + ObjCInterfaceDecl::PropertyMap PropMap; + IDecl->collectPropertiesToImplement(PropMap); if (PropMap.empty()) return; - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> SuperPropMap; + ObjCInterfaceDecl::PropertyMap SuperPropMap; CollectSuperClassPropertyImplementations(IDecl, SuperPropMap); - for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator + for (ObjCInterfaceDecl::PropertyMap::iterator P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { ObjCPropertyDecl *Prop = P->second; // If property to be implemented in the super class, ignore. if (SuperPropMap[Prop->getIdentifier()]) continue; - // Is there a matching propery synthesize/dynamic? + // Is there a matching property synthesize/dynamic? if (Prop->isInvalidDecl() || Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || IMPDecl->FindPropertyImplIvarDecl(Prop->getIdentifier())) @@ -1583,7 +1548,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, ActOnPropertyImplDecl(S, SourceLocation(), SourceLocation(), true, /* property = */ Prop->getIdentifier(), - /* ivar = */ getDefaultSynthIvarName(Prop, Context), + /* ivar = */ Prop->getDefaultSynthIvarName(Context), Prop->getLocation())); if (PIDecl) { Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis); @@ -1606,11 +1571,11 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl *CDecl, const SelectorSet &InsMap) { - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> SuperPropMap; + ObjCContainerDecl::PropertyMap SuperPropMap; if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) CollectSuperClassPropertyImplementations(IDecl, SuperPropMap); - llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*> PropMap; + ObjCContainerDecl::PropertyMap PropMap; CollectImmediateProperties(CDecl, PropMap, SuperPropMap); if (PropMap.empty()) return; @@ -1621,7 +1586,7 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, EI = IMPDecl->propimpl_end(); I != EI; ++I) PropImplMap.insert(I->getPropertyDecl()); - for (llvm::DenseMap<IdentifierInfo *, ObjCPropertyDecl*>::iterator + for (ObjCContainerDecl::PropertyMap::iterator P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { ObjCPropertyDecl *Prop = P->second; // Is there a matching propery synthesize/dynamic? @@ -1847,7 +1812,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, property->getGetterName(), property->getType(), 0, CD, /*isInstance=*/true, - /*isVariadic=*/false, /*isSynthesized=*/true, + /*isVariadic=*/false, /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) ? @@ -1867,7 +1832,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, } else // A user declared getter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation - GetterMethod->setSynthesized(true); + GetterMethod->setPropertyAccessor(true); property->setGetterMethodDecl(GetterMethod); // Skip setter if property is read-only. @@ -1885,7 +1850,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, ObjCMethodDecl::Create(Context, Loc, Loc, property->getSetterName(), Context.VoidTy, 0, CD, /*isInstance=*/true, /*isVariadic=*/false, - /*isSynthesized=*/true, + /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, (property->getPropertyImplementation() == @@ -1916,7 +1881,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property, } else // A user declared setter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation - SetterMethod->setSynthesized(true); + SetterMethod->setPropertyAccessor(true); property->setSetterMethodDecl(SetterMethod); } // Add any synthesized methods to the global pool. This allows us to @@ -2121,7 +2086,9 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, // issue any warning. if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC) ; - else { + else if (propertyInPrimaryClass) { + // Don't issue warning on property with no life time in class + // extension as it is inherited from property in primary class. // Skip this warning in gc-only mode. if (getLangOpts().getGC() != LangOptions::GCOnly) Diag(Loc, diag::warn_objc_property_no_assignment_attribute); diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 9382f7dddc6c..911187857fe1 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -49,7 +49,7 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, bool HadMultipleCandidates, E = S.DefaultFunctionArrayConversion(E.take()); if (E.isInvalid()) return ExprError(); - return move(E); + return E; } static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, @@ -555,6 +555,7 @@ static MakeDeductionFailureInfo(ASTContext &Context, Result.Data = 0; switch (TDK) { case Sema::TDK_Success: + case Sema::TDK_Invalid: case Sema::TDK_InstantiationDepth: case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: @@ -597,6 +598,7 @@ static MakeDeductionFailureInfo(ASTContext &Context, void OverloadCandidate::DeductionFailureInfo::Destroy() { switch (static_cast<Sema::TemplateDeductionResult>(Result)) { case Sema::TDK_Success: + case Sema::TDK_Invalid: case Sema::TDK_InstantiationDepth: case Sema::TDK_Incomplete: case Sema::TDK_TooManyArguments: @@ -637,6 +639,7 @@ TemplateParameter OverloadCandidate::DeductionFailureInfo::getTemplateParameter() { switch (static_cast<Sema::TemplateDeductionResult>(Result)) { case Sema::TDK_Success: + case Sema::TDK_Invalid: case Sema::TDK_InstantiationDepth: case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: @@ -664,6 +667,7 @@ TemplateArgumentList * OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() { switch (static_cast<Sema::TemplateDeductionResult>(Result)) { case Sema::TDK_Success: + case Sema::TDK_Invalid: case Sema::TDK_InstantiationDepth: case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: @@ -688,6 +692,7 @@ OverloadCandidate::DeductionFailureInfo::getTemplateArgumentList() { const TemplateArgument *OverloadCandidate::DeductionFailureInfo::getFirstArg() { switch (static_cast<Sema::TemplateDeductionResult>(Result)) { case Sema::TDK_Success: + case Sema::TDK_Invalid: case Sema::TDK_InstantiationDepth: case Sema::TDK_Incomplete: case Sema::TDK_TooManyArguments: @@ -713,6 +718,7 @@ const TemplateArgument * OverloadCandidate::DeductionFailureInfo::getSecondArg() { switch (static_cast<Sema::TemplateDeductionResult>(Result)) { case Sema::TDK_Success: + case Sema::TDK_Invalid: case Sema::TDK_InstantiationDepth: case Sema::TDK_Incomplete: case Sema::TDK_TooManyArguments: @@ -734,13 +740,17 @@ OverloadCandidate::DeductionFailureInfo::getSecondArg() { return 0; } -void OverloadCandidateSet::clear() { +void OverloadCandidateSet::destroyCandidates() { for (iterator i = begin(), e = end(); i != e; ++i) { for (unsigned ii = 0, ie = i->NumConversions; ii != ie; ++ii) i->Conversions[ii].~ImplicitConversionSequence(); if (!i->Viable && i->FailureKind == ovl_fail_bad_deduction) i->DeductionFailure.Destroy(); } +} + +void OverloadCandidateSet::clear() { + destroyCandidates(); NumInlineSequences = 0; Candidates.clear(); Functions.clear(); @@ -1668,7 +1678,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { return To->getKind() == BuiltinType::UInt; } - // C++0x [conv.prom]p3: + // C++11 [conv.prom]p3: // A prvalue of an unscoped enumeration type whose underlying type is not // fixed (7.2) can be converted to an rvalue a prvalue of the first of the // following types that can represent all the values of the enumeration @@ -1680,12 +1690,26 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { // with lowest integer conversion rank (4.13) greater than the rank of long // long in which all the values of the enumeration can be represented. If // there are two such extended types, the signed one is chosen. + // C++11 [conv.prom]p4: + // A prvalue of an unscoped enumeration type whose underlying type is fixed + // can be converted to a prvalue of its underlying type. Moreover, if + // integral promotion can be applied to its underlying type, a prvalue of an + // unscoped enumeration type whose underlying type is fixed can also be + // converted to a prvalue of the promoted underlying type. if (const EnumType *FromEnumType = FromType->getAs<EnumType>()) { // C++0x 7.2p9: Note that this implicit enum to int conversion is not // provided for a scoped enumeration. if (FromEnumType->getDecl()->isScoped()) return false; + // We can perform an integral promotion to the underlying type of the enum, + // even if that's not the promoted type. + if (FromEnumType->getDecl()->isFixed()) { + QualType Underlying = FromEnumType->getDecl()->getIntegerType(); + return Context.hasSameUnqualifiedType(Underlying, ToType) || + IsIntegralPromotion(From, Underlying, ToType); + } + // We have already pre-calculated the promotion type, so this is trivial. if (ToType->isIntegerType() && !RequireCompleteType(From->getLocStart(), FromType, 0)) @@ -2899,8 +2923,6 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType, case OR_Success: { // Record the standard conversion we used and the conversion function. CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function); - S.MarkFunctionReferenced(From->getLocStart(), Constructor); - QualType ThisType = Constructor->getThisType(S.Context); // Initializer lists don't have conversions as such. User.Before.setAsIdentityConversion(); @@ -3081,8 +3103,6 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // Record the standard conversion we used and the conversion function. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Best->Function)) { - S.MarkFunctionReferenced(From->getLocStart(), Constructor); - // C++ [over.ics.user]p1: // If the user-defined conversion is specified by a // constructor (12.3.1), the initial standard conversion @@ -3111,8 +3131,6 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, } if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(Best->Function)) { - S.MarkFunctionReferenced(From->getLocStart(), Conversion); - // C++ [over.ics.user]p1: // // [...] If the user-defined conversion is specified by a @@ -4025,8 +4043,6 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, if (!Best->FinalConversion.DirectBinding) return false; - if (Best->Function) - S.MarkFunctionReferenced(DeclLoc, Best->Function); ICS.setUserDefined(); ICS.UserDefined.Before = Best->Conversions[0].Standard; ICS.UserDefined.After = Best->FinalConversion; @@ -5531,7 +5547,7 @@ Sema::AddMethodTemplateCandidate(FunctionTemplateDecl *MethodTmpl, // functions. In such a case, the candidate functions generated from each // function template are combined with the set of non-template candidate // functions. - TemplateDeductionInfo Info(Context, CandidateSet.getLocation()); + TemplateDeductionInfo Info(CandidateSet.getLocation()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult Result = DeduceTemplateArguments(MethodTmpl, ExplicitTemplateArgs, Args, @@ -5581,7 +5597,7 @@ Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate, // functions. In such a case, the candidate functions generated from each // function template are combined with the set of non-template candidate // functions. - TemplateDeductionInfo Info(Context, CandidateSet.getLocation()); + TemplateDeductionInfo Info(CandidateSet.getLocation()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, Args, @@ -5703,7 +5719,7 @@ Sema::AddConversionCandidate(CXXConversionDecl *Conversion, // there are 0 arguments (i.e., nothing is allocated using ASTContext's // allocator). QualType CallResultType = ConversionType.getNonLValueExprType(Context); - CallExpr Call(Context, &ConversionFn, 0, 0, CallResultType, VK, + CallExpr Call(Context, &ConversionFn, MultiExprArg(), CallResultType, VK, From->getLocStart()); ImplicitConversionSequence ICS = TryCopyInitialization(*this, &Call, ToType, @@ -5765,7 +5781,7 @@ Sema::AddTemplateConversionCandidate(FunctionTemplateDecl *FunctionTemplate, if (!CandidateSet.isNewCandidate(FunctionTemplate)) return; - TemplateDeductionInfo Info(Context, CandidateSet.getLocation()); + TemplateDeductionInfo Info(CandidateSet.getLocation()); CXXConversionDecl *Specialization = 0; if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, ToType, @@ -6770,17 +6786,16 @@ public: // bool operator==(T, T); // bool operator!=(T, T); void addRelationalPointerOrEnumeralOverloads() { - // C++ [over.built]p1: - // If there is a user-written candidate with the same name and parameter - // types as a built-in candidate operator function, the built-in operator - // function is hidden and is not included in the set of candidate - // functions. + // C++ [over.match.oper]p3: + // [...]the built-in candidates include all of the candidate operator + // functions defined in 13.6 that, compared to the given operator, [...] + // do not have the same parameter-type-list as any non-template non-member + // candidate. // - // The text is actually in a note, but if we don't implement it then we end - // up with ambiguities when the user provides an overloaded operator for - // an enumeration type. Note that only enumeration types have this problem, - // so we track which enumeration types we've seen operators for. Also, the - // only other overloaded operator with enumeration argumenst, operator=, + // Note that in practice, this only affects enumeration types because there + // aren't any built-in candidates of record type, and a user-defined operator + // must have an operand of record or enumeration type. Also, the only other + // overloaded operator with enumeration arguments, operator=, // cannot be overloaded for enumeration types, so this is the only place // where we must suppress candidates like this. llvm::DenseSet<std::pair<CanQualType, CanQualType> > @@ -6795,6 +6810,9 @@ public: if (!C->Viable || !C->Function || C->Function->getNumParams() != 2) continue; + if (C->Function->isFunctionTemplateSpecialization()) + continue; + QualType FirstParamType = C->Function->getParamDecl(0)->getType().getUnqualifiedType(); QualType SecondParamType = @@ -7652,8 +7670,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, llvm::ArrayRef<Expr *> Args, TemplateArgumentListInfo *ExplicitTemplateArgs, OverloadCandidateSet& CandidateSet, - bool PartialOverloading, - bool StdNamespaceIsAssociated) { + bool PartialOverloading) { ADLResult Fns; // FIXME: This approach for uniquing ADL results (and removing @@ -7664,8 +7681,7 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, // we supposed to consider on ADL candidates, anyway? // FIXME: Pass in the explicit template arguments? - ArgumentDependentLookup(Name, Operator, Loc, Args, Fns, - StdNamespaceIsAssociated); + ArgumentDependentLookup(Name, Operator, Loc, Args, Fns); // Erase all of the candidates we already knew about. for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(), @@ -7976,10 +7992,20 @@ void ImplicitConversionSequence::DiagnoseAmbiguousConversion( const PartialDiagnostic &PDiag) const { S.Diag(CaretLoc, PDiag) << Ambiguous.getFromType() << Ambiguous.getToType(); - for (AmbiguousConversionSequence::const_iterator - I = Ambiguous.begin(), E = Ambiguous.end(); I != E; ++I) { + // FIXME: The note limiting machinery is borrowed from + // OverloadCandidateSet::NoteCandidates; there's an opportunity for + // refactoring here. + const OverloadsShown ShowOverloads = S.Diags.getShowOverloads(); + unsigned CandsShown = 0; + AmbiguousConversionSequence::const_iterator I, E; + for (I = Ambiguous.begin(), E = Ambiguous.end(); I != E; ++I) { + if (CandsShown >= 4 && ShowOverloads == Ovl_Best) + break; + ++CandsShown; S.NoteOverloadCandidate(*I); } + if (I != E) + S.Diag(SourceLocation(), diag::note_ovl_too_many_candidates) << int(E - I); } namespace { @@ -8515,7 +8541,7 @@ void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { } void NoteBuiltinOperatorCandidate(Sema &S, - const char *Opc, + StringRef Opc, SourceLocation OpLoc, OverloadCandidate *Cand) { assert(Cand->NumConversions <= 2 && "builtin operator is not binary"); @@ -8561,6 +8587,7 @@ RankDeductionFailure(const OverloadCandidate::DeductionFailureInfo &DFI) { case Sema::TDK_Success: llvm_unreachable("TDK_success while diagnosing bad deduction"); + case Sema::TDK_Invalid: case Sema::TDK_Incomplete: return 1; @@ -8783,7 +8810,7 @@ void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, void OverloadCandidateSet::NoteCandidates(Sema &S, OverloadCandidateDisplayKind OCD, llvm::ArrayRef<Expr *> Args, - const char *Opc, + StringRef Opc, SourceLocation OpLoc) { // Sort the candidates by viability and position. Sorting directly would // be prohibitive, so we make a set of pointers and sort those. @@ -8807,8 +8834,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, bool ReportedAmbiguousConversions = false; SmallVectorImpl<OverloadCandidate*>::iterator I, E; - const DiagnosticsEngine::OverloadsShown ShowOverloads = - S.Diags.getShowOverloads(); + const OverloadsShown ShowOverloads = S.Diags.getShowOverloads(); unsigned CandsShown = 0; for (I = Cands.begin(), E = Cands.end(); I != E; ++I) { OverloadCandidate *Cand = *I; @@ -8816,7 +8842,7 @@ void OverloadCandidateSet::NoteCandidates(Sema &S, // Set an arbitrary limit on the number of candidate functions we'll spam // the user with. FIXME: This limit should depend on details of the // candidate list. - if (CandsShown >= 4 && ShowOverloads == DiagnosticsEngine::Ovl_Best) { + if (CandsShown >= 4 && ShowOverloads == Ovl_Best) { break; } ++CandsShown; @@ -8979,7 +9005,7 @@ private: // function template specialization, which is added to the set of // overloaded functions considered. FunctionDecl *Specialization = 0; - TemplateDeductionInfo Info(Context, OvlExpr->getNameLoc()); + TemplateDeductionInfo Info(OvlExpr->getNameLoc()); if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments(FunctionTemplate, &OvlExplicitTemplateArgs, @@ -9201,7 +9227,6 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, Fn = Resolver.getMatchingFunctionDecl(); assert(Fn); FoundResult = *Resolver.getMatchingFunctionAccessPair(); - MarkFunctionReferenced(AddressOfExpr->getLocStart(), Fn); if (Complain) CheckAddressOfMemberAccess(AddressOfExpr, FoundResult); } @@ -9257,7 +9282,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, // function template specialization, which is added to the set of // overloaded functions considered. FunctionDecl *Specialization = 0; - TemplateDeductionInfo Info(Context, ovl->getNameLoc()); + TemplateDeductionInfo Info(ovl->getNameLoc()); if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs, Specialization, Info)) { @@ -9457,8 +9482,7 @@ void Sema::AddOverloadedCallCandidates(UnresolvedLookupExpr *ULE, AddArgumentDependentLookupCandidates(ULE->getName(), /*Operator*/ false, ULE->getExprLoc(), Args, ExplicitTemplateArgs, - CandidateSet, PartialOverloading, - ULE->isStdAssociatedNamespace()); + CandidateSet, PartialOverloading); } /// Attempt to recover from an ill-formed use of a non-dependent name in a @@ -9509,7 +9533,7 @@ DiagnoseTwoPhaseLookup(Sema &SemaRef, SourceLocation FnLoc, // declaring the function there instead. Sema::AssociatedNamespaceSet AssociatedNamespaces; Sema::AssociatedClassSet AssociatedClasses; - SemaRef.FindAssociatedClassesAndNamespaces(Args, + SemaRef.FindAssociatedClassesAndNamespaces(FnLoc, Args, AssociatedNamespaces, AssociatedClasses); // Never suggest declaring a function within namespace 'std'. @@ -9632,6 +9656,20 @@ class NoTypoCorrectionCCC : public CorrectionCandidateCallback { return false; } }; + +class BuildRecoveryCallExprRAII { + Sema &SemaRef; +public: + BuildRecoveryCallExprRAII(Sema &S) : SemaRef(S) { + assert(SemaRef.IsBuildingRecoveryCallExpr == false); + SemaRef.IsBuildingRecoveryCallExpr = true; + } + + ~BuildRecoveryCallExprRAII() { + SemaRef.IsBuildingRecoveryCallExpr = false; + } +}; + } /// Attempts to recover from a call where no functions were found. @@ -9644,6 +9682,15 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, llvm::MutableArrayRef<Expr *> Args, SourceLocation RParenLoc, bool EmptyLookup, bool AllowTypoCorrection) { + // Do not try to recover if it is already building a recovery call. + // This stops infinite loops for template instantiations like + // + // template <typename T> auto foo(T t) -> decltype(foo(t)) {} + // template <typename T> auto foo(T t) -> decltype(foo(&t)) {} + // + if (SemaRef.IsBuildingRecoveryCallExpr) + return ExprError(); + BuildRecoveryCallExprRAII RCE(SemaRef); CXXScopeSpec SS; SS.Adopt(ULE->getQualifierLoc()); @@ -9695,20 +9742,15 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, RParenLoc); } -/// ResolveOverloadedCallFn - Given the call expression that calls Fn -/// (which eventually refers to the declaration Func) and the call -/// arguments Args/NumArgs, attempt to resolve the function call down -/// to a specific function. If overload resolution succeeds, returns -/// the function declaration produced by overload -/// resolution. Otherwise, emits diagnostics, deletes all of the -/// arguments and Fn, and returns NULL. -ExprResult -Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, - SourceLocation LParenLoc, - Expr **Args, unsigned NumArgs, - SourceLocation RParenLoc, - Expr *ExecConfig, - bool AllowTypoCorrection) { +/// \brief Constructs and populates an OverloadedCandidateSet from +/// the given function. +/// \returns true when an the ExprResult output parameter has been set. +bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, + UnresolvedLookupExpr *ULE, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc, + OverloadCandidateSet *CandidateSet, + ExprResult *Result) { #ifndef NDEBUG if (ULE->requiresADL()) { // To do ADL, we must have found an unqualified name. @@ -9724,62 +9766,79 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, // We don't perform ADL in C. assert(getLangOpts().CPlusPlus && "ADL enabled in C"); - } else - assert(!ULE->isStdAssociatedNamespace() && - "std is associated namespace but not doing ADL"); + } #endif UnbridgedCastsSet UnbridgedCasts; - if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts)) - return ExprError(); - - OverloadCandidateSet CandidateSet(Fn->getExprLoc()); + if (checkArgPlaceholdersForOverload(*this, Args, NumArgs, UnbridgedCasts)) { + *Result = ExprError(); + return true; + } // Add the functions denoted by the callee to the set of candidate // functions, including those from argument-dependent lookup. AddOverloadedCallCandidates(ULE, llvm::makeArrayRef(Args, NumArgs), - CandidateSet); + *CandidateSet); // If we found nothing, try to recover. // BuildRecoveryCallExpr diagnoses the error itself, so we just bail // out if it fails. - if (CandidateSet.empty()) { + if (CandidateSet->empty()) { // In Microsoft mode, if we are inside a template class member function then // create a type dependent CallExpr. The goal is to postpone name lookup // to instantiation time to be able to search into type dependent base // classes. if (getLangOpts().MicrosoftMode && CurContext->isDependentContext() && (isa<FunctionDecl>(CurContext) || isa<CXXRecordDecl>(CurContext))) { - CallExpr *CE = new (Context) CallExpr(Context, Fn, Args, NumArgs, - Context.DependentTy, VK_RValue, - RParenLoc); + CallExpr *CE = new (Context) CallExpr(Context, Fn, + llvm::makeArrayRef(Args, NumArgs), + Context.DependentTy, VK_RValue, + RParenLoc); CE->setTypeDependent(true); - return Owned(CE); + *Result = Owned(CE); + return true; } - return BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, - llvm::MutableArrayRef<Expr *>(Args, NumArgs), - RParenLoc, /*EmptyLookup=*/true, - AllowTypoCorrection); + return false; } UnbridgedCasts.restore(); + return false; +} - OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best)) { +/// FinishOverloadedCallExpr - given an OverloadCandidateSet, builds and returns +/// the completed call expression. If overload resolution fails, emits +/// diagnostics and returns ExprError() +static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, + UnresolvedLookupExpr *ULE, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc, + Expr *ExecConfig, + OverloadCandidateSet *CandidateSet, + OverloadCandidateSet::iterator *Best, + OverloadingResult OverloadResult, + bool AllowTypoCorrection) { + if (CandidateSet->empty()) + return BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc, + llvm::MutableArrayRef<Expr *>(Args, NumArgs), + RParenLoc, /*EmptyLookup=*/true, + AllowTypoCorrection); + + switch (OverloadResult) { case OR_Success: { - FunctionDecl *FDecl = Best->Function; - MarkFunctionReferenced(Fn->getExprLoc(), FDecl); - CheckUnresolvedLookupAccess(ULE, Best->FoundDecl); - DiagnoseUseOfDecl(FDecl, ULE->getNameLoc()); - Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); - return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, RParenLoc, - ExecConfig); + FunctionDecl *FDecl = (*Best)->Function; + SemaRef.MarkFunctionReferenced(Fn->getExprLoc(), FDecl); + SemaRef.CheckUnresolvedLookupAccess(ULE, (*Best)->FoundDecl); + SemaRef.DiagnoseUseOfDecl(FDecl, ULE->getNameLoc()); + Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); + return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, + RParenLoc, ExecConfig); } case OR_No_Viable_Function: { // Try to recover by looking for viable functions which the user might // have meant to call. - ExprResult Recovery = BuildRecoveryCallExpr(*this, S, Fn, ULE, LParenLoc, + ExprResult Recovery = BuildRecoveryCallExpr(SemaRef, S, Fn, ULE, LParenLoc, llvm::MutableArrayRef<Expr *>(Args, NumArgs), RParenLoc, /*EmptyLookup=*/false, @@ -9787,44 +9846,73 @@ Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, UnresolvedLookupExpr *ULE, if (!Recovery.isInvalid()) return Recovery; - Diag(Fn->getLocStart(), + SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_no_viable_function_in_call) << ULE->getName() << Fn->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, - llvm::makeArrayRef(Args, NumArgs)); + CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, + llvm::makeArrayRef(Args, NumArgs)); break; } case OR_Ambiguous: - Diag(Fn->getLocStart(), diag::err_ovl_ambiguous_call) + SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_ambiguous_call) << ULE->getName() << Fn->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_ViableCandidates, - llvm::makeArrayRef(Args, NumArgs)); + CandidateSet->NoteCandidates(SemaRef, OCD_ViableCandidates, + llvm::makeArrayRef(Args, NumArgs)); break; - case OR_Deleted: - { - Diag(Fn->getLocStart(), diag::err_ovl_deleted_call) - << Best->Function->isDeleted() - << ULE->getName() - << getDeletedOrUnavailableSuffix(Best->Function) - << Fn->getSourceRange(); - CandidateSet.NoteCandidates(*this, OCD_AllCandidates, - llvm::makeArrayRef(Args, NumArgs)); + case OR_Deleted: { + SemaRef.Diag(Fn->getLocStart(), diag::err_ovl_deleted_call) + << (*Best)->Function->isDeleted() + << ULE->getName() + << SemaRef.getDeletedOrUnavailableSuffix((*Best)->Function) + << Fn->getSourceRange(); + CandidateSet->NoteCandidates(SemaRef, OCD_AllCandidates, + llvm::makeArrayRef(Args, NumArgs)); - // We emitted an error for the unvailable/deleted function call but keep - // the call in the AST. - FunctionDecl *FDecl = Best->Function; - Fn = FixOverloadedFunctionReference(Fn, Best->FoundDecl, FDecl); - return BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, - RParenLoc, ExecConfig); - } + // We emitted an error for the unvailable/deleted function call but keep + // the call in the AST. + FunctionDecl *FDecl = (*Best)->Function; + Fn = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); + return SemaRef.BuildResolvedCallExpr(Fn, FDecl, LParenLoc, Args, NumArgs, + RParenLoc, ExecConfig); + } } // Overload resolution failed. return ExprError(); } +/// BuildOverloadedCallExpr - Given the call expression that calls Fn +/// (which eventually refers to the declaration Func) and the call +/// arguments Args/NumArgs, attempt to resolve the function call down +/// to a specific function. If overload resolution succeeds, returns +/// the call expression produced by overload resolution. +/// Otherwise, emits diagnostics and returns ExprError. +ExprResult Sema::BuildOverloadedCallExpr(Scope *S, Expr *Fn, + UnresolvedLookupExpr *ULE, + SourceLocation LParenLoc, + Expr **Args, unsigned NumArgs, + SourceLocation RParenLoc, + Expr *ExecConfig, + bool AllowTypoCorrection) { + OverloadCandidateSet CandidateSet(Fn->getExprLoc()); + ExprResult result; + + if (buildOverloadedCallSet(S, Fn, ULE, Args, NumArgs, LParenLoc, + &CandidateSet, &result)) + return result; + + OverloadCandidateSet::iterator Best; + OverloadingResult OverloadResult = + CandidateSet.BestViableFunction(*this, Fn->getLocStart(), Best); + + return FinishOverloadedCallExpr(*this, S, Fn, ULE, LParenLoc, Args, NumArgs, + RParenLoc, ExecConfig, &CandidateSet, + &Best, OverloadResult, + AllowTypoCorrection); +} + static bool IsOverloaded(const UnresolvedSetImpl &Functions) { return Functions.size() > 1 || (Functions.size() == 1 && isa<FunctionTemplateDecl>(*Functions.begin())); @@ -9889,10 +9977,10 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, - &Args[0], NumArgs, + llvm::makeArrayRef(Args, NumArgs), Context.DependentTy, VK_RValue, - OpLoc)); + OpLoc, false)); } // Build an empty overload set. @@ -9968,7 +10056,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, unsigned OpcIn, Args[0] = Input; CallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(), - Args, NumArgs, ResultTy, VK, OpLoc); + llvm::makeArrayRef(Args, NumArgs), + ResultTy, VK, OpLoc, false); if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, FnDecl)) @@ -10069,7 +10158,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return Owned(new (Context) BinaryOperator(Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, OK_Ordinary, - OpLoc)); + OpLoc, + FPFeatures.fp_contract)); return Owned(new (Context) CompoundAssignOperator(Args[0], Args[1], Opc, Context.DependentTy, @@ -10077,7 +10167,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, OK_Ordinary, Context.DependentTy, Context.DependentTy, - OpLoc)); + OpLoc, + FPFeatures.fp_contract)); } // FIXME: save results of ADL from here? @@ -10089,11 +10180,9 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, NestedNameSpecifierLoc(), OpNameInfo, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); - return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, - Args, 2, - Context.DependentTy, - VK_RValue, - OpLoc)); + return Owned(new (Context) CXXOperatorCallExpr(Context, Op, Fn, Args, + Context.DependentTy, VK_RValue, + OpLoc, FPFeatures.fp_contract)); } // Always do placeholder-like conversions on the RHS. @@ -10208,7 +10297,8 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, CXXOperatorCallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, Op, FnExpr.take(), - Args, 2, ResultTy, VK, OpLoc); + Args, ResultTy, VK, OpLoc, + FPFeatures.fp_contract); if (CheckCallReturnType(FnDecl->getResultType(), OpLoc, TheCall, FnDecl)) @@ -10270,7 +10360,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (Result.isInvalid()) CandidateSet.NoteCandidates(*this, OCD_AllCandidates, Args, BinaryOperator::getOpcodeStr(Opc), OpLoc); - return move(Result); + return Result; } case OR_Ambiguous: @@ -10337,10 +10427,10 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, // Can't add any actual overloads yet return Owned(new (Context) CXXOperatorCallExpr(Context, OO_Subscript, Fn, - Args, 2, + Args, Context.DependentTy, VK_RValue, - RLoc)); + RLoc, false)); } // Handle placeholders on both operands. @@ -10416,8 +10506,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, CXXOperatorCallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, OO_Subscript, - FnExpr.take(), Args, 2, - ResultTy, VK, RLoc); + FnExpr.take(), Args, + ResultTy, VK, RLoc, + false); if (CheckCallReturnType(FnDecl->getResultType(), LLoc, TheCall, FnDecl)) @@ -10534,7 +10625,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, } CXXMemberCallExpr *call - = new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs, + = new (Context) CXXMemberCallExpr(Context, MemExprE, + llvm::makeArrayRef(Args, NumArgs), resultType, valueKind, RParenLoc); if (CheckCallReturnType(proto->getResultType(), @@ -10676,7 +10768,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, assert(Method && "Member call to something that isn't a method?"); CXXMemberCallExpr *TheCall = - new (Context) CXXMemberCallExpr(Context, MemExprE, Args, NumArgs, + new (Context) CXXMemberCallExpr(Context, MemExprE, + llvm::makeArrayRef(Args, NumArgs), ResultType, VK, RParenLoc); // Check for a valid return type. @@ -10904,6 +10997,11 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // that calls this method, using Object for the implicit object // parameter and passing along the remaining arguments. CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); + + // An error diagnostic has already been printed when parsing the declaration. + if (Method->isInvalidDecl()) + return ExprError(); + const FunctionProtoType *Proto = Method->getType()->getAs<FunctionProtoType>(); @@ -10942,8 +11040,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, CXXOperatorCallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, OO_Call, NewFn.take(), - MethodArgs, NumArgs + 1, - ResultTy, VK, RParenLoc); + llvm::makeArrayRef(MethodArgs, NumArgs+1), + ResultTy, VK, RParenLoc, false); delete [] MethodArgs; if (CheckCallReturnType(Method->getResultType(), LParenLoc, TheCall, @@ -10966,7 +11064,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, if (ObjRes.isInvalid()) IsError = true; else - Object = move(ObjRes); + Object = ObjRes; TheCall->setArg(0, Object.take()); // Check the argument types. @@ -11116,7 +11214,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc) { ResultTy = ResultTy.getNonLValueExprType(Context); CXXOperatorCallExpr *TheCall = new (Context) CXXOperatorCallExpr(Context, OO_Arrow, FnExpr.take(), - &Base, 1, ResultTy, VK, OpLoc); + Base, ResultTy, VK, OpLoc, false); if (CheckCallReturnType(Method->getResultType(), OpLoc, TheCall, Method)) @@ -11187,7 +11285,8 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, ResultTy = ResultTy.getNonLValueExprType(Context); UserDefinedLiteral *UDL = - new (Context) UserDefinedLiteral(Context, Fn.take(), ConvArgs, Args.size(), + new (Context) UserDefinedLiteral(Context, Fn.take(), + llvm::makeArrayRef(ConvArgs, Args.size()), ResultTy, VK, LitEndLoc, UDSuffixLoc); if (CheckCallReturnType(FD->getResultType(), UDSuffixLoc, UDL, FD)) @@ -11199,6 +11298,80 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, return MaybeBindToTemporary(UDL); } +/// Build a call to 'begin' or 'end' for a C++11 for-range statement. If the +/// given LookupResult is non-empty, it is assumed to describe a member which +/// will be invoked. Otherwise, the function will be found via argument +/// dependent lookup. +/// CallExpr is set to a valid expression and FRS_Success returned on success, +/// otherwise CallExpr is set to ExprError() and some non-success value +/// is returned. +Sema::ForRangeStatus +Sema::BuildForRangeBeginEndCall(Scope *S, SourceLocation Loc, + SourceLocation RangeLoc, VarDecl *Decl, + BeginEndFunction BEF, + const DeclarationNameInfo &NameInfo, + LookupResult &MemberLookup, + OverloadCandidateSet *CandidateSet, + Expr *Range, ExprResult *CallExpr) { + CandidateSet->clear(); + if (!MemberLookup.empty()) { + ExprResult MemberRef = + BuildMemberReferenceExpr(Range, Range->getType(), Loc, + /*IsPtr=*/false, CXXScopeSpec(), + /*TemplateKWLoc=*/SourceLocation(), + /*FirstQualifierInScope=*/0, + MemberLookup, + /*TemplateArgs=*/0); + if (MemberRef.isInvalid()) { + *CallExpr = ExprError(); + Diag(Range->getLocStart(), diag::note_in_for_range) + << RangeLoc << BEF << Range->getType(); + return FRS_DiagnosticIssued; + } + *CallExpr = ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(), Loc, 0); + if (CallExpr->isInvalid()) { + *CallExpr = ExprError(); + Diag(Range->getLocStart(), diag::note_in_for_range) + << RangeLoc << BEF << Range->getType(); + return FRS_DiagnosticIssued; + } + } else { + UnresolvedSet<0> FoundNames; + UnresolvedLookupExpr *Fn = + UnresolvedLookupExpr::Create(Context, /*NamingClass=*/0, + NestedNameSpecifierLoc(), NameInfo, + /*NeedsADL=*/true, /*Overloaded=*/false, + FoundNames.begin(), FoundNames.end()); + + bool CandidateSetError = buildOverloadedCallSet(S, Fn, Fn, &Range, 1, Loc, + CandidateSet, CallExpr); + if (CandidateSet->empty() || CandidateSetError) { + *CallExpr = ExprError(); + return FRS_NoViableFunction; + } + OverloadCandidateSet::iterator Best; + OverloadingResult OverloadResult = + CandidateSet->BestViableFunction(*this, Fn->getLocStart(), Best); + + if (OverloadResult == OR_No_Viable_Function) { + *CallExpr = ExprError(); + return FRS_NoViableFunction; + } + *CallExpr = FinishOverloadedCallExpr(*this, S, Fn, Fn, Loc, &Range, 1, + Loc, 0, CandidateSet, &Best, + OverloadResult, + /*AllowTypoCorrection=*/false); + if (CallExpr->isInvalid() || OverloadResult != OR_Success) { + *CallExpr = ExprError(); + Diag(Range->getLocStart(), diag::note_in_for_range) + << RangeLoc << BEF << Range->getType(); + return FRS_DiagnosticIssued; + } + } + return FRS_Success; +} + + /// FixOverloadedFunctionReference - E is an expression that refers to /// a C++ overloaded function (possibly with some parentheses and /// perhaps a '&' around it). We have resolved the overloaded function @@ -11358,6 +11531,7 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, TemplateArgs, type, valueKind, OK_Ordinary); ME->setHadMultipleCandidates(true); + MarkMemberReferenced(ME); return ME; } diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index 722ac19be533..a8d75b290f19 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -31,6 +31,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Initialization.h" #include "clang/AST/ExprObjC.h" #include "clang/Lex/Preprocessor.h" @@ -91,9 +92,8 @@ namespace { return new (S.Context) GenericSelectionExpr(S.Context, gse->getGenericLoc(), gse->getControllingExpr(), - assocTypes.data(), - assocs.data(), - numAssocs, + assocTypes, + assocs, gse->getDefaultLoc(), gse->getRParenLoc(), gse->containsUnexpandedParameterPack(), @@ -187,7 +187,7 @@ namespace { UnaryOperatorKind opcode, Expr *op); - ExprResult complete(Expr *syntacticForm); + virtual ExprResult complete(Expr *syntacticForm); OpaqueValueExpr *capture(Expr *op); OpaqueValueExpr *captureValueAsResult(Expr *op); @@ -198,7 +198,14 @@ namespace { } /// Return true if assignments have a non-void result. - virtual bool assignmentsHaveResult() { return true; } + bool CanCaptureValueOfType(QualType ty) { + assert(!ty->isIncompleteType()); + assert(!ty->isDependentType()); + + if (const CXXRecordDecl *ClassDecl = ty->getAsCXXRecordDecl()) + return ClassDecl->isTriviallyCopyable(); + return true; + } virtual Expr *rebuildAndCaptureObject(Expr *) = 0; virtual ExprResult buildGet() = 0; @@ -206,7 +213,7 @@ namespace { bool captureSetValueAsResult) = 0; }; - /// A PseudoOpBuilder for Objective-C @properties. + /// A PseudoOpBuilder for Objective-C \@properties. class ObjCPropertyOpBuilder : public PseudoOpBuilder { ObjCPropertyRefExpr *RefExpr; ObjCPropertyRefExpr *SyntacticRefExpr; @@ -239,6 +246,9 @@ namespace { Expr *rebuildAndCaptureObject(Expr *syntacticBase); ExprResult buildGet(); ExprResult buildSet(Expr *op, SourceLocation, bool); + ExprResult complete(Expr *SyntacticForm); + + bool isWeakProperty() const; }; /// A PseudoOpBuilder for Objective-C array/dictionary indexing. @@ -292,7 +302,7 @@ OpaqueValueExpr *PseudoOpBuilder::capture(Expr *e) { /// operation. This routine is safe against expressions which may /// already be captured. /// -/// \param Returns the captured expression, which will be the +/// \returns the captured expression, which will be the /// same as the input if the input was already captured OpaqueValueExpr *PseudoOpBuilder::captureValueAsResult(Expr *e) { assert(ResultIndex == PseudoObjectExpr::NoResult); @@ -353,7 +363,7 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc, syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS, opcode, capturedRHS->getType(), capturedRHS->getValueKind(), - OK_Ordinary, opcLoc); + OK_Ordinary, opcLoc, false); } else { ExprResult opLHS = buildGet(); if (opLHS.isInvalid()) return ExprError(); @@ -372,12 +382,12 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc, OK_Ordinary, opLHS.get()->getType(), result.get()->getType(), - opcLoc); + opcLoc, false); } // The result of the assignment, if not void, is the value set into // the l-value. - result = buildSet(result.take(), opcLoc, assignmentsHaveResult()); + result = buildSet(result.take(), opcLoc, /*captureSetValueAsResult*/ true); if (result.isInvalid()) return ExprError(); addSemanticExpr(result.take()); @@ -401,7 +411,7 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, QualType resultType = result.get()->getType(); // That's the postfix result. - if (UnaryOperator::isPostfix(opcode) && assignmentsHaveResult()) { + if (UnaryOperator::isPostfix(opcode) && CanCaptureValueOfType(resultType)) { result = capture(result.take()); setResultToLastSemantic(); } @@ -420,8 +430,7 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, // Store that back into the result. The value stored is the result // of a prefix operation. - result = buildSet(result.take(), opcLoc, - UnaryOperator::isPrefix(opcode) && assignmentsHaveResult()); + result = buildSet(result.take(), opcLoc, UnaryOperator::isPrefix(opcode)); if (result.isInvalid()) return ExprError(); addSemanticExpr(result.take()); @@ -472,6 +481,23 @@ static ObjCMethodDecl *LookupMethodInReceiverType(Sema &S, Selector sel, return S.LookupMethodInObjectType(sel, IT, false); } +bool ObjCPropertyOpBuilder::isWeakProperty() const { + QualType T; + if (RefExpr->isExplicitProperty()) { + const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty(); + if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) + return true; + + T = Prop->getType(); + } else if (Getter) { + T = Getter->getResultType(); + } else { + return false; + } + + return T.getObjCLifetime() == Qualifiers::OCL_Weak; +} + bool ObjCPropertyOpBuilder::findGetter() { if (Getter) return true; @@ -532,7 +558,7 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) { // Do a normal method lookup first. if (ObjCMethodDecl *setter = LookupMethodInReceiverType(S, SetterSelector, RefExpr)) { - if (setter->isSynthesized() && warn) + if (setter->isPropertyAccessor() && warn) if (const ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(setter->getDeclContext())) { const StringRef thisPropertyName(prop->getName()); @@ -617,7 +643,7 @@ ExprResult ObjCPropertyOpBuilder::buildGet() { /// Store to an Objective-C property reference. /// -/// \param bindSetValueAsResult - If true, capture the actual +/// \param captureSetValueAsResult If true, capture the actual /// value being set as the value of the property operation. ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, bool captureSetValueAsResult) { @@ -676,7 +702,8 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, ObjCMessageExpr *msgExpr = cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit()); Expr *arg = msgExpr->getArg(0); - msgExpr->setArg(0, captureValueAsResult(arg)); + if (CanCaptureValueOfType(arg->getType())) + msgExpr->setArg(0, captureValueAsResult(arg)); } return msg; @@ -819,6 +846,19 @@ ObjCPropertyOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, return PseudoOpBuilder::buildIncDecOperation(Sc, opcLoc, opcode, op); } +ExprResult ObjCPropertyOpBuilder::complete(Expr *SyntacticForm) { + if (S.getLangOpts().ObjCAutoRefCount && isWeakProperty()) { + DiagnosticsEngine::Level Level = + S.Diags.getDiagnosticLevel(diag::warn_arc_repeated_use_of_weak, + SyntacticForm->getLocStart()); + if (Level != DiagnosticsEngine::Ignored) + S.getCurFunction()->recordUseOfWeak(SyntacticRefExpr, + SyntacticRefExpr->isMessagingGetter()); + } + + return PseudoOpBuilder::complete(SyntacticForm); +} + // ObjCSubscript build stuff. // @@ -1035,7 +1075,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { 0 /*TypeSourceInfo */, S.Context.getTranslationUnitDecl(), true /*Instance*/, false/*isVariadic*/, - /*isSynthesized=*/false, + /*isPropertyAccessor=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, false); @@ -1151,7 +1191,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { ResultTInfo, S.Context.getTranslationUnitDecl(), true /*Instance*/, false/*isVariadic*/, - /*isSynthesized=*/false, + /*isPropertyAccessor=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, false); @@ -1255,7 +1295,7 @@ ExprResult ObjCSubscriptOpBuilder::buildGet() { /// Store into the container the "op" object at "Index"'ed location /// by building this messaging expression: /// - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index; -/// \param bindSetValueAsResult - If true, capture the actual +/// \param captureSetValueAsResult If true, capture the actual /// value being set as the value of the property operation. ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, bool captureSetValueAsResult) { @@ -1279,7 +1319,8 @@ ExprResult ObjCSubscriptOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, ObjCMessageExpr *msgExpr = cast<ObjCMessageExpr>(msg.get()->IgnoreImplicit()); Expr *arg = msgExpr->getArg(0); - msgExpr->setArg(0, captureValueAsResult(arg)); + if (CanCaptureValueOfType(arg->getType())) + msgExpr->setArg(0, captureValueAsResult(arg)); } return msg; @@ -1333,7 +1374,7 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc, // Do nothing if either argument is dependent. if (LHS->isTypeDependent() || RHS->isTypeDependent()) return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy, - VK_RValue, OK_Ordinary, opcLoc); + VK_RValue, OK_Ordinary, opcLoc, false); // Filter out non-overload placeholder types in the RHS. if (RHS->getType()->isNonOverloadPlaceholderType()) { @@ -1404,14 +1445,14 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) { cop->getObjectKind(), cop->getComputationLHSType(), cop->getComputationResultType(), - cop->getOperatorLoc()); + cop->getOperatorLoc(), false); } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) { Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS()); Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr(); return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(), bop->getType(), bop->getValueKind(), bop->getObjectKind(), - bop->getOperatorLoc()); + bop->getOperatorLoc(), false); } else { assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject)); return stripOpaqueValuesFromPseudoObjectRef(*this, syntax); diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 86884b787339..f55174e05cc1 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -28,27 +28,10 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/BitVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Triple.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCInst.h" -#include "llvm/MC/MCInstPrinter.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCObjectFileInfo.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCStreamer.h" -#include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/MC/MCTargetAsmParser.h" -#include "llvm/MC/MCParser/MCAsmLexer.h" -#include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/Support/SourceMgr.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/TargetSelect.h" using namespace clang; using namespace sema; @@ -177,6 +160,13 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { !E->isUnusedResultAWarning(WarnExpr, Loc, R1, R2, Context)) return; + // If this is a GNU statement expression expanded from a macro, it is probably + // unused because it is a function-like macro that can be used as either an + // expression or statement. Don't warn, because it is almost certainly a + // false positive. + if (isa<StmtExpr>(E) && Loc.isMacroID()) + return; + // Okay, we have an unused result. Depending on what the base expression is, // we might want to make a more specific diagnostic. Check for one of these // cases now. @@ -271,7 +261,7 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, MultiStmtArg elts, bool isStmtExpr) { unsigned NumElts = elts.size(); - Stmt **Elts = reinterpret_cast<Stmt**>(elts.release()); + Stmt **Elts = elts.data(); // If we're in C89 mode, check that we don't have any decls after stmts. If // so, emit an extension diagnostic. if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) { @@ -381,8 +371,10 @@ Sema::ActOnLabelStmt(SourceLocation IdentLoc, LabelDecl *TheDecl, // Otherwise, things are good. Fill in the declaration and return it. LabelStmt *LS = new (Context) LabelStmt(IdentLoc, TheDecl, SubStmt); TheDecl->setStmt(LS); - if (!TheDecl->isGnuLocal()) + if (!TheDecl->isGnuLocal()) { + TheDecl->setLocStart(IdentLoc); TheDecl->setLocation(IdentLoc); + } return Owned(LS); } @@ -1566,25 +1558,6 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, ForLoc, RParenLoc)); } -namespace { - -enum BeginEndFunction { - BEF_begin, - BEF_end -}; - -/// Build a variable declaration for a for-range statement. -static VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, - QualType Type, const char *Name) { - DeclContext *DC = SemaRef.CurContext; - IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); - TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); - VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, - TInfo, SC_Auto, SC_None); - Decl->setImplicit(); - return Decl; -} - /// Finish building a variable declaration for a for-range statement. /// \return true if an error occurs. static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, @@ -1617,12 +1590,14 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, return false; } +namespace { + /// Produce a note indicating which begin/end function was implicitly called -/// by a C++0x for-range statement. This is often not obvious from the code, +/// by a C++11 for-range statement. This is often not obvious from the code, /// nor from the diagnostics produced when analysing the implicit expressions /// required in a for-range statement. void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E, - BeginEndFunction BEF) { + Sema::BeginEndFunction BEF) { CallExpr *CE = dyn_cast<CallExpr>(E); if (!CE) return; @@ -1643,56 +1618,16 @@ void NoteForRangeBeginEndFunction(Sema &SemaRef, Expr *E, << BEF << IsTemplate << Description << E->getType(); } -/// Build a call to 'begin' or 'end' for a C++0x for-range statement. If the -/// given LookupResult is non-empty, it is assumed to describe a member which -/// will be invoked. Otherwise, the function will be found via argument -/// dependent lookup. -static ExprResult BuildForRangeBeginEndCall(Sema &SemaRef, Scope *S, - SourceLocation Loc, - VarDecl *Decl, - BeginEndFunction BEF, - const DeclarationNameInfo &NameInfo, - LookupResult &MemberLookup, - Expr *Range) { - ExprResult CallExpr; - if (!MemberLookup.empty()) { - ExprResult MemberRef = - SemaRef.BuildMemberReferenceExpr(Range, Range->getType(), Loc, - /*IsPtr=*/false, CXXScopeSpec(), - /*TemplateKWLoc=*/SourceLocation(), - /*FirstQualifierInScope=*/0, - MemberLookup, - /*TemplateArgs=*/0); - if (MemberRef.isInvalid()) - return ExprError(); - CallExpr = SemaRef.ActOnCallExpr(S, MemberRef.get(), Loc, MultiExprArg(), - Loc, 0); - if (CallExpr.isInvalid()) - return ExprError(); - } else { - UnresolvedSet<0> FoundNames; - // C++0x [stmt.ranged]p1: For the purposes of this name lookup, namespace - // std is an associated namespace. - UnresolvedLookupExpr *Fn = - UnresolvedLookupExpr::Create(SemaRef.Context, /*NamingClass=*/0, - NestedNameSpecifierLoc(), NameInfo, - /*NeedsADL=*/true, /*Overloaded=*/false, - FoundNames.begin(), FoundNames.end(), - /*LookInStdNamespace=*/true); - CallExpr = SemaRef.BuildOverloadedCallExpr(S, Fn, Fn, Loc, &Range, 1, Loc, - 0, /*AllowTypoCorrection=*/false); - if (CallExpr.isInvalid()) { - SemaRef.Diag(Range->getLocStart(), diag::note_for_range_type) - << Range->getType(); - return ExprError(); - } - } - if (FinishForRangeVarDecl(SemaRef, Decl, CallExpr.get(), Loc, - diag::err_for_range_iter_deduction_failure)) { - NoteForRangeBeginEndFunction(SemaRef, CallExpr.get(), BEF); - return ExprError(); - } - return CallExpr; +/// Build a variable declaration for a for-range statement. +VarDecl *BuildForRangeVarDecl(Sema &SemaRef, SourceLocation Loc, + QualType Type, const char *Name) { + DeclContext *DC = SemaRef.CurContext; + IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); + TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); + VarDecl *Decl = VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, + TInfo, SC_Auto, SC_None); + Decl->setImplicit(); + return Decl; } } @@ -1723,7 +1658,7 @@ static bool ObjCEnumerationCollection(Expr *Collection) { StmtResult Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, Stmt *First, SourceLocation ColonLoc, Expr *Range, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, BuildForRangeKind Kind) { if (!First || !Range) return StmtError(); @@ -1761,15 +1696,137 @@ Sema::ActOnCXXForRangeStmt(SourceLocation ForLoc, return BuildCXXForRangeStmt(ForLoc, ColonLoc, RangeDecl.get(), /*BeginEndDecl=*/0, /*Cond=*/0, /*Inc=*/0, DS, - RParenLoc); + RParenLoc, Kind); } -/// BuildCXXForRangeStmt - Build or instantiate a C++0x for-range statement. +/// \brief Create the initialization, compare, and increment steps for +/// the range-based for loop expression. +/// This function does not handle array-based for loops, +/// which are created in Sema::BuildCXXForRangeStmt. +/// +/// \returns a ForRangeStatus indicating success or what kind of error occurred. +/// BeginExpr and EndExpr are set and FRS_Success is returned on success; +/// CandidateSet and BEF are set and some non-success value is returned on +/// failure. +static Sema::ForRangeStatus BuildNonArrayForRange(Sema &SemaRef, Scope *S, + Expr *BeginRange, Expr *EndRange, + QualType RangeType, + VarDecl *BeginVar, + VarDecl *EndVar, + SourceLocation ColonLoc, + OverloadCandidateSet *CandidateSet, + ExprResult *BeginExpr, + ExprResult *EndExpr, + Sema::BeginEndFunction *BEF) { + DeclarationNameInfo BeginNameInfo( + &SemaRef.PP.getIdentifierTable().get("begin"), ColonLoc); + DeclarationNameInfo EndNameInfo(&SemaRef.PP.getIdentifierTable().get("end"), + ColonLoc); + + LookupResult BeginMemberLookup(SemaRef, BeginNameInfo, + Sema::LookupMemberName); + LookupResult EndMemberLookup(SemaRef, EndNameInfo, Sema::LookupMemberName); + + if (CXXRecordDecl *D = RangeType->getAsCXXRecordDecl()) { + // - if _RangeT is a class type, the unqualified-ids begin and end are + // looked up in the scope of class _RangeT as if by class member access + // lookup (3.4.5), and if either (or both) finds at least one + // declaration, begin-expr and end-expr are __range.begin() and + // __range.end(), respectively; + SemaRef.LookupQualifiedName(BeginMemberLookup, D); + SemaRef.LookupQualifiedName(EndMemberLookup, D); + + if (BeginMemberLookup.empty() != EndMemberLookup.empty()) { + SourceLocation RangeLoc = BeginVar->getLocation(); + *BEF = BeginMemberLookup.empty() ? Sema::BEF_end : Sema::BEF_begin; + + SemaRef.Diag(RangeLoc, diag::err_for_range_member_begin_end_mismatch) + << RangeLoc << BeginRange->getType() << *BEF; + return Sema::FRS_DiagnosticIssued; + } + } else { + // - otherwise, begin-expr and end-expr are begin(__range) and + // end(__range), respectively, where begin and end are looked up with + // argument-dependent lookup (3.4.2). For the purposes of this name + // lookup, namespace std is an associated namespace. + + } + + *BEF = Sema::BEF_begin; + Sema::ForRangeStatus RangeStatus = + SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, BeginVar, + Sema::BEF_begin, BeginNameInfo, + BeginMemberLookup, CandidateSet, + BeginRange, BeginExpr); + + if (RangeStatus != Sema::FRS_Success) + return RangeStatus; + if (FinishForRangeVarDecl(SemaRef, BeginVar, BeginExpr->get(), ColonLoc, + diag::err_for_range_iter_deduction_failure)) { + NoteForRangeBeginEndFunction(SemaRef, BeginExpr->get(), *BEF); + return Sema::FRS_DiagnosticIssued; + } + + *BEF = Sema::BEF_end; + RangeStatus = + SemaRef.BuildForRangeBeginEndCall(S, ColonLoc, ColonLoc, EndVar, + Sema::BEF_end, EndNameInfo, + EndMemberLookup, CandidateSet, + EndRange, EndExpr); + if (RangeStatus != Sema::FRS_Success) + return RangeStatus; + if (FinishForRangeVarDecl(SemaRef, EndVar, EndExpr->get(), ColonLoc, + diag::err_for_range_iter_deduction_failure)) { + NoteForRangeBeginEndFunction(SemaRef, EndExpr->get(), *BEF); + return Sema::FRS_DiagnosticIssued; + } + return Sema::FRS_Success; +} + +/// Speculatively attempt to dereference an invalid range expression. +/// If the attempt fails, this function will return a valid, null StmtResult +/// and emit no diagnostics. +static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, + SourceLocation ForLoc, + Stmt *LoopVarDecl, + SourceLocation ColonLoc, + Expr *Range, + SourceLocation RangeLoc, + SourceLocation RParenLoc) { + // Determine whether we can rebuild the for-range statement with a + // dereferenced range expression. + ExprResult AdjustedRange; + { + Sema::SFINAETrap Trap(SemaRef); + + AdjustedRange = SemaRef.BuildUnaryOp(S, RangeLoc, UO_Deref, Range); + if (AdjustedRange.isInvalid()) + return StmtResult(); + + StmtResult SR = + SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc, + AdjustedRange.get(), RParenLoc, + Sema::BFRK_Check); + if (SR.isInvalid()) + return StmtResult(); + } + + // The attempt to dereference worked well enough that it could produce a valid + // loop. Produce a fixit, and rebuild the loop with diagnostics enabled, in + // case there are any other (non-fatal) problems with it. + SemaRef.Diag(RangeLoc, diag::err_for_range_dereference) + << Range->getType() << FixItHint::CreateInsertion(RangeLoc, "*"); + return SemaRef.ActOnCXXForRangeStmt(ForLoc, LoopVarDecl, ColonLoc, + AdjustedRange.get(), RParenLoc, + Sema::BFRK_Rebuild); +} + +/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement. StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, - SourceLocation RParenLoc) { + SourceLocation RParenLoc, BuildForRangeKind Kind) { Scope *S = getCurScope(); DeclStmt *RangeDS = cast<DeclStmt>(RangeDecl); @@ -1855,50 +1912,43 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, return StmtError(); } } else { - DeclarationNameInfo BeginNameInfo(&PP.getIdentifierTable().get("begin"), - ColonLoc); - DeclarationNameInfo EndNameInfo(&PP.getIdentifierTable().get("end"), - ColonLoc); - - LookupResult BeginMemberLookup(*this, BeginNameInfo, LookupMemberName); - LookupResult EndMemberLookup(*this, EndNameInfo, LookupMemberName); - - if (CXXRecordDecl *D = RangeType->getAsCXXRecordDecl()) { - // - if _RangeT is a class type, the unqualified-ids begin and end are - // looked up in the scope of class _RangeT as if by class member access - // lookup (3.4.5), and if either (or both) finds at least one - // declaration, begin-expr and end-expr are __range.begin() and - // __range.end(), respectively; - LookupQualifiedName(BeginMemberLookup, D); - LookupQualifiedName(EndMemberLookup, D); - - if (BeginMemberLookup.empty() != EndMemberLookup.empty()) { - Diag(ColonLoc, diag::err_for_range_member_begin_end_mismatch) - << RangeType << BeginMemberLookup.empty(); - return StmtError(); - } - } else { - // - otherwise, begin-expr and end-expr are begin(__range) and - // end(__range), respectively, where begin and end are looked up with - // argument-dependent lookup (3.4.2). For the purposes of this name - // lookup, namespace std is an associated namespace. + OverloadCandidateSet CandidateSet(RangeLoc); + Sema::BeginEndFunction BEFFailure; + ForRangeStatus RangeStatus = + BuildNonArrayForRange(*this, S, BeginRangeRef.get(), + EndRangeRef.get(), RangeType, + BeginVar, EndVar, ColonLoc, &CandidateSet, + &BeginExpr, &EndExpr, &BEFFailure); + + // If building the range failed, try dereferencing the range expression + // unless a diagnostic was issued or the end function is problematic. + if (Kind == BFRK_Build && RangeStatus == FRS_NoViableFunction && + BEFFailure == BEF_begin) { + StmtResult SR = RebuildForRangeWithDereference(*this, S, ForLoc, + LoopVarDecl, ColonLoc, + Range, RangeLoc, + RParenLoc); + if (SR.isInvalid() || SR.isUsable()) + return SR; } - BeginExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, BeginVar, - BEF_begin, BeginNameInfo, - BeginMemberLookup, - BeginRangeRef.get()); - if (BeginExpr.isInvalid()) - return StmtError(); - - EndExpr = BuildForRangeBeginEndCall(*this, S, ColonLoc, EndVar, - BEF_end, EndNameInfo, - EndMemberLookup, EndRangeRef.get()); - if (EndExpr.isInvalid()) + // Otherwise, emit diagnostics if we haven't already. + if (RangeStatus == FRS_NoViableFunction) { + Expr *Range = BEFFailure ? EndRangeRef.get() : BeginRangeRef.get(); + Diag(Range->getLocStart(), diag::err_for_range_invalid) + << RangeLoc << Range->getType() << BEFFailure; + CandidateSet.NoteCandidates(*this, OCD_AllCandidates, + llvm::makeArrayRef(&Range, /*NumArgs=*/1)); + } + // Return an error if no fix was discovered. + if (RangeStatus != FRS_Success) return StmtError(); } - // C++0x [decl.spec.auto]p6: BeginType and EndType must be the same. + assert(!BeginExpr.isInvalid() && !EndExpr.isInvalid() && + "invalid range expression in for loop"); + + // C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same. QualType BeginType = BeginVar->getType(), EndType = EndVar->getType(); if (!Context.hasSameType(BeginType, EndType)) { Diag(RangeLoc, diag::err_for_range_begin_end_types_differ) @@ -1930,6 +1980,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, NotEqExpr = ActOnBooleanCondition(S, ColonLoc, NotEqExpr.get()); NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get()); if (NotEqExpr.isInvalid()) { + Diag(RangeLoc, diag::note_for_range_invalid_iterator) + << RangeLoc << 0 << BeginRangeRef.get()->getType(); NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); if (!Context.hasSameType(BeginType, EndType)) NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end); @@ -1945,6 +1997,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, IncrExpr = ActOnUnaryOp(S, ColonLoc, tok::plusplus, BeginRef.get()); IncrExpr = ActOnFinishFullExpr(IncrExpr.get()); if (IncrExpr.isInvalid()) { + Diag(RangeLoc, diag::note_for_range_invalid_iterator) + << RangeLoc << 2 << BeginRangeRef.get()->getType() ; NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); return StmtError(); } @@ -1957,12 +2011,15 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, ExprResult DerefExpr = ActOnUnaryOp(S, ColonLoc, tok::star, BeginRef.get()); if (DerefExpr.isInvalid()) { + Diag(RangeLoc, diag::note_for_range_invalid_iterator) + << RangeLoc << 1 << BeginRangeRef.get()->getType(); NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); return StmtError(); } - // Attach *__begin as initializer for VD. - if (!LoopVar->isInvalidDecl()) { + // Attach *__begin as initializer for VD. Don't touch it if we're just + // trying to determine whether this would be a valid range. + if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) { AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false, /*TypeMayContainAuto=*/true); if (LoopVar->isInvalidDecl()) @@ -1973,6 +2030,11 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation ColonLoc, RangeVar->setUsed(); } + // Don't bother to actually allocate the result if we're just trying to + // determine whether it would be valid. + if (Kind == BFRK_Check) + return StmtResult(); + return Owned(new (Context) CXXForRangeStmt(RangeDS, cast_or_null<DeclStmt>(BeginEndDecl.get()), NotEqExpr.take(), IncrExpr.take(), @@ -2485,600 +2547,6 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { return Owned(Result); } -/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently -/// ignore "noop" casts in places where an lvalue is required by an inline asm. -/// We emulate this behavior when -fheinous-gnu-extensions is specified, but -/// provide a strong guidance to not use it. -/// -/// This method checks to see if the argument is an acceptable l-value and -/// returns false if it is a case we can handle. -static bool CheckAsmLValue(const Expr *E, Sema &S) { - // Type dependent expressions will be checked during instantiation. - if (E->isTypeDependent()) - return false; - - if (E->isLValue()) - return false; // Cool, this is an lvalue. - - // Okay, this is not an lvalue, but perhaps it is the result of a cast that we - // are supposed to allow. - const Expr *E2 = E->IgnoreParenNoopCasts(S.Context); - if (E != E2 && E2->isLValue()) { - if (!S.getLangOpts().HeinousExtensions) - S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue) - << E->getSourceRange(); - else - S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue) - << E->getSourceRange(); - // Accept, even if we emitted an error diagnostic. - return false; - } - - // None of the above, just randomly invalid non-lvalue. - return true; -} - -/// isOperandMentioned - Return true if the specified operand # is mentioned -/// anywhere in the decomposed asm string. -static bool isOperandMentioned(unsigned OpNo, - ArrayRef<AsmStmt::AsmStringPiece> AsmStrPieces) { - for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) { - const AsmStmt::AsmStringPiece &Piece = AsmStrPieces[p]; - if (!Piece.isOperand()) continue; - - // If this is a reference to the input and if the input was the smaller - // one, then we have to reject this asm. - if (Piece.getOperandNo() == OpNo) - return true; - } - return false; -} - -StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc, bool IsSimple, - bool IsVolatile, unsigned NumOutputs, - unsigned NumInputs, IdentifierInfo **Names, - MultiExprArg constraints, MultiExprArg exprs, - Expr *asmString, MultiExprArg clobbers, - SourceLocation RParenLoc, bool MSAsm) { - unsigned NumClobbers = clobbers.size(); - StringLiteral **Constraints = - reinterpret_cast<StringLiteral**>(constraints.get()); - Expr **Exprs = exprs.get(); - StringLiteral *AsmString = cast<StringLiteral>(asmString); - StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.get()); - - SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; - - // The parser verifies that there is a string literal here. - if (!AsmString->isAscii()) - return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character) - << AsmString->getSourceRange()); - - for (unsigned i = 0; i != NumOutputs; i++) { - StringLiteral *Literal = Constraints[i]; - if (!Literal->isAscii()) - return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) - << Literal->getSourceRange()); - - StringRef OutputName; - if (Names[i]) - OutputName = Names[i]->getName(); - - TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); - if (!Context.getTargetInfo().validateOutputConstraint(Info)) - return StmtError(Diag(Literal->getLocStart(), - diag::err_asm_invalid_output_constraint) - << Info.getConstraintStr()); - - // Check that the output exprs are valid lvalues. - Expr *OutputExpr = Exprs[i]; - if (CheckAsmLValue(OutputExpr, *this)) { - return StmtError(Diag(OutputExpr->getLocStart(), - diag::err_asm_invalid_lvalue_in_output) - << OutputExpr->getSourceRange()); - } - - OutputConstraintInfos.push_back(Info); - } - - SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; - - for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { - StringLiteral *Literal = Constraints[i]; - if (!Literal->isAscii()) - return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) - << Literal->getSourceRange()); - - StringRef InputName; - if (Names[i]) - InputName = Names[i]->getName(); - - TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); - if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(), - NumOutputs, Info)) { - return StmtError(Diag(Literal->getLocStart(), - diag::err_asm_invalid_input_constraint) - << Info.getConstraintStr()); - } - - Expr *InputExpr = Exprs[i]; - - // Only allow void types for memory constraints. - if (Info.allowsMemory() && !Info.allowsRegister()) { - if (CheckAsmLValue(InputExpr, *this)) - return StmtError(Diag(InputExpr->getLocStart(), - diag::err_asm_invalid_lvalue_in_input) - << Info.getConstraintStr() - << InputExpr->getSourceRange()); - } - - if (Info.allowsRegister()) { - if (InputExpr->getType()->isVoidType()) { - return StmtError(Diag(InputExpr->getLocStart(), - diag::err_asm_invalid_type_in_input) - << InputExpr->getType() << Info.getConstraintStr() - << InputExpr->getSourceRange()); - } - } - - ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); - if (Result.isInvalid()) - return StmtError(); - - Exprs[i] = Result.take(); - InputConstraintInfos.push_back(Info); - } - - // Check that the clobbers are valid. - for (unsigned i = 0; i != NumClobbers; i++) { - StringLiteral *Literal = Clobbers[i]; - if (!Literal->isAscii()) - return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) - << Literal->getSourceRange()); - - StringRef Clobber = Literal->getString(); - - if (!Context.getTargetInfo().isValidClobber(Clobber)) - return StmtError(Diag(Literal->getLocStart(), - diag::err_asm_unknown_register_name) << Clobber); - } - - AsmStmt *NS = - new (Context) AsmStmt(Context, AsmLoc, IsSimple, IsVolatile, MSAsm, - NumOutputs, NumInputs, Names, Constraints, Exprs, - AsmString, NumClobbers, Clobbers, RParenLoc); - // Validate the asm string, ensuring it makes sense given the operands we - // have. - SmallVector<AsmStmt::AsmStringPiece, 8> Pieces; - unsigned DiagOffs; - if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { - Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) - << AsmString->getSourceRange(); - return StmtError(); - } - - // Validate tied input operands for type mismatches. - for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) { - TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; - - // If this is a tied constraint, verify that the output and input have - // either exactly the same type, or that they are int/ptr operands with the - // same size (int/long, int*/long, are ok etc). - if (!Info.hasTiedOperand()) continue; - - unsigned TiedTo = Info.getTiedOperand(); - unsigned InputOpNo = i+NumOutputs; - Expr *OutputExpr = Exprs[TiedTo]; - Expr *InputExpr = Exprs[InputOpNo]; - - if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent()) - continue; - - QualType InTy = InputExpr->getType(); - QualType OutTy = OutputExpr->getType(); - if (Context.hasSameType(InTy, OutTy)) - continue; // All types can be tied to themselves. - - // Decide if the input and output are in the same domain (integer/ptr or - // floating point. - enum AsmDomain { - AD_Int, AD_FP, AD_Other - } InputDomain, OutputDomain; - - if (InTy->isIntegerType() || InTy->isPointerType()) - InputDomain = AD_Int; - else if (InTy->isRealFloatingType()) - InputDomain = AD_FP; - else - InputDomain = AD_Other; - - if (OutTy->isIntegerType() || OutTy->isPointerType()) - OutputDomain = AD_Int; - else if (OutTy->isRealFloatingType()) - OutputDomain = AD_FP; - else - OutputDomain = AD_Other; - - // They are ok if they are the same size and in the same domain. This - // allows tying things like: - // void* to int* - // void* to int if they are the same size. - // double to long double if they are the same size. - // - uint64_t OutSize = Context.getTypeSize(OutTy); - uint64_t InSize = Context.getTypeSize(InTy); - if (OutSize == InSize && InputDomain == OutputDomain && - InputDomain != AD_Other) - continue; - - // If the smaller input/output operand is not mentioned in the asm string, - // then we can promote the smaller one to a larger input and the asm string - // won't notice. - bool SmallerValueMentioned = false; - - // If this is a reference to the input and if the input was the smaller - // one, then we have to reject this asm. - if (isOperandMentioned(InputOpNo, Pieces)) { - // This is a use in the asm string of the smaller operand. Since we - // codegen this by promoting to a wider value, the asm will get printed - // "wrong". - SmallerValueMentioned |= InSize < OutSize; - } - if (isOperandMentioned(TiedTo, Pieces)) { - // If this is a reference to the output, and if the output is the larger - // value, then it's ok because we'll promote the input to the larger type. - SmallerValueMentioned |= OutSize < InSize; - } - - // If the smaller value wasn't mentioned in the asm string, and if the - // output was a register, just extend the shorter one to the size of the - // larger one. - if (!SmallerValueMentioned && InputDomain != AD_Other && - OutputConstraintInfos[TiedTo].allowsRegister()) - continue; - - // Either both of the operands were mentioned or the smaller one was - // mentioned. One more special case that we'll allow: if the tied input is - // integer, unmentioned, and is a constant, then we'll allow truncating it - // down to the size of the destination. - if (InputDomain == AD_Int && OutputDomain == AD_Int && - !isOperandMentioned(InputOpNo, Pieces) && - InputExpr->isEvaluatable(Context)) { - CastKind castKind = - (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast); - InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take(); - Exprs[InputOpNo] = InputExpr; - NS->setInputExpr(i, InputExpr); - continue; - } - - Diag(InputExpr->getLocStart(), - diag::err_asm_tying_incompatible_types) - << InTy << OutTy << OutputExpr->getSourceRange() - << InputExpr->getSourceRange(); - return StmtError(); - } - - return Owned(NS); -} - -// isMSAsmKeyword - Return true if this is an MS-style inline asm keyword. These -// require special handling. -static bool isMSAsmKeyword(StringRef Name) { - bool Ret = llvm::StringSwitch<bool>(Name) - .Cases("EVEN", "ALIGN", true) // Alignment directives. - .Cases("LENGTH", "SIZE", "TYPE", true) // Type and variable sizes. - .Case("_emit", true) // _emit Pseudoinstruction. - .Default(false); - return Ret; -} - -static StringRef getSpelling(Sema &SemaRef, Token AsmTok) { - StringRef Asm; - SmallString<512> TokenBuf; - TokenBuf.resize(512); - bool StringInvalid = false; - Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid); - assert (!StringInvalid && "Expected valid string!"); - return Asm; -} - -static void patchMSAsmStrings(Sema &SemaRef, bool &IsSimple, - SourceLocation AsmLoc, - ArrayRef<Token> AsmToks, - const TargetInfo &TI, - std::vector<llvm::BitVector> &AsmRegs, - std::vector<llvm::BitVector> &AsmNames, - std::vector<std::string> &AsmStrings) { - assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); - - // Assume simple asm stmt until we parse a non-register identifer (or we just - // need to bail gracefully). - IsSimple = true; - - SmallString<512> Asm; - unsigned NumAsmStrings = 0; - for (unsigned i = 0, e = AsmToks.size(); i != e; ++i) { - - // Determine if this should be considered a new asm. - bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() || - AsmToks[i].is(tok::kw_asm); - - // Emit the previous asm string. - if (i && isNewAsm) { - AsmStrings[NumAsmStrings++] = Asm.c_str(); - if (AsmToks[i].is(tok::kw_asm)) { - ++i; // Skip __asm - assert (i != e && "Expected another token."); - } - } - - // Start a new asm string with the opcode. - if (isNewAsm) { - AsmRegs[NumAsmStrings].resize(AsmToks.size()); - AsmNames[NumAsmStrings].resize(AsmToks.size()); - - StringRef Piece = AsmToks[i].getIdentifierInfo()->getName(); - // MS-style inline asm keywords require special handling. - if (isMSAsmKeyword(Piece)) - IsSimple = false; - - // TODO: Verify this is a valid opcode. - Asm = Piece; - continue; - } - - if (i && AsmToks[i].hasLeadingSpace()) - Asm += ' '; - - // Check the operand(s). - switch (AsmToks[i].getKind()) { - default: - IsSimple = false; - Asm += getSpelling(SemaRef, AsmToks[i]); - break; - case tok::comma: Asm += ","; break; - case tok::colon: Asm += ":"; break; - case tok::l_square: Asm += "["; break; - case tok::r_square: Asm += "]"; break; - case tok::l_brace: Asm += "{"; break; - case tok::r_brace: Asm += "}"; break; - case tok::numeric_constant: - Asm += getSpelling(SemaRef, AsmToks[i]); - break; - case tok::identifier: { - IdentifierInfo *II = AsmToks[i].getIdentifierInfo(); - StringRef Name = II->getName(); - - // Valid register? - if (TI.isValidGCCRegisterName(Name)) { - AsmRegs[NumAsmStrings].set(i); - Asm += Name; - break; - } - - IsSimple = false; - - // MS-style inline asm keywords require special handling. - if (isMSAsmKeyword(Name)) { - IsSimple = false; - Asm += Name; - break; - } - - // FIXME: Why are we missing this segment register? - if (Name == "fs") { - Asm += Name; - break; - } - - // Lookup the identifier. - // TODO: Someone with more experience with clang should verify this the - // proper way of doing a symbol lookup. - DeclarationName DeclName(II); - Scope *CurScope = SemaRef.getCurScope(); - LookupResult R(SemaRef, DeclName, AsmLoc, Sema::LookupOrdinaryName); - if (!SemaRef.LookupName(R, CurScope, false/*AllowBuiltinCreation*/)) - break; - - assert (R.isSingleResult() && "Expected a single result?!"); - NamedDecl *Decl = R.getFoundDecl(); - switch (Decl->getKind()) { - default: - assert(0 && "Unknown decl kind."); - break; - case Decl::Var: { - case Decl::ParmVar: - AsmNames[NumAsmStrings].set(i); - - VarDecl *Var = cast<VarDecl>(Decl); - QualType Ty = Var->getType(); - (void)Ty; // Avoid warning. - // TODO: Patch identifier with valid operand. One potential idea is to - // probe the backend with type information to guess the possible - // operand. - break; - } - } - break; - } - } - } - - // Emit the final (and possibly only) asm string. - AsmStrings[NumAsmStrings] = Asm.c_str(); -} - -// Build the unmodified MSAsmString. -static std::string buildMSAsmString(Sema &SemaRef, - ArrayRef<Token> AsmToks, - unsigned &NumAsmStrings) { - assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); - NumAsmStrings = 0; - - SmallString<512> Asm; - for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { - bool isNewAsm = i == 0 || AsmToks[i].isAtStartOfLine() || - AsmToks[i].is(tok::kw_asm); - - if (isNewAsm) { - ++NumAsmStrings; - if (i) - Asm += '\n'; - if (AsmToks[i].is(tok::kw_asm)) { - i++; // Skip __asm - assert (i != e && "Expected another token"); - } - } - - if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm) - Asm += ' '; - - Asm += getSpelling(SemaRef, AsmToks[i]); - } - return Asm.c_str(); -} - -StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, - SourceLocation LBraceLoc, - ArrayRef<Token> AsmToks, - SourceLocation EndLoc) { - // MS-style inline assembly is not fully supported, so emit a warning. - Diag(AsmLoc, diag::warn_unsupported_msasm); - SmallVector<StringRef,4> Clobbers; - std::set<std::string> ClobberRegs; - SmallVector<IdentifierInfo*, 4> Inputs; - SmallVector<IdentifierInfo*, 4> Outputs; - - // Empty asm statements don't need to instantiate the AsmParser, etc. - if (AsmToks.empty()) { - StringRef AsmString; - MSAsmStmt *NS = - new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, - /*IsVolatile*/ true, AsmToks, Inputs, Outputs, - AsmString, Clobbers, EndLoc); - return Owned(NS); - } - - unsigned NumAsmStrings; - std::string AsmString = buildMSAsmString(*this, AsmToks, NumAsmStrings); - - bool IsSimple; - std::vector<llvm::BitVector> Regs; - std::vector<llvm::BitVector> Names; - std::vector<std::string> PatchedAsmStrings; - - Regs.resize(NumAsmStrings); - Names.resize(NumAsmStrings); - PatchedAsmStrings.resize(NumAsmStrings); - - // Rewrite operands to appease the AsmParser. - patchMSAsmStrings(*this, IsSimple, AsmLoc, AsmToks, - Context.getTargetInfo(), Regs, Names, PatchedAsmStrings); - - // patchMSAsmStrings doesn't correctly patch non-simple asm statements. - if (!IsSimple) { - MSAsmStmt *NS = - new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, - /*IsVolatile*/ true, AsmToks, Inputs, Outputs, - AsmString, Clobbers, EndLoc); - return Owned(NS); - } - - // Initialize targets and assembly printers/parsers. - llvm::InitializeAllTargetInfos(); - llvm::InitializeAllTargetMCs(); - llvm::InitializeAllAsmParsers(); - - // Get the target specific parser. - std::string Error; - const std::string &TT = Context.getTargetInfo().getTriple().getTriple(); - const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error)); - - OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT)); - OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); - OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); - OwningPtr<llvm::MCSubtargetInfo> - STI(TheTarget->createMCSubtargetInfo(TT, "", "")); - - for (unsigned i = 0, e = PatchedAsmStrings.size(); i != e; ++i) { - llvm::SourceMgr SrcMgr; - llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); - llvm::MemoryBuffer *Buffer = - llvm::MemoryBuffer::getMemBuffer(PatchedAsmStrings[i], "<inline asm>"); - - // Tell SrcMgr about this buffer, which is what the parser will pick up. - SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); - - OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx)); - OwningPtr<llvm::MCAsmParser> - Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); - OwningPtr<llvm::MCTargetAsmParser> - TargetParser(TheTarget->createMCAsmParser(*STI, *Parser)); - // Change to the Intel dialect. - Parser->setAssemblerDialect(1); - Parser->setTargetParser(*TargetParser.get()); - - // Prime the lexer. - Parser->Lex(); - - // Parse the opcode. - StringRef IDVal; - Parser->ParseIdentifier(IDVal); - - // Canonicalize the opcode to lower case. - SmallString<128> Opcode; - for (unsigned i = 0, e = IDVal.size(); i != e; ++i) - Opcode.push_back(tolower(IDVal[i])); - - // Parse the operands. - llvm::SMLoc IDLoc; - SmallVector<llvm::MCParsedAsmOperand*, 8> Operands; - bool HadError = TargetParser->ParseInstruction(Opcode.str(), IDLoc, - Operands); - assert (!HadError && "Unexpected error parsing instruction"); - - // Match the MCInstr. - SmallVector<llvm::MCInst, 2> Instrs; - HadError = TargetParser->MatchInstruction(IDLoc, Operands, Instrs); - assert (!HadError && "Unexpected error matching instruction"); - assert ((Instrs.size() == 1) && "Expected only a single instruction."); - - // Get the instruction descriptor. - llvm::MCInst Inst = Instrs[0]; - const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); - const llvm::MCInstrDesc &Desc = MII->get(Inst.getOpcode()); - llvm::MCInstPrinter *IP = - TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI); - - // Build the list of clobbers. - for (unsigned i = 0, e = Desc.getNumDefs(); i != e; ++i) { - const llvm::MCOperand &Op = Inst.getOperand(i); - if (!Op.isReg()) - continue; - - std::string Reg; - llvm::raw_string_ostream OS(Reg); - IP->printRegName(OS, Op.getReg()); - - StringRef Clobber(OS.str()); - if (!Context.getTargetInfo().isValidClobber(Clobber)) - return StmtError(Diag(AsmLoc, diag::err_asm_unknown_register_name) << - Clobber); - ClobberRegs.insert(Reg); - } - } - for (std::set<std::string>::iterator I = ClobberRegs.begin(), - E = ClobberRegs.end(); I != E; ++I) - Clobbers.push_back(*I); - - MSAsmStmt *NS = - new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, - /*IsVolatile*/ true, AsmToks, Inputs, Outputs, - AsmString, Clobbers, EndLoc); - return Owned(NS); -} - StmtResult Sema::ActOnObjCAtCatchStmt(SourceLocation AtLoc, SourceLocation RParen, Decl *Parm, @@ -3104,7 +2572,7 @@ Sema::ActOnObjCAtTryStmt(SourceLocation AtLoc, Stmt *Try, getCurFunction()->setHasBranchProtectedScope(); unsigned NumCatchStmts = CatchStmts.size(); return Owned(ObjCAtTryStmt::Create(Context, AtLoc, Try, - CatchStmts.release(), + CatchStmts.data(), NumCatchStmts, Finally)); } @@ -3239,7 +2707,7 @@ Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, unsigned NumHandlers = RawHandlers.size(); assert(NumHandlers > 0 && "The parser shouldn't call this if there are no handlers."); - Stmt **Handlers = RawHandlers.get(); + Stmt **Handlers = RawHandlers.data(); SmallVector<TypeWithHandler, 8> TypesWithHandlers; diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp new file mode 100644 index 000000000000..7c2c766e4615 --- /dev/null +++ b/lib/Sema/SemaStmtAsm.cpp @@ -0,0 +1,661 @@ +//===--- SemaStmtAsm.cpp - Semantic Analysis for Asm Statements -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements semantic analysis for inline asm statements. +// +//===----------------------------------------------------------------------===// + +#include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/Lookup.h" +#include "clang/AST/RecordLayout.h" +#include "clang/AST/TypeLoc.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCObjectFileInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCTargetAsmParser.h" +#include "llvm/MC/MCParser/MCAsmParser.h" +#include "llvm/Support/SourceMgr.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/TargetSelect.h" +using namespace clang; +using namespace sema; + +/// CheckAsmLValue - GNU C has an extremely ugly extension whereby they silently +/// ignore "noop" casts in places where an lvalue is required by an inline asm. +/// We emulate this behavior when -fheinous-gnu-extensions is specified, but +/// provide a strong guidance to not use it. +/// +/// This method checks to see if the argument is an acceptable l-value and +/// returns false if it is a case we can handle. +static bool CheckAsmLValue(const Expr *E, Sema &S) { + // Type dependent expressions will be checked during instantiation. + if (E->isTypeDependent()) + return false; + + if (E->isLValue()) + return false; // Cool, this is an lvalue. + + // Okay, this is not an lvalue, but perhaps it is the result of a cast that we + // are supposed to allow. + const Expr *E2 = E->IgnoreParenNoopCasts(S.Context); + if (E != E2 && E2->isLValue()) { + if (!S.getLangOpts().HeinousExtensions) + S.Diag(E2->getLocStart(), diag::err_invalid_asm_cast_lvalue) + << E->getSourceRange(); + else + S.Diag(E2->getLocStart(), diag::warn_invalid_asm_cast_lvalue) + << E->getSourceRange(); + // Accept, even if we emitted an error diagnostic. + return false; + } + + // None of the above, just randomly invalid non-lvalue. + return true; +} + +/// isOperandMentioned - Return true if the specified operand # is mentioned +/// anywhere in the decomposed asm string. +static bool isOperandMentioned(unsigned OpNo, + ArrayRef<GCCAsmStmt::AsmStringPiece> AsmStrPieces) { + for (unsigned p = 0, e = AsmStrPieces.size(); p != e; ++p) { + const GCCAsmStmt::AsmStringPiece &Piece = AsmStrPieces[p]; + if (!Piece.isOperand()) continue; + + // If this is a reference to the input and if the input was the smaller + // one, then we have to reject this asm. + if (Piece.getOperandNo() == OpNo) + return true; + } + return false; +} + +StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, + bool IsVolatile, unsigned NumOutputs, + unsigned NumInputs, IdentifierInfo **Names, + MultiExprArg constraints, MultiExprArg exprs, + Expr *asmString, MultiExprArg clobbers, + SourceLocation RParenLoc) { + unsigned NumClobbers = clobbers.size(); + StringLiteral **Constraints = + reinterpret_cast<StringLiteral**>(constraints.data()); + Expr **Exprs = exprs.data(); + StringLiteral *AsmString = cast<StringLiteral>(asmString); + StringLiteral **Clobbers = reinterpret_cast<StringLiteral**>(clobbers.data()); + + SmallVector<TargetInfo::ConstraintInfo, 4> OutputConstraintInfos; + + // The parser verifies that there is a string literal here. + if (!AsmString->isAscii()) + return StmtError(Diag(AsmString->getLocStart(),diag::err_asm_wide_character) + << AsmString->getSourceRange()); + + for (unsigned i = 0; i != NumOutputs; i++) { + StringLiteral *Literal = Constraints[i]; + if (!Literal->isAscii()) + return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) + << Literal->getSourceRange()); + + StringRef OutputName; + if (Names[i]) + OutputName = Names[i]->getName(); + + TargetInfo::ConstraintInfo Info(Literal->getString(), OutputName); + if (!Context.getTargetInfo().validateOutputConstraint(Info)) + return StmtError(Diag(Literal->getLocStart(), + diag::err_asm_invalid_output_constraint) + << Info.getConstraintStr()); + + // Check that the output exprs are valid lvalues. + Expr *OutputExpr = Exprs[i]; + if (CheckAsmLValue(OutputExpr, *this)) { + return StmtError(Diag(OutputExpr->getLocStart(), + diag::err_asm_invalid_lvalue_in_output) + << OutputExpr->getSourceRange()); + } + + OutputConstraintInfos.push_back(Info); + } + + SmallVector<TargetInfo::ConstraintInfo, 4> InputConstraintInfos; + + for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) { + StringLiteral *Literal = Constraints[i]; + if (!Literal->isAscii()) + return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) + << Literal->getSourceRange()); + + StringRef InputName; + if (Names[i]) + InputName = Names[i]->getName(); + + TargetInfo::ConstraintInfo Info(Literal->getString(), InputName); + if (!Context.getTargetInfo().validateInputConstraint(OutputConstraintInfos.data(), + NumOutputs, Info)) { + return StmtError(Diag(Literal->getLocStart(), + diag::err_asm_invalid_input_constraint) + << Info.getConstraintStr()); + } + + Expr *InputExpr = Exprs[i]; + + // Only allow void types for memory constraints. + if (Info.allowsMemory() && !Info.allowsRegister()) { + if (CheckAsmLValue(InputExpr, *this)) + return StmtError(Diag(InputExpr->getLocStart(), + diag::err_asm_invalid_lvalue_in_input) + << Info.getConstraintStr() + << InputExpr->getSourceRange()); + } + + if (Info.allowsRegister()) { + if (InputExpr->getType()->isVoidType()) { + return StmtError(Diag(InputExpr->getLocStart(), + diag::err_asm_invalid_type_in_input) + << InputExpr->getType() << Info.getConstraintStr() + << InputExpr->getSourceRange()); + } + } + + ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); + if (Result.isInvalid()) + return StmtError(); + + Exprs[i] = Result.take(); + InputConstraintInfos.push_back(Info); + } + + // Check that the clobbers are valid. + for (unsigned i = 0; i != NumClobbers; i++) { + StringLiteral *Literal = Clobbers[i]; + if (!Literal->isAscii()) + return StmtError(Diag(Literal->getLocStart(),diag::err_asm_wide_character) + << Literal->getSourceRange()); + + StringRef Clobber = Literal->getString(); + + if (!Context.getTargetInfo().isValidClobber(Clobber)) + return StmtError(Diag(Literal->getLocStart(), + diag::err_asm_unknown_register_name) << Clobber); + } + + GCCAsmStmt *NS = + new (Context) GCCAsmStmt(Context, AsmLoc, IsSimple, IsVolatile, NumOutputs, + NumInputs, Names, Constraints, Exprs, AsmString, + NumClobbers, Clobbers, RParenLoc); + // Validate the asm string, ensuring it makes sense given the operands we + // have. + SmallVector<GCCAsmStmt::AsmStringPiece, 8> Pieces; + unsigned DiagOffs; + if (unsigned DiagID = NS->AnalyzeAsmString(Pieces, Context, DiagOffs)) { + Diag(getLocationOfStringLiteralByte(AsmString, DiagOffs), DiagID) + << AsmString->getSourceRange(); + return StmtError(); + } + + // Validate constraints and modifiers. + for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { + GCCAsmStmt::AsmStringPiece &Piece = Pieces[i]; + if (!Piece.isOperand()) continue; + + // Look for the correct constraint index. + unsigned Idx = 0; + unsigned ConstraintIdx = 0; + for (unsigned i = 0, e = NS->getNumOutputs(); i != e; ++i, ++ConstraintIdx) { + TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; + if (Idx == Piece.getOperandNo()) + break; + ++Idx; + + if (Info.isReadWrite()) { + if (Idx == Piece.getOperandNo()) + break; + ++Idx; + } + } + + for (unsigned i = 0, e = NS->getNumInputs(); i != e; ++i, ++ConstraintIdx) { + TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; + if (Idx == Piece.getOperandNo()) + break; + ++Idx; + + if (Info.isReadWrite()) { + if (Idx == Piece.getOperandNo()) + break; + ++Idx; + } + } + + // Now that we have the right indexes go ahead and check. + StringLiteral *Literal = Constraints[ConstraintIdx]; + const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr(); + if (Ty->isDependentType() || Ty->isIncompleteType()) + continue; + + unsigned Size = Context.getTypeSize(Ty); + if (!Context.getTargetInfo() + .validateConstraintModifier(Literal->getString(), Piece.getModifier(), + Size)) + Diag(Exprs[ConstraintIdx]->getLocStart(), + diag::warn_asm_mismatched_size_modifier); + } + + // Validate tied input operands for type mismatches. + for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) { + TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; + + // If this is a tied constraint, verify that the output and input have + // either exactly the same type, or that they are int/ptr operands with the + // same size (int/long, int*/long, are ok etc). + if (!Info.hasTiedOperand()) continue; + + unsigned TiedTo = Info.getTiedOperand(); + unsigned InputOpNo = i+NumOutputs; + Expr *OutputExpr = Exprs[TiedTo]; + Expr *InputExpr = Exprs[InputOpNo]; + + if (OutputExpr->isTypeDependent() || InputExpr->isTypeDependent()) + continue; + + QualType InTy = InputExpr->getType(); + QualType OutTy = OutputExpr->getType(); + if (Context.hasSameType(InTy, OutTy)) + continue; // All types can be tied to themselves. + + // Decide if the input and output are in the same domain (integer/ptr or + // floating point. + enum AsmDomain { + AD_Int, AD_FP, AD_Other + } InputDomain, OutputDomain; + + if (InTy->isIntegerType() || InTy->isPointerType()) + InputDomain = AD_Int; + else if (InTy->isRealFloatingType()) + InputDomain = AD_FP; + else + InputDomain = AD_Other; + + if (OutTy->isIntegerType() || OutTy->isPointerType()) + OutputDomain = AD_Int; + else if (OutTy->isRealFloatingType()) + OutputDomain = AD_FP; + else + OutputDomain = AD_Other; + + // They are ok if they are the same size and in the same domain. This + // allows tying things like: + // void* to int* + // void* to int if they are the same size. + // double to long double if they are the same size. + // + uint64_t OutSize = Context.getTypeSize(OutTy); + uint64_t InSize = Context.getTypeSize(InTy); + if (OutSize == InSize && InputDomain == OutputDomain && + InputDomain != AD_Other) + continue; + + // If the smaller input/output operand is not mentioned in the asm string, + // then we can promote the smaller one to a larger input and the asm string + // won't notice. + bool SmallerValueMentioned = false; + + // If this is a reference to the input and if the input was the smaller + // one, then we have to reject this asm. + if (isOperandMentioned(InputOpNo, Pieces)) { + // This is a use in the asm string of the smaller operand. Since we + // codegen this by promoting to a wider value, the asm will get printed + // "wrong". + SmallerValueMentioned |= InSize < OutSize; + } + if (isOperandMentioned(TiedTo, Pieces)) { + // If this is a reference to the output, and if the output is the larger + // value, then it's ok because we'll promote the input to the larger type. + SmallerValueMentioned |= OutSize < InSize; + } + + // If the smaller value wasn't mentioned in the asm string, and if the + // output was a register, just extend the shorter one to the size of the + // larger one. + if (!SmallerValueMentioned && InputDomain != AD_Other && + OutputConstraintInfos[TiedTo].allowsRegister()) + continue; + + // Either both of the operands were mentioned or the smaller one was + // mentioned. One more special case that we'll allow: if the tied input is + // integer, unmentioned, and is a constant, then we'll allow truncating it + // down to the size of the destination. + if (InputDomain == AD_Int && OutputDomain == AD_Int && + !isOperandMentioned(InputOpNo, Pieces) && + InputExpr->isEvaluatable(Context)) { + CastKind castKind = + (OutTy->isBooleanType() ? CK_IntegralToBoolean : CK_IntegralCast); + InputExpr = ImpCastExprToType(InputExpr, OutTy, castKind).take(); + Exprs[InputOpNo] = InputExpr; + NS->setInputExpr(i, InputExpr); + continue; + } + + Diag(InputExpr->getLocStart(), + diag::err_asm_tying_incompatible_types) + << InTy << OutTy << OutputExpr->getSourceRange() + << InputExpr->getSourceRange(); + return StmtError(); + } + + return Owned(NS); +} + +// getSpelling - Get the spelling of the AsmTok token. +static StringRef getSpelling(Sema &SemaRef, Token AsmTok) { + StringRef Asm; + SmallString<512> TokenBuf; + TokenBuf.resize(512); + bool StringInvalid = false; + Asm = SemaRef.PP.getSpelling(AsmTok, TokenBuf, &StringInvalid); + assert (!StringInvalid && "Expected valid string!"); + return Asm; +} + +// Build the inline assembly string. Returns true on error. +static bool buildMSAsmString(Sema &SemaRef, + SourceLocation AsmLoc, + ArrayRef<Token> AsmToks, + llvm::SmallVectorImpl<unsigned> &TokOffsets, + std::string &AsmString) { + assert (!AsmToks.empty() && "Didn't expect an empty AsmToks!"); + + SmallString<512> Asm; + for (unsigned i = 0, e = AsmToks.size(); i < e; ++i) { + bool isNewAsm = ((i == 0) || + AsmToks[i].isAtStartOfLine() || + AsmToks[i].is(tok::kw_asm)); + if (isNewAsm) { + if (i != 0) + Asm += "\n\t"; + + if (AsmToks[i].is(tok::kw_asm)) { + i++; // Skip __asm + if (i == e) { + SemaRef.Diag(AsmLoc, diag::err_asm_empty); + return true; + } + + } + } + + if (i && AsmToks[i].hasLeadingSpace() && !isNewAsm) + Asm += ' '; + + StringRef Spelling = getSpelling(SemaRef, AsmToks[i]); + Asm += Spelling; + TokOffsets.push_back(Asm.size()); + } + AsmString = Asm.str(); + return false; +} + +namespace { + +class MCAsmParserSemaCallbackImpl : public llvm::MCAsmParserSemaCallback { + Sema &SemaRef; + SourceLocation AsmLoc; + ArrayRef<Token> AsmToks; + ArrayRef<unsigned> TokOffsets; + +public: + MCAsmParserSemaCallbackImpl(Sema &Ref, SourceLocation Loc, + ArrayRef<Token> Toks, + ArrayRef<unsigned> Offsets) + : SemaRef(Ref), AsmLoc(Loc), AsmToks(Toks), TokOffsets(Offsets) { } + ~MCAsmParserSemaCallbackImpl() {} + + void *LookupInlineAsmIdentifier(StringRef Name, void *SrcLoc, unsigned &Size){ + SourceLocation Loc = SourceLocation::getFromPtrEncoding(SrcLoc); + NamedDecl *OpDecl = SemaRef.LookupInlineAsmIdentifier(Name, Loc, Size); + return static_cast<void *>(OpDecl); + } + + bool LookupInlineAsmField(StringRef Base, StringRef Member, + unsigned &Offset) { + return SemaRef.LookupInlineAsmField(Base, Member, Offset, AsmLoc); + } + + static void MSAsmDiagHandlerCallback(const llvm::SMDiagnostic &D, + void *Context) { + ((MCAsmParserSemaCallbackImpl*)Context)->MSAsmDiagHandler(D); + } + void MSAsmDiagHandler(const llvm::SMDiagnostic &D) { + // Compute an offset into the inline asm buffer. + // FIXME: This isn't right if .macro is involved (but hopefully, no + // real-world code does that). + const llvm::SourceMgr &LSM = *D.getSourceMgr(); + const llvm::MemoryBuffer *LBuf = + LSM.getMemoryBuffer(LSM.FindBufferContainingLoc(D.getLoc())); + unsigned Offset = D.getLoc().getPointer() - LBuf->getBufferStart(); + + // Figure out which token that offset points into. + const unsigned *OffsetPtr = + std::lower_bound(TokOffsets.begin(), TokOffsets.end(), Offset); + unsigned TokIndex = OffsetPtr - TokOffsets.begin(); + + // If we come up with an answer which seems sane, use it; otherwise, + // just point at the __asm keyword. + // FIXME: Assert the answer is sane once we handle .macro correctly. + SourceLocation Loc = AsmLoc; + if (TokIndex < AsmToks.size()) { + const Token *Tok = &AsmToks[TokIndex]; + Loc = Tok->getLocation(); + Loc = Loc.getLocWithOffset(Offset - (*OffsetPtr - Tok->getLength())); + } + SemaRef.Diag(Loc, diag::err_inline_ms_asm_parsing) << D.getMessage(); + } +}; + +} + +NamedDecl *Sema::LookupInlineAsmIdentifier(StringRef Name, SourceLocation Loc, + unsigned &Size) { + Size = 0; + LookupResult Result(*this, &Context.Idents.get(Name), Loc, + Sema::LookupOrdinaryName); + + if (!LookupName(Result, getCurScope())) { + // If we don't find anything, return null; the AsmParser will assume + // it is a label of some sort. + return 0; + } + + if (!Result.isSingleResult()) { + // FIXME: Diagnose result. + return 0; + } + + NamedDecl *ND = Result.getFoundDecl(); + if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) { + if (VarDecl *Var = dyn_cast<VarDecl>(ND)) + Size = Context.getTypeInfo(Var->getType()).first; + + return ND; + } + + // FIXME: Handle other kinds of results? (FieldDecl, etc.) + // FIXME: Diagnose if we find something we can't handle, like a typedef. + return 0; +} + +bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, + unsigned &Offset, SourceLocation AsmLoc) { + Offset = 0; + LookupResult BaseResult(*this, &Context.Idents.get(Base), SourceLocation(), + LookupOrdinaryName); + + if (!LookupName(BaseResult, getCurScope())) + return true; + + if (!BaseResult.isSingleResult()) + return true; + + NamedDecl *FoundDecl = BaseResult.getFoundDecl(); + const RecordType *RT = 0; + if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) { + RT = VD->getType()->getAs<RecordType>(); + } else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(FoundDecl)) { + RT = TD->getUnderlyingType()->getAs<RecordType>(); + } + if (!RT) + return true; + + if (RequireCompleteType(AsmLoc, QualType(RT, 0), 0)) + return true; + + LookupResult FieldResult(*this, &Context.Idents.get(Member), SourceLocation(), + LookupMemberName); + + if (!LookupQualifiedName(FieldResult, RT->getDecl())) + return true; + + // FIXME: Handle IndirectFieldDecl? + FieldDecl *FD = dyn_cast<FieldDecl>(FieldResult.getFoundDecl()); + if (!FD) + return true; + + const ASTRecordLayout &RL = Context.getASTRecordLayout(RT->getDecl()); + unsigned i = FD->getFieldIndex(); + CharUnits Result = Context.toCharUnitsFromBits(RL.getFieldOffset(i)); + Offset = (unsigned)Result.getQuantity(); + + return false; +} + +StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, + ArrayRef<Token> AsmToks,SourceLocation EndLoc) { + SmallVector<IdentifierInfo*, 4> Names; + SmallVector<StringRef, 4> ConstraintRefs; + SmallVector<Expr*, 4> Exprs; + SmallVector<StringRef, 4> ClobberRefs; + + // Empty asm statements don't need to instantiate the AsmParser, etc. + if (AsmToks.empty()) { + StringRef EmptyAsmStr; + MSAsmStmt *NS = + new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, /*IsSimple*/ true, + /*IsVolatile*/ true, AsmToks, /*NumOutputs*/ 0, + /*NumInputs*/ 0, Names, ConstraintRefs, Exprs, + EmptyAsmStr, ClobberRefs, EndLoc); + return Owned(NS); + } + + std::string AsmString; + llvm::SmallVector<unsigned, 8> TokOffsets; + if (buildMSAsmString(*this, AsmLoc, AsmToks, TokOffsets, AsmString)) + return StmtError(); + + // Get the target specific parser. + std::string Error; + const std::string &TT = Context.getTargetInfo().getTriple().getTriple(); + const llvm::Target *TheTarget(llvm::TargetRegistry::lookupTarget(TT, Error)); + + OwningPtr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(TT)); + OwningPtr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); + OwningPtr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); + OwningPtr<llvm::MCSubtargetInfo> + STI(TheTarget->createMCSubtargetInfo(TT, "", "")); + + llvm::SourceMgr SrcMgr; + llvm::MCContext Ctx(*MAI, *MRI, MOFI.get(), &SrcMgr); + llvm::MemoryBuffer *Buffer = + llvm::MemoryBuffer::getMemBuffer(AsmString, "<inline asm>"); + + // Tell SrcMgr about this buffer, which is what the parser will pick up. + SrcMgr.AddNewSourceBuffer(Buffer, llvm::SMLoc()); + + OwningPtr<llvm::MCStreamer> Str(createNullStreamer(Ctx)); + OwningPtr<llvm::MCAsmParser> + Parser(createMCAsmParser(SrcMgr, Ctx, *Str.get(), *MAI)); + OwningPtr<llvm::MCTargetAsmParser> + TargetParser(TheTarget->createMCAsmParser(*STI, *Parser)); + + // Get the instruction descriptor. + const llvm::MCInstrInfo *MII = TheTarget->createMCInstrInfo(); + llvm::MCInstPrinter *IP = + TheTarget->createMCInstPrinter(1, *MAI, *MII, *MRI, *STI); + + // Change to the Intel dialect. + Parser->setAssemblerDialect(1); + Parser->setTargetParser(*TargetParser.get()); + Parser->setParsingInlineAsm(true); + TargetParser->setParsingInlineAsm(true); + + MCAsmParserSemaCallbackImpl MCAPSI(*this, AsmLoc, AsmToks, TokOffsets); + TargetParser->setSemaCallback(&MCAPSI); + SrcMgr.setDiagHandler(MCAsmParserSemaCallbackImpl::MSAsmDiagHandlerCallback, + &MCAPSI); + + unsigned NumOutputs; + unsigned NumInputs; + std::string AsmStringIR; + SmallVector<std::pair<void *, bool>, 4> OpDecls; + SmallVector<std::string, 4> Constraints; + SmallVector<std::string, 4> Clobbers; + if (Parser->ParseMSInlineAsm(AsmLoc.getPtrEncoding(), AsmStringIR, + NumOutputs, NumInputs, OpDecls, Constraints, + Clobbers, MII, IP, MCAPSI)) + return StmtError(); + + // Build the vector of clobber StringRefs. + unsigned NumClobbers = Clobbers.size(); + ClobberRefs.resize(NumClobbers); + for (unsigned i = 0; i != NumClobbers; ++i) + ClobberRefs[i] = StringRef(Clobbers[i]); + + // Recast the void pointers and build the vector of constraint StringRefs. + unsigned NumExprs = NumOutputs + NumInputs; + Names.resize(NumExprs); + ConstraintRefs.resize(NumExprs); + Exprs.resize(NumExprs); + for (unsigned i = 0, e = NumExprs; i != e; ++i) { + NamedDecl *OpDecl = static_cast<NamedDecl *>(OpDecls[i].first); + if (!OpDecl) + return StmtError(); + + DeclarationNameInfo NameInfo(OpDecl->getDeclName(), AsmLoc); + ExprResult OpExpr = BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, + OpDecl); + if (OpExpr.isInvalid()) + return StmtError(); + + // Need offset of variable. + if (OpDecls[i].second) + OpExpr = BuildUnaryOp(getCurScope(), AsmLoc, clang::UO_AddrOf, + OpExpr.take()); + + Names[i] = OpDecl->getIdentifier(); + ConstraintRefs[i] = StringRef(Constraints[i]); + Exprs[i] = OpExpr.take(); + } + + bool IsSimple = NumExprs > 0; + MSAsmStmt *NS = + new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, + /*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs, + Names, ConstraintRefs, Exprs, AsmStringIR, + ClobberRefs, EndLoc); + return Owned(NS); +} diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp index 3c15b7a8afad..b268b4502c4f 100644 --- a/lib/Sema/SemaStmtAttr.cpp +++ b/lib/Sema/SemaStmtAttr.cpp @@ -48,11 +48,16 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range) { switch (A.getKind()) { + case AttributeList::UnknownAttribute: + S.Diag(A.getLoc(), A.isDeclspecAttribute() ? + diag::warn_unhandled_ms_attribute_ignored : + diag::warn_unknown_attribute_ignored) << A.getName(); + return 0; case AttributeList::AT_FallThrough: return handleFallThroughAttr(S, St, A, Range); default: - // if we're here, then we parsed an attribute, but didn't recognize it as a - // statement attribute => it is declaration attribute + // if we're here, then we parsed a known attribute, but didn't recognize + // it as a statement attribute => it is declaration attribute S.Diag(A.getRange().getBegin(), diag::warn_attribute_invalid_on_stmt) << A.getName()->getName() << St->getLocStart(); return 0; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 4dbf3e45b387..f56b05406d07 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -333,7 +333,8 @@ void Sema::LookupTemplateName(LookupResult &Found, if (LookupCtx) Diag(Found.getNameLoc(), diag::err_no_member_template_suggest) << Name << LookupCtx << CorrectedQuotedStr << SS.getRange() - << FixItHint::CreateReplacement(Found.getNameLoc(), CorrectedStr); + << FixItHint::CreateReplacement(Corrected.getCorrectionRange(), + CorrectedStr); else Diag(Found.getNameLoc(), diag::err_no_template_suggest) << Name << CorrectedQuotedStr @@ -1104,6 +1105,9 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (Attr) ProcessDeclAttributeList(S, NewClass, Attr); + if (PrevClassTemplate) + mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl()); + AddPushedVisibilityAttribute(NewClass); if (TUK != TUK_Friend) @@ -1138,8 +1142,6 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, NewTemplate->setInvalidDecl(); NewClass->setInvalidDecl(); } - if (PrevClassTemplate) - mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl()); ActOnDocumentableDecl(NewTemplate); @@ -1204,11 +1206,17 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, /// of a template template parameter, recursively. static bool DiagnoseUnexpandedParameterPacks(Sema &S, TemplateTemplateParmDecl *TTP) { + // A template template parameter which is a parameter pack is also a pack + // expansion. + if (TTP->isParameterPack()) + return false; + TemplateParameterList *Params = TTP->getTemplateParameters(); for (unsigned I = 0, N = Params->size(); I != N; ++I) { NamedDecl *P = Params->getParam(I); if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) { - if (S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(), + if (!NTTP->isParameterPack() && + S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(), NTTP->getTypeSourceInfo(), Sema::UPPC_NonTypeTemplateParameterType)) return true; @@ -1321,7 +1329,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, } else if (NonTypeTemplateParmDecl *NewNonTypeParm = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) { // Check for unexpanded parameter packs. - if (DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(), + if (!NewNonTypeParm->isParameterPack() && + DiagnoseUnexpandedParameterPack(NewNonTypeParm->getLocation(), NewNonTypeParm->getTypeSourceInfo(), UPPC_NonTypeTemplateParameterType)) { Invalid = true; @@ -1342,7 +1351,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, if (NewNonTypeParm->isParameterPack()) { assert(!NewNonTypeParm->hasDefaultArgument() && "Parameter packs can't have a default argument!"); - SawParameterPack = true; + if (!NewNonTypeParm->isPackExpansion()) + SawParameterPack = true; } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() && NewNonTypeParm->hasDefaultArgument()) { OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc(); @@ -1389,7 +1399,8 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, if (NewTemplateParm->isParameterPack()) { assert(!NewTemplateParm->hasDefaultArgument() && "Parameter packs can't have a default argument!"); - SawParameterPack = true; + if (!NewTemplateParm->isPackExpansion()) + SawParameterPack = true; } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && NewTemplateParm->hasDefaultArgument()) { OldDefaultLoc = OldTemplateParm->getDefaultArgument().getLocation(); @@ -1416,10 +1427,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, MissingDefaultArg = true; } - // C++0x [temp.param]p11: + // C++11 [temp.param]p11: // If a template parameter of a primary class template or alias template // is a template parameter pack, it shall be the last template parameter. - if (SawParameterPack && (NewParam + 1) != NewParamEnd && + if (SawParameterPack && (NewParam + 1) != NewParamEnd && (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) { Diag((*NewParam)->getLocation(), diag::err_template_param_pack_must_be_last_template_parameter); @@ -1998,9 +2009,11 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, for (unsigned I = 0; I < Depth; ++I) TemplateArgLists.addOuterTemplateArguments(0, 0); + LocalInstantiationScope Scope(*this); InstantiatingTemplate Inst(*this, TemplateLoc, Template); if (Inst) return QualType(); + CanonType = SubstType(Pattern->getUnderlyingType(), TemplateArgLists, AliasTemplate->getLocation(), AliasTemplate->getDeclName()); @@ -2085,7 +2098,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, Converted.data(), Converted.size(), 0); ClassTemplate->AddSpecialization(Decl, InsertPos); - Decl->setLexicalDeclContext(CurContext); + if (ClassTemplate->isOutOfLine()) + Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext()); } CanonType = Context.getTypeDeclType(Decl); @@ -2137,7 +2151,6 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, } QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); - TemplateArgsIn.release(); if (Result.isNull()) return true; @@ -2831,6 +2844,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Declaration: case TemplateArgument::Integral: + case TemplateArgument::NullPtr: // We've already checked this template argument, so just copy // it to the list of converted arguments. Converted.push_back(Arg.getArgument()); @@ -2947,7 +2961,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - if (CheckTemplateArgument(TempParm, Arg)) + if (CheckTemplateArgument(TempParm, Arg, ArgumentPackIndex)) return true; Converted.push_back(Arg.getArgument()); @@ -2965,6 +2979,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, llvm_unreachable("Declaration argument with template template parameter"); case TemplateArgument::Integral: llvm_unreachable("Integral argument with template template parameter"); + case TemplateArgument::NullPtr: + llvm_unreachable("Null pointer argument with template template parameter"); case TemplateArgument::Pack: llvm_unreachable("Caller must expand template argument packs"); @@ -2996,6 +3012,33 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template, return true; } +/// \brief Check whether the template parameter is a pack expansion, and if so, +/// determine the number of parameters produced by that expansion. For instance: +/// +/// \code +/// template<typename ...Ts> struct A { +/// template<Ts ...NTs, template<Ts> class ...TTs, typename ...Us> struct B; +/// }; +/// \endcode +/// +/// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us +/// is not a pack expansion, so returns an empty Optional. +static llvm::Optional<unsigned> getExpandedPackSize(NamedDecl *Param) { + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + if (NTTP->isExpandedParameterPack()) + return NTTP->getNumExpansionTypes(); + } + + if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Param)) { + if (TTP->isExpandedParameterPack()) + return TTP->getNumExpansionTemplateParameters(); + } + + return llvm::Optional<unsigned>(); +} + /// \brief Check that the given template argument list is well-formed /// for specializing the given template. bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, @@ -3008,15 +3051,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, *ExpansionIntoFixedList = false; TemplateParameterList *Params = Template->getTemplateParameters(); - unsigned NumParams = Params->size(); - unsigned NumArgs = TemplateArgs.size(); - bool Invalid = false; SourceLocation RAngleLoc = TemplateArgs.getRAngleLoc(); - bool HasParameterPack = - NumParams > 0 && Params->getParam(NumParams - 1)->isTemplateParameterPack(); - // C++ [temp.arg]p1: // [...] The type and form of each template-argument specified in // a template-id shall match the type and form specified for the @@ -3024,38 +3061,50 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // template-parameter-list. bool isTemplateTemplateParameter = isa<TemplateTemplateParmDecl>(Template); SmallVector<TemplateArgument, 2> ArgumentPack; - TemplateParameterList::iterator Param = Params->begin(), - ParamEnd = Params->end(); - unsigned ArgIdx = 0; + unsigned ArgIdx = 0, NumArgs = TemplateArgs.size(); LocalInstantiationScope InstScope(*this, true); - bool SawPackExpansion = false; - while (Param != ParamEnd) { - if (ArgIdx < NumArgs) { - // If we have an expanded parameter pack, make sure we don't have too - // many arguments. - // FIXME: This really should fall out from the normal arity checking. - if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - if (NTTP->isExpandedParameterPack() && - ArgumentPack.size() >= NTTP->getNumExpansionTypes()) { - Diag(TemplateLoc, diag::err_template_arg_list_different_arity) - << true - << (isa<ClassTemplateDecl>(Template)? 0 : - isa<FunctionTemplateDecl>(Template)? 1 : - isa<TemplateTemplateParmDecl>(Template)? 2 : 3) - << Template; - Diag(Template->getLocation(), diag::note_template_decl_here) - << Params->getSourceRange(); - return true; - } + for (TemplateParameterList::iterator Param = Params->begin(), + ParamEnd = Params->end(); + Param != ParamEnd; /* increment in loop */) { + // If we have an expanded parameter pack, make sure we don't have too + // many arguments. + if (llvm::Optional<unsigned> Expansions = getExpandedPackSize(*Param)) { + if (*Expansions == ArgumentPack.size()) { + // We're done with this parameter pack. Pack up its arguments and add + // them to the list. + Converted.push_back( + TemplateArgument::CreatePackCopy(Context, + ArgumentPack.data(), + ArgumentPack.size())); + ArgumentPack.clear(); + + // This argument is assigned to the next parameter. + ++Param; + continue; + } else if (ArgIdx == NumArgs && !PartialTemplateArgs) { + // Not enough arguments for this parameter pack. + Diag(TemplateLoc, diag::err_template_arg_list_different_arity) + << false + << (isa<ClassTemplateDecl>(Template)? 0 : + isa<FunctionTemplateDecl>(Template)? 1 : + isa<TemplateTemplateParmDecl>(Template)? 2 : 3) + << Template; + Diag(Template->getLocation(), diag::note_template_decl_here) + << Params->getSourceRange(); + return true; } + } + if (ArgIdx < NumArgs) { // Check the template argument we were given. if (CheckTemplateArgument(*Param, TemplateArgs[ArgIdx], Template, TemplateLoc, RAngleLoc, ArgumentPack.size(), Converted)) return true; + // We're now done with this argument. + ++ArgIdx; + if ((*Param)->isTemplateParameterPack()) { // The template parameter was a template parameter pack, so take the // deduced argument and place it on the argument pack. Note that we @@ -3067,16 +3116,47 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // Move to the next template parameter. ++Param; } - - // If this template argument is a pack expansion, record that fact - // and break out; we can't actually check any more. - if (TemplateArgs[ArgIdx].getArgument().isPackExpansion()) { - SawPackExpansion = true; - ++ArgIdx; - break; + + // If we just saw a pack expansion, then directly convert the remaining + // arguments, because we don't know what parameters they'll match up + // with. + if (TemplateArgs[ArgIdx-1].getArgument().isPackExpansion()) { + bool InFinalParameterPack = Param != ParamEnd && + Param + 1 == ParamEnd && + (*Param)->isTemplateParameterPack() && + !getExpandedPackSize(*Param); + + if (!InFinalParameterPack && !ArgumentPack.empty()) { + // If we were part way through filling in an expanded parameter pack, + // fall back to just producing individual arguments. + Converted.insert(Converted.end(), + ArgumentPack.begin(), ArgumentPack.end()); + ArgumentPack.clear(); + } + + while (ArgIdx < NumArgs) { + if (InFinalParameterPack) + ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument()); + else + Converted.push_back(TemplateArgs[ArgIdx].getArgument()); + ++ArgIdx; + } + + // Push the argument pack onto the list of converted arguments. + if (InFinalParameterPack) { + Converted.push_back( + TemplateArgument::CreatePackCopy(Context, + ArgumentPack.data(), + ArgumentPack.size())); + ArgumentPack.clear(); + } else if (ExpansionIntoFixedList) { + // We have expanded a pack into a fixed list. + *ExpansionIntoFixedList = true; + } + + return false; } - - ++ArgIdx; + continue; } @@ -3087,14 +3167,30 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, ArgumentPack.data(), ArgumentPack.size())); - return Invalid; + return false; } // If we have a template parameter pack with no more corresponding // arguments, just break out now and we'll fill in the argument pack below. - if ((*Param)->isTemplateParameterPack()) - break; - + if ((*Param)->isTemplateParameterPack()) { + assert(!getExpandedPackSize(*Param) && + "Should have dealt with this already"); + + // A non-expanded parameter pack before the end of the parameter list + // only occurs for an ill-formed template parameter list, unless we've + // got a partial argument list for a function template, so just bail out. + if (Param + 1 != ParamEnd) + return true; + + Converted.push_back(TemplateArgument::CreatePackCopy(Context, + ArgumentPack.data(), + ArgumentPack.size())); + ArgumentPack.clear(); + + ++Param; + continue; + } + // Check whether we have a default argument. TemplateArgumentLoc Arg; @@ -3181,86 +3277,12 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, ++ArgIdx; } - // If we saw a pack expansion, then directly convert the remaining arguments, - // because we don't know what parameters they'll match up with. - if (SawPackExpansion) { - bool AddToArgumentPack - = Param != ParamEnd && (*Param)->isTemplateParameterPack(); - while (ArgIdx < NumArgs) { - if (AddToArgumentPack) - ArgumentPack.push_back(TemplateArgs[ArgIdx].getArgument()); - else - Converted.push_back(TemplateArgs[ArgIdx].getArgument()); - ++ArgIdx; - } - - // Push the argument pack onto the list of converted arguments. - if (AddToArgumentPack) { - if (ArgumentPack.empty()) - Converted.push_back(TemplateArgument(0, 0)); - else { - Converted.push_back( - TemplateArgument::CreatePackCopy(Context, - ArgumentPack.data(), - ArgumentPack.size())); - ArgumentPack.clear(); - } - } else if (ExpansionIntoFixedList) { - // We have expanded a pack into a fixed list. - *ExpansionIntoFixedList = true; - } - - return Invalid; - } - // If we have any leftover arguments, then there were too many arguments. // Complain and fail. if (ArgIdx < NumArgs) return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs); - - // If we have an expanded parameter pack, make sure we don't have too - // many arguments. - // FIXME: This really should fall out from the normal arity checking. - if (Param != ParamEnd) { - if (NonTypeTemplateParmDecl *NTTP - = dyn_cast<NonTypeTemplateParmDecl>(*Param)) { - if (NTTP->isExpandedParameterPack() && - ArgumentPack.size() < NTTP->getNumExpansionTypes()) { - Diag(TemplateLoc, diag::err_template_arg_list_different_arity) - << false - << (isa<ClassTemplateDecl>(Template)? 0 : - isa<FunctionTemplateDecl>(Template)? 1 : - isa<TemplateTemplateParmDecl>(Template)? 2 : 3) - << Template; - Diag(Template->getLocation(), diag::note_template_decl_here) - << Params->getSourceRange(); - return true; - } - } - } - - // Form argument packs for each of the parameter packs remaining. - while (Param != ParamEnd) { - // If we're checking a partial list of template arguments, don't fill - // in arguments for non-template parameter packs. - if ((*Param)->isTemplateParameterPack()) { - if (!HasParameterPack) - return true; - if (ArgumentPack.empty()) - Converted.push_back(TemplateArgument(0, 0)); - else { - Converted.push_back(TemplateArgument::CreatePackCopy(Context, - ArgumentPack.data(), - ArgumentPack.size())); - ArgumentPack.clear(); - } - } else if (!PartialTemplateArgs) - return diagnoseArityMismatch(*this, Template, TemplateLoc, TemplateArgs); - - ++Param; - } - return Invalid; + return false; } namespace { @@ -3650,7 +3672,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) { case NPV_NullPointer: S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument((Decl *)0); + Converted = TemplateArgument(ParamType, /*isNullPtr*/true); return false; case NPV_Error: @@ -3738,7 +3760,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, return true; } - NamedDecl *Entity = DRE->getDecl(); + ValueDecl *Entity = DRE->getDecl(); // Cannot refer to non-static data members if (FieldDecl *Field = dyn_cast<FieldDecl>(Entity)) { @@ -3926,7 +3948,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, } // Create the template argument. - Converted = TemplateArgument(Entity->getCanonicalDecl()); + Converted = TemplateArgument(cast<ValueDecl>(Entity->getCanonicalDecl()), + ParamType->isReferenceType()); S.MarkAnyDeclReferenced(Arg->getLocStart(), Entity); return false; } @@ -3947,7 +3970,7 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, return true; case NPV_NullPointer: S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument((Decl *)0); + Converted = TemplateArgument(ParamType, /*isNullPtr*/true); return false; case NPV_NotNullPointer: break; @@ -4016,10 +4039,12 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, if (isa<NonTypeTemplateParmDecl>(VD) || (isa<VarDecl>(VD) && S.Context.getCanonicalType(VD->getType()).isConstQualified())) { - if (Arg->isTypeDependent() || Arg->isValueDependent()) + if (Arg->isTypeDependent() || Arg->isValueDependent()) { Converted = TemplateArgument(Arg); - else - Converted = TemplateArgument(VD->getCanonicalDecl()); + } else { + VD = cast<ValueDecl>(VD->getCanonicalDecl()); + Converted = TemplateArgument(VD, /*isReferenceParam*/false); + } return Invalid; } } @@ -4040,10 +4065,12 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, // Okay: this is the address of a non-static member, and therefore // a member pointer constant. - if (Arg->isTypeDependent() || Arg->isValueDependent()) + if (Arg->isTypeDependent() || Arg->isValueDependent()) { Converted = TemplateArgument(Arg); - else - Converted = TemplateArgument(DRE->getDecl()->getCanonicalDecl()); + } else { + ValueDecl *D = cast<ValueDecl>(DRE->getDecl()->getCanonicalDecl()); + Converted = TemplateArgument(D, /*isReferenceParam*/false); + } return Invalid; } @@ -4396,8 +4423,8 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, case NPV_NullPointer: Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument((Decl *)0); - return Owned(Arg);; + Converted = TemplateArgument(ParamType, /*isNullPtr*/true); + return Owned(Arg); } } @@ -4417,8 +4444,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, /// This routine implements the semantics of C++ [temp.arg.template]. /// It returns true if an error occurred, and false otherwise. bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, - const TemplateArgumentLoc &Arg) { - TemplateName Name = Arg.getArgument().getAsTemplate(); + const TemplateArgumentLoc &Arg, + unsigned ArgumentPackIndex) { + TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template) { // Any dependent template name is fine. @@ -4448,8 +4476,12 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, << Template; } + TemplateParameterList *Params = Param->getTemplateParameters(); + if (Param->isExpandedParameterPack()) + Params = Param->getExpansionTemplateParameters(ArgumentPackIndex); + return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), - Param->getTemplateParameters(), + Params, true, TPL_TemplateTemplateArgumentMatch, Arg.getLocation()); @@ -4463,12 +4495,9 @@ ExprResult Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc) { - assert(Arg.getKind() == TemplateArgument::Declaration && - "Only declaration template arguments permitted here"); - // For a NULL non-type template argument, return nullptr casted to the // parameter's type. - if (!Arg.getAsDecl()) { + if (Arg.getKind() == TemplateArgument::NullPtr) { return ImpCastExprToType( new (Context) CXXNullPtrLiteralExpr(Context.NullPtrTy, Loc), ParamType, @@ -4476,7 +4505,9 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, ? CK_NullToMemberPointer : CK_NullToPointer); } - + assert(Arg.getKind() == TemplateArgument::Declaration && + "Only declaration template arguments permitted here"); + ValueDecl *VD = cast<ValueDecl>(Arg.getAsDecl()); if (VD->getDeclContext()->isRecord() && @@ -4524,7 +4555,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, assert(!RefExpr.isInvalid() && Context.hasSameType(((Expr*) RefExpr.get())->getType(), ParamType.getUnqualifiedType())); - return move(RefExpr); + return RefExpr; } } @@ -4542,7 +4573,7 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, if (RefExpr.isInvalid()) return ExprError(); - return move(RefExpr); + return RefExpr; } // Take the address of everything else @@ -5071,10 +5102,10 @@ static bool CheckNonTypeClassTemplatePartialSpecializationArgs(Sema &S, continue; } - Expr *ArgExpr = Args[I].getAsExpr(); - if (!ArgExpr) { + if (Args[I].getKind() != TemplateArgument::Expression) continue; - } + + Expr *ArgExpr = Args[I].getAsExpr(); // We can have a pack expansion of any of the bullets below. if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(ArgExpr)) @@ -5173,7 +5204,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // NOTE: KWLoc is the location of the tag keyword. This will instead // store the location of the outermost template keyword in the declaration. SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0 - ? TemplateParameterLists.get()[0]->getTemplateLoc() : SourceLocation(); + ? TemplateParameterLists[0]->getTemplateLoc() : SourceLocation(); // Find the class template we're specializing TemplateName Name = TemplateD.getAsVal<TemplateName>(); @@ -5199,7 +5230,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, = MatchTemplateParametersToScopeSpecifier(TemplateNameLoc, TemplateNameLoc, SS, - (TemplateParameterList**)TemplateParameterLists.get(), + TemplateParameterLists.data(), TemplateParameterLists.size(), TUK == TUK_Friend, isExplicitSpecialization, @@ -5354,7 +5385,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (TemplateParameterLists.size() > 0) { Specialization->setTemplateParameterListsInfo(Context, TemplateParameterLists.size(), - (TemplateParameterList**) TemplateParameterLists.release()); + TemplateParameterLists.data()); } PrevDecl = 0; CanonType = Context.getTypeDeclType(Specialization); @@ -5382,7 +5413,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TemplateParams, AS_none, /*ModulePrivateLoc=*/SourceLocation(), TemplateParameterLists.size() - 1, - (TemplateParameterList**) TemplateParameterLists.release()); + TemplateParameterLists.data()); } // Create a new class template partial specialization declaration node. @@ -5406,7 +5437,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (TemplateParameterLists.size() > 1 && SS.isSet()) { Partial->setTemplateParameterListsInfo(Context, TemplateParameterLists.size() - 1, - (TemplateParameterList**) TemplateParameterLists.release()); + TemplateParameterLists.data()); } if (!PrevPartial) @@ -5461,7 +5492,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (TemplateParameterLists.size() > 0) { Specialization->setTemplateParameterListsInfo(Context, TemplateParameterLists.size(), - (TemplateParameterList**) TemplateParameterLists.release()); + TemplateParameterLists.data()); } if (!PrevDecl) @@ -5544,7 +5575,6 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Specialization->setTypeAsWritten(WrittenTy); Specialization->setTemplateKeywordLoc(TemplateKWLoc); } - TemplateArgsIn.release(); // C++ [temp.expl.spec]p9: // A template explicit specialization is in the scope of the @@ -5579,7 +5609,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Decl *Sema::ActOnTemplateDeclarator(Scope *S, MultiTemplateParamsArg TemplateParameterLists, Declarator &D) { - Decl *NewDecl = HandleDeclarator(S, D, move(TemplateParameterLists)); + Decl *NewDecl = HandleDeclarator(S, D, TemplateParameterLists); ActOnDocumentableDecl(NewDecl); return NewDecl; } @@ -5598,7 +5628,7 @@ Decl *Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, D.setFunctionDefinitionKind(FDK_Definition); Decl *DP = HandleDeclarator(ParentScope, D, - move(TemplateParameterLists)); + TemplateParameterLists); if (FunctionTemplateDecl *FunctionTemplate = dyn_cast_or_null<FunctionTemplateDecl>(DP)) return ActOnStartOfFunctionDef(FnBodyScope, @@ -5902,7 +5932,7 @@ Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD, // Perform template argument deduction to determine whether we may be // specializing this template. // FIXME: It is somewhat wasteful to build - TemplateDeductionInfo Info(Context, FD->getLocation()); + TemplateDeductionInfo Info(FD->getLocation()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK = DeduceTemplateArguments(FunTmpl, ExplicitTemplateArgs, @@ -6399,7 +6429,6 @@ Sema::ActOnExplicitInstantiation(Scope *S, TemplateArgs, Context.getTypeDeclType(Specialization)); Specialization->setTypeAsWritten(WrittenTy); - TemplateArgsIn.release(); // Set source locations for keywords. Specialization->setExternLoc(ExternLoc); @@ -6475,9 +6504,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, Decl *TagD = ActOnTag(S, TagSpec, Sema::TUK_Reference, KWLoc, SS, Name, NameLoc, Attr, AS_none, /*ModulePrivateLoc=*/SourceLocation(), - MultiTemplateParamsArg(*this, 0, 0), - Owned, IsDependent, SourceLocation(), false, - TypeResult()); + MultiTemplateParamsArg(), Owned, IsDependent, + SourceLocation(), false, TypeResult()); assert(!IsDependent && "explicit instantiation of dependent name not yet handled"); if (!TagD) @@ -6729,12 +6757,10 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TemplateIdAnnotation *TemplateId = D.getName().TemplateId; TemplateArgs.setLAngleLoc(TemplateId->LAngleLoc); TemplateArgs.setRAngleLoc(TemplateId->RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(*this, - TemplateId->getTemplateArgs(), + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, TemplateArgs); HasExplicitTemplateArgs = true; - TemplateArgsPtr.release(); } // C++ [temp.explicit]p1: @@ -6762,7 +6788,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (!FunTmpl) continue; - TemplateDeductionInfo Info(Context, D.getIdentifierLoc()); + TemplateDeductionInfo Info(D.getIdentifierLoc()); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK = DeduceTemplateArguments(FunTmpl, diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 9500ec3219d4..bf4533d6998c 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -158,9 +158,6 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { /// \brief Determine whether two declaration pointers refer to the same /// declaration. static bool isSameDeclaration(Decl *X, Decl *Y) { - if (!X || !Y) - return !X && !Y; - if (NamedDecl *NX = dyn_cast<NamedDecl>(X)) X = NX->getUnderlyingDecl(); if (NamedDecl *NY = dyn_cast<NamedDecl>(Y)) @@ -262,7 +259,27 @@ checkDeducedTemplateArguments(ASTContext &Context, // If we deduced two declarations, make sure they they refer to the // same declaration. if (Y.getKind() == TemplateArgument::Declaration && - isSameDeclaration(X.getAsDecl(), Y.getAsDecl())) + isSameDeclaration(X.getAsDecl(), Y.getAsDecl()) && + X.isDeclForReferenceParam() == Y.isDeclForReferenceParam()) + return X; + + // All other combinations are incompatible. + return DeducedTemplateArgument(); + + case TemplateArgument::NullPtr: + // If we deduced a null pointer and a dependent expression, keep the + // null pointer. + if (Y.getKind() == TemplateArgument::Expression) + return X; + + // If we deduced a null pointer and an integral constant, keep the + // integral constant. + if (Y.getKind() == TemplateArgument::Integral) + return Y; + + // If we deduced two null pointers, make sure they have the same type. + if (Y.getKind() == TemplateArgument::NullPtr && + Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType())) return X; // All other combinations are incompatible. @@ -356,13 +373,15 @@ DeduceNonTypeTemplateArgument(Sema &S, static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, NonTypeTemplateParmDecl *NTTP, - Decl *D, + ValueDecl *D, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); - DeducedTemplateArgument NewDeduced(D? D->getCanonicalDecl() : 0); + D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : 0; + TemplateArgument New(D, NTTP->getType()->isReferenceType()); + DeducedTemplateArgument NewDeduced(New); DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[NTTP->getIndex()], NewDeduced); @@ -570,7 +589,10 @@ static void PrepareArgumentPackDeduction(Sema &S, SavedPacks[I] = Deduced[PackIndices[I]]; Deduced[PackIndices[I]] = TemplateArgument(); - // If the template arugment pack was explicitly specified, add that to + if (!S.CurrentInstantiationScope) + continue; + + // If the template argument pack was explicitly specified, add that to // the set of deduced arguments. const TemplateArgument *ExplicitArgs; unsigned NumExplicitArgs; @@ -612,7 +634,7 @@ FinishArgumentPackDeduction(Sema &S, if (NewlyDeducedPacks[I].empty()) { // If we deduced an empty argument pack, create it now. - NewPack = DeducedTemplateArgument(TemplateArgument(0, 0)); + NewPack = DeducedTemplateArgument(TemplateArgument::getEmptyPack()); } else { TemplateArgument *ArgumentPack = new (S.Context) TemplateArgument [NewlyDeducedPacks[I].size()]; @@ -1371,9 +1393,11 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // If this is a base class, try to perform template argument // deduction from it. if (NextT != RecordT) { + TemplateDeductionInfo BaseInfo(Info.getLocation()); Sema::TemplateDeductionResult BaseResult = DeduceTemplateArguments(S, TemplateParams, SpecParam, - QualType(NextT, 0), Info, Deduced); + QualType(NextT, 0), BaseInfo, + Deduced); // If template argument deduction for this base was successful, // note that we had some success. Otherwise, ignore any deductions @@ -1382,6 +1406,9 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, Successful = true; DeducedOrig.clear(); DeducedOrig.append(Deduced.begin(), Deduced.end()); + Info.Param = BaseInfo.Param; + Info.FirstArg = BaseInfo.FirstArg; + Info.SecondArg = BaseInfo.SecondArg; } else Deduced = DeducedOrig; @@ -1596,7 +1623,17 @@ DeduceTemplateArguments(Sema &S, case TemplateArgument::Declaration: if (Arg.getKind() == TemplateArgument::Declaration && - isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl())) + isSameDeclaration(Param.getAsDecl(), Arg.getAsDecl()) && + Param.isDeclForReferenceParam() == Arg.isDeclForReferenceParam()) + return Sema::TDK_Success; + + Info.FirstArg = Param; + Info.SecondArg = Arg; + return Sema::TDK_NonDeducedMismatch; + + case TemplateArgument::NullPtr: + if (Arg.getKind() == TemplateArgument::NullPtr && + S.Context.hasSameType(Param.getNullPtrType(), Arg.getNullPtrType())) return Sema::TDK_Success; Info.FirstArg = Param; @@ -1867,7 +1904,11 @@ static bool isSameTemplateArg(ASTContext &Context, Context.getCanonicalType(Y.getAsType()); case TemplateArgument::Declaration: - return isSameDeclaration(X.getAsDecl(), Y.getAsDecl()); + return isSameDeclaration(X.getAsDecl(), Y.getAsDecl()) && + X.isDeclForReferenceParam() == Y.isDeclForReferenceParam(); + + case TemplateArgument::NullPtr: + return Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType()); case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: @@ -1937,6 +1978,14 @@ getTrivialTemplateArgumentLoc(Sema &S, return TemplateArgumentLoc(TemplateArgument(E), E); } + case TemplateArgument::NullPtr: { + Expr *E + = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) + .takeAs<Expr>(); + return TemplateArgumentLoc(TemplateArgument(NTTPType, /*isNullPtr*/true), + E); + } + case TemplateArgument::Integral: { Expr *E = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).takeAs<Expr>(); @@ -2162,6 +2211,9 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, TemplateDeductionInfo &Info) { + if (Partial->isInvalidDecl()) + return TDK_Invalid; + // C++ [temp.class.spec.match]p2: // A partial specialization matches a given actual template // argument list if the template arguments of the partial @@ -2601,12 +2653,13 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // explicitly-specified set (C++0x [temp.arg.explicit]p9). const TemplateArgument *ExplicitArgs; unsigned NumExplicitArgs; - if (CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs, + if (CurrentInstantiationScope && + CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs, &NumExplicitArgs) == Param) Builder.push_back(TemplateArgument(ExplicitArgs, NumExplicitArgs)); else - Builder.push_back(TemplateArgument(0, 0)); + Builder.push_back(TemplateArgument::getEmptyPack()); continue; } @@ -2784,7 +2837,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, // Otherwise, see if we can resolve a function type FunctionDecl *Specialization = 0; - TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc()); + TemplateDeductionInfo Info(Ovl->getNameLoc()); if (S.DeduceTemplateArguments(FunTmpl, &ExplicitTemplateArgs, Specialization, Info)) continue; @@ -2815,7 +2868,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, // So we do not reject deductions which were made elsewhere. SmallVector<DeducedTemplateArgument, 8> Deduced(TemplateParams->size()); - TemplateDeductionInfo Info(S.Context, Ovl->getNameLoc()); + TemplateDeductionInfo Info(Ovl->getNameLoc()); Sema::TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType, ArgType, Info, Deduced, TDF); @@ -2992,8 +3045,6 @@ DeduceTemplateArgumentByListElement(Sema &S, /// /// \param Args the function call arguments /// -/// \param NumArgs the number of arguments in Args -/// /// \param Name the name of the function being called. This is only significant /// when the function template is a conversion function template, in which /// case this routine will also perform template argument deduction based on @@ -3013,6 +3064,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, llvm::ArrayRef<Expr *> Args, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { + if (FunctionTemplate->isInvalidDecl()) + return TDK_Invalid; + FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); // C++ [temp.deduct.call]p1: @@ -3269,6 +3323,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType ArgFunctionType, FunctionDecl *&Specialization, TemplateDeductionInfo &Info) { + if (FunctionTemplate->isInvalidDecl()) + return TDK_Invalid; + FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); @@ -3328,6 +3385,9 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, QualType ToType, CXXConversionDecl *&Specialization, TemplateDeductionInfo &Info) { + if (FunctionTemplate->isInvalidDecl()) + return TDK_Invalid; + CXXConversionDecl *Conv = cast<CXXConversionDecl>(FunctionTemplate->getTemplatedDecl()); QualType FromType = Conv->getConversionType(); @@ -3572,7 +3632,7 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType InitType = Init->getType(); unsigned TDF = 0; - TemplateDeductionInfo Info(Context, Loc); + TemplateDeductionInfo Info(Loc); InitListExpr *InitList = dyn_cast<InitListExpr>(Init); if (InitList) { @@ -3594,10 +3654,11 @@ Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, return DAR_Failed; } - QualType DeducedType = Deduced[0].getAsType(); - if (DeducedType.isNull()) + if (Deduced[0].getKind() != TemplateArgument::Type) return DAR_Failed; + QualType DeducedType = Deduced[0].getAsType(); + if (InitList) { DeducedType = BuildStdInitializerList(DeducedType, Loc); if (DeducedType.isNull()) @@ -3637,26 +3698,23 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, llvm::SmallBitVector &Deduced); /// \brief If this is a non-static member function, -static void MaybeAddImplicitObjectParameterType(ASTContext &Context, +static void AddImplicitObjectParameterType(ASTContext &Context, CXXMethodDecl *Method, SmallVectorImpl<QualType> &ArgTypes) { - if (Method->isStatic()) - return; - - // C++ [over.match.funcs]p4: - // - // For non-static member functions, the type of the implicit - // object parameter is - // - "lvalue reference to cv X" for functions declared without a - // ref-qualifier or with the & ref-qualifier - // - "rvalue reference to cv X" for functions declared with the - // && ref-qualifier + // C++11 [temp.func.order]p3: + // [...] The new parameter is of type "reference to cv A," where cv are + // the cv-qualifiers of the function template (if any) and A is + // the class of which the function template is a member. // - // FIXME: We don't have ref-qualifiers yet, so we don't do that part. + // The standard doesn't say explicitly, but we pick the appropriate kind of + // reference type based on [over.match.funcs]p4. QualType ArgTy = Context.getTypeDeclType(Method->getParent()); ArgTy = Context.getQualifiedType(ArgTy, Qualifiers::fromCVRMask(Method->getTypeQualifiers())); - ArgTy = Context.getLValueReferenceType(ArgTy); + if (Method->getRefQualifier() == RQ_RValue) + ArgTy = Context.getRValueReferenceType(ArgTy); + else + ArgTy = Context.getLValueReferenceType(ArgTy); ArgTypes.push_back(ArgTy); } @@ -3682,7 +3740,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, // C++0x [temp.deduct.partial]p3: // The types used to determine the ordering depend on the context in which // the partial ordering is done: - TemplateDeductionInfo Info(S.Context, Loc); + TemplateDeductionInfo Info(Loc); CXXMethodDecl *Method1 = 0; CXXMethodDecl *Method2 = 0; bool IsNonStatic2 = false; @@ -3697,7 +3755,7 @@ static bool isAtLeastAsSpecializedAs(Sema &S, IsNonStatic1 = Method1 && !Method1->isStatic(); IsNonStatic2 = Method2 && !Method2->isStatic(); - // C++0x [temp.func.order]p3: + // C++11 [temp.func.order]p3: // [...] If only one of the function templates is a non-static // member, that function template is considered to have a new // first parameter inserted in its function parameter list. The @@ -3705,22 +3763,25 @@ static bool isAtLeastAsSpecializedAs(Sema &S, // the cv-qualifiers of the function template (if any) and A is // the class of which the function template is a member. // + // Note that we interpret this to mean "if one of the function + // templates is a non-static member and the other is a non-member"; + // otherwise, the ordering rules for static functions against non-static + // functions don't make any sense. + // // C++98/03 doesn't have this provision, so instead we drop the - // first argument of the free function or static member, which - // seems to match existing practice. + // first argument of the free function, which seems to match + // existing practice. SmallVector<QualType, 4> Args1; - unsigned Skip1 = !S.getLangOpts().CPlusPlus0x && - IsNonStatic2 && !IsNonStatic1; - if (S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !IsNonStatic2) - MaybeAddImplicitObjectParameterType(S.Context, Method1, Args1); + unsigned Skip1 = !S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !Method1; + if (S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !Method2) + AddImplicitObjectParameterType(S.Context, Method1, Args1); Args1.insert(Args1.end(), Proto1->arg_type_begin() + Skip1, Proto1->arg_type_end()); SmallVector<QualType, 4> Args2; - Skip2 = !S.getLangOpts().CPlusPlus0x && - IsNonStatic1 && !IsNonStatic2; - if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !IsNonStatic1) - MaybeAddImplicitObjectParameterType(S.Context, Method2, Args2); + Skip2 = !S.getLangOpts().CPlusPlus0x && IsNonStatic1 && !Method2; + if (S.getLangOpts().CPlusPlus0x && IsNonStatic2 && !Method1) + AddImplicitObjectParameterType(S.Context, Method2, Args2); Args2.insert(Args2.end(), Proto2->arg_type_begin() + Skip2, Proto2->arg_type_end()); @@ -4118,7 +4179,7 @@ Sema::getMoreSpecializedPartialSpecialization( // template partial specialization's template arguments, for // example. SmallVector<DeducedTemplateArgument, 4> Deduced; - TemplateDeductionInfo Info(Context, Loc); + TemplateDeductionInfo Info(Loc); QualType PT1 = PS1->getInjectedSpecializationType(); QualType PT2 = PS2->getInjectedSpecializationType(); @@ -4496,6 +4557,11 @@ MarkUsedTemplateParameters(ASTContext &Ctx, case TemplateArgument::Declaration: break; + case TemplateArgument::NullPtr: + MarkUsedTemplateParameters(Ctx, TemplateArg.getNullPtrType(), OnlyDeduced, + Depth, Used); + break; + case TemplateArgument::Type: MarkUsedTemplateParameters(Ctx, TemplateArg.getAsType(), OnlyDeduced, Depth, Used); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 20e755fdaee1..665dd07b8f85 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -769,7 +769,7 @@ namespace { /// instantiating it. Decl *TransformDefinition(SourceLocation Loc, Decl *D); - /// \bried Transform the first qualifier within a scope by instantiating the + /// \brief Transform the first qualifier within a scope by instantiating the /// declaration. NamedDecl *TransformFirstQualifierInScope(NamedDecl *D, SourceLocation Loc); @@ -802,11 +802,24 @@ namespace { ExprResult TransformPredefinedExpr(PredefinedExpr *E); ExprResult TransformDeclRefExpr(DeclRefExpr *E); ExprResult TransformCXXDefaultArgExpr(CXXDefaultArgExpr *E); + ExprResult TransformTemplateParmRefExpr(DeclRefExpr *E, NonTypeTemplateParmDecl *D); ExprResult TransformSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E); - + + /// \brief Rebuild a DeclRefExpr for a ParmVarDecl reference. + ExprResult RebuildParmVarDeclRefExpr(ParmVarDecl *PD, SourceLocation Loc); + + /// \brief Transform a reference to a function parameter pack. + ExprResult TransformFunctionParmPackRefExpr(DeclRefExpr *E, + ParmVarDecl *PD); + + /// \brief Transform a FunctionParmPackExpr which was built when we couldn't + /// expand a function parameter pack reference which refers to an expanded + /// pack. + ExprResult TransformFunctionParmPackExpr(FunctionParmPackExpr *E); + QualType TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc TL); QualType TransformFunctionProtoType(TypeLocBuilder &TLB, @@ -835,7 +848,7 @@ namespace { ExprResult Result = TreeTransform<TemplateInstantiator>::TransformCallExpr(CE); getSema().CallsUndergoingInstantiation.pop_back(); - return move(Result); + return Result; } ExprResult TransformLambdaExpr(LambdaExpr *E) { @@ -1161,10 +1174,11 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( result = SemaRef.Owned(argExpr); type = argExpr->getType(); - } else if (arg.getKind() == TemplateArgument::Declaration) { + } else if (arg.getKind() == TemplateArgument::Declaration || + arg.getKind() == TemplateArgument::NullPtr) { ValueDecl *VD; - if (Decl *D = arg.getAsDecl()) { - VD = cast<ValueDecl>(D); + if (arg.getKind() == TemplateArgument::Declaration) { + VD = cast<ValueDecl>(arg.getAsDecl()); // Find the instantiation of the template argument. This is // required for nested templates. @@ -1230,8 +1244,81 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( } ExprResult +TemplateInstantiator::RebuildParmVarDeclRefExpr(ParmVarDecl *PD, + SourceLocation Loc) { + DeclarationNameInfo NameInfo(PD->getDeclName(), Loc); + return getSema().BuildDeclarationNameExpr(CXXScopeSpec(), NameInfo, PD); +} + +ExprResult +TemplateInstantiator::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) { + if (getSema().ArgumentPackSubstitutionIndex != -1) { + // We can expand this parameter pack now. + ParmVarDecl *D = E->getExpansion(getSema().ArgumentPackSubstitutionIndex); + ValueDecl *VD = cast_or_null<ValueDecl>(TransformDecl(E->getExprLoc(), D)); + if (!VD) + return ExprError(); + return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(VD), E->getExprLoc()); + } + + QualType T = TransformType(E->getType()); + if (T.isNull()) + return ExprError(); + + // Transform each of the parameter expansions into the corresponding + // parameters in the instantiation of the function decl. + llvm::SmallVector<Decl*, 8> Parms; + Parms.reserve(E->getNumExpansions()); + for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end(); + I != End; ++I) { + ParmVarDecl *D = + cast_or_null<ParmVarDecl>(TransformDecl(E->getExprLoc(), *I)); + if (!D) + return ExprError(); + Parms.push_back(D); + } + + return FunctionParmPackExpr::Create(getSema().Context, T, + E->getParameterPack(), + E->getParameterPackLocation(), Parms); +} + +ExprResult +TemplateInstantiator::TransformFunctionParmPackRefExpr(DeclRefExpr *E, + ParmVarDecl *PD) { + typedef LocalInstantiationScope::DeclArgumentPack DeclArgumentPack; + llvm::PointerUnion<Decl *, DeclArgumentPack *> *Found + = getSema().CurrentInstantiationScope->findInstantiationOf(PD); + assert(Found && "no instantiation for parameter pack"); + + Decl *TransformedDecl; + if (DeclArgumentPack *Pack = Found->dyn_cast<DeclArgumentPack *>()) { + // If this is a reference to a function parameter pack which we can substitute + // but can't yet expand, build a FunctionParmPackExpr for it. + if (getSema().ArgumentPackSubstitutionIndex == -1) { + QualType T = TransformType(E->getType()); + if (T.isNull()) + return ExprError(); + return FunctionParmPackExpr::Create(getSema().Context, T, PD, + E->getExprLoc(), *Pack); + } + + TransformedDecl = (*Pack)[getSema().ArgumentPackSubstitutionIndex]; + } else { + TransformedDecl = Found->get<Decl*>(); + } + + // We have either an unexpanded pack or a specific expansion. + return RebuildParmVarDeclRefExpr(cast<ParmVarDecl>(TransformedDecl), + E->getExprLoc()); +} + +ExprResult TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { NamedDecl *D = E->getDecl(); + + // Handle references to non-type template parameters and non-type template + // parameter packs. if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { if (NTTP->getDepth() < TemplateArgs.getNumLevels()) return TransformTemplateParmRefExpr(E, NTTP); @@ -1240,6 +1327,11 @@ TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { // FindInstantiatedDecl will find it in the local instantiation scope. } + // Handle references to function parameter packs. + if (ParmVarDecl *PD = dyn_cast<ParmVarDecl>(D)) + if (PD->isParameterPack()) + return TransformFunctionParmPackRefExpr(E, PD); + return TreeTransform<TemplateInstantiator>::TransformDeclRefExpr(E); } @@ -2159,7 +2251,7 @@ Sema::InstantiateClassTemplateSpecialization( Template->getPartialSpecializations(PartialSpecs); for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; - TemplateDeductionInfo Info(Context, PointOfInstantiation); + TemplateDeductionInfo Info(PointOfInstantiation); if (TemplateDeductionResult Result = DeduceTemplateArguments(Partial, ClassTemplateSpec->getTemplateArgs(), @@ -2543,8 +2635,25 @@ bool Sema::Subst(const TemplateArgumentLoc *Args, unsigned NumArgs, return Instantiator.TransformTemplateArguments(Args, NumArgs, Result); } + +static const Decl* getCanonicalParmVarDecl(const Decl *D) { + // When storing ParmVarDecls in the local instantiation scope, we always + // want to use the ParmVarDecl from the canonical function declaration, + // since the map is then valid for any redeclaration or definition of that + // function. + if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(D)) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) { + unsigned i = PV->getFunctionScopeIndex(); + return FD->getCanonicalDecl()->getParamDecl(i); + } + } + return D; +} + + llvm::PointerUnion<Decl *, LocalInstantiationScope::DeclArgumentPack *> * LocalInstantiationScope::findInstantiationOf(const Decl *D) { + D = getCanonicalParmVarDecl(D); for (LocalInstantiationScope *Current = this; Current; Current = Current->Outer) { @@ -2576,6 +2685,7 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) { } void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) { + D = getCanonicalParmVarDecl(D); llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; if (Stored.isNull()) Stored = Inst; @@ -2588,11 +2698,13 @@ void LocalInstantiationScope::InstantiatedLocal(const Decl *D, Decl *Inst) { void LocalInstantiationScope::InstantiatedLocalPackArg(const Decl *D, Decl *Inst) { + D = getCanonicalParmVarDecl(D); DeclArgumentPack *Pack = LocalDecls[D].get<DeclArgumentPack *>(); Pack->push_back(Inst); } void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) { + D = getCanonicalParmVarDecl(D); llvm::PointerUnion<Decl *, DeclArgumentPack *> &Stored = LocalDecls[D]; assert(Stored.isNull() && "Already instantiated this local"); DeclArgumentPack *Pack = new DeclArgumentPack; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index bdbe71dd8aba..19c46ab9c97f 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -158,6 +158,22 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, SemaRef.MarkDeclarationsReferencedInType(D->getLocation(), DI->getType()); } + // HACK: g++ has a bug where it gets the value kind of ?: wrong. + // libstdc++ relies upon this bug in its implementation of common_type. + // If we happen to be processing that implementation, fake up the g++ ?: + // semantics. See LWG issue 2141 for more information on the bug. + const DecltypeType *DT = DI->getType()->getAs<DecltypeType>(); + CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D->getDeclContext()); + if (DT && RD && isa<ConditionalOperator>(DT->getUnderlyingExpr()) && + DT->isReferenceType() && + RD->getEnclosingNamespaceContext() == SemaRef.getStdNamespace() && + RD->getIdentifier() && RD->getIdentifier()->isStr("common_type") && + D->getIdentifier() && D->getIdentifier()->isStr("type") && + SemaRef.getSourceManager().isInSystemHeader(D->getLocStart())) + // Fold it to the (non-reference) type which g++ would have produced. + DI = SemaRef.Context.getTrivialTypeSourceInfo( + DI->getType().getNonReferenceType()); + // Create the new typedef TypedefNameDecl *Typedef; if (IsTypeAlias) @@ -510,7 +526,7 @@ Decl *TemplateDeclInstantiator::VisitFriendDecl(FriendDecl *D) { if (!InstTy) return 0; - FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getLocation(), + FriendDecl *FD = SemaRef.CheckFriendTypeDecl(D->getLocStart(), D->getFriendLoc(), InstTy); if (!FD) return 0; @@ -1008,6 +1024,30 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { return Record; } +/// \brief Adjust the given function type for an instantiation of the +/// given declaration, to cope with modifications to the function's type that +/// aren't reflected in the type-source information. +/// +/// \param D The declaration we're instantiating. +/// \param TInfo The already-instantiated type. +static QualType adjustFunctionTypeForInstantiation(ASTContext &Context, + FunctionDecl *D, + TypeSourceInfo *TInfo) { + const FunctionProtoType *OrigFunc + = D->getType()->castAs<FunctionProtoType>(); + const FunctionProtoType *NewFunc + = TInfo->getType()->castAs<FunctionProtoType>(); + if (OrigFunc->getExtInfo() == NewFunc->getExtInfo()) + return TInfo->getType(); + + FunctionProtoType::ExtProtoInfo NewEPI = NewFunc->getExtProtoInfo(); + NewEPI.ExtInfo = OrigFunc->getExtInfo(); + return Context.getFunctionType(NewFunc->getResultType(), + NewFunc->arg_type_begin(), + NewFunc->getNumArgs(), + NewEPI); +} + /// Normal class members are of more specific types and therefore /// don't make it here. This function serves two purposes: /// 1) instantiating function templates @@ -1048,7 +1088,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, TypeSourceInfo *TInfo = SubstFunctionType(D, Params); if (!TInfo) return 0; - QualType T = TInfo->getType(); + QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo); NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); if (QualifierLoc) { @@ -1075,7 +1115,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, FunctionDecl *Function = FunctionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), - D->getLocation(), D->getDeclName(), T, TInfo, + D->getNameInfo(), T, TInfo, D->getStorageClass(), D->getStorageClassAsWritten(), D->isInlineSpecified(), D->hasWrittenPrototype(), D->isConstexpr()); @@ -1366,7 +1406,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, TypeSourceInfo *TInfo = SubstFunctionType(D, Params); if (!TInfo) return 0; - QualType T = TInfo->getType(); + QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo); // \brief If the type of this function, after ignoring parentheses, // is not *directly* a function type, then we're instantiating a function @@ -1657,7 +1697,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( IsExpandedParameterPack = true; DI = D->getTypeSourceInfo(); T = DI->getType(); - } else if (isa<PackExpansionTypeLoc>(TL)) { + } else if (D->isPackExpansion()) { // The non-type template parameter pack's type is a pack expansion of types. // Determine whether we need to expand this parameter pack into separate // types. @@ -1771,27 +1811,121 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( return Param; } +static void collectUnexpandedParameterPacks( + Sema &S, + TemplateParameterList *Params, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + for (TemplateParameterList::const_iterator I = Params->begin(), + E = Params->end(); I != E; ++I) { + if ((*I)->isTemplateParameterPack()) + continue; + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*I)) + S.collectUnexpandedParameterPacks(NTTP->getTypeSourceInfo()->getTypeLoc(), + Unexpanded); + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(*I)) + collectUnexpandedParameterPacks(S, TTP->getTemplateParameters(), + Unexpanded); + } +} + Decl * TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( TemplateTemplateParmDecl *D) { // Instantiate the template parameter list of the template template parameter. TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams; - { + SmallVector<TemplateParameterList*, 8> ExpandedParams; + + bool IsExpandedParameterPack = false; + + if (D->isExpandedParameterPack()) { + // The template template parameter pack is an already-expanded pack + // expansion of template parameters. Substitute into each of the expanded + // parameters. + ExpandedParams.reserve(D->getNumExpansionTemplateParameters()); + for (unsigned I = 0, N = D->getNumExpansionTemplateParameters(); + I != N; ++I) { + LocalInstantiationScope Scope(SemaRef); + TemplateParameterList *Expansion = + SubstTemplateParams(D->getExpansionTemplateParameters(I)); + if (!Expansion) + return 0; + ExpandedParams.push_back(Expansion); + } + + IsExpandedParameterPack = true; + InstParams = TempParams; + } else if (D->isPackExpansion()) { + // The template template parameter pack expands to a pack of template + // template parameters. Determine whether we need to expand this parameter + // pack into separate parameters. + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + collectUnexpandedParameterPacks(SemaRef, D->getTemplateParameters(), + Unexpanded); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + llvm::Optional<unsigned> NumExpansions; + if (SemaRef.CheckParameterPacksForExpansion(D->getLocation(), + TempParams->getSourceRange(), + Unexpanded, + TemplateArgs, + Expand, RetainExpansion, + NumExpansions)) + return 0; + + if (Expand) { + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I); + LocalInstantiationScope Scope(SemaRef); + TemplateParameterList *Expansion = SubstTemplateParams(TempParams); + if (!Expansion) + return 0; + ExpandedParams.push_back(Expansion); + } + + // Note that we have an expanded parameter pack. The "type" of this + // expanded parameter pack is the original expansion type, but callers + // will end up using the expanded parameter pack types for type-checking. + IsExpandedParameterPack = true; + InstParams = TempParams; + } else { + // We cannot fully expand the pack expansion now, so just substitute + // into the pattern. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); + + LocalInstantiationScope Scope(SemaRef); + InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return 0; + } + } else { // Perform the actual substitution of template parameters within a new, // local instantiation scope. LocalInstantiationScope Scope(SemaRef); InstParams = SubstTemplateParams(TempParams); if (!InstParams) - return NULL; + return 0; } // Build the template template parameter. - TemplateTemplateParmDecl *Param - = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, D->getLocation(), + TemplateTemplateParmDecl *Param; + if (IsExpandedParameterPack) + Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, + D->getLocation(), + D->getDepth() - TemplateArgs.getNumLevels(), + D->getPosition(), + D->getIdentifier(), InstParams, + ExpandedParams); + else + Param = TemplateTemplateParmDecl::Create(SemaRef.Context, Owner, + D->getLocation(), D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), D->isParameterPack(), - D->getIdentifier(), InstParams); + D->getPosition(), + D->isParameterPack(), + D->getIdentifier(), InstParams); Param->setDefaultArgument(D->getDefaultArgument(), false); Param->setAccess(AS_public); @@ -1813,7 +1947,12 @@ Decl *TemplateDeclInstantiator::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { D->getIdentLocation(), D->getNominatedNamespace(), D->getCommonAncestor()); - Owner->addDecl(Inst); + + // Add the using directive to its declaration context + // only if this is not a function or method. + if (!Owner->isFunctionOrMethod()) + Owner->addDecl(Inst); + return Inst; } @@ -2863,7 +3002,7 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New, const MultiLevelTemplateArgumentList &TemplateArgs) { SmallVector<CXXCtorInitializer*, 4> NewInits; - bool AnyErrors = false; + bool AnyErrors = Tmpl->isInvalidDecl(); // Instantiate all the initializers. for (CXXConstructorDecl::init_const_iterator Inits = Tmpl->init_begin(), @@ -3031,7 +3170,7 @@ ExprResult Sema::SubstInitializer(Expr *Init, isa<CXXTemporaryObjectExpr>(Construct)) return SubstExpr(Init, TemplateArgs); - ASTOwningVector<Expr*> NewArgs(*this); + SmallVector<Expr*, 8> NewArgs; if (SubstExprs(Construct->getArgs(), Construct->getNumArgs(), true, TemplateArgs, NewArgs)) return ExprError(); @@ -3043,7 +3182,7 @@ ExprResult Sema::SubstInitializer(Expr *Init, // Build a ParenListExpr to represent anything else. // FIXME: Fake locations! SourceLocation Loc = PP.getLocForEndOfToken(Init->getLocStart()); - return ActOnParenListExpr(Loc, Loc, move_arg(NewArgs)); + return ActOnParenListExpr(Loc, Loc, NewArgs); } // TODO: this could be templated if the various decl types used the @@ -3298,7 +3437,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (Decl *FD = Found->dyn_cast<Decl *>()) return cast<NamedDecl>(FD); - unsigned PackIdx = ArgumentPackSubstitutionIndex; + int PackIdx = ArgumentPackSubstitutionIndex; + assert(PackIdx != -1 && "found declaration pack but not pack expanding"); return cast<NamedDecl>((*Found->get<DeclArgumentPack *>())[PackIdx]); } diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index aece90b78590..6147d63ef44b 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -727,6 +727,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_enum: case TST_union: case TST_struct: + case TST_interface: case TST_class: case TST_auto: case TST_unknown_anytype: diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 54f8dbaf0127..4b23167951aa 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -105,7 +105,8 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, case AttributeList::AT_ThisCall: \ case AttributeList::AT_Pascal: \ case AttributeList::AT_Regparm: \ - case AttributeList::AT_Pcs \ + case AttributeList::AT_Pcs: \ + case AttributeList::AT_PnaclCall \ namespace { /// An object which stores processing state for the entire @@ -552,19 +553,28 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, SourceLocation loc = declarator.getLocStart(); // ...and *prepend* it to the declarator. + SourceLocation NoLoc; declarator.AddInnermostTypeInfo(DeclaratorChunk::getFunction( - /*proto*/ true, - /*variadic*/ false, - /*ambiguous*/ false, SourceLocation(), - /*args*/ 0, 0, - /*type quals*/ 0, - /*ref-qualifier*/true, SourceLocation(), - /*const qualifier*/SourceLocation(), - /*volatile qualifier*/SourceLocation(), - /*mutable qualifier*/SourceLocation(), - /*EH*/ EST_None, SourceLocation(), 0, 0, 0, 0, - /*parens*/ loc, loc, - declarator)); + /*HasProto=*/true, + /*IsAmbiguous=*/false, + /*LParenLoc=*/NoLoc, + /*ArgInfo=*/0, + /*NumArgs=*/0, + /*EllipsisLoc=*/NoLoc, + /*RParenLoc=*/NoLoc, + /*TypeQuals=*/0, + /*RefQualifierIsLvalueRef=*/true, + /*RefQualifierLoc=*/NoLoc, + /*ConstQualifierLoc=*/NoLoc, + /*VolatileQualifierLoc=*/NoLoc, + /*MutableLoc=*/NoLoc, + EST_None, + /*ESpecLoc=*/NoLoc, + /*Exceptions=*/0, + /*ExceptionRanges=*/0, + /*NumExceptions=*/0, + /*NoexceptExpr=*/0, + loc, loc, declarator)); // For consistency, make sure the state still has us as processing // the decl spec. @@ -636,7 +646,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // "<proto1,proto2>" is an objc qualified ID with a missing id. if (DeclSpec::ProtocolQualifierListTy PQ = DS.getProtocolQualifiers()) { Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**)PQ, + (ObjCProtocolDecl*const*)PQ, DS.getNumProtocolQualifiers()); Result = Context.getObjCObjectPointerType(Result); break; @@ -698,11 +708,15 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case DeclSpec::TSW_longlong: Result = Context.LongLongTy; - // long long is a C99 feature. - if (!S.getLangOpts().C99) - S.Diag(DS.getTypeSpecWidthLoc(), - S.getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_longlong : diag::ext_longlong); + // 'long long' is a C99 or C++11 feature. + if (!S.getLangOpts().C99) { + if (S.getLangOpts().CPlusPlus) + S.Diag(DS.getTypeSpecWidthLoc(), + S.getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); + else + S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong); + } break; } } else { @@ -713,11 +727,15 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case DeclSpec::TSW_longlong: Result = Context.UnsignedLongLongTy; - // long long is a C99 feature. - if (!S.getLangOpts().C99) - S.Diag(DS.getTypeSpecWidthLoc(), - S.getLangOpts().CPlusPlus0x ? - diag::warn_cxx98_compat_longlong : diag::ext_longlong); + // 'long long' is a C99 or C++11 feature. + if (!S.getLangOpts().C99) { + if (S.getLangOpts().CPlusPlus) + S.Diag(DS.getTypeSpecWidthLoc(), + S.getLangOpts().CPlusPlus0x ? + diag::warn_cxx98_compat_longlong : diag::ext_cxx11_longlong); + else + S.Diag(DS.getTypeSpecWidthLoc(), diag::ext_c99_longlong); + } break; } } @@ -753,7 +771,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { case DeclSpec::TST_class: case DeclSpec::TST_enum: case DeclSpec::TST_union: - case DeclSpec::TST_struct: { + case DeclSpec::TST_struct: + case DeclSpec::TST_interface: { TypeDecl *D = dyn_cast_or_null<TypeDecl>(DS.getRepAsDecl()); if (!D) { // This can happen in C++ with ambiguous lookups. @@ -794,18 +813,18 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { if (DS.getNumProtocolQualifiers()) Result = Context.getObjCObjectType(Result, - (ObjCProtocolDecl**) PQ, + (ObjCProtocolDecl*const*) PQ, DS.getNumProtocolQualifiers()); } else if (Result->isObjCIdType()) { // id<protocol-list> Result = Context.getObjCObjectType(Context.ObjCBuiltinIdTy, - (ObjCProtocolDecl**) PQ, + (ObjCProtocolDecl*const*) PQ, DS.getNumProtocolQualifiers()); Result = Context.getObjCObjectPointerType(Result); } else if (Result->isObjCClassType()) { // Class<protocol-list> Result = Context.getObjCObjectType(Context.ObjCBuiltinClassTy, - (ObjCProtocolDecl**) PQ, + (ObjCProtocolDecl*const*) PQ, DS.getNumProtocolQualifiers()); Result = Context.getObjCObjectPointerType(Result); } else { @@ -1853,30 +1872,31 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case TTK_Struct: Error = 1; /* Struct member */ break; case TTK_Union: Error = 2; /* Union member */ break; case TTK_Class: Error = 3; /* Class member */ break; + case TTK_Interface: Error = 4; /* Interface member */ break; } break; case Declarator::CXXCatchContext: case Declarator::ObjCCatchContext: - Error = 4; // Exception declaration + Error = 5; // Exception declaration break; case Declarator::TemplateParamContext: - Error = 5; // Template parameter + Error = 6; // Template parameter break; case Declarator::BlockLiteralContext: - Error = 6; // Block literal + Error = 7; // Block literal break; case Declarator::TemplateTypeArgContext: - Error = 7; // Template type argument + Error = 8; // Template type argument break; case Declarator::AliasDeclContext: case Declarator::AliasTemplateContext: - Error = 9; // Type alias + Error = 10; // Type alias break; case Declarator::TrailingReturnContext: - Error = 10; // Function return type + Error = 11; // Function return type break; case Declarator::TypeNameContext: - Error = 11; // Generic + Error = 12; // Generic break; case Declarator::FileContext: case Declarator::BlockContext: @@ -1887,11 +1907,11 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, } if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) - Error = 8; + Error = 9; // In Objective-C it is an error to use 'auto' on a function declarator. if (D.isFunctionDeclarator()) - Error = 10; + Error = 11; // C++11 [dcl.spec.auto]p2: 'auto' is always fine if the declarator // contains a trailing return type. That is only legal at the outermost @@ -2149,16 +2169,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, ASTContext &Context = S.Context; const LangOptions &LangOpts = S.getLangOpts(); - bool ImplicitlyNoexcept = false; - if (D.getName().getKind() == UnqualifiedId::IK_OperatorFunctionId && - LangOpts.CPlusPlus0x) { - OverloadedOperatorKind OO = D.getName().OperatorFunctionId.Operator; - /// In C++0x, deallocation functions (normal and array operator delete) - /// are implicitly noexcept. - if (OO == OO_Delete || OO == OO_Array_Delete) - ImplicitlyNoexcept = true; - } - // The name we're declaring, if any. DeclarationName Name; if (D.getIdentifier()) @@ -2558,12 +2568,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, Exceptions, EPI); - if (FTI.getExceptionSpecType() == EST_None && - ImplicitlyNoexcept && chunkIndex == 0) { - // Only the outermost chunk is marked noexcept, of course. - EPI.ExceptionSpecType = EST_BasicNoexcept; - } - T = Context.getFunctionType(T, ArgTys.data(), ArgTys.size(), EPI); } @@ -2657,6 +2661,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // C++0x [dcl.constexpr]p8: A constexpr specifier for a non-static member // function that is not a constructor declares that function to be const. + // FIXME: This should be deferred until we know whether this is a static + // member function (for an out-of-class definition, we don't know + // this until we perform redeclaration lookup). if (D.getDeclSpec().isConstexprSpecified() && !FreeFunction && D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static && D.getName().getKind() != UnqualifiedId::IK_ConstructorName && @@ -2668,6 +2675,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), FnTy->getNumArgs(), EPI); + // Rebuild any parens around the identifier in the function type. + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + if (D.getTypeObject(i).Kind != DeclaratorChunk::Paren) + break; + T = S.BuildParenType(T); + } } // C++11 [dcl.fct]p6 (w/DR1417): @@ -2721,6 +2734,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, T = Context.getFunctionType(FnTy->getResultType(), FnTy->arg_type_begin(), FnTy->getNumArgs(), EPI); + // Rebuild any parens around the identifier in the function type. + for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) { + if (D.getTypeObject(i).Kind != DeclaratorChunk::Paren) + break; + T = S.BuildParenType(T); + } } } @@ -2985,6 +3004,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { return AttributeList::AT_Pascal; case AttributedType::attr_pcs: return AttributeList::AT_Pcs; + case AttributedType::attr_pnaclcall: + return AttributeList::AT_PnaclCall; } llvm_unreachable("unexpected attribute kind!"); } @@ -3271,6 +3292,8 @@ namespace { TL.setLocalRangeEnd(Chunk.EndLoc); const DeclaratorChunk::FunctionTypeInfo &FTI = Chunk.Fun; + TL.setLParenLoc(FTI.getLParenLoc()); + TL.setRParenLoc(FTI.getRParenLoc()); for (unsigned i = 0, e = TL.getNumArgs(), tpi = 0; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.ArgInfo[i].Param); TL.setArg(tpi++, Param); @@ -3588,7 +3611,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, // Forbid __weak if the runtime doesn't support it. if (lifetime == Qualifiers::OCL_Weak && - !S.getLangOpts().ObjCRuntimeHasWeak && !NonObjCPointer) { + !S.getLangOpts().ObjCARCWeak && !NonObjCPointer) { // Actually, delay this until we know what we're parsing. if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { @@ -3611,11 +3634,12 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, while (const PointerType *ptr = T->getAs<PointerType>()) T = ptr->getPointeeType(); if (const ObjCObjectPointerType *ObjT = T->getAs<ObjCObjectPointerType>()) { - ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl(); - if (Class->isArcWeakrefUnavailable()) { - S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class); - S.Diag(ObjT->getInterfaceDecl()->getLocation(), - diag::note_class_declared); + if (ObjCInterfaceDecl *Class = ObjT->getInterfaceDecl()) { + if (Class->isArcWeakrefUnavailable()) { + S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class); + S.Diag(ObjT->getInterfaceDecl()->getLocation(), + diag::note_class_declared); + } } } } @@ -3875,14 +3899,14 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, return true; } + // Delay if the type didn't work out to a function. + if (!unwrapped.isFunctionType()) return false; + // Otherwise, a calling convention. CallingConv CC; if (S.CheckCallingConvAttr(attr, CC)) return true; - // Delay if the type didn't work out to a function. - if (!unwrapped.isFunctionType()) return false; - const FunctionType *fn = unwrapped.get(); CallingConv CCOld = fn->getCallConv(); if (S.Context.getCanonicalCallConv(CC) == @@ -4429,6 +4453,20 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, return RequireCompleteType(Loc, T, Diagnoser); } +/// \brief Get diagnostic %select index for tag kind for +/// literal type diagnostic message. +/// WARNING: Indexes apply to particular diagnostics only! +/// +/// \returns diagnostic %select index. +static unsigned getLiteralDiagFromTagKind(TagTypeKind Tag) { + switch (Tag) { + case TTK_Struct: return 0; + case TTK_Interface: return 1; + case TTK_Class: return 2; + default: llvm_unreachable("Invalid tag kind for literal type diagnostic!"); + } +} + /// @brief Ensure that the type T is a literal type. /// /// This routine checks whether the type @p T is a literal type. If @p T is an @@ -4485,7 +4523,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, // of constexpr constructors. if (RD->getNumVBases()) { Diag(RD->getLocation(), diag::note_non_literal_virtual_base) - << RD->isStruct() << RD->getNumVBases(); + << getLiteralDiagFromTagKind(RD->getTagKind()) << RD->getNumVBases(); for (CXXRecordDecl::base_class_const_iterator I = RD->vbases_begin(), E = RD->vbases_end(); I != E; ++I) Diag(I->getLocStart(), @@ -4578,15 +4616,21 @@ static QualType getDecltypeForExpr(Sema &S, Expr *E) { // member access (5.2.5), decltype(e) is the type of the entity named // by e. If there is no such entity, or if e names a set of overloaded // functions, the program is ill-formed; + // + // We apply the same rules for Objective-C ivar and property references. if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { if (const ValueDecl *VD = dyn_cast<ValueDecl>(DRE->getDecl())) return VD->getType(); - } - if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { if (const FieldDecl *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) return FD->getType(); + } else if (const ObjCIvarRefExpr *IR = dyn_cast<ObjCIvarRefExpr>(E)) { + return IR->getDecl()->getType(); + } else if (const ObjCPropertyRefExpr *PR = dyn_cast<ObjCPropertyRefExpr>(E)) { + if (PR->isExplicitProperty()) + return PR->getExplicitProperty()->getType(); } - + // C++11 [expr.lambda.prim]p18: // Every occurrence of decltype((x)) where x is a possibly // parenthesized id-expression that names an entity of automatic diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 619ad330b95b..294d74244673 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -574,6 +574,10 @@ public: /// \brief Transform the captures and body of a lambda expression. ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator); + ExprResult TransformAddressOfOperand(Expr *E); + ExprResult TransformDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E, + bool IsAddressOfOperand); + #define STMT(Node, Parent) \ StmtResult Transform##Node(Node *S); #define EXPR(Node, Parent) \ @@ -1162,32 +1166,23 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildAsmStmt(SourceLocation AsmLoc, - bool IsSimple, - bool IsVolatile, - unsigned NumOutputs, - unsigned NumInputs, - IdentifierInfo **Names, - MultiExprArg Constraints, - MultiExprArg Exprs, - Expr *AsmString, - MultiExprArg Clobbers, - SourceLocation RParenLoc, - bool MSAsm) { - return getSema().ActOnAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, - NumInputs, Names, move(Constraints), - Exprs, AsmString, Clobbers, - RParenLoc, MSAsm); + StmtResult RebuildGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, + bool IsVolatile, unsigned NumOutputs, + unsigned NumInputs, IdentifierInfo **Names, + MultiExprArg Constraints, MultiExprArg Exprs, + Expr *AsmString, MultiExprArg Clobbers, + SourceLocation RParenLoc) { + return getSema().ActOnGCCAsmStmt(AsmLoc, IsSimple, IsVolatile, NumOutputs, + NumInputs, Names, Constraints, Exprs, + AsmString, Clobbers, RParenLoc); } /// \brief Build a new MS style inline asm statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc, - SourceLocation LBraceLoc, - ArrayRef<Token> AsmToks, - SourceLocation EndLoc) { + StmtResult RebuildMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, + ArrayRef<Token> AsmToks, SourceLocation EndLoc) { return getSema().ActOnMSAsmStmt(AsmLoc, LBraceLoc, AsmToks, EndLoc); } @@ -1199,7 +1194,7 @@ public: Stmt *TryBody, MultiStmtArg CatchStmts, Stmt *Finally) { - return getSema().ActOnObjCAtTryStmt(AtLoc, TryBody, move(CatchStmts), + return getSema().ActOnObjCAtTryStmt(AtLoc, TryBody, CatchStmts, Finally); } @@ -1325,7 +1320,7 @@ public: StmtResult RebuildCXXTryStmt(SourceLocation TryLoc, Stmt *TryBlock, MultiStmtArg Handlers) { - return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, move(Handlers)); + return getSema().ActOnCXXTryBlock(TryLoc, TryBlock, Handlers); } /// \brief Build a new C++0x range-based for statement. @@ -1339,7 +1334,8 @@ public: Stmt *LoopVar, SourceLocation RParenLoc) { return getSema().BuildCXXForRangeStmt(ForLoc, ColonLoc, Range, BeginEnd, - Cond, Inc, LoopVar, RParenLoc); + Cond, Inc, LoopVar, RParenLoc, + Sema::BFRK_Rebuild); } /// \brief Build a new C++0x range-based for statement. @@ -1478,7 +1474,7 @@ public: if (Result.isInvalid()) return ExprError(); - return move(Result); + return Result; } /// \brief Build a new array subscript expression. @@ -1503,7 +1499,7 @@ public: SourceLocation RParenLoc, Expr *ExecConfig = 0) { return getSema().ActOnCallExpr(/*Scope=*/0, Callee, LParenLoc, - move(Args), RParenLoc, ExecConfig); + Args, RParenLoc, ExecConfig); } /// \brief Build a new member access expression. @@ -1638,15 +1634,15 @@ public: SourceLocation RBraceLoc, QualType ResultTy) { ExprResult Result - = SemaRef.ActOnInitList(LBraceLoc, move(Inits), RBraceLoc); + = SemaRef.ActOnInitList(LBraceLoc, Inits, RBraceLoc); if (Result.isInvalid() || ResultTy->isDependentType()) - return move(Result); + return Result; // Patch in the result type we were given, which may have been computed // when the initial InitListExpr was built. InitListExpr *ILE = cast<InitListExpr>((Expr *)Result.get()); ILE->setType(ResultTy); - return move(Result); + return Result; } /// \brief Build a new designated initializer expression. @@ -1664,8 +1660,7 @@ public: if (Result.isInvalid()) return ExprError(); - ArrayExprs.release(); - return move(Result); + return Result; } /// \brief Build a new value-initialized expression. @@ -1696,7 +1691,7 @@ public: ExprResult RebuildParenListExpr(SourceLocation LParenLoc, MultiExprArg SubExprs, SourceLocation RParenLoc) { - return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, move(SubExprs)); + return getSema().ActOnParenListExpr(LParenLoc, RParenLoc, SubExprs); } /// \brief Build a new address-of-label expression. @@ -1974,8 +1969,7 @@ public: SourceLocation LParenLoc, SourceLocation RParenLoc) { return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, - MultiExprArg(getSema(), 0, 0), - RParenLoc); + MultiExprArg(), RParenLoc); } /// \brief Build a new C++ "new" expression. @@ -1995,7 +1989,7 @@ public: Expr *Initializer) { return getSema().BuildCXXNew(StartLoc, UseGlobal, PlacementLParen, - move(PlacementArgs), + PlacementArgs, PlacementRParen, TypeIdParens, AllocatedType, @@ -2083,7 +2077,8 @@ public: NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, const DeclarationNameInfo &NameInfo, - const TemplateArgumentListInfo *TemplateArgs) { + const TemplateArgumentListInfo *TemplateArgs, + bool IsAddressOfOperand) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); @@ -2091,7 +2086,8 @@ public: return getSema().BuildQualifiedTemplateIdExpr(SS, TemplateKWLoc, NameInfo, TemplateArgs); - return getSema().BuildQualifiedDeclarationNameExpr(SS, NameInfo); + return getSema().BuildQualifiedDeclarationNameExpr(SS, NameInfo, + IsAddressOfOperand); } /// \brief Build a new template-id expression. @@ -2120,13 +2116,13 @@ public: bool RequiresZeroInit, CXXConstructExpr::ConstructionKind ConstructKind, SourceRange ParenRange) { - ASTOwningVector<Expr*> ConvertedArgs(SemaRef); - if (getSema().CompleteConstructorCall(Constructor, move(Args), Loc, + SmallVector<Expr*, 8> ConvertedArgs; + if (getSema().CompleteConstructorCall(Constructor, Args, Loc, ConvertedArgs)) return ExprError(); return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable, - move_arg(ConvertedArgs), + ConvertedArgs, HadMultipleCandidates, RequiresZeroInit, ConstructKind, ParenRange); @@ -2142,7 +2138,7 @@ public: SourceLocation RParenLoc) { return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, - move(Args), + Args, RParenLoc); } @@ -2156,7 +2152,7 @@ public: SourceLocation RParenLoc) { return getSema().BuildCXXTypeConstructExpr(TSInfo, LParenLoc, - move(Args), + Args, RParenLoc); } @@ -2288,7 +2284,7 @@ public: ReceiverTypeInfo->getType(), /*SuperLoc=*/SourceLocation(), Sel, Method, LBracLoc, SelectorLocs, - RBracLoc, move(Args)); + RBracLoc, Args); } /// \brief Build a new Objective-C instance message. @@ -2303,7 +2299,7 @@ public: Receiver->getType(), /*SuperLoc=*/SourceLocation(), Sel, Method, LBracLoc, SelectorLocs, - RBracLoc, move(Args)); + RBracLoc, Args); } /// \brief Build a new Objective-C ivar reference expression. @@ -2326,7 +2322,7 @@ public: return ExprError(); if (Result.get()) - return move(Result); + return Result; return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(), /*FIXME:*/IvarLoc, IsArrow, @@ -2355,7 +2351,7 @@ public: return ExprError(); if (Result.get()) - return move(Result); + return Result; return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(), /*FIXME:*/PropertyLoc, IsArrow, @@ -2398,7 +2394,7 @@ public: return ExprError(); if (Result.get()) - return move(Result); + return Result; return getSema().BuildMemberReferenceExpr(Base.get(), Base.get()->getType(), /*FIXME:*/IsaLoc, IsArrow, @@ -2424,21 +2420,17 @@ public: // Build a reference to the __builtin_shufflevector builtin FunctionDecl *Builtin = cast<FunctionDecl>(*Lookup.first); - ExprResult Callee - = SemaRef.Owned(new (SemaRef.Context) DeclRefExpr(Builtin, false, - Builtin->getType(), - VK_LValue, BuiltinLoc)); - Callee = SemaRef.UsualUnaryConversions(Callee.take()); - if (Callee.isInvalid()) - return ExprError(); + Expr *Callee = new (SemaRef.Context) DeclRefExpr(Builtin, false, + SemaRef.Context.BuiltinFnTy, + VK_RValue, BuiltinLoc); + QualType CalleePtrTy = SemaRef.Context.getPointerType(Builtin->getType()); + Callee = SemaRef.ImpCastExprToType(Callee, CalleePtrTy, + CK_BuiltinFnToFnPtr).take(); // Build the CallExpr - unsigned NumSubExprs = SubExprs.size(); - Expr **Subs = (Expr **)SubExprs.release(); ExprResult TheCall = SemaRef.Owned( - new (SemaRef.Context) CallExpr(SemaRef.Context, Callee.take(), - Subs, NumSubExprs, - Builtin->getCallResultType(), + new (SemaRef.Context) CallExpr(SemaRef.Context, Callee, SubExprs, + Builtin->getCallResultType(), Expr::getValueKindForType(Builtin->getResultType()), RParenLoc)); @@ -2478,6 +2470,7 @@ public: case TemplateArgument::Declaration: case TemplateArgument::Pack: case TemplateArgument::TemplateExpansion: + case TemplateArgument::NullPtr: llvm_unreachable("Pack expansion pattern has no parameter packs"); case TemplateArgument::Type: @@ -2515,10 +2508,7 @@ public: // Just create the expression; there is not any interesting semantic // analysis here because we can't actually build an AtomicExpr until // we are sure it is semantically sound. - unsigned NumSubExprs = SubExprs.size(); - Expr **Subs = (Expr **)SubExprs.release(); - return new (SemaRef.Context) AtomicExpr(BuiltinLoc, Subs, - NumSubExprs, RetTy, Op, + return new (SemaRef.Context) AtomicExpr(BuiltinLoc, SubExprs, RetTy, Op, RParenLoc); } @@ -2963,6 +2953,7 @@ void TreeTransform<Derived>::InventTemplateArgumentLoc( case TemplateArgument::Declaration: case TemplateArgument::Integral: case TemplateArgument::Pack: + case TemplateArgument::NullPtr: Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo()); break; } @@ -2976,8 +2967,10 @@ bool TreeTransform<Derived>::TransformTemplateArgument( switch (Arg.getKind()) { case TemplateArgument::Null: case TemplateArgument::Integral: - Output = Input; - return false; + case TemplateArgument::Pack: + case TemplateArgument::Declaration: + case TemplateArgument::NullPtr: + llvm_unreachable("Unexpected TemplateArgument"); case TemplateArgument::Type: { TypeSourceInfo *DI = Input.getTypeSourceInfo(); @@ -2991,28 +2984,6 @@ bool TreeTransform<Derived>::TransformTemplateArgument( return false; } - case TemplateArgument::Declaration: { - // FIXME: we should never have to transform one of these. - DeclarationName Name; - if (NamedDecl *ND = dyn_cast<NamedDecl>(Arg.getAsDecl())) - Name = ND->getDeclName(); - TemporaryBase Rebase(*this, Input.getLocation(), Name); - Decl *D = getDerived().TransformDecl(Input.getLocation(), Arg.getAsDecl()); - if (!D) return true; - - Expr *SourceExpr = Input.getSourceDeclExpression(); - if (SourceExpr) { - EnterExpressionEvaluationContext Unevaluated(getSema(), - Sema::ConstantEvaluated); - ExprResult E = getDerived().TransformExpr(SourceExpr); - E = SemaRef.ActOnConstantExpression(E); - SourceExpr = (E.isInvalid() ? 0 : E.take()); - } - - Output = TemplateArgumentLoc(TemplateArgument(D), SourceExpr); - return false; - } - case TemplateArgument::Template: { NestedNameSpecifierLoc QualifierLoc = Input.getTemplateQualifierLoc(); if (QualifierLoc) { @@ -3051,35 +3022,6 @@ bool TreeTransform<Derived>::TransformTemplateArgument( Output = TemplateArgumentLoc(TemplateArgument(E.take()), E.take()); return false; } - - case TemplateArgument::Pack: { - SmallVector<TemplateArgument, 4> TransformedArgs; - TransformedArgs.reserve(Arg.pack_size()); - for (TemplateArgument::pack_iterator A = Arg.pack_begin(), - AEnd = Arg.pack_end(); - A != AEnd; ++A) { - - // FIXME: preserve source information here when we start - // caring about parameter packs. - - TemplateArgumentLoc InputArg; - TemplateArgumentLoc OutputArg; - getDerived().InventTemplateArgumentLoc(*A, InputArg); - if (getDerived().TransformTemplateArgument(InputArg, OutputArg)) - return true; - - TransformedArgs.push_back(OutputArg.getArgument()); - } - - TemplateArgument *TransformedArgsPtr - = new (getSema().Context) TemplateArgument[TransformedArgs.size()]; - std::copy(TransformedArgs.begin(), TransformedArgs.end(), - TransformedArgsPtr); - Output = TemplateArgumentLoc(TemplateArgument(TransformedArgsPtr, - TransformedArgs.size()), - Input.getLocInfo()); - return false; - } } // Work around bogus GCC warning @@ -4260,6 +4202,8 @@ TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB, FunctionProtoTypeLoc NewTL = TLB.push<FunctionProtoTypeLoc>(Result); NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); for (unsigned i = 0, e = NewTL.getNumArgs(); i != e; ++i) NewTL.setArg(i, ParamDecls[i]); @@ -4283,6 +4227,8 @@ QualType TreeTransform<Derived>::TransformFunctionNoProtoType( FunctionNoProtoTypeLoc NewTL = TLB.push<FunctionNoProtoTypeLoc>(Result); NewTL.setLocalRangeBegin(TL.getLocalRangeBegin()); + NewTL.setLParenLoc(TL.getLParenLoc()); + NewTL.setRParenLoc(TL.getRParenLoc()); NewTL.setLocalRangeEnd(TL.getLocalRangeEnd()); return Result; @@ -4339,7 +4285,8 @@ template<typename Derived> QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB, TypeOfExprTypeLoc TL) { // typeof expressions are not potentially evaluated contexts - EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, + Sema::ReuseLambdaContextDecl); ExprResult E = getDerived().TransformExpr(TL.getUnderlyingExpr()); if (E.isInvalid()) @@ -5099,7 +5046,7 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S, bool SubStmtInvalid = false; bool SubStmtChanged = false; - ASTOwningVector<Stmt*> Statements(getSema()); + SmallVector<Stmt*, 8> Statements; for (CompoundStmt::body_iterator B = S->body_begin(), BEnd = S->body_end(); B != BEnd; ++B) { StmtResult Result = getDerived().TransformStmt(*B); @@ -5126,7 +5073,7 @@ TreeTransform<Derived>::TransformCompoundStmt(CompoundStmt *S, return SemaRef.Owned(S); return getDerived().RebuildCompoundStmt(S->getLBracLoc(), - move_arg(Statements), + Statements, S->getRBracLoc(), IsStmtExpr); } @@ -5533,14 +5480,14 @@ TreeTransform<Derived>::TransformDeclStmt(DeclStmt *S) { template<typename Derived> StmtResult -TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { +TreeTransform<Derived>::TransformGCCAsmStmt(GCCAsmStmt *S) { - ASTOwningVector<Expr*> Constraints(getSema()); - ASTOwningVector<Expr*> Exprs(getSema()); + SmallVector<Expr*, 8> Constraints; + SmallVector<Expr*, 8> Exprs; SmallVector<IdentifierInfo *, 4> Names; ExprResult AsmString; - ASTOwningVector<Expr*> Clobbers(getSema()); + SmallVector<Expr*, 8> Clobbers; bool ExprsChanged = false; @@ -5585,23 +5532,15 @@ TreeTransform<Derived>::TransformAsmStmt(AsmStmt *S) { // Go through the clobbers. for (unsigned I = 0, E = S->getNumClobbers(); I != E; ++I) - Clobbers.push_back(S->getClobber(I)); + Clobbers.push_back(S->getClobberStringLiteral(I)); // No need to transform the asm string literal. AsmString = SemaRef.Owned(S->getAsmString()); - - return getDerived().RebuildAsmStmt(S->getAsmLoc(), - S->isSimple(), - S->isVolatile(), - S->getNumOutputs(), - S->getNumInputs(), - Names.data(), - move_arg(Constraints), - move_arg(Exprs), - AsmString.get(), - move_arg(Clobbers), - S->getRParenLoc(), - S->isMSAsm()); + return getDerived().RebuildGCCAsmStmt(S->getAsmLoc(), S->isSimple(), + S->isVolatile(), S->getNumOutputs(), + S->getNumInputs(), Names.data(), + Constraints, Exprs, AsmString.get(), + Clobbers, S->getRParenLoc()); } template<typename Derived> @@ -5624,7 +5563,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { // Transform the @catch statements (if present). bool AnyCatchChanged = false; - ASTOwningVector<Stmt*> CatchStmts(SemaRef); + SmallVector<Stmt*, 8> CatchStmts; for (unsigned I = 0, N = S->getNumCatchStmts(); I != N; ++I) { StmtResult Catch = getDerived().TransformStmt(S->getCatchStmt(I)); if (Catch.isInvalid()) @@ -5651,7 +5590,7 @@ TreeTransform<Derived>::TransformObjCAtTryStmt(ObjCAtTryStmt *S) { // Build a new statement. return getDerived().RebuildObjCAtTryStmt(S->getAtTryLoc(), TryBody.get(), - move_arg(CatchStmts), Finally.get()); + CatchStmts, Finally.get()); } template<typename Derived> @@ -5855,7 +5794,7 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) { // Transform the handlers. bool HandlerChanged = false; - ASTOwningVector<Stmt*> Handlers(SemaRef); + SmallVector<Stmt*, 8> Handlers; for (unsigned I = 0, N = S->getNumHandlers(); I != N; ++I) { StmtResult Handler = getDerived().TransformCXXCatchStmt(S->getHandler(I)); @@ -5872,7 +5811,7 @@ TreeTransform<Derived>::TransformCXXTryStmt(CXXTryStmt *S) { return SemaRef.Owned(S); return getDerived().RebuildCXXTryStmt(S->getTryLoc(), TryBlock.get(), - move_arg(Handlers)); + Handlers); } template<typename Derived> @@ -6205,10 +6144,22 @@ TreeTransform<Derived>::TransformParenExpr(ParenExpr *E) { E->getRParen()); } +/// \brief The operand of a unary address-of operator has special rules: it's +/// allowed to refer to a non-static member of a class even if there's no 'this' +/// object available. +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformAddressOfOperand(Expr *E) { + if (DependentScopeDeclRefExpr *DRE = dyn_cast<DependentScopeDeclRefExpr>(E)) + return getDerived().TransformDependentScopeDeclRefExpr(DRE, true); + else + return getDerived().TransformExpr(E); +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformUnaryOperator(UnaryOperator *E) { - ExprResult SubExpr = getDerived().TransformExpr(E->getSubExpr()); + ExprResult SubExpr = TransformAddressOfOperand(E->getSubExpr()); if (SubExpr.isInvalid()) return ExprError(); @@ -6338,7 +6289,8 @@ TreeTransform<Derived>::TransformUnaryExprOrTypeTraitExpr( // C++0x [expr.sizeof]p1: // The operand is either an expression, which is an unevaluated operand // [...] - EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, + Sema::ReuseLambdaContextDecl); ExprResult SubExpr = getDerived().TransformExpr(E->getArgumentExpr()); if (SubExpr.isInvalid()) @@ -6386,7 +6338,7 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E) { // Transform arguments. bool ArgChanged = false; - ASTOwningVector<Expr*> Args(SemaRef); + SmallVector<Expr*, 8> Args; if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgChanged)) return ExprError(); @@ -6394,13 +6346,13 @@ TreeTransform<Derived>::TransformCallExpr(CallExpr *E) { if (!getDerived().AlwaysRebuild() && Callee.get() == E->getCallee() && !ArgChanged) - return SemaRef.MaybeBindToTemporary(E);; + return SemaRef.MaybeBindToTemporary(E); // FIXME: Wrong source location information for the '('. SourceLocation FakeLParenLoc = ((Expr *)Callee.get())->getSourceRange().getBegin(); return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc, - move_arg(Args), + Args, E->getRParenLoc()); } @@ -6499,6 +6451,9 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { RHS.get() == E->getRHS()) return SemaRef.Owned(E); + Sema::FPContractStateRAII FPContractState(getSema()); + getSema().FPFeatures.fp_contract = E->isFPContractable(); + return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get()); } @@ -6645,7 +6600,7 @@ ExprResult TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) { bool InitChanged = false; - ASTOwningVector<Expr*, 4> Inits(SemaRef); + SmallVector<Expr*, 4> Inits; if (getDerived().TransformExprs(E->getInits(), E->getNumInits(), false, Inits, &InitChanged)) return ExprError(); @@ -6653,7 +6608,7 @@ TreeTransform<Derived>::TransformInitListExpr(InitListExpr *E) { if (!getDerived().AlwaysRebuild() && !InitChanged) return SemaRef.Owned(E); - return getDerived().RebuildInitList(E->getLBraceLoc(), move_arg(Inits), + return getDerived().RebuildInitList(E->getLBraceLoc(), Inits, E->getRBraceLoc(), E->getType()); } @@ -6668,7 +6623,7 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { return ExprError(); // transform the designators. - ASTOwningVector<Expr*, 4> ArrayExprs(SemaRef); + SmallVector<Expr*, 4> ArrayExprs; bool ExprChanged = false; for (DesignatedInitExpr::designators_iterator D = E->designators_begin(), DEnd = E->designators_end(); @@ -6720,7 +6675,7 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { !ExprChanged) return SemaRef.Owned(E); - return getDerived().RebuildDesignatedInitExpr(Desig, move_arg(ArrayExprs), + return getDerived().RebuildDesignatedInitExpr(Desig, ArrayExprs, E->getEqualOrColonLoc(), E->usesGNUSyntax(), Init.get()); } @@ -6768,13 +6723,13 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformParenListExpr(ParenListExpr *E) { bool ArgumentChanged = false; - ASTOwningVector<Expr*, 4> Inits(SemaRef); + SmallVector<Expr*, 4> Inits; if (TransformExprs(E->getExprs(), E->getNumExprs(), true, Inits, &ArgumentChanged)) return ExprError(); return getDerived().RebuildParenListExpr(E->getLParenLoc(), - move_arg(Inits), + Inits, E->getRParenLoc()); } @@ -6875,13 +6830,13 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { static_cast<Expr *>(Object.get())->getLocEnd()); // Transform the call arguments. - ASTOwningVector<Expr*> Args(SemaRef); + SmallVector<Expr*, 8> Args; if (getDerived().TransformExprs(E->getArgs() + 1, E->getNumArgs() - 1, true, Args)) return ExprError(); return getDerived().RebuildCallExpr(Object.get(), FakeLParenLoc, - move_arg(Args), + Args, E->getLocEnd()); } @@ -6905,7 +6860,11 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { if (Callee.isInvalid()) return ExprError(); - ExprResult First = getDerived().TransformExpr(E->getArg(0)); + ExprResult First; + if (E->getOperator() == OO_Amp) + First = getDerived().TransformAddressOfOperand(E->getArg(0)); + else + First = getDerived().TransformExpr(E->getArg(0)); if (First.isInvalid()) return ExprError(); @@ -6922,6 +6881,9 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { (E->getNumArgs() != 2 || Second.get() == E->getArg(1))) return SemaRef.MaybeBindToTemporary(E); + Sema::FPContractStateRAII FPContractState(getSema()); + getSema().FPFeatures.fp_contract = E->isFPContractable(); + return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(), E->getOperatorLoc(), Callee.get(), @@ -6950,7 +6912,7 @@ TreeTransform<Derived>::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) { // Transform arguments. bool ArgChanged = false; - ASTOwningVector<Expr*> Args(SemaRef); + SmallVector<Expr*, 8> Args; if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgChanged)) return ExprError(); @@ -6964,7 +6926,7 @@ TreeTransform<Derived>::TransformCUDAKernelCallExpr(CUDAKernelCallExpr *E) { SourceLocation FakeLParenLoc = ((Expr *)Callee.get())->getSourceRange().getBegin(); return getDerived().RebuildCallExpr(Callee.get(), FakeLParenLoc, - move_arg(Args), + Args, E->getRParenLoc(), EC.get()); } @@ -6989,9 +6951,6 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { SourceLocation FakeLAngleLoc = SemaRef.PP.getLocForEndOfToken(E->getOperatorLoc()); SourceLocation FakeRAngleLoc = E->getSubExpr()->getSourceRange().getBegin(); - SourceLocation FakeRParenLoc - = SemaRef.PP.getLocForEndOfToken( - E->getSubExpr()->getSourceRange().getEnd()); return getDerived().RebuildCXXNamedCastExpr(E->getOperatorLoc(), E->getStmtClass(), FakeLAngleLoc, @@ -6999,7 +6958,7 @@ TreeTransform<Derived>::TransformCXXNamedCastExpr(CXXNamedCastExpr *E) { FakeRAngleLoc, FakeRAngleLoc, SubExpr.get(), - FakeRParenLoc); + E->getRParenLoc()); } template<typename Derived> @@ -7074,7 +7033,8 @@ TreeTransform<Derived>::TransformCXXTypeidExpr(CXXTypeidExpr *E) { // after we perform semantic analysis. We speculatively assume it is // unevaluated; it will get fixed later if the subexpression is in fact // potentially evaluated. - EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated); + EnterExpressionEvaluationContext Unevaluated(SemaRef, Sema::Unevaluated, + Sema::ReuseLambdaContextDecl); ExprResult SubExpr = getDerived().TransformExpr(E->getExprOperand()); if (SubExpr.isInvalid()) @@ -7222,7 +7182,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { // Transform the placement arguments (if any). bool ArgumentChanged = false; - ASTOwningVector<Expr*> PlacementArgs(SemaRef); + SmallVector<Expr*, 8> PlacementArgs; if (getDerived().TransformExprs(E->getPlacementArgs(), E->getNumPlacementArgs(), true, PlacementArgs, &ArgumentChanged)) @@ -7313,7 +7273,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) { return getDerived().RebuildCXXNewExpr(E->getLocStart(), E->isGlobalNew(), /*FIXME:*/E->getLocStart(), - move_arg(PlacementArgs), + PlacementArgs, /*FIXME:*/E->getLocStart(), E->getTypeIdParens(), AllocType, @@ -7512,7 +7472,8 @@ TreeTransform<Derived>::TransformUnresolvedLookupExpr( // If we have template arguments, rebuild them, then rebuild the // templateid expression. TemplateArgumentListInfo TransArgs(Old->getLAngleLoc(), Old->getRAngleLoc()); - if (getDerived().TransformTemplateArguments(Old->getTemplateArgs(), + if (Old->hasExplicitTemplateArgs() && + getDerived().TransformTemplateArguments(Old->getTemplateArgs(), Old->getNumTemplateArgs(), TransArgs)) return ExprError(); @@ -7732,6 +7693,14 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( DependentScopeDeclRefExpr *E) { + return TransformDependentScopeDeclRefExpr(E, /*IsAddressOfOperand*/false); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( + DependentScopeDeclRefExpr *E, + bool IsAddressOfOperand) { NestedNameSpecifierLoc QualifierLoc = getDerived().TransformNestedNameSpecifierLoc(E->getQualifierLoc()); if (!QualifierLoc) @@ -7758,7 +7727,8 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc, TemplateKWLoc, NameInfo, - /*TemplateArgs*/ 0); + /*TemplateArgs*/ 0, + IsAddressOfOperand); } TemplateArgumentListInfo TransArgs(E->getLAngleLoc(), E->getRAngleLoc()); @@ -7770,7 +7740,8 @@ TreeTransform<Derived>::TransformDependentScopeDeclRefExpr( return getDerived().RebuildDependentScopeDeclRefExpr(QualifierLoc, TemplateKWLoc, NameInfo, - &TransArgs); + &TransArgs, + IsAddressOfOperand); } template<typename Derived> @@ -7796,7 +7767,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { return ExprError(); bool ArgumentChanged = false; - ASTOwningVector<Expr*> Args(SemaRef); + SmallVector<Expr*, 8> Args; if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgumentChanged)) return ExprError(); @@ -7813,7 +7784,7 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(), Constructor, E->isElidable(), - move_arg(Args), + Args, E->hadMultipleCandidates(), E->requiresZeroInitialization(), E->getConstructionKind(), @@ -7857,7 +7828,7 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( return ExprError(); bool ArgumentChanged = false; - ASTOwningVector<Expr*> Args(SemaRef); + SmallVector<Expr*, 8> Args; Args.reserve(E->getNumArgs()); if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args, &ArgumentChanged)) @@ -7874,19 +7845,13 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr( return getDerived().RebuildCXXTemporaryObjectExpr(T, /*FIXME:*/T->getTypeLoc().getEndLoc(), - move_arg(Args), + Args, E->getLocEnd()); } template<typename Derived> ExprResult TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { - // Create the local class that will describe the lambda. - CXXRecordDecl *Class - = getSema().createLambdaClosureType(E->getIntroducerRange(), - /*KnownDependent=*/false); - getDerived().transformedLocalDecl(E->getLambdaClass(), Class); - // Transform the type of the lambda parameters and start the definition of // the lambda itself. TypeSourceInfo *MethodTy @@ -7894,6 +7859,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { if (!MethodTy) return ExprError(); + // Create the local class that will describe the lambda. + CXXRecordDecl *Class + = getSema().createLambdaClosureType(E->getIntroducerRange(), + MethodTy, + /*KnownDependent=*/false); + getDerived().transformedLocalDecl(E->getLambdaClass(), Class); + // Transform lambda parameters. llvm::SmallVector<QualType, 4> ParamTypes; llvm::SmallVector<ParmVarDecl *, 4> Params; @@ -8038,7 +8010,7 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( return ExprError(); bool ArgumentChanged = false; - ASTOwningVector<Expr*> Args(SemaRef); + SmallVector<Expr*, 8> Args; Args.reserve(E->arg_size()); if (getDerived().TransformExprs(E->arg_begin(), E->arg_size(), true, Args, &ArgumentChanged)) @@ -8052,7 +8024,7 @@ TreeTransform<Derived>::TransformCXXUnresolvedConstructExpr( // FIXME: we're faking the locations of the commas return getDerived().RebuildCXXUnresolvedConstructExpr(T, E->getLParenLoc(), - move_arg(Args), + Args, E->getRParenLoc()); } @@ -8346,6 +8318,13 @@ TreeTransform<Derived>::TransformSubstNonTypeTemplateParmExpr( template<typename Derived> ExprResult +TreeTransform<Derived>::TransformFunctionParmPackExpr(FunctionParmPackExpr *E) { + // Default behavior is to do nothing with this transformation. + return SemaRef.Owned(E); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformMaterializeTemporaryExpr( MaterializeTemporaryExpr *E) { return getDerived().TransformExpr(E->GetTemporaryExpr()); @@ -8576,7 +8555,7 @@ ExprResult TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { // Transform arguments. bool ArgChanged = false; - ASTOwningVector<Expr*> Args(SemaRef); + SmallVector<Expr*, 8> Args; Args.reserve(E->getNumArgs()); if (getDerived().TransformExprs(E->getArgs(), E->getNumArgs(), false, Args, &ArgChanged)) @@ -8602,7 +8581,7 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { SelLocs, E->getMethodDecl(), E->getLeftLoc(), - move_arg(Args), + Args, E->getRightLoc()); } @@ -8627,7 +8606,7 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { SelLocs, E->getMethodDecl(), E->getLeftLoc(), - move_arg(Args), + Args, E->getRightLoc()); } @@ -8740,7 +8719,7 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { bool ArgumentChanged = false; - ASTOwningVector<Expr*> SubExprs(SemaRef); + SmallVector<Expr*, 8> SubExprs; SubExprs.reserve(E->getNumSubExprs()); if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false, SubExprs, &ArgumentChanged)) @@ -8751,7 +8730,7 @@ TreeTransform<Derived>::TransformShuffleVectorExpr(ShuffleVectorExpr *E) { return SemaRef.Owned(E); return getDerived().RebuildShuffleVectorExpr(E->getBuiltinLoc(), - move_arg(SubExprs), + SubExprs, E->getRParenLoc()); } @@ -8854,7 +8833,7 @@ ExprResult TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) { QualType RetTy = getDerived().TransformType(E->getType()); bool ArgumentChanged = false; - ASTOwningVector<Expr*> SubExprs(SemaRef); + SmallVector<Expr*, 8> SubExprs; SubExprs.reserve(E->getNumSubExprs()); if (getDerived().TransformExprs(E->getSubExprs(), E->getNumSubExprs(), false, SubExprs, &ArgumentChanged)) @@ -8864,7 +8843,7 @@ TreeTransform<Derived>::TransformAtomicExpr(AtomicExpr *E) { !ArgumentChanged) return SemaRef.Owned(E); - return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), move_arg(SubExprs), + return getDerived().RebuildAtomicExpr(E->getBuiltinLoc(), SubExprs, RetTy, E->getOp(), E->getRParenLoc()); } @@ -9185,7 +9164,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, if (Result.isInvalid()) return ExprError(); - return move(Result); + return Result; } } @@ -9200,7 +9179,12 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, // IsAcceptableNonMemberOperatorCandidate for each of these? Functions.append(ULE->decls_begin(), ULE->decls_end()); } else { - Functions.addDecl(cast<DeclRefExpr>(Callee)->getDecl()); + // If we've resolved this to a particular non-member function, just call + // that function. If we resolved it to a member function, + // CreateOverloaded* will find that function for us. + NamedDecl *ND = cast<DeclRefExpr>(Callee)->getDecl(); + if (!isa<CXXMethodDecl>(ND)) + Functions.addDecl(ND); } // Add any functions found via argument-dependent lookup. @@ -9240,7 +9224,7 @@ TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op, if (Result.isInvalid()) return ExprError(); - return move(Result); + return Result; } template<typename Derived> diff --git a/lib/Serialization/ASTCommon.cpp b/lib/Serialization/ASTCommon.cpp index 67f74f7d7a51..0ec03cfe1e68 100644 --- a/lib/Serialization/ASTCommon.cpp +++ b/lib/Serialization/ASTCommon.cpp @@ -60,6 +60,9 @@ serialization::TypeIdxFromBuiltin(const BuiltinType *BT) { case BuiltinType::ObjCId: ID = PREDEF_TYPE_OBJC_ID; break; case BuiltinType::ObjCClass: ID = PREDEF_TYPE_OBJC_CLASS; break; case BuiltinType::ObjCSel: ID = PREDEF_TYPE_OBJC_SEL; break; + case BuiltinType::BuiltinFn: + ID = PREDEF_TYPE_BUILTIN_FN; break; + } return TypeIdx(ID); diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 3adbc5783397..deba302e2138 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -30,13 +30,16 @@ #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" #include "clang/Basic/OnDiskHashTable.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemStatCache.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" #include "clang/Basic/VersionTuple.h" #include "llvm/ADT/StringExtras.h" @@ -62,353 +65,306 @@ using namespace clang::serialization::reader; ASTReaderListener::~ASTReaderListener() {} -bool -PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts) { - const LangOptions &PPLangOpts = PP.getLangOpts(); - -#define LANGOPT(Name, Bits, Default, Description) \ - if (PPLangOpts.Name != LangOpts.Name) { \ - Reader.Diag(diag::err_pch_langopt_mismatch) \ - << Description << LangOpts.Name << PPLangOpts.Name; \ +/// \brief Compare the given set of language options against an existing set of +/// language options. +/// +/// \param Diags If non-NULL, diagnostics will be emitted via this engine. +/// +/// \returns true if the languagae options mis-match, false otherwise. +static bool checkLanguageOptions(const LangOptions &LangOpts, + const LangOptions &ExistingLangOpts, + DiagnosticsEngine *Diags) { +#define LANGOPT(Name, Bits, Default, Description) \ + if (ExistingLangOpts.Name != LangOpts.Name) { \ + if (Diags) \ + Diags->Report(diag::err_pch_langopt_mismatch) \ + << Description << LangOpts.Name << ExistingLangOpts.Name; \ + return true; \ + } + +#define VALUE_LANGOPT(Name, Bits, Default, Description) \ + if (ExistingLangOpts.Name != LangOpts.Name) { \ + if (Diags) \ + Diags->Report(diag::err_pch_langopt_value_mismatch) \ + << Description; \ return true; \ } -#define VALUE_LANGOPT(Name, Bits, Default, Description) \ - if (PPLangOpts.Name != LangOpts.Name) { \ - Reader.Diag(diag::err_pch_langopt_value_mismatch) \ - << Description; \ - return true; \ -} - -#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ - if (PPLangOpts.get##Name() != LangOpts.get##Name()) { \ - Reader.Diag(diag::err_pch_langopt_value_mismatch) \ - << Description; \ - return true; \ +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + if (ExistingLangOpts.get##Name() != LangOpts.get##Name()) { \ + if (Diags) \ + Diags->Report(diag::err_pch_langopt_value_mismatch) \ + << Description; \ + return true; \ } #define BENIGN_LANGOPT(Name, Bits, Default, Description) #define BENIGN_ENUM_LANGOPT(Name, Type, Bits, Default, Description) #include "clang/Basic/LangOptions.def" - if (PPLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) { - Reader.Diag(diag::err_pch_langopt_value_mismatch) + if (ExistingLangOpts.ObjCRuntime != LangOpts.ObjCRuntime) { + if (Diags) + Diags->Report(diag::err_pch_langopt_value_mismatch) << "target Objective-C runtime"; return true; } - + return false; } -bool PCHValidator::ReadTargetTriple(StringRef Triple) { - if (Triple == PP.getTargetInfo().getTriple().str()) - return false; - - Reader.Diag(diag::warn_pch_target_triple) - << Triple << PP.getTargetInfo().getTriple().str(); - return true; -} +/// \brief Compare the given set of target options against an existing set of +/// target options. +/// +/// \param Diags If non-NULL, diagnostics will be emitted via this engine. +/// +/// \returns true if the target options mis-match, false otherwise. +static bool checkTargetOptions(const TargetOptions &TargetOpts, + const TargetOptions &ExistingTargetOpts, + DiagnosticsEngine *Diags) { +#define CHECK_TARGET_OPT(Field, Name) \ + if (TargetOpts.Field != ExistingTargetOpts.Field) { \ + if (Diags) \ + Diags->Report(diag::err_pch_targetopt_mismatch) \ + << Name << TargetOpts.Field << ExistingTargetOpts.Field; \ + return true; \ + } + + CHECK_TARGET_OPT(Triple, "target"); + CHECK_TARGET_OPT(CPU, "target CPU"); + CHECK_TARGET_OPT(ABI, "target ABI"); + CHECK_TARGET_OPT(CXXABI, "target C++ ABI"); + CHECK_TARGET_OPT(LinkerVersion, "target linker version"); +#undef CHECK_TARGET_OPT + + // Compare feature sets. + SmallVector<StringRef, 4> ExistingFeatures( + ExistingTargetOpts.FeaturesAsWritten.begin(), + ExistingTargetOpts.FeaturesAsWritten.end()); + SmallVector<StringRef, 4> ReadFeatures(TargetOpts.FeaturesAsWritten.begin(), + TargetOpts.FeaturesAsWritten.end()); + std::sort(ExistingFeatures.begin(), ExistingFeatures.end()); + std::sort(ReadFeatures.begin(), ReadFeatures.end()); + + unsigned ExistingIdx = 0, ExistingN = ExistingFeatures.size(); + unsigned ReadIdx = 0, ReadN = ReadFeatures.size(); + while (ExistingIdx < ExistingN && ReadIdx < ReadN) { + if (ExistingFeatures[ExistingIdx] == ReadFeatures[ReadIdx]) { + ++ExistingIdx; + ++ReadIdx; + continue; + } -namespace { - struct EmptyStringRef { - bool operator ()(StringRef r) const { return r.empty(); } - }; - struct EmptyBlock { - bool operator ()(const PCHPredefinesBlock &r) const {return r.Data.empty();} - }; -} + if (ReadFeatures[ReadIdx] < ExistingFeatures[ExistingIdx]) { + if (Diags) + Diags->Report(diag::err_pch_targetopt_feature_mismatch) + << false << ReadFeatures[ReadIdx]; + return true; + } -static bool EqualConcatenations(SmallVector<StringRef, 2> L, - PCHPredefinesBlocks R) { - // First, sum up the lengths. - unsigned LL = 0, RL = 0; - for (unsigned I = 0, N = L.size(); I != N; ++I) { - LL += L[I].size(); - } - for (unsigned I = 0, N = R.size(); I != N; ++I) { - RL += R[I].Data.size(); - } - if (LL != RL) - return false; - if (LL == 0 && RL == 0) + if (Diags) + Diags->Report(diag::err_pch_targetopt_feature_mismatch) + << true << ExistingFeatures[ExistingIdx]; return true; - - // Kick out empty parts, they confuse the algorithm below. - L.erase(std::remove_if(L.begin(), L.end(), EmptyStringRef()), L.end()); - R.erase(std::remove_if(R.begin(), R.end(), EmptyBlock()), R.end()); - - // Do it the hard way. At this point, both vectors must be non-empty. - StringRef LR = L[0], RR = R[0].Data; - unsigned LI = 0, RI = 0, LN = L.size(), RN = R.size(); - (void) RN; - for (;;) { - // Compare the current pieces. - if (LR.size() == RR.size()) { - // If they're the same length, it's pretty easy. - if (LR != RR) - return false; - // Both pieces are done, advance. - ++LI; - ++RI; - // If either string is done, they're both done, since they're the same - // length. - if (LI == LN) { - assert(RI == RN && "Strings not the same length after all?"); - return true; - } - LR = L[LI]; - RR = R[RI].Data; - } else if (LR.size() < RR.size()) { - // Right piece is longer. - if (!RR.startswith(LR)) - return false; - ++LI; - assert(LI != LN && "Strings not the same length after all?"); - RR = RR.substr(LR.size()); - LR = L[LI]; - } else { - // Left piece is longer. - if (!LR.startswith(RR)) - return false; - ++RI; - assert(RI != RN && "Strings not the same length after all?"); - LR = LR.substr(RR.size()); - RR = R[RI].Data; - } } -} -static std::pair<FileID, StringRef::size_type> -FindMacro(const PCHPredefinesBlocks &Buffers, StringRef MacroDef) { - std::pair<FileID, StringRef::size_type> Res; - for (unsigned I = 0, N = Buffers.size(); I != N; ++I) { - Res.second = Buffers[I].Data.find(MacroDef); - if (Res.second != StringRef::npos) { - Res.first = Buffers[I].BufferID; - break; - } + if (ExistingIdx < ExistingN) { + if (Diags) + Diags->Report(diag::err_pch_targetopt_feature_mismatch) + << true << ExistingFeatures[ExistingIdx]; + return true; } - return Res; -} - -bool PCHValidator::ReadPredefinesBuffer(const PCHPredefinesBlocks &Buffers, - StringRef OriginalFileName, - std::string &SuggestedPredefines, - FileManager &FileMgr) { - // We are in the context of an implicit include, so the predefines buffer will - // have a #include entry for the PCH file itself (as normalized by the - // preprocessor initialization). Find it and skip over it in the checking - // below. - SmallString<256> PCHInclude; - PCHInclude += "#include \""; - PCHInclude += HeaderSearch::NormalizeDashIncludePath(OriginalFileName, - FileMgr); - PCHInclude += "\"\n"; - std::pair<StringRef,StringRef> Split = - StringRef(PP.getPredefines()).split(PCHInclude.str()); - StringRef Left = Split.first, Right = Split.second; - if (Left == PP.getPredefines()) { - Error("Missing PCH include entry!"); + + if (ReadIdx < ReadN) { + if (Diags) + Diags->Report(diag::err_pch_targetopt_feature_mismatch) + << false << ReadFeatures[ReadIdx]; return true; } - // If the concatenation of all the PCH buffers is equal to the adjusted - // command line, we're done. - SmallVector<StringRef, 2> CommandLine; - CommandLine.push_back(Left); - CommandLine.push_back(Right); - if (EqualConcatenations(CommandLine, Buffers)) - return false; + return false; +} - SourceManager &SourceMgr = PP.getSourceManager(); - - // The predefines buffers are different. Determine what the differences are, - // and whether they require us to reject the PCH file. - SmallVector<StringRef, 8> PCHLines; - for (unsigned I = 0, N = Buffers.size(); I != N; ++I) - Buffers[I].Data.split(PCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); - - SmallVector<StringRef, 8> CmdLineLines; - Left.split(CmdLineLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); - - // Pick out implicit #includes after the PCH and don't consider them for - // validation; we will insert them into SuggestedPredefines so that the - // preprocessor includes them. - std::string IncludesAfterPCH; - SmallVector<StringRef, 8> AfterPCHLines; - Right.split(AfterPCHLines, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false); - for (unsigned i = 0, e = AfterPCHLines.size(); i != e; ++i) { - if (AfterPCHLines[i].startswith("#include ")) { - IncludesAfterPCH += AfterPCHLines[i]; - IncludesAfterPCH += '\n'; - } else { - CmdLineLines.push_back(AfterPCHLines[i]); - } - } - - // Make sure we add the includes last into SuggestedPredefines before we - // exit this function. - struct AddIncludesRAII { - std::string &SuggestedPredefines; - std::string &IncludesAfterPCH; - - AddIncludesRAII(std::string &SuggestedPredefines, - std::string &IncludesAfterPCH) - : SuggestedPredefines(SuggestedPredefines), - IncludesAfterPCH(IncludesAfterPCH) { } - ~AddIncludesRAII() { - SuggestedPredefines += IncludesAfterPCH; - } - } AddIncludes(SuggestedPredefines, IncludesAfterPCH); - - // Sort both sets of predefined buffer lines, since we allow some extra - // definitions and they may appear at any point in the output. - std::sort(CmdLineLines.begin(), CmdLineLines.end()); - std::sort(PCHLines.begin(), PCHLines.end()); - - // Determine which predefines that were used to build the PCH file are missing - // from the command line. - std::vector<StringRef> MissingPredefines; - std::set_difference(PCHLines.begin(), PCHLines.end(), - CmdLineLines.begin(), CmdLineLines.end(), - std::back_inserter(MissingPredefines)); - - bool MissingDefines = false; - bool ConflictingDefines = false; - for (unsigned I = 0, N = MissingPredefines.size(); I != N; ++I) { - StringRef Missing = MissingPredefines[I]; - if (Missing.startswith("#include ")) { - // An -include was specified when generating the PCH; it is included in - // the PCH, just ignore it. - continue; - } - if (!Missing.startswith("#define ")) { - Reader.Diag(diag::warn_pch_compiler_options_mismatch); - return true; - } +bool +PCHValidator::ReadLanguageOptions(const LangOptions &LangOpts, + bool Complain) { + const LangOptions &ExistingLangOpts = PP.getLangOpts(); + return checkLanguageOptions(LangOpts, ExistingLangOpts, + Complain? &Reader.Diags : 0); +} - // This is a macro definition. Determine the name of the macro we're - // defining. - std::string::size_type StartOfMacroName = strlen("#define "); - std::string::size_type EndOfMacroName - = Missing.find_first_of("( \n\r", StartOfMacroName); - assert(EndOfMacroName != std::string::npos && - "Couldn't find the end of the macro name"); - StringRef MacroName = Missing.slice(StartOfMacroName, EndOfMacroName); - - // Determine whether this macro was given a different definition on the - // command line. - std::string MacroDefStart = "#define " + MacroName.str(); - std::string::size_type MacroDefLen = MacroDefStart.size(); - SmallVector<StringRef, 8>::iterator ConflictPos - = std::lower_bound(CmdLineLines.begin(), CmdLineLines.end(), - MacroDefStart); - for (; ConflictPos != CmdLineLines.end(); ++ConflictPos) { - if (!ConflictPos->startswith(MacroDefStart)) { - // Different macro; we're done. - ConflictPos = CmdLineLines.end(); - break; - } +bool PCHValidator::ReadTargetOptions(const TargetOptions &TargetOpts, + bool Complain) { + const TargetOptions &ExistingTargetOpts = PP.getTargetInfo().getTargetOpts(); + return checkTargetOptions(TargetOpts, ExistingTargetOpts, + Complain? &Reader.Diags : 0); +} - assert(ConflictPos->size() > MacroDefLen && - "Invalid #define in predefines buffer?"); - if ((*ConflictPos)[MacroDefLen] != ' ' && - (*ConflictPos)[MacroDefLen] != '(') - continue; // Longer macro name; keep trying. +namespace { + typedef llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> > + MacroDefinitionsMap; +} - // We found a conflicting macro definition. - break; - } +/// \brief Collect the macro definitions provided by the given preprocessor +/// options. +static void collectMacroDefinitions(const PreprocessorOptions &PPOpts, + MacroDefinitionsMap &Macros, + SmallVectorImpl<StringRef> *MacroNames = 0){ + for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) { + StringRef Macro = PPOpts.Macros[I].first; + bool IsUndef = PPOpts.Macros[I].second; - if (ConflictPos != CmdLineLines.end()) { - Reader.Diag(diag::warn_cmdline_conflicting_macro_def) - << MacroName; + std::pair<StringRef, StringRef> MacroPair = Macro.split('='); + StringRef MacroName = MacroPair.first; + StringRef MacroBody = MacroPair.second; - // Show the definition of this macro within the PCH file. - std::pair<FileID, StringRef::size_type> MacroLoc = - FindMacro(Buffers, Missing); - assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!"); - SourceLocation PCHMissingLoc = - SourceMgr.getLocForStartOfFile(MacroLoc.first) - .getLocWithOffset(MacroLoc.second); - Reader.Diag(PCHMissingLoc, diag::note_pch_macro_defined_as) << MacroName; + // For an #undef'd macro, we only care about the name. + if (IsUndef) { + if (MacroNames && !Macros.count(MacroName)) + MacroNames->push_back(MacroName); - ConflictingDefines = true; + Macros[MacroName] = std::make_pair("", true); continue; } - // If the macro doesn't conflict, then we'll just pick up the macro - // definition from the PCH file. Warn the user that they made a mistake. - if (ConflictingDefines) - continue; // Don't complain if there are already conflicting defs - - if (!MissingDefines) { - Reader.Diag(diag::warn_cmdline_missing_macro_defs); - MissingDefines = true; + // For a #define'd macro, figure out the actual definition. + if (MacroName.size() == Macro.size()) + MacroBody = "1"; + else { + // Note: GCC drops anything following an end-of-line character. + StringRef::size_type End = MacroBody.find_first_of("\n\r"); + MacroBody = MacroBody.substr(0, End); } - // Show the definition of this macro within the PCH file. - std::pair<FileID, StringRef::size_type> MacroLoc = - FindMacro(Buffers, Missing); - assert(MacroLoc.second!=StringRef::npos && "Unable to find macro!"); - SourceLocation PCHMissingLoc = - SourceMgr.getLocForStartOfFile(MacroLoc.first) - .getLocWithOffset(MacroLoc.second); - Reader.Diag(PCHMissingLoc, diag::note_using_macro_def_from_pch); + if (MacroNames && !Macros.count(MacroName)) + MacroNames->push_back(MacroName); + Macros[MacroName] = std::make_pair(MacroBody, false); } +} + +/// \brief Check the preprocessor options deserialized from the control block +/// against the preprocessor options in an existing preprocessor. +/// +/// \param Diags If non-null, produce diagnostics for any mismatches incurred. +static bool checkPreprocessorOptions(const PreprocessorOptions &PPOpts, + const PreprocessorOptions &ExistingPPOpts, + DiagnosticsEngine *Diags, + FileManager &FileMgr, + std::string &SuggestedPredefines) { + // Check macro definitions. + MacroDefinitionsMap ASTFileMacros; + collectMacroDefinitions(PPOpts, ASTFileMacros); + MacroDefinitionsMap ExistingMacros; + SmallVector<StringRef, 4> ExistingMacroNames; + collectMacroDefinitions(ExistingPPOpts, ExistingMacros, &ExistingMacroNames); + + for (unsigned I = 0, N = ExistingMacroNames.size(); I != N; ++I) { + // Dig out the macro definition in the existing preprocessor options. + StringRef MacroName = ExistingMacroNames[I]; + std::pair<StringRef, bool> Existing = ExistingMacros[MacroName]; + + // Check whether we know anything about this macro name or not. + llvm::StringMap<std::pair<StringRef, bool /*IsUndef*/> >::iterator Known + = ASTFileMacros.find(MacroName); + if (Known == ASTFileMacros.end()) { + // FIXME: Check whether this identifier was referenced anywhere in the + // AST file. If so, we should reject the AST file. Unfortunately, this + // information isn't in the control block. What shall we do about it? + + if (Existing.second) { + SuggestedPredefines += "#undef "; + SuggestedPredefines += MacroName.str(); + SuggestedPredefines += '\n'; + } else { + SuggestedPredefines += "#define "; + SuggestedPredefines += MacroName.str(); + SuggestedPredefines += ' '; + SuggestedPredefines += Existing.first.str(); + SuggestedPredefines += '\n'; + } + continue; + } - if (ConflictingDefines) - return true; - - // Determine what predefines were introduced based on command-line - // parameters that were not present when building the PCH - // file. Extra #defines are okay, so long as the identifiers being - // defined were not used within the precompiled header. - std::vector<StringRef> ExtraPredefines; - std::set_difference(CmdLineLines.begin(), CmdLineLines.end(), - PCHLines.begin(), PCHLines.end(), - std::back_inserter(ExtraPredefines)); - for (unsigned I = 0, N = ExtraPredefines.size(); I != N; ++I) { - StringRef &Extra = ExtraPredefines[I]; - if (!Extra.startswith("#define ")) { - Reader.Diag(diag::warn_pch_compiler_options_mismatch); + // If the macro was defined in one but undef'd in the other, we have a + // conflict. + if (Existing.second != Known->second.second) { + if (Diags) { + Diags->Report(diag::err_pch_macro_def_undef) + << MacroName << Known->second.second; + } return true; } - // This is an extra macro definition. Determine the name of the - // macro we're defining. - std::string::size_type StartOfMacroName = strlen("#define "); - std::string::size_type EndOfMacroName - = Extra.find_first_of("( \n\r", StartOfMacroName); - assert(EndOfMacroName != std::string::npos && - "Couldn't find the end of the macro name"); - StringRef MacroName = Extra.slice(StartOfMacroName, EndOfMacroName); - - // Check whether this name was used somewhere in the PCH file. If - // so, defining it as a macro could change behavior, so we reject - // the PCH file. - if (IdentifierInfo *II = Reader.get(MacroName)) { - Reader.Diag(diag::warn_macro_name_used_in_pch) << II; - return true; + // If the macro was #undef'd in both, or if the macro bodies are identical, + // it's fine. + if (Existing.second || Existing.first == Known->second.first) + continue; + + // The macro bodies differ; complain. + if (Diags) { + Diags->Report(diag::err_pch_macro_def_conflict) + << MacroName << Known->second.first << Existing.first; } + return true; + } - // Add this definition to the suggested predefines buffer. - SuggestedPredefines += Extra; - SuggestedPredefines += '\n'; + // Check whether we're using predefines. + if (PPOpts.UsePredefines != ExistingPPOpts.UsePredefines) { + if (Diags) { + Diags->Report(diag::err_pch_undef) << ExistingPPOpts.UsePredefines; + } + return true; + } + + // Compute the #include and #include_macros lines we need. + for (unsigned I = 0, N = ExistingPPOpts.Includes.size(); I != N; ++I) { + StringRef File = ExistingPPOpts.Includes[I]; + if (File == ExistingPPOpts.ImplicitPCHInclude) + continue; + + if (std::find(PPOpts.Includes.begin(), PPOpts.Includes.end(), File) + != PPOpts.Includes.end()) + continue; + + SuggestedPredefines += "#include \""; + SuggestedPredefines += + HeaderSearch::NormalizeDashIncludePath(File, FileMgr); + SuggestedPredefines += "\"\n"; + } + + for (unsigned I = 0, N = ExistingPPOpts.MacroIncludes.size(); I != N; ++I) { + StringRef File = ExistingPPOpts.MacroIncludes[I]; + if (std::find(PPOpts.MacroIncludes.begin(), PPOpts.MacroIncludes.end(), + File) + != PPOpts.MacroIncludes.end()) + continue; + + SuggestedPredefines += "#__include_macros \""; + SuggestedPredefines += + HeaderSearch::NormalizeDashIncludePath(File, FileMgr); + SuggestedPredefines += "\"\n##\n"; } - // If we get here, it's because the predefines buffer had compatible - // contents. Accept the PCH file. return false; } +bool PCHValidator::ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, + bool Complain, + std::string &SuggestedPredefines) { + const PreprocessorOptions &ExistingPPOpts = PP.getPreprocessorOpts(); + + return checkPreprocessorOptions(PPOpts, ExistingPPOpts, + Complain? &Reader.Diags : 0, + PP.getFileManager(), + SuggestedPredefines); +} + void PCHValidator::ReadHeaderFileInfo(const HeaderFileInfo &HFI, unsigned ID) { PP.getHeaderSearchInfo().setHeaderFileInfoForUID(HFI, ID); ++NumHeaderInfos; } -void PCHValidator::ReadCounter(unsigned Value) { +void PCHValidator::ReadCounter(const ModuleFile &M, unsigned Value) { PP.setCounterValue(Value); } @@ -527,6 +483,7 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, return II; } + unsigned ObjCOrBuiltinID = ReadUnalignedLE16(d); unsigned Bits = ReadUnalignedLE16(d); bool CPlusPlusOperatorKeyword = Bits & 0x01; Bits >>= 1; @@ -536,13 +493,11 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, Bits >>= 1; bool ExtensionToken = Bits & 0x01; Bits >>= 1; - bool hasMacroDefinition = Bits & 0x01; + bool hadMacroDefinition = Bits & 0x01; Bits >>= 1; - unsigned ObjCOrBuiltinID = Bits & 0x7FF; - Bits >>= 11; assert(Bits == 0 && "Extra bits in the identifier?"); - DataLen -= 6; + DataLen -= 8; // Build the IdentifierInfo itself and link the identifier ID with // the new IdentifierInfo. @@ -570,31 +525,14 @@ IdentifierInfo *ASTIdentifierLookupTrait::ReadData(const internal_key_type& k, // If this identifier is a macro, deserialize the macro // definition. - if (hasMacroDefinition) { - // FIXME: Check for conflicts? - uint32_t Offset = ReadUnalignedLE32(d); - unsigned LocalSubmoduleID = ReadUnalignedLE32(d); - - // Determine whether this macro definition should be visible now, or - // whether it is in a hidden submodule. - bool Visible = true; - if (SubmoduleID GlobalSubmoduleID - = Reader.getGlobalSubmoduleID(F, LocalSubmoduleID)) { - if (Module *Owner = Reader.getSubmodule(GlobalSubmoduleID)) { - if (Owner->NameVisibility == Module::Hidden) { - // The owning module is not visible, and this macro definition should - // not be, either. - Visible = false; - - // Note that this macro definition was hidden because its owning - // module is not yet visible. - Reader.HiddenNamesMap[Owner].push_back(II); - } - } + if (hadMacroDefinition) { + SmallVector<MacroID, 4> MacroIDs; + while (uint32_t LocalID = ReadUnalignedLE32(d)) { + MacroIDs.push_back(Reader.getGlobalMacroID(F, LocalID)); + DataLen -= 4; } - - Reader.setIdentifierIsMacro(II, F, Offset, Visible); - DataLen -= 8; + DataLen -= 4; + Reader.setIdentifierIsMacro(II, MacroIDs); } Reader.SetIdentifierInfo(ID, II); @@ -780,16 +718,6 @@ void ASTReader::Error(unsigned DiagID, Diag(DiagID) << Arg1 << Arg2; } -/// \brief Tell the AST listener about the predefines buffers in the chain. -bool ASTReader::CheckPredefinesBuffers() { - if (Listener) - return Listener->ReadPredefinesBuffer(PCHPredefinesBuffers, - ActualOriginalFileName, - SuggestedPredefines, - FileMgr); - return false; -} - //===----------------------------------------------------------------------===// // Source Manager Deserialization //===----------------------------------------------------------------------===// @@ -808,7 +736,7 @@ bool ASTReader::ParseLineTable(ModuleFile &F, unsigned FilenameLen = Record[Idx++]; std::string Filename(&Record[Idx], &Record[Idx] + FilenameLen); Idx += FilenameLen; - MaybeAddSystemRootToFilename(Filename); + MaybeAddSystemRootToFilename(F, Filename); FileIDs[I] = LineTable.getLineTableFilenameID(Filename); } @@ -841,106 +769,8 @@ bool ASTReader::ParseLineTable(ModuleFile &F, return false; } -namespace { - -class ASTStatData { -public: - const ino_t ino; - const dev_t dev; - const mode_t mode; - const time_t mtime; - const off_t size; - - ASTStatData(ino_t i, dev_t d, mode_t mo, time_t m, off_t s) - : ino(i), dev(d), mode(mo), mtime(m), size(s) {} -}; - -class ASTStatLookupTrait { - public: - typedef const char *external_key_type; - typedef const char *internal_key_type; - - typedef ASTStatData data_type; - - static unsigned ComputeHash(const char *path) { - return llvm::HashString(path); - } - - static internal_key_type GetInternalKey(const char *path) { return path; } - - static bool EqualKey(internal_key_type a, internal_key_type b) { - return strcmp(a, b) == 0; - } - - static std::pair<unsigned, unsigned> - ReadKeyDataLength(const unsigned char*& d) { - unsigned KeyLen = (unsigned) clang::io::ReadUnalignedLE16(d); - unsigned DataLen = (unsigned) *d++; - return std::make_pair(KeyLen + 1, DataLen); - } - - static internal_key_type ReadKey(const unsigned char *d, unsigned) { - return (const char *)d; - } - - static data_type ReadData(const internal_key_type, const unsigned char *d, - unsigned /*DataLen*/) { - using namespace clang::io; - - ino_t ino = (ino_t) ReadUnalignedLE32(d); - dev_t dev = (dev_t) ReadUnalignedLE32(d); - mode_t mode = (mode_t) ReadUnalignedLE16(d); - time_t mtime = (time_t) ReadUnalignedLE64(d); - off_t size = (off_t) ReadUnalignedLE64(d); - return data_type(ino, dev, mode, mtime, size); - } -}; - -/// \brief stat() cache for precompiled headers. -/// -/// This cache is very similar to the stat cache used by pretokenized -/// headers. -class ASTStatCache : public FileSystemStatCache { - typedef OnDiskChainedHashTable<ASTStatLookupTrait> CacheTy; - CacheTy *Cache; - - unsigned &NumStatHits, &NumStatMisses; -public: - ASTStatCache(const unsigned char *Buckets, const unsigned char *Base, - unsigned &NumStatHits, unsigned &NumStatMisses) - : Cache(0), NumStatHits(NumStatHits), NumStatMisses(NumStatMisses) { - Cache = CacheTy::Create(Buckets, Base); - } - - ~ASTStatCache() { delete Cache; } - - LookupResult getStat(const char *Path, struct stat &StatBuf, - int *FileDescriptor) { - // Do the lookup for the file's data in the AST file. - CacheTy::iterator I = Cache->find(Path); - - // If we don't get a hit in the AST file just forward to 'stat'. - if (I == Cache->end()) { - ++NumStatMisses; - return statChained(Path, StatBuf, FileDescriptor); - } - - ++NumStatHits; - ASTStatData Data = *I; - - StatBuf.st_ino = Data.ino; - StatBuf.st_dev = Data.dev; - StatBuf.st_mtime = Data.mtime; - StatBuf.st_mode = Data.mode; - StatBuf.st_size = Data.size; - return CacheExists; - } -}; -} // end anonymous namespace - - /// \brief Read a source manager block -ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) { +bool ASTReader::ReadSourceManagerBlock(ModuleFile &F) { using namespace SrcMgr; llvm::BitstreamCursor &SLocEntryCursor = F.SLocEntryCursor; @@ -954,13 +784,13 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) { // The stream itself is going to skip over the source manager block. if (F.Stream.SkipBlock()) { Error("malformed block record in AST file"); - return Failure; + return true; } // Enter the source manager block. if (SLocEntryCursor.EnterSubBlock(SOURCE_MANAGER_BLOCK_ID)) { Error("malformed source manager block record in AST file"); - return Failure; + return true; } RecordData Record; @@ -969,9 +799,9 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) { if (Code == llvm::bitc::END_BLOCK) { if (SLocEntryCursor.ReadBlockEnd()) { Error("error at end of Source Manager block in AST file"); - return Failure; + return true; } - return Success; + return false; } if (Code == llvm::bitc::ENTER_SUBBLOCK) { @@ -979,7 +809,7 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) { SLocEntryCursor.ReadSubBlockID(); if (SLocEntryCursor.SkipBlock()) { Error("malformed block record in AST file"); - return Failure; + return true; } continue; } @@ -1001,7 +831,7 @@ ASTReader::ASTReadResult ASTReader::ReadSourceManagerBlock(ModuleFile &F) { case SM_SLOC_BUFFER_ENTRY: case SM_SLOC_EXPANSION_ENTRY: // Once we hit one of the source location entries, we're done. - return Success; + return false; } } } @@ -1039,14 +869,13 @@ resolveFileRelativeToOriginalDir(const std::string &Filename, return currPCHPath.str(); } -/// \brief Read in the source location entry with the given ID. -ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) { +bool ASTReader::ReadSLocEntry(int ID) { if (ID == 0) - return Success; + return false; if (unsigned(-ID) - 2 >= getTotalNumSLocs() || ID > 0) { Error("source location entry ID out-of-range for AST file"); - return Failure; + return true; } ModuleFile *F = GlobalSLocEntryMap.find(-ID)->second; @@ -1060,7 +889,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) { Code == llvm::bitc::ENTER_SUBBLOCK || Code == llvm::bitc::DEFINE_ABBREV) { Error("incorrectly-formatted source location entry in AST file"); - return Failure; + return true; } RecordData Record; @@ -1069,58 +898,18 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) { switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { default: Error("incorrectly-formatted source location entry in AST file"); - return Failure; + return true; case SM_SLOC_FILE_ENTRY: { - if (Record.size() < 7) { - Error("source location entry is incorrect"); - return Failure; - } - // We will detect whether a file changed and return 'Failure' for it, but // we will also try to fail gracefully by setting up the SLocEntry. - ASTReader::ASTReadResult Result = Success; - - bool OverriddenBuffer = Record[6]; - - std::string OrigFilename(BlobStart, BlobStart + BlobLen); - std::string Filename = OrigFilename; - MaybeAddSystemRootToFilename(Filename); - const FileEntry *File = - OverriddenBuffer? FileMgr.getVirtualFile(Filename, (off_t)Record[4], - (time_t)Record[5]) - : FileMgr.getFile(Filename, /*OpenFile=*/false); - if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() && - OriginalDir != CurrentDir) { - std::string resolved = resolveFileRelativeToOriginalDir(Filename, - OriginalDir, - CurrentDir); - if (!resolved.empty()) - File = FileMgr.getFile(resolved); - } - if (File == 0) - File = FileMgr.getVirtualFile(Filename, (off_t)Record[4], - (time_t)Record[5]); - if (File == 0) { - std::string ErrorStr = "could not find file '"; - ErrorStr += Filename; - ErrorStr += "' referenced by AST file"; - Error(ErrorStr.c_str()); - return Failure; - } + unsigned InputID = Record[4]; + InputFile IF = getInputFile(*F, InputID); + const FileEntry *File = IF.getPointer(); + bool OverriddenBuffer = IF.getInt(); - if (!DisableValidation && - ((off_t)Record[4] != File->getSize() -#if !defined(LLVM_ON_WIN32) - // In our regression testing, the Windows file system seems to - // have inconsistent modification times that sometimes - // erroneously trigger this error-handling path. - || (time_t)Record[5] != File->getModificationTime() -#endif - )) { - Error(diag::err_fe_pch_file_modified, Filename); - Result = Failure; - } + if (!IF.getPointer()) + return true; SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); if (IncludeLoc.isInvalid() && F->Kind != MK_MainFile) { @@ -1133,12 +922,12 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) { ID, BaseOffset + Record[0]); SrcMgr::FileInfo &FileInfo = const_cast<SrcMgr::FileInfo&>(SourceMgr.getSLocEntry(FID).getFile()); - FileInfo.NumCreatedFIDs = Record[7]; + FileInfo.NumCreatedFIDs = Record[5]; if (Record[3]) FileInfo.setHasLineDirectives(); - const DeclID *FirstDecl = F->FileSortedDecls + Record[8]; - unsigned NumFileDecls = Record[9]; + const DeclID *FirstDecl = F->FileSortedDecls + Record[6]; + unsigned NumFileDecls = Record[7]; if (NumFileDecls) { assert(F->FileSortedDecls && "FILE_SORTED_DECLS not encountered yet ?"); FileDeclIDs[FID] = FileDeclsInfo(F, llvm::makeArrayRef(FirstDecl, @@ -1157,23 +946,24 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) { if (RecCode != SM_SLOC_BUFFER_BLOB) { Error("AST record has invalid code"); - return Failure; + return true; } llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1), - Filename); + File->getName()); SourceMgr.overrideFileContents(File, Buffer); } - if (Result == Failure) - return Failure; break; } case SM_SLOC_BUFFER_ENTRY: { const char *Name = BlobStart; unsigned Offset = Record[0]; + SrcMgr::CharacteristicKind + FileCharacter = (SrcMgr::CharacteristicKind)Record[2]; + SourceLocation IncludeLoc = ReadSourceLocation(*F, Record[1]); unsigned Code = SLocEntryCursor.ReadCode(); Record.clear(); unsigned RecCode @@ -1181,23 +971,14 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) { if (RecCode != SM_SLOC_BUFFER_BLOB) { Error("AST record has invalid code"); - return Failure; + return true; } llvm::MemoryBuffer *Buffer = llvm::MemoryBuffer::getMemBuffer(StringRef(BlobStart, BlobLen - 1), Name); - FileID BufferID = SourceMgr.createFileIDForMemBuffer(Buffer, ID, - BaseOffset + Offset); - - if (strcmp(Name, "<built-in>") == 0 && F->Kind == MK_PCH) { - PCHPredefinesBlock Block = { - BufferID, - StringRef(BlobStart, BlobLen - 1) - }; - PCHPredefinesBuffers.push_back(Block); - } - + SourceMgr.createFileIDForMemBuffer(Buffer, FileCharacter, ID, + BaseOffset + Offset, IncludeLoc); break; } @@ -1213,7 +994,7 @@ ASTReader::ASTReadResult ASTReader::ReadSLocEntryRecord(int ID) { } } - return Success; + return false; } /// \brief Find the location where the module F is imported. @@ -1258,7 +1039,8 @@ bool ASTReader::ReadBlockAbbrevs(llvm::BitstreamCursor &Cursor, } } -void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { +void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset, + MacroInfo *Hint) { llvm::BitstreamCursor &Stream = F.MacroCursor; // Keep track of where we are in the stream, then jump back there @@ -1270,6 +1052,24 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { SmallVector<IdentifierInfo*, 16> MacroArgs; MacroInfo *Macro = 0; + // RAII object to add the loaded macro information once we're done + // adding tokens. + struct AddLoadedMacroInfoRAII { + Preprocessor &PP; + MacroInfo *Hint; + MacroInfo *MI; + IdentifierInfo *II; + + AddLoadedMacroInfoRAII(Preprocessor &PP, MacroInfo *Hint) + : PP(PP), Hint(Hint), MI(), II() { } + ~AddLoadedMacroInfoRAII( ) { + if (MI) { + // Finally, install the macro. + PP.addLoadedMacroInfo(II, MI, Hint); + } + } + } AddLoadedMacroInfo(PP, Hint); + while (true) { unsigned Code = Stream.ReadCode(); switch (Code) { @@ -1312,18 +1112,31 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { Error("macro must have a name in AST file"); return; } - - SourceLocation Loc = ReadSourceLocation(F, Record[1]); - bool isUsed = Record[2]; + unsigned GlobalID = getGlobalMacroID(F, Record[1]); + + // If this macro has already been loaded, don't do so again. + if (MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS]) + return; + + SubmoduleID GlobalSubmoduleID = getGlobalSubmoduleID(F, Record[2]); + unsigned NextIndex = 3; + SourceLocation Loc = ReadSourceLocation(F, Record, NextIndex); MacroInfo *MI = PP.AllocateMacroInfo(Loc); - MI->setIsUsed(isUsed); + + // Record this macro. + MacrosLoaded[GlobalID - NUM_PREDEF_MACRO_IDS] = MI; + + SourceLocation UndefLoc = ReadSourceLocation(F, Record, NextIndex); + if (UndefLoc.isValid()) + MI->setUndefLoc(UndefLoc); + + MI->setIsUsed(Record[NextIndex++]); MI->setIsFromAST(); - bool IsPublic = Record[3]; - unsigned NextIndex = 4; + bool IsPublic = Record[NextIndex++]; MI->setVisibility(IsPublic, ReadSourceLocation(F, Record, NextIndex)); - + if (RecType == PP_MACRO_FUNCTION_LIKE) { // Decode function-like macro info. bool isC99VarArgs = Record[NextIndex++]; @@ -1341,8 +1154,60 @@ void ASTReader::ReadMacroRecord(ModuleFile &F, uint64_t Offset) { PP.getPreprocessorAllocator()); } - // Finally, install the macro. - PP.setMacroInfo(II, MI, /*LoadedFromAST=*/true); + if (DeserializationListener) + DeserializationListener->MacroRead(GlobalID, MI); + + // If an update record marked this as undefined, do so now. + // FIXME: Only if the submodule this update came from is visible? + MacroUpdatesMap::iterator Update = MacroUpdates.find(GlobalID); + if (Update != MacroUpdates.end()) { + if (MI->getUndefLoc().isInvalid()) { + for (unsigned I = 0, N = Update->second.size(); I != N; ++I) { + bool Hidden = false; + if (unsigned SubmoduleID = Update->second[I].first) { + if (Module *Owner = getSubmodule(SubmoduleID)) { + if (Owner->NameVisibility == Module::Hidden) { + // Note that this #undef is hidden. + Hidden = true; + + // Record this hiding for later. + HiddenNamesMap[Owner].push_back( + HiddenName(II, MI, Update->second[I].second.UndefLoc)); + } + } + } + + if (!Hidden) { + MI->setUndefLoc(Update->second[I].second.UndefLoc); + if (PPMutationListener *Listener = PP.getPPMutationListener()) + Listener->UndefinedMacro(MI); + break; + } + } + } + MacroUpdates.erase(Update); + } + + // Determine whether this macro definition is visible. + bool Hidden = !MI->isPublic(); + if (!Hidden && GlobalSubmoduleID) { + if (Module *Owner = getSubmodule(GlobalSubmoduleID)) { + if (Owner->NameVisibility == Module::Hidden) { + // The owning module is not visible, and this macro definition + // should not be, either. + Hidden = true; + + // Note that this macro definition was hidden because its owning + // module is not yet visible. + HiddenNamesMap[Owner].push_back(HiddenName(II, MI)); + } + } + } + MI->setHidden(Hidden); + + // Make sure we install the macro once we're done. + AddLoadedMacroInfo.MI = MI; + AddLoadedMacroInfo.II = II; // Remember that we saw this macro last so that we add the tokens that // form its body to it. @@ -1451,18 +1316,16 @@ HeaderFileInfoTrait::ReadData(const internal_key_type, const unsigned char *d, return HFI; } -void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ModuleFile &F, - uint64_t LocalOffset, bool Visible) { - if (Visible) { - // Note that this identifier has a macro definition. - II->setHasMacroDefinition(true); - } - - // Adjust the offset to a global offset. - UnreadMacroRecordOffsets[II] = F.GlobalBitOffset + LocalOffset; +void ASTReader::setIdentifierIsMacro(IdentifierInfo *II, ArrayRef<MacroID> IDs){ + II->setHadMacroDefinition(true); + assert(NumCurrentElementsDeserializing > 0 &&"Missing deserialization guard"); + PendingMacroIDs[II].append(IDs.begin(), IDs.end()); } void ASTReader::ReadDefinedMacros() { + // Note that we are loading defined macros. + Deserializing Macros(this); + for (ModuleReverseIterator I = ModuleMgr.rbegin(), E = ModuleMgr.rend(); I != E; ++I) { llvm::BitstreamCursor &MacroCursor = (*I)->MacroCursor; @@ -1514,26 +1377,6 @@ void ASTReader::ReadDefinedMacros() { } } } - - // Drain the unread macro-record offsets map. - while (!UnreadMacroRecordOffsets.empty()) - LoadMacroDefinition(UnreadMacroRecordOffsets.begin()); -} - -void ASTReader::LoadMacroDefinition( - llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos) { - assert(Pos != UnreadMacroRecordOffsets.end() && "Unknown macro definition"); - uint64_t Offset = Pos->second; - UnreadMacroRecordOffsets.erase(Pos); - - RecordLocation Loc = getLocalBitOffset(Offset); - ReadMacroRecord(*Loc.F, Loc.Offset); -} - -void ASTReader::LoadMacroDefinition(IdentifierInfo *II) { - llvm::DenseMap<IdentifierInfo *, uint64_t>::iterator Pos - = UnreadMacroRecordOffsets.find(II); - LoadMacroDefinition(Pos); } namespace { @@ -1582,6 +1425,9 @@ namespace { } void ASTReader::updateOutOfDateIdentifier(IdentifierInfo &II) { + // Note that we are loading an identifier. + Deserializing AnIdentifier(this); + unsigned PriorGeneration = 0; if (getContext().getLangOpts().Modules) PriorGeneration = IdentifierGeneration[&II]; @@ -1602,14 +1448,132 @@ void ASTReader::markIdentifierUpToDate(IdentifierInfo *II) { IdentifierGeneration[II] = CurrentGeneration; } +llvm::PointerIntPair<const FileEntry *, 1, bool> +ASTReader::getInputFile(ModuleFile &F, unsigned ID, bool Complain) { + // If this ID is bogus, just return an empty input file. + if (ID == 0 || ID > F.InputFilesLoaded.size()) + return InputFile(); + + // If we've already loaded this input file, return it. + if (F.InputFilesLoaded[ID-1].getPointer()) + return F.InputFilesLoaded[ID-1]; + + // Go find this input file. + llvm::BitstreamCursor &Cursor = F.InputFilesCursor; + SavedStreamPosition SavedPosition(Cursor); + Cursor.JumpToBit(F.InputFileOffsets[ID-1]); + + unsigned Code = Cursor.ReadCode(); + RecordData Record; + const char *BlobStart = 0; + unsigned BlobLen = 0; + switch ((InputFileRecordTypes)Cursor.ReadRecord(Code, Record, + &BlobStart, &BlobLen)) { + case INPUT_FILE: { + unsigned StoredID = Record[0]; + assert(ID == StoredID && "Bogus stored ID or offset"); + (void)StoredID; + off_t StoredSize = (off_t)Record[1]; + time_t StoredTime = (time_t)Record[2]; + bool Overridden = (bool)Record[3]; + + // Get the file entry for this input file. + StringRef OrigFilename(BlobStart, BlobLen); + std::string Filename = OrigFilename; + MaybeAddSystemRootToFilename(F, Filename); + const FileEntry *File + = Overridden? FileMgr.getVirtualFile(Filename, StoredSize, StoredTime) + : FileMgr.getFile(Filename, /*OpenFile=*/false); + + // If we didn't find the file, resolve it relative to the + // original directory from which this AST file was created. + if (File == 0 && !F.OriginalDir.empty() && !CurrentDir.empty() && + F.OriginalDir != CurrentDir) { + std::string Resolved = resolveFileRelativeToOriginalDir(Filename, + F.OriginalDir, + CurrentDir); + if (!Resolved.empty()) + File = FileMgr.getFile(Resolved); + } + + // For an overridden file, create a virtual file with the stored + // size/timestamp. + if (Overridden && File == 0) { + File = FileMgr.getVirtualFile(Filename, StoredSize, StoredTime); + } + + if (File == 0) { + if (Complain) { + std::string ErrorStr = "could not find file '"; + ErrorStr += Filename; + ErrorStr += "' referenced by AST file"; + Error(ErrorStr.c_str()); + } + return InputFile(); + } + + // Note that we've loaded this input file. + F.InputFilesLoaded[ID-1] = InputFile(File, Overridden); + + // Check if there was a request to override the contents of the file + // that was part of the precompiled header. Overridding such a file + // can lead to problems when lexing using the source locations from the + // PCH. + SourceManager &SM = getSourceManager(); + if (!Overridden && SM.isFileOverridden(File)) { + Error(diag::err_fe_pch_file_overridden, Filename); + // After emitting the diagnostic, recover by disabling the override so + // that the original file will be used. + SM.disableFileContentsOverride(File); + // The FileEntry is a virtual file entry with the size of the contents + // that would override the original contents. Set it to the original's + // size/time. + FileMgr.modifyFileEntry(const_cast<FileEntry*>(File), + StoredSize, StoredTime); + } + + // For an overridden file, there is nothing to validate. + if (Overridden) + return InputFile(File, Overridden); + + // The stat info from the FileEntry came from the cached stat + // info of the PCH, so we cannot trust it. + struct stat StatBuf; + if (::stat(File->getName(), &StatBuf) != 0) { + StatBuf.st_size = File->getSize(); + StatBuf.st_mtime = File->getModificationTime(); + } + + if ((StoredSize != StatBuf.st_size +#if !defined(LLVM_ON_WIN32) + // In our regression testing, the Windows file system seems to + // have inconsistent modification times that sometimes + // erroneously trigger this error-handling path. + || StoredTime != StatBuf.st_mtime +#endif + )) { + if (Complain) + Error(diag::err_fe_pch_file_modified, Filename); + + return InputFile(); + } + + return InputFile(File, Overridden); + } + } + + return InputFile(); +} + const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) { + ModuleFile &M = ModuleMgr.getPrimaryModule(); std::string Filename = filenameStrRef; - MaybeAddSystemRootToFilename(Filename); + MaybeAddSystemRootToFilename(M, Filename); const FileEntry *File = FileMgr.getFile(Filename); - if (File == 0 && !OriginalDir.empty() && !CurrentDir.empty() && - OriginalDir != CurrentDir) { + if (File == 0 && !M.OriginalDir.empty() && !CurrentDir.empty() && + M.OriginalDir != CurrentDir) { std::string resolved = resolveFileRelativeToOriginalDir(Filename, - OriginalDir, + M.OriginalDir, CurrentDir); if (!resolved.empty()) File = FileMgr.getFile(resolved); @@ -1621,9 +1585,10 @@ const FileEntry *ASTReader::getFileEntry(StringRef filenameStrRef) { /// \brief If we are loading a relocatable PCH file, and the filename is /// not an absolute path, add the system root to the beginning of the file /// name. -void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) { +void ASTReader::MaybeAddSystemRootToFilename(ModuleFile &M, + std::string &Filename) { // If this is not a relocatable PCH file, there's nothing to do. - if (!RelocatablePCH) + if (!M.RelocatablePCH) return; if (Filename.empty() || llvm::sys::path::is_absolute(Filename)) @@ -1643,29 +1608,226 @@ void ASTReader::MaybeAddSystemRootToFilename(std::string &Filename) { } ASTReader::ASTReadResult -ASTReader::ReadASTBlock(ModuleFile &F) { +ASTReader::ReadControlBlock(ModuleFile &F, + llvm::SmallVectorImpl<ModuleFile *> &Loaded, + unsigned ClientLoadCapabilities) { llvm::BitstreamCursor &Stream = F.Stream; - if (Stream.EnterSubBlock(AST_BLOCK_ID)) { + if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { Error("malformed block record in AST file"); return Failure; } - // Read all of the records and blocks for the ASt file. + // Read all of the records and blocks in the control block. RecordData Record; while (!Stream.AtEndOfStream()) { unsigned Code = Stream.ReadCode(); if (Code == llvm::bitc::END_BLOCK) { if (Stream.ReadBlockEnd()) { - Error("error at end of module block in AST file"); + Error("error at end of control block in AST file"); return Failure; } + // Validate all of the input files. + if (!DisableValidation) { + bool Complain = (ClientLoadCapabilities & ARR_OutOfDate) == 0; + for (unsigned I = 0, N = Record[0]; I < N; ++I) + if (!getInputFile(F, I+1, Complain).getPointer()) + return OutOfDate; + } + return Success; } if (Code == llvm::bitc::ENTER_SUBBLOCK) { switch (Stream.ReadSubBlockID()) { + case INPUT_FILES_BLOCK_ID: + F.InputFilesCursor = Stream; + if (Stream.SkipBlock() || // Skip with the main cursor + // Read the abbreviations + ReadBlockAbbrevs(F.InputFilesCursor, INPUT_FILES_BLOCK_ID)) { + Error("malformed block record in AST file"); + return Failure; + } + continue; + + default: + if (!Stream.SkipBlock()) + continue; + break; + } + + Error("malformed block record in AST file"); + return Failure; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + // Read and process a record. + Record.clear(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + switch ((ControlRecordTypes)Stream.ReadRecord(Code, Record, + &BlobStart, &BlobLen)) { + case METADATA: { + if (Record[0] != VERSION_MAJOR && !DisableValidation) { + if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) + Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old + : diag::warn_pch_version_too_new); + return VersionMismatch; + } + + bool hasErrors = Record[5]; + if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) { + Diag(diag::err_pch_with_compiler_errors); + return HadErrors; + } + + F.RelocatablePCH = Record[4]; + + const std::string &CurBranch = getClangFullRepositoryVersion(); + StringRef ASTBranch(BlobStart, BlobLen); + if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { + if ((ClientLoadCapabilities & ARR_VersionMismatch) == 0) + Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch; + return VersionMismatch; + } + break; + } + + case IMPORTS: { + // Load each of the imported PCH files. + unsigned Idx = 0, N = Record.size(); + while (Idx < N) { + // Read information about the AST file. + ModuleKind ImportedKind = (ModuleKind)Record[Idx++]; + unsigned Length = Record[Idx++]; + SmallString<128> ImportedFile(Record.begin() + Idx, + Record.begin() + Idx + Length); + Idx += Length; + + // Load the AST file. + switch(ReadASTCore(ImportedFile, ImportedKind, &F, Loaded, + ClientLoadCapabilities)) { + case Failure: return Failure; + // If we have to ignore the dependency, we'll have to ignore this too. + case OutOfDate: return OutOfDate; + case VersionMismatch: return VersionMismatch; + case ConfigurationMismatch: return ConfigurationMismatch; + case HadErrors: return HadErrors; + case Success: break; + } + } + break; + } + + case LANGUAGE_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch) == 0; + if (Listener && &F == *ModuleMgr.begin() && + ParseLanguageOptions(Record, Complain, *Listener) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case TARGET_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; + if (Listener && &F == *ModuleMgr.begin() && + ParseTargetOptions(Record, Complain, *Listener) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case DIAGNOSTIC_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; + if (Listener && &F == *ModuleMgr.begin() && + ParseDiagnosticOptions(Record, Complain, *Listener) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case FILE_SYSTEM_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; + if (Listener && &F == *ModuleMgr.begin() && + ParseFileSystemOptions(Record, Complain, *Listener) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case HEADER_SEARCH_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; + if (Listener && &F == *ModuleMgr.begin() && + ParseHeaderSearchOptions(Record, Complain, *Listener) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case PREPROCESSOR_OPTIONS: { + bool Complain = (ClientLoadCapabilities & ARR_ConfigurationMismatch)==0; + if (Listener && &F == *ModuleMgr.begin() && + ParsePreprocessorOptions(Record, Complain, *Listener, + SuggestedPredefines) && + !DisableValidation) + return ConfigurationMismatch; + break; + } + + case ORIGINAL_FILE: + F.OriginalSourceFileID = FileID::get(Record[0]); + F.ActualOriginalSourceFileName.assign(BlobStart, BlobLen); + F.OriginalSourceFileName = F.ActualOriginalSourceFileName; + MaybeAddSystemRootToFilename(F, F.OriginalSourceFileName); + break; + + case ORIGINAL_PCH_DIR: + F.OriginalDir.assign(BlobStart, BlobLen); + break; + + case INPUT_FILE_OFFSETS: + F.InputFileOffsets = (const uint32_t *)BlobStart; + F.InputFilesLoaded.resize(Record[0]); + break; + } + } + + Error("premature end of bitstream in AST file"); + return Failure; +} + +bool ASTReader::ReadASTBlock(ModuleFile &F) { + llvm::BitstreamCursor &Stream = F.Stream; + + if (Stream.EnterSubBlock(AST_BLOCK_ID)) { + Error("malformed block record in AST file"); + return true; + } + + // Read all of the records and blocks for the AST file. + RecordData Record; + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) { + Error("error at end of module block in AST file"); + return true; + } + + DeclContext *DC = Context.getTranslationUnitDecl(); + if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage()) + DC->setMustBuildLookupTable(); + + return false; + } + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + switch (Stream.ReadSubBlockID()) { case DECLTYPES_BLOCK_ID: // We lazily load the decls block, but we want to set up the // DeclsCursor cursor to point into it. Clone our current bitcode @@ -1676,14 +1838,14 @@ ASTReader::ReadASTBlock(ModuleFile &F) { // Read the abbrevs. ReadBlockAbbrevs(F.DeclsCursor, DECLTYPES_BLOCK_ID)) { Error("malformed block record in AST file"); - return Failure; + return true; } break; case DECL_UPDATES_BLOCK_ID: if (Stream.SkipBlock()) { Error("malformed block record in AST file"); - return Failure; + return true; } break; @@ -1695,7 +1857,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { if (Stream.SkipBlock() || ReadBlockAbbrevs(F.MacroCursor, PREPROCESSOR_BLOCK_ID)) { Error("malformed block record in AST file"); - return Failure; + return true; } F.MacroStartOffset = F.MacroCursor.GetCurrentBitNo(); break; @@ -1706,7 +1868,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { ReadBlockAbbrevs(F.PreprocessorDetailCursor, PREPROCESSOR_DETAIL_BLOCK_ID)) { Error("malformed preprocessor detail record in AST file"); - return Failure; + return true; } F.PreprocessorDetailStartOffset = F.PreprocessorDetailCursor.GetCurrentBitNo(); @@ -1718,31 +1880,13 @@ ASTReader::ReadASTBlock(ModuleFile &F) { break; case SOURCE_MANAGER_BLOCK_ID: - switch (ReadSourceManagerBlock(F)) { - case Success: - break; - - case Failure: - Error("malformed source manager block in AST file"); - return Failure; - - case IgnorePCH: - return IgnorePCH; - } + if (ReadSourceManagerBlock(F)) + return true; break; case SUBMODULE_BLOCK_ID: - switch (ReadSubmoduleBlock(F)) { - case Success: - break; - - case Failure: - Error("malformed submodule block in AST file"); - return Failure; - - case IgnorePCH: - return IgnorePCH; - } + if (ReadSubmoduleBlock(F)) + return true; break; case COMMENTS_BLOCK_ID: { @@ -1750,7 +1894,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { if (Stream.SkipBlock() || ReadBlockAbbrevs(C, COMMENTS_BLOCK_ID)) { Error("malformed comments block in AST file"); - return Failure; + return true; } CommentsCursors.push_back(std::make_pair(C, &F)); break; @@ -1760,7 +1904,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { if (!Stream.SkipBlock()) break; Error("malformed block record in AST file"); - return Failure; + return true; } continue; } @@ -1779,54 +1923,10 @@ ASTReader::ReadASTBlock(ModuleFile &F) { default: // Default behavior: ignore. break; - case METADATA: { - if (Record[0] != VERSION_MAJOR && !DisableValidation) { - Diag(Record[0] < VERSION_MAJOR? diag::warn_pch_version_too_old - : diag::warn_pch_version_too_new); - return IgnorePCH; - } - - bool hasErrors = Record[5]; - if (hasErrors && !DisableValidation && !AllowASTWithCompilerErrors) { - Diag(diag::err_pch_with_compiler_errors); - return IgnorePCH; - } - - RelocatablePCH = Record[4]; - if (Listener) { - std::string TargetTriple(BlobStart, BlobLen); - if (Listener->ReadTargetTriple(TargetTriple)) - return IgnorePCH; - } - break; - } - - case IMPORTS: { - // Load each of the imported PCH files. - unsigned Idx = 0, N = Record.size(); - while (Idx < N) { - // Read information about the AST file. - ModuleKind ImportedKind = (ModuleKind)Record[Idx++]; - unsigned Length = Record[Idx++]; - SmallString<128> ImportedFile(Record.begin() + Idx, - Record.begin() + Idx + Length); - Idx += Length; - - // Load the AST file. - switch(ReadASTCore(ImportedFile, ImportedKind, &F)) { - case Failure: return Failure; - // If we have to ignore the dependency, we'll have to ignore this too. - case IgnorePCH: return IgnorePCH; - case Success: break; - } - } - break; - } - case TYPE_OFFSET: { if (F.LocalNumTypes != 0) { Error("duplicate TYPE_OFFSET record in AST file"); - return Failure; + return true; } F.TypeOffsets = (const uint32_t *)BlobStart; F.LocalNumTypes = Record[0]; @@ -1850,7 +1950,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case DECL_OFFSET: { if (F.LocalNumDecls != 0) { Error("duplicate DECL_OFFSET record in AST file"); - return Failure; + return true; } F.DeclOffsets = (const DeclOffset *)BlobStart; F.LocalNumDecls = Record[0]; @@ -1904,11 +2004,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) { break; } - case LANGUAGE_OPTIONS: - if (ParseLanguageOptions(Record) && !DisableValidation) - return IgnorePCH; - break; - case IDENTIFIER_TABLE: F.IdentifierTableData = BlobStart; if (Record[0]) { @@ -1925,7 +2020,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case IDENTIFIER_OFFSET: { if (F.LocalNumIdentifiers != 0) { Error("duplicate IDENTIFIER_OFFSET record in AST file"); - return Failure; + return true; } F.IdentifierOffsets = (const uint32_t *)BlobStart; F.LocalNumIdentifiers = Record[0]; @@ -1949,7 +2044,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { } break; } - + case EXTERNAL_DEFINITIONS: for (unsigned I = 0, N = Record.size(); I != N; ++I) ExternalDefinitions.push_back(getGlobalDeclID(F, Record[I])); @@ -1980,7 +2075,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case WEAK_UNDECLARED_IDENTIFIERS: if (Record.size() % 4 != 0) { Error("invalid weak identifiers record"); - return Failure; + return true; } // FIXME: Ignore weak undeclared identifiers from non-original PCH @@ -2050,11 +2145,12 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case PP_COUNTER_VALUE: if (!Record.empty() && Listener) - Listener->ReadCounter(Record[0]); + Listener->ReadCounter(F, Record[0]); break; case FILE_SORTED_DECLS: F.FileSortedDecls = (const DeclID *)BlobStart; + F.NumFileSortedDecls = Record[0]; break; case SOURCE_LOCATION_OFFSETS: { @@ -2098,7 +2194,9 @@ ASTReader::ReadASTBlock(ModuleFile &F) { ContinuousRangeMap<uint32_t, int, 2>::Builder SLocRemap(F.SLocRemap); ContinuousRangeMap<uint32_t, int, 2>::Builder IdentifierRemap(F.IdentifierRemap); - ContinuousRangeMap<uint32_t, int, 2>::Builder + ContinuousRangeMap<uint32_t, int, 2>::Builder + MacroRemap(F.MacroRemap); + ContinuousRangeMap<uint32_t, int, 2>::Builder PreprocessedEntityRemap(F.PreprocessedEntityRemap); ContinuousRangeMap<uint32_t, int, 2>::Builder SubmoduleRemap(F.SubmoduleRemap); @@ -2114,11 +2212,12 @@ ASTReader::ReadASTBlock(ModuleFile &F) { ModuleFile *OM = ModuleMgr.lookup(Name); if (!OM) { Error("SourceLocation remap refers to unknown module"); - return Failure; + return true; } uint32_t SLocOffset = io::ReadUnalignedLE32(Data); uint32_t IdentifierIDOffset = io::ReadUnalignedLE32(Data); + uint32_t MacroIDOffset = io::ReadUnalignedLE32(Data); uint32_t PreprocessedEntityIDOffset = io::ReadUnalignedLE32(Data); uint32_t SubmoduleIDOffset = io::ReadUnalignedLE32(Data); uint32_t SelectorIDOffset = io::ReadUnalignedLE32(Data); @@ -2131,6 +2230,8 @@ ASTReader::ReadASTBlock(ModuleFile &F) { IdentifierRemap.insert( std::make_pair(IdentifierIDOffset, OM->BaseIdentifierID - IdentifierIDOffset)); + MacroRemap.insert(std::make_pair(MacroIDOffset, + OM->BaseMacroID - MacroIDOffset)); PreprocessedEntityRemap.insert( std::make_pair(PreprocessedEntityIDOffset, OM->BasePreprocessedEntityID - PreprocessedEntityIDOffset)); @@ -2152,12 +2253,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case SOURCE_MANAGER_LINE_TABLE: if (ParseLineTable(F, Record)) - return Failure; - break; - - case FILE_SOURCE_LOCATION_OFFSETS: - F.SLocFileOffsets = (const uint32_t *)BlobStart; - F.LocalNumSLocFileEntries = Record[0]; + return true; break; case SOURCE_LOCATION_PRELOADS: { @@ -2165,25 +2261,13 @@ ASTReader::ReadASTBlock(ModuleFile &F) { // which is based off F.SLocEntryBaseID. if (!F.PreloadSLocEntries.empty()) { Error("Multiple SOURCE_LOCATION_PRELOADS records in AST file"); - return Failure; + return true; } F.PreloadSLocEntries.swap(Record); break; } - case STAT_CACHE: { - if (!DisableStatCache) { - ASTStatCache *MyStatCache = - new ASTStatCache((const unsigned char *)BlobStart + Record[0], - (const unsigned char *)BlobStart, - NumStatHits, NumStatMisses); - FileMgr.addStatCache(MyStatCache); - F.StatCache = MyStatCache; - } - break; - } - case EXT_VECTOR_DECLS: for (unsigned I = 0, N = Record.size(); I != N; ++I) ExtVectorDecls.push_back(getGlobalDeclID(F, Record[I])); @@ -2192,7 +2276,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case VTABLE_USES: if (Record.size() % 3 != 0) { Error("Invalid VTABLE_USES record"); - return Failure; + return true; } // Later tables overwrite earlier ones. @@ -2215,13 +2299,15 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case PENDING_IMPLICIT_INSTANTIATIONS: if (PendingInstantiations.size() % 2 != 0) { + Error("Invalid existing PendingInstantiations"); + return true; + } + + if (Record.size() % 2 != 0) { Error("Invalid PENDING_IMPLICIT_INSTANTIATIONS block"); - return Failure; + return true; } - - // Later lists of pending instantiations overwrite earlier ones. - // FIXME: This is most certainly wrong for modules. - PendingInstantiations.clear(); + for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { PendingInstantiations.push_back(getGlobalDeclID(F, Record[I++])); PendingInstantiations.push_back( @@ -2237,34 +2323,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) { SemaDeclRefs.push_back(getGlobalDeclID(F, Record[I])); break; - case ORIGINAL_FILE_NAME: - // The primary AST will be the last to get here, so it will be the one - // that's used. - ActualOriginalFileName.assign(BlobStart, BlobLen); - OriginalFileName = ActualOriginalFileName; - MaybeAddSystemRootToFilename(OriginalFileName); - break; - - case ORIGINAL_FILE_ID: - OriginalFileID = FileID::get(Record[0]); - break; - - case ORIGINAL_PCH_DIR: - // The primary AST will be the last to get here, so it will be the one - // that's used. - OriginalDir.assign(BlobStart, BlobLen); - break; - - case VERSION_CONTROL_BRANCH_REVISION: { - const std::string &CurBranch = getClangFullRepositoryVersion(); - StringRef ASTBranch(BlobStart, BlobLen); - if (StringRef(CurBranch) != ASTBranch && !DisableValidation) { - Diag(diag::warn_pch_different_branch) << ASTBranch << CurBranch; - return IgnorePCH; - } - break; - } - case PPD_ENTITIES_OFFSETS: { F.PreprocessedEntityOffsets = (const PPEntityOffset *)BlobStart; assert(BlobLen % sizeof(PPEntityOffset) == 0); @@ -2300,7 +2358,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case DECL_UPDATE_OFFSETS: { if (Record.size() % 2 != 0) { Error("invalid DECL_UPDATE_OFFSETS block in AST file"); - return Failure; + return true; } for (unsigned I = 0, N = Record.size(); I != N; I += 2) DeclUpdateOffsets[getGlobalDeclID(F, Record[I])] @@ -2311,7 +2369,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case DECL_REPLACEMENTS: { if (Record.size() % 3 != 0) { Error("invalid DECL_REPLACEMENTS block in AST file"); - return Failure; + return true; } for (unsigned I = 0, N = Record.size(); I != N; I += 3) ReplacedDecls[getGlobalDeclID(F, Record[I])] @@ -2322,7 +2380,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case OBJC_CATEGORIES_MAP: { if (F.LocalNumObjCCategoriesInMap != 0) { Error("duplicate OBJC_CATEGORIES_MAP record in AST file"); - return Failure; + return true; } F.LocalNumObjCCategoriesInMap = Record[0]; @@ -2337,7 +2395,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case CXX_BASE_SPECIFIER_OFFSETS: { if (F.LocalNumCXXBaseSpecifiers != 0) { Error("duplicate CXX_BASE_SPECIFIER_OFFSETS record in AST file"); - return Failure; + return true; } F.LocalNumCXXBaseSpecifiers = Record[0]; @@ -2347,11 +2405,6 @@ ASTReader::ReadASTBlock(ModuleFile &F) { } case DIAG_PRAGMA_MAPPINGS: - if (Record.size() % 2 != 0) { - Error("invalid DIAG_USER_MAPPINGS block in AST file"); - return Failure; - } - if (F.PragmaDiagMappings.empty()) F.PragmaDiagMappings.swap(Record); else @@ -2428,7 +2481,7 @@ ASTReader::ReadASTBlock(ModuleFile &F) { case LOCAL_REDECLARATIONS_MAP: { if (F.LocalNumRedeclarationsInMap != 0) { Error("duplicate LOCAL_REDECLARATIONS_MAP record in AST file"); - return Failure; + return true; } F.LocalNumRedeclarationsInMap = Record[0]; @@ -2445,113 +2498,77 @@ ASTReader::ReadASTBlock(ModuleFile &F) { } break; } - } - } - Error("premature end of bitstream in AST file"); - return Failure; -} - -ASTReader::ASTReadResult ASTReader::validateFileEntries(ModuleFile &M) { - llvm::BitstreamCursor &SLocEntryCursor = M.SLocEntryCursor; - - for (unsigned i = 0, e = M.LocalNumSLocFileEntries; i != e; ++i) { - SLocEntryCursor.JumpToBit(M.SLocFileOffsets[i]); - unsigned Code = SLocEntryCursor.ReadCode(); - if (Code == llvm::bitc::END_BLOCK || - Code == llvm::bitc::ENTER_SUBBLOCK || - Code == llvm::bitc::DEFINE_ABBREV) { - Error("incorrectly-formatted source location entry in AST file"); - return Failure; - } - RecordData Record; - const char *BlobStart; - unsigned BlobLen; - switch (SLocEntryCursor.ReadRecord(Code, Record, &BlobStart, &BlobLen)) { - default: - Error("incorrectly-formatted source location entry in AST file"); - return Failure; + case MACRO_OFFSET: { + if (F.LocalNumMacros != 0) { + Error("duplicate MACRO_OFFSET record in AST file"); + return true; + } + F.MacroOffsets = (const uint32_t *)BlobStart; + F.LocalNumMacros = Record[0]; + unsigned LocalBaseMacroID = Record[1]; + F.BaseMacroID = getTotalNumMacros(); - case SM_SLOC_FILE_ENTRY: { - // If the buffer was overridden, the file need not exist. - if (Record[6]) - break; - - StringRef Filename(BlobStart, BlobLen); - const FileEntry *File = getFileEntry(Filename); + if (F.LocalNumMacros > 0) { + // Introduce the global -> local mapping for macros within this module. + GlobalMacroMap.insert(std::make_pair(getTotalNumMacros() + 1, &F)); - if (File == 0) { - std::string ErrorStr = "could not find file '"; - ErrorStr += Filename; - ErrorStr += "' referenced by AST file"; - Error(ErrorStr.c_str()); - return IgnorePCH; - } + // Introduce the local -> global mapping for macros within this module. + F.MacroRemap.insertOrReplace( + std::make_pair(LocalBaseMacroID, + F.BaseMacroID - LocalBaseMacroID)); - if (Record.size() < 7) { - Error("source location entry is incorrect"); - return Failure; - } - - off_t StoredSize = (off_t)Record[4]; - time_t StoredTime = (time_t)Record[5]; - - // Check if there was a request to override the contents of the file - // that was part of the precompiled header. Overridding such a file - // can lead to problems when lexing using the source locations from the - // PCH. - SourceManager &SM = getSourceManager(); - if (SM.isFileOverridden(File)) { - Error(diag::err_fe_pch_file_overridden, Filename); - // After emitting the diagnostic, recover by disabling the override so - // that the original file will be used. - SM.disableFileContentsOverride(File); - // The FileEntry is a virtual file entry with the size of the contents - // that would override the original contents. Set it to the original's - // size/time. - FileMgr.modifyFileEntry(const_cast<FileEntry*>(File), - StoredSize, StoredTime); + MacrosLoaded.resize(MacrosLoaded.size() + F.LocalNumMacros); } + break; + } - // The stat info from the FileEntry came from the cached stat - // info of the PCH, so we cannot trust it. - struct stat StatBuf; - if (::stat(File->getName(), &StatBuf) != 0) { - StatBuf.st_size = File->getSize(); - StatBuf.st_mtime = File->getModificationTime(); - } + case MACRO_UPDATES: { + for (unsigned I = 0, N = Record.size(); I != N; /* in loop */) { + MacroID ID = getGlobalMacroID(F, Record[I++]); + if (I == N) + break; - if ((StoredSize != StatBuf.st_size -#if !defined(LLVM_ON_WIN32) - // In our regression testing, the Windows file system seems to - // have inconsistent modification times that sometimes - // erroneously trigger this error-handling path. - || StoredTime != StatBuf.st_mtime -#endif - )) { - Error(diag::err_fe_pch_file_modified, Filename); - return IgnorePCH; + SourceLocation UndefLoc = ReadSourceLocation(F, Record, I); + SubmoduleID SubmoduleID = getGlobalSubmoduleID(F, Record[I++]);; + MacroUpdate Update; + Update.UndefLoc = UndefLoc; + MacroUpdates[ID].push_back(std::make_pair(SubmoduleID, Update)); } - break; } } } - - return Success; + Error("premature end of bitstream in AST file"); + return true; } void ASTReader::makeNamesVisible(const HiddenNames &Names) { for (unsigned I = 0, N = Names.size(); I != N; ++I) { - if (Decl *D = Names[I].dyn_cast<Decl *>()) - D->Hidden = false; - else { - IdentifierInfo *II = Names[I].get<IdentifierInfo *>(); - if (!II->hasMacroDefinition()) { - II->setHasMacroDefinition(true); - if (DeserializationListener) - DeserializationListener->MacroVisible(II); + switch (Names[I].getKind()) { + case HiddenName::Declaration: + Names[I].getDecl()->Hidden = false; + break; + + case HiddenName::MacroVisibility: { + std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro(); + Macro.second->setHidden(!Macro.second->isPublic()); + if (Macro.second->isDefined()) { + PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); + } + break; + } + + case HiddenName::MacroUndef: { + std::pair<IdentifierInfo *, MacroInfo *> Macro = Names[I].getMacro(); + if (Macro.second->isDefined()) { + Macro.second->setUndefLoc(Names[I].getMacroUndefLoc()); + if (PPMutationListener *Listener = PP.getPPMutationListener()) + Listener->UndefinedMacro(Macro.second); + PP.makeLoadedMacroInfoVisible(Macro.first, Macro.second); } + break; + } } } } @@ -2631,7 +2648,7 @@ void ASTReader::makeModuleVisible(Module *Mod, for (unsigned I = 0, N = Mod->Imports.size(); I != N; ++I) { Module *Imported = Mod->Imports[I]; - if (Visited.count(Imported)) + if (!Visited.insert(Imported)) continue; bool Acceptable = UnrestrictedWildcard; @@ -2649,32 +2666,62 @@ void ASTReader::makeModuleVisible(Module *Mod, if (!Acceptable) continue; - Visited.insert(Imported); Stack.push_back(Imported); } } } ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, - ModuleKind Type) { + ModuleKind Type, + unsigned ClientLoadCapabilities) { // Bump the generation number. unsigned PreviousGeneration = CurrentGeneration++; - - switch(ReadASTCore(FileName, Type, /*ImportedBy=*/0)) { - case Failure: return Failure; - case IgnorePCH: return IgnorePCH; - case Success: break; + + unsigned NumModules = ModuleMgr.size(); + llvm::SmallVector<ModuleFile *, 4> Loaded; + switch(ASTReadResult ReadResult = ReadASTCore(FileName, Type, + /*ImportedBy=*/0, Loaded, + ClientLoadCapabilities)) { + case Failure: + case OutOfDate: + case VersionMismatch: + case ConfigurationMismatch: + case HadErrors: + ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, ModuleMgr.end()); + return ReadResult; + + case Success: + break; } // Here comes stuff that we only do once the entire chain is loaded. - // Check the predefines buffers. - if (!DisableValidation && Type == MK_PCH && - // FIXME: CheckPredefinesBuffers also sets the SuggestedPredefines; - // if DisableValidation is true, defines that were set on command-line - // but not in the PCH file will not be added to SuggestedPredefines. - CheckPredefinesBuffers()) - return IgnorePCH; + // Load the AST blocks of all of the modules that we loaded. + for (llvm::SmallVectorImpl<ModuleFile *>::iterator M = Loaded.begin(), + MEnd = Loaded.end(); + M != MEnd; ++M) { + ModuleFile &F = **M; + + // Read the AST block. + if (ReadASTBlock(F)) + return Failure; + + // Once read, set the ModuleFile bit base offset and update the size in + // bits of all files we've seen. + F.GlobalBitOffset = TotalModulesSizeInBits; + TotalModulesSizeInBits += F.SizeInBits; + GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F)); + + // Preload SLocEntries. + for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) { + int Index = int(F.PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID; + // Load it through the SourceManager and don't call ReadSLocEntry() + // directly because the entry may have already been loaded in which case + // calling ReadSLocEntry() directly would trigger an assertion in + // SourceManager. + SourceMgr.getLoadedSLocEntryByID(Index); + } + } // Mark all of the identifiers in the identifier table as being out of date, // so that various accessors know to check the loaded modules when the @@ -2707,17 +2754,19 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, if (DeserializationListener) DeserializationListener->ReaderInitialized(this); - if (!OriginalFileID.isInvalid()) { - OriginalFileID = FileID::get(ModuleMgr.getPrimaryModule().SLocEntryBaseID - + OriginalFileID.getOpaqueValue() - 1); + ModuleFile &PrimaryModule = ModuleMgr.getPrimaryModule(); + if (!PrimaryModule.OriginalSourceFileID.isInvalid()) { + PrimaryModule.OriginalSourceFileID + = FileID::get(PrimaryModule.SLocEntryBaseID + + PrimaryModule.OriginalSourceFileID.getOpaqueValue() - 1); - // If this AST file is a precompiled preamble, then set the preamble file ID - // of the source manager to the file source file from which the preamble was - // built. + // If this AST file is a precompiled preamble, then set the + // preamble file ID of the source manager to the file source file + // from which the preamble was built. if (Type == MK_Preamble) { - SourceMgr.setPreambleFileID(OriginalFileID); + SourceMgr.setPreambleFileID(PrimaryModule.OriginalSourceFileID); } else if (Type == MK_MainFile) { - SourceMgr.setMainFileID(OriginalFileID); + SourceMgr.setMainFileID(PrimaryModule.OriginalSourceFileID); } } @@ -2732,9 +2781,12 @@ ASTReader::ASTReadResult ASTReader::ReadAST(const std::string &FileName, return Success; } -ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, - ModuleKind Type, - ModuleFile *ImportedBy) { +ASTReader::ASTReadResult +ASTReader::ReadASTCore(StringRef FileName, + ModuleKind Type, + ModuleFile *ImportedBy, + llvm::SmallVectorImpl<ModuleFile *> &Loaded, + unsigned ClientLoadCapabilities) { ModuleFile *M; bool NewModule; std::string ErrorStr; @@ -2785,7 +2837,7 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, unsigned BlockID = Stream.ReadSubBlockID(); - // We only know the AST subblock ID. + // We only know the control subblock ID. switch (BlockID) { case llvm::bitc::BLOCKINFO_BLOCK_ID: if (Stream.ReadBlockInfoBlock()) { @@ -2793,29 +2845,23 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, return Failure; } break; - case AST_BLOCK_ID: - switch (ReadASTBlock(F)) { + case CONTROL_BLOCK_ID: + switch (ReadControlBlock(F, Loaded, ClientLoadCapabilities)) { case Success: break; - case Failure: - return Failure; - - case IgnorePCH: - // FIXME: We could consider reading through to the end of this - // AST block, skipping subblocks, to see if there are other - // AST blocks elsewhere. - - // FIXME: We can't clear loaded slocentries anymore. - //SourceMgr.ClearPreallocatedSLocEntries(); - - // Remove the stat cache. - if (F.StatCache) - FileMgr.removeStatCache((ASTStatCache*)F.StatCache); - - return IgnorePCH; + case Failure: return Failure; + case OutOfDate: return OutOfDate; + case VersionMismatch: return VersionMismatch; + case ConfigurationMismatch: return ConfigurationMismatch; + case HadErrors: return HadErrors; } break; + case AST_BLOCK_ID: + // Record that we've loaded this module. + Loaded.push_back(M); + return Success; + default: if (Stream.SkipBlock()) { Error("malformed block record in AST file"); @@ -2825,32 +2871,6 @@ ASTReader::ASTReadResult ASTReader::ReadASTCore(StringRef FileName, } } - // Once read, set the ModuleFile bit base offset and update the size in - // bits of all files we've seen. - F.GlobalBitOffset = TotalModulesSizeInBits; - TotalModulesSizeInBits += F.SizeInBits; - GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F)); - - // Make sure that the files this module was built against are still available. - if (!DisableValidation) { - switch(validateFileEntries(*M)) { - case Failure: return Failure; - case IgnorePCH: return IgnorePCH; - case Success: break; - } - } - - // Preload SLocEntries. - for (unsigned I = 0, N = M->PreloadSLocEntries.size(); I != N; ++I) { - int Index = int(M->PreloadSLocEntries[I] - 1) + F.SLocEntryBaseID; - // Load it through the SourceManager and don't call ReadSLocEntryRecord() - // directly because the entry may have already been loaded in which case - // calling ReadSLocEntryRecord() directly would trigger an assertion in - // SourceManager. - SourceMgr.getLoadedSLocEntryByID(Index); - } - - return Success; } @@ -3038,8 +3058,8 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName, // We only know the AST subblock ID. switch (BlockID) { - case AST_BLOCK_ID: - if (Stream.EnterSubBlock(AST_BLOCK_ID)) { + case CONTROL_BLOCK_ID: + if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { Diags.Report(diag::err_fe_pch_malformed_block) << ASTFileName; return std::string(); } @@ -3071,19 +3091,191 @@ std::string ASTReader::getOriginalSourceFile(const std::string &ASTFileName, Record.clear(); const char *BlobStart = 0; unsigned BlobLen = 0; - if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) - == ORIGINAL_FILE_NAME) + if (Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen) == ORIGINAL_FILE) return std::string(BlobStart, BlobLen); } return std::string(); } -ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { +namespace { + class SimplePCHValidator : public ASTReaderListener { + const LangOptions &ExistingLangOpts; + const TargetOptions &ExistingTargetOpts; + const PreprocessorOptions &ExistingPPOpts; + FileManager &FileMgr; + + public: + SimplePCHValidator(const LangOptions &ExistingLangOpts, + const TargetOptions &ExistingTargetOpts, + const PreprocessorOptions &ExistingPPOpts, + FileManager &FileMgr) + : ExistingLangOpts(ExistingLangOpts), + ExistingTargetOpts(ExistingTargetOpts), + ExistingPPOpts(ExistingPPOpts), + FileMgr(FileMgr) + { + } + + virtual bool ReadLanguageOptions(const LangOptions &LangOpts, + bool Complain) { + return checkLanguageOptions(ExistingLangOpts, LangOpts, 0); + } + virtual bool ReadTargetOptions(const TargetOptions &TargetOpts, + bool Complain) { + return checkTargetOptions(ExistingTargetOpts, TargetOpts, 0); + } + virtual bool ReadPreprocessorOptions(const PreprocessorOptions &PPOpts, + bool Complain, + std::string &SuggestedPredefines) { + return checkPreprocessorOptions(ExistingPPOpts, PPOpts, 0, FileMgr, + SuggestedPredefines); + } + }; +} + +bool ASTReader::readASTFileControlBlock(StringRef Filename, + FileManager &FileMgr, + ASTReaderListener &Listener) { + // Open the AST file. + std::string ErrStr; + OwningPtr<llvm::MemoryBuffer> Buffer; + Buffer.reset(FileMgr.getBufferForFile(Filename, &ErrStr)); + if (!Buffer) { + return true; + } + + // Initialize the stream + llvm::BitstreamReader StreamFile; + llvm::BitstreamCursor Stream; + StreamFile.init((const unsigned char *)Buffer->getBufferStart(), + (const unsigned char *)Buffer->getBufferEnd()); + Stream.init(StreamFile); + + // Sniff for the signature. + if (Stream.Read(8) != 'C' || + Stream.Read(8) != 'P' || + Stream.Read(8) != 'C' || + Stream.Read(8) != 'H') { + return true; + } + + RecordData Record; + bool InControlBlock = false; + while (!Stream.AtEndOfStream()) { + unsigned Code = Stream.ReadCode(); + + if (Code == llvm::bitc::ENTER_SUBBLOCK) { + unsigned BlockID = Stream.ReadSubBlockID(); + + // We only know the control subblock ID. + switch (BlockID) { + case CONTROL_BLOCK_ID: + if (Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { + return true; + } else { + InControlBlock = true; + } + break; + + default: + if (Stream.SkipBlock()) + return true; + break; + } + continue; + } + + if (Code == llvm::bitc::END_BLOCK) { + if (Stream.ReadBlockEnd()) { + return true; + } + + InControlBlock = false; + continue; + } + + if (Code == llvm::bitc::DEFINE_ABBREV) { + Stream.ReadAbbrevRecord(); + continue; + } + + Record.clear(); + const char *BlobStart = 0; + unsigned BlobLen = 0; + unsigned RecCode = Stream.ReadRecord(Code, Record, &BlobStart, &BlobLen); + if (InControlBlock) { + switch ((ControlRecordTypes)RecCode) { + case METADATA: { + if (Record[0] != VERSION_MAJOR) { + return true; + } + + const std::string &CurBranch = getClangFullRepositoryVersion(); + StringRef ASTBranch(BlobStart, BlobLen); + if (StringRef(CurBranch) != ASTBranch) + return true; + + break; + } + case LANGUAGE_OPTIONS: + if (ParseLanguageOptions(Record, false, Listener)) + return true; + break; + + case TARGET_OPTIONS: + if (ParseTargetOptions(Record, false, Listener)) + return true; + break; + + case DIAGNOSTIC_OPTIONS: + if (ParseDiagnosticOptions(Record, false, Listener)) + return true; + break; + + case FILE_SYSTEM_OPTIONS: + if (ParseFileSystemOptions(Record, false, Listener)) + return true; + break; + + case HEADER_SEARCH_OPTIONS: + if (ParseHeaderSearchOptions(Record, false, Listener)) + return true; + break; + + case PREPROCESSOR_OPTIONS: { + std::string IgnoredSuggestedPredefines; + if (ParsePreprocessorOptions(Record, false, Listener, + IgnoredSuggestedPredefines)) + return true; + break; + } + + default: + // No other validation to perform. + break; + } + } + } + + return false; +} + + +bool ASTReader::isAcceptableASTFile(StringRef Filename, + FileManager &FileMgr, + const LangOptions &LangOpts, + const TargetOptions &TargetOpts, + const PreprocessorOptions &PPOpts) { + SimplePCHValidator validator(LangOpts, TargetOpts, PPOpts, FileMgr); + return !readASTFileControlBlock(Filename, FileMgr, validator); +} + +bool ASTReader::ReadSubmoduleBlock(ModuleFile &F) { // Enter the submodule block. if (F.Stream.EnterSubBlock(SUBMODULE_BLOCK_ID)) { Error("malformed submodule block record in AST file"); - return Failure; + return true; } ModuleMap &ModMap = PP.getHeaderSearchInfo().getModuleMap(); @@ -3095,9 +3287,9 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (Code == llvm::bitc::END_BLOCK) { if (F.Stream.ReadBlockEnd()) { Error("error at end of submodule block in AST file"); - return Failure; + return true; } - return Success; + return false; } if (Code == llvm::bitc::ENTER_SUBBLOCK) { @@ -3105,7 +3297,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { F.Stream.ReadSubBlockID(); if (F.Stream.SkipBlock()) { Error("malformed block record in AST file"); - return Failure; + return true; } continue; } @@ -3126,12 +3318,12 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { case SUBMODULE_DEFINITION: { if (First) { Error("missing submodule metadata record at beginning of block"); - return Failure; + return true; } if (Record.size() < 7) { Error("malformed module definition"); - return Failure; + return true; } StringRef Name(BlobStart, BlobLen); @@ -3157,9 +3349,10 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (GlobalIndex >= SubmodulesLoaded.size() || SubmodulesLoaded[GlobalIndex]) { Error("too many submodules"); - return Failure; + return true; } + CurrentModule->setASTFile(F.File); CurrentModule->IsFromModuleFile = true; CurrentModule->IsSystem = IsSystem || CurrentModule->IsSystem; CurrentModule->InferSubmodules = InferSubmodules; @@ -3175,7 +3368,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { case SUBMODULE_UMBRELLA_HEADER: { if (First) { Error("missing submodule metadata record at beginning of block"); - return Failure; + return true; } if (!CurrentModule) @@ -3187,7 +3380,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { ModMap.setUmbrellaHeader(CurrentModule, Umbrella); else if (CurrentModule->getUmbrellaHeader() != Umbrella) { Error("mismatched umbrella headers in submodule"); - return Failure; + return true; } } break; @@ -3196,7 +3389,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { case SUBMODULE_HEADER: { if (First) { Error("missing submodule metadata record at beginning of block"); - return Failure; + return true; } if (!CurrentModule) @@ -3208,15 +3401,51 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { if (std::find(CurrentModule->Headers.begin(), CurrentModule->Headers.end(), File) == CurrentModule->Headers.end()) - ModMap.addHeader(CurrentModule, File); + ModMap.addHeader(CurrentModule, File, false); } break; } - + + case SUBMODULE_EXCLUDED_HEADER: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + // FIXME: Be more lazy about this! + StringRef FileName(BlobStart, BlobLen); + if (const FileEntry *File = PP.getFileManager().getFile(FileName)) { + if (std::find(CurrentModule->Headers.begin(), + CurrentModule->Headers.end(), + File) == CurrentModule->Headers.end()) + ModMap.addHeader(CurrentModule, File, true); + } + break; + } + + case SUBMODULE_TOPHEADER: { + if (First) { + Error("missing submodule metadata record at beginning of block"); + return true; + } + + if (!CurrentModule) + break; + + // FIXME: Be more lazy about this! + StringRef FileName(BlobStart, BlobLen); + if (const FileEntry *File = PP.getFileManager().getFile(FileName)) + CurrentModule->TopHeaders.insert(File); + break; + } + case SUBMODULE_UMBRELLA_DIR: { if (First) { Error("missing submodule metadata record at beginning of block"); - return Failure; + return true; } if (!CurrentModule) @@ -3229,7 +3458,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { ModMap.setUmbrellaDir(CurrentModule, Umbrella); else if (CurrentModule->getUmbrellaDir() != Umbrella) { Error("mismatched umbrella directories in submodule"); - return Failure; + return true; } } break; @@ -3238,7 +3467,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { case SUBMODULE_METADATA: { if (!First) { Error("submodule metadata record not at beginning of block"); - return Failure; + return true; } First = false; @@ -3264,7 +3493,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { case SUBMODULE_IMPORTS: { if (First) { Error("missing submodule metadata record at beginning of block"); - return Failure; + return true; } if (!CurrentModule) @@ -3285,7 +3514,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { case SUBMODULE_EXPORTS: { if (First) { Error("missing submodule metadata record at beginning of block"); - return Failure; + return true; } if (!CurrentModule) @@ -3309,7 +3538,7 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { case SUBMODULE_REQUIRES: { if (First) { Error("missing submodule metadata record at beginning of block"); - return Failure; + return true; } if (!CurrentModule) @@ -3331,27 +3560,144 @@ ASTReader::ASTReadResult ASTReader::ReadSubmoduleBlock(ModuleFile &F) { /// them to the AST listener if one is set. /// /// \returns true if the listener deems the file unacceptable, false otherwise. -bool ASTReader::ParseLanguageOptions(const RecordData &Record) { - if (Listener) { - LangOptions LangOpts; - unsigned Idx = 0; +bool ASTReader::ParseLanguageOptions(const RecordData &Record, + bool Complain, + ASTReaderListener &Listener) { + LangOptions LangOpts; + unsigned Idx = 0; #define LANGOPT(Name, Bits, Default, Description) \ LangOpts.Name = Record[Idx++]; #define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ LangOpts.set##Name(static_cast<LangOptions::Type>(Record[Idx++])); #include "clang/Basic/LangOptions.def" - ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++]; - VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx); - LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion); - - unsigned Length = Record[Idx++]; - LangOpts.CurrentModule.assign(Record.begin() + Idx, - Record.begin() + Idx + Length); - return Listener->ReadLanguageOptions(LangOpts); + ObjCRuntime::Kind runtimeKind = (ObjCRuntime::Kind) Record[Idx++]; + VersionTuple runtimeVersion = ReadVersionTuple(Record, Idx); + LangOpts.ObjCRuntime = ObjCRuntime(runtimeKind, runtimeVersion); + + unsigned Length = Record[Idx++]; + LangOpts.CurrentModule.assign(Record.begin() + Idx, + Record.begin() + Idx + Length); + return Listener.ReadLanguageOptions(LangOpts, Complain); +} + +bool ASTReader::ParseTargetOptions(const RecordData &Record, + bool Complain, + ASTReaderListener &Listener) { + unsigned Idx = 0; + TargetOptions TargetOpts; + TargetOpts.Triple = ReadString(Record, Idx); + TargetOpts.CPU = ReadString(Record, Idx); + TargetOpts.ABI = ReadString(Record, Idx); + TargetOpts.CXXABI = ReadString(Record, Idx); + TargetOpts.LinkerVersion = ReadString(Record, Idx); + for (unsigned N = Record[Idx++]; N; --N) { + TargetOpts.FeaturesAsWritten.push_back(ReadString(Record, Idx)); + } + for (unsigned N = Record[Idx++]; N; --N) { + TargetOpts.Features.push_back(ReadString(Record, Idx)); } - return false; + return Listener.ReadTargetOptions(TargetOpts, Complain); +} + +bool ASTReader::ParseDiagnosticOptions(const RecordData &Record, bool Complain, + ASTReaderListener &Listener) { + DiagnosticOptions DiagOpts; + unsigned Idx = 0; +#define DIAGOPT(Name, Bits, Default) DiagOpts.Name = Record[Idx++]; +#define ENUM_DIAGOPT(Name, Type, Bits, Default) \ + DiagOpts.set##Name(static_cast<Type>(Record[Idx++])); +#include "clang/Basic/DiagnosticOptions.def" + + for (unsigned N = Record[Idx++]; N; --N) { + DiagOpts.Warnings.push_back(ReadString(Record, Idx)); + } + + return Listener.ReadDiagnosticOptions(DiagOpts, Complain); +} + +bool ASTReader::ParseFileSystemOptions(const RecordData &Record, bool Complain, + ASTReaderListener &Listener) { + FileSystemOptions FSOpts; + unsigned Idx = 0; + FSOpts.WorkingDir = ReadString(Record, Idx); + return Listener.ReadFileSystemOptions(FSOpts, Complain); +} + +bool ASTReader::ParseHeaderSearchOptions(const RecordData &Record, + bool Complain, + ASTReaderListener &Listener) { + HeaderSearchOptions HSOpts; + unsigned Idx = 0; + HSOpts.Sysroot = ReadString(Record, Idx); + + // Include entries. + for (unsigned N = Record[Idx++]; N; --N) { + std::string Path = ReadString(Record, Idx); + frontend::IncludeDirGroup Group + = static_cast<frontend::IncludeDirGroup>(Record[Idx++]); + bool IsUserSupplied = Record[Idx++]; + bool IsFramework = Record[Idx++]; + bool IgnoreSysRoot = Record[Idx++]; + bool IsInternal = Record[Idx++]; + bool ImplicitExternC = Record[Idx++]; + HSOpts.UserEntries.push_back( + HeaderSearchOptions::Entry(Path, Group, IsUserSupplied, IsFramework, + IgnoreSysRoot, IsInternal, ImplicitExternC)); + } + + // System header prefixes. + for (unsigned N = Record[Idx++]; N; --N) { + std::string Prefix = ReadString(Record, Idx); + bool IsSystemHeader = Record[Idx++]; + HSOpts.SystemHeaderPrefixes.push_back( + HeaderSearchOptions::SystemHeaderPrefix(Prefix, IsSystemHeader)); + } + + HSOpts.ResourceDir = ReadString(Record, Idx); + HSOpts.ModuleCachePath = ReadString(Record, Idx); + HSOpts.DisableModuleHash = Record[Idx++]; + HSOpts.UseBuiltinIncludes = Record[Idx++]; + HSOpts.UseStandardSystemIncludes = Record[Idx++]; + HSOpts.UseStandardCXXIncludes = Record[Idx++]; + HSOpts.UseLibcxx = Record[Idx++]; + + return Listener.ReadHeaderSearchOptions(HSOpts, Complain); +} + +bool ASTReader::ParsePreprocessorOptions(const RecordData &Record, + bool Complain, + ASTReaderListener &Listener, + std::string &SuggestedPredefines) { + PreprocessorOptions PPOpts; + unsigned Idx = 0; + + // Macro definitions/undefs + for (unsigned N = Record[Idx++]; N; --N) { + std::string Macro = ReadString(Record, Idx); + bool IsUndef = Record[Idx++]; + PPOpts.Macros.push_back(std::make_pair(Macro, IsUndef)); + } + + // Includes + for (unsigned N = Record[Idx++]; N; --N) { + PPOpts.Includes.push_back(ReadString(Record, Idx)); + } + + // Macro Includes + for (unsigned N = Record[Idx++]; N; --N) { + PPOpts.MacroIncludes.push_back(ReadString(Record, Idx)); + } + + PPOpts.UsePredefines = Record[Idx++]; + PPOpts.ImplicitPCHInclude = ReadString(Record, Idx); + PPOpts.ImplicitPTHInclude = ReadString(Record, Idx); + PPOpts.ObjCXXARCStandardLibrary = + static_cast<ObjCXXARCStandardLibraryKind>(Record[Idx++]); + SuggestedPredefines.clear(); + return Listener.ReadPreprocessorOptions(PPOpts, Complain, + SuggestedPredefines); } std::pair<ModuleFile *, unsigned> @@ -3365,6 +3711,23 @@ ASTReader::getModulePreprocessedEntity(unsigned GlobalIndex) { return std::make_pair(M, LocalIndex); } +std::pair<PreprocessingRecord::iterator, PreprocessingRecord::iterator> +ASTReader::getModulePreprocessedEntities(ModuleFile &Mod) const { + if (PreprocessingRecord *PPRec = PP.getPreprocessingRecord()) + return PPRec->getIteratorsForLoadedRange(Mod.BasePreprocessedEntityID, + Mod.NumPreprocessedEntities); + + return std::make_pair(PreprocessingRecord::iterator(), + PreprocessingRecord::iterator()); +} + +std::pair<ASTReader::ModuleDeclIterator, ASTReader::ModuleDeclIterator> +ASTReader::getModuleFileLevelDecls(ModuleFile &Mod) { + return std::make_pair(ModuleDeclIterator(this, &Mod, Mod.FileSortedDecls), + ModuleDeclIterator(this, &Mod, + Mod.FileSortedDecls + Mod.NumFileSortedDecls)); +} + PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { PreprocessedEntityID PPID = Index+1; std::pair<ModuleFile *, unsigned> PPInfo = getModulePreprocessedEntity(Index); @@ -3455,7 +3818,7 @@ PreprocessedEntity *ASTReader::ReadPreprocessedEntity(unsigned Index) { InclusionDirective *ID = new (PPRec) InclusionDirective(PPRec, Kind, StringRef(BlobStart, Record[0]), - Record[1], + Record[1], Record[3], File, Range); return ID; @@ -3476,7 +3839,7 @@ PreprocessedEntityID ASTReader::findNextPreprocessedEntity( EndI = GlobalSLocOffsetMap.end(); SLocMapI != EndI; ++SLocMapI) { ModuleFile &M = *SLocMapI->second; if (M.NumPreprocessedEntities) - return getGlobalPreprocessedEntityID(M, M.BasePreprocessedEntityID); + return M.BasePreprocessedEntityID; } return getTotalNumPreprocessedEntities(); @@ -3559,8 +3922,7 @@ ASTReader::findBeginPreprocessedEntity(SourceLocation BLoc) const { if (PPI == pp_end) return findNextPreprocessedEntity(SLocMapI); - return getGlobalPreprocessedEntityID(M, - M.BasePreprocessedEntityID + (PPI - pp_begin)); + return M.BasePreprocessedEntityID + (PPI - pp_begin); } /// \brief Returns the first preprocessed entity ID that begins after \arg ELoc. @@ -3589,8 +3951,7 @@ ASTReader::findEndPreprocessedEntity(SourceLocation ELoc) const { if (PPI == pp_end) return findNextPreprocessedEntity(SLocMapI); - return getGlobalPreprocessedEntityID(M, - M.BasePreprocessedEntityID + (PPI - pp_begin)); + return M.BasePreprocessedEntityID + (PPI - pp_begin); } /// \brief Returns a pair of [Begin, End) indices of preallocated @@ -3681,14 +4042,31 @@ HeaderFileInfo ASTReader::GetHeaderFileInfo(const FileEntry *FE) { } void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) { + // FIXME: Make it work properly with modules. + llvm::SmallVector<DiagnosticsEngine::DiagState *, 32> DiagStates; for (ModuleIterator I = ModuleMgr.begin(), E = ModuleMgr.end(); I != E; ++I) { ModuleFile &F = *(*I); unsigned Idx = 0; + DiagStates.clear(); + assert(!Diag.DiagStates.empty()); + DiagStates.push_back(&Diag.DiagStates.front()); // the command-line one. while (Idx < F.PragmaDiagMappings.size()) { SourceLocation Loc = ReadSourceLocation(F, F.PragmaDiagMappings[Idx++]); + unsigned DiagStateID = F.PragmaDiagMappings[Idx++]; + if (DiagStateID != 0) { + Diag.DiagStatePoints.push_back( + DiagnosticsEngine::DiagStatePoint(DiagStates[DiagStateID-1], + FullSourceLoc(Loc, SourceMgr))); + continue; + } + + assert(DiagStateID == 0); + // A new DiagState was created here. Diag.DiagStates.push_back(*Diag.GetCurDiagState()); + DiagnosticsEngine::DiagState *NewState = &Diag.DiagStates.back(); + DiagStates.push_back(NewState); Diag.DiagStatePoints.push_back( - DiagnosticsEngine::DiagStatePoint(&Diag.DiagStates.back(), + DiagnosticsEngine::DiagStatePoint(NewState, FullSourceLoc(Loc, SourceMgr))); while (1) { assert(Idx < F.PragmaDiagMappings.size() && @@ -4258,6 +4636,8 @@ void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { } void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { TL.setLocalRangeBegin(ReadSourceLocation(Record, Idx)); + TL.setLParenLoc(ReadSourceLocation(Record, Idx)); + TL.setRParenLoc(ReadSourceLocation(Record, Idx)); TL.setLocalRangeEnd(ReadSourceLocation(Record, Idx)); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) { TL.setArg(i, ReadDeclAs<ParmVarDecl>(Record, Idx)); @@ -4467,6 +4847,10 @@ QualType ASTReader::GetType(TypeID ID) { case PREDEF_TYPE_VA_LIST_TAG: T = Context.getVaListTagType(); break; + + case PREDEF_TYPE_BUILTIN_FN: + T = Context.BuiltinFnTy; + break; } assert(!T.isNull() && "Unknown predefined type"); @@ -4537,7 +4921,9 @@ ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F, case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: + case TemplateArgument::NullPtr: case TemplateArgument::Pack: + // FIXME: Is this right? return TemplateArgumentLocInfo(); } llvm_unreachable("unexpected template argument loc"); @@ -4593,7 +4979,7 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { } serialization::DeclID -ASTReader::getGlobalDeclID(ModuleFile &F, unsigned LocalID) const { +ASTReader::getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const { if (LocalID < NUM_PREDEF_DECL_IDS) return LocalID; @@ -4930,8 +5316,10 @@ namespace { continue; if (ND->getDeclName() != This->Name) { - assert(!This->Name.getCXXNameType().isNull() && - "Name mismatch without a type"); + // A name might be null because the decl's redeclarable part is + // currently read before reading its name. The lookup is triggered by + // building that decl (likely indirectly), and so it is later in the + // sense of "already existing" and can be ignored here. continue; } @@ -5132,13 +5520,15 @@ void ASTReader::PrintStats() { = IdentifiersLoaded.size() - std::count(IdentifiersLoaded.begin(), IdentifiersLoaded.end(), (IdentifierInfo *)0); + unsigned NumMacrosLoaded + = MacrosLoaded.size() - std::count(MacrosLoaded.begin(), + MacrosLoaded.end(), + (MacroInfo *)0); unsigned NumSelectorsLoaded = SelectorsLoaded.size() - std::count(SelectorsLoaded.begin(), SelectorsLoaded.end(), Selector()); - std::fprintf(stderr, " %u stat cache hits\n", NumStatHits); - std::fprintf(stderr, " %u stat cache misses\n", NumStatMisses); if (unsigned TotalNumSLocEntries = getTotalNumSLocs()) std::fprintf(stderr, " %u/%u source location entries read (%f%%)\n", NumSLocEntriesRead, TotalNumSLocEntries, @@ -5155,6 +5545,10 @@ void ASTReader::PrintStats() { std::fprintf(stderr, " %u/%u identifiers read (%f%%)\n", NumIdentifiersLoaded, (unsigned)IdentifiersLoaded.size(), ((float)NumIdentifiersLoaded/IdentifiersLoaded.size() * 100)); + if (!MacrosLoaded.empty()) + std::fprintf(stderr, " %u/%u macros read (%f%%)\n", + NumMacrosLoaded, (unsigned)MacrosLoaded.size(), + ((float)NumMacrosLoaded/MacrosLoaded.size() * 100)); if (!SelectorsLoaded.empty()) std::fprintf(stderr, " %u/%u selectors read (%f%%)\n", NumSelectorsLoaded, (unsigned)SelectorsLoaded.size(), @@ -5213,6 +5607,7 @@ void ASTReader::dump() { dumpModuleIDMap("Global type map", GlobalTypeMap); dumpModuleIDMap("Global declaration map", GlobalDeclMap); dumpModuleIDMap("Global identifier map", GlobalIdentifierMap); + dumpModuleIDMap("Global macro map", GlobalMacroMap); dumpModuleIDMap("Global submodule map", GlobalSubmoduleMap); dumpModuleIDMap("Global selector map", GlobalSelectorMap); dumpModuleIDMap("Global preprocessed entity map", @@ -5246,7 +5641,7 @@ void ASTReader::getMemoryBufferSizes(MemoryBufferSizes &sizes) const { void ASTReader::InitializeSema(Sema &S) { SemaObj = &S; - S.ExternalSource = this; + S.addExternalSource(this); // Makes sure any declarations that were deserialized "too early" // still get added to the identifier's declaration chains. @@ -5281,6 +5676,9 @@ void ASTReader::InitializeSema(Sema &S) { } IdentifierInfo* ASTReader::get(const char *NameStart, const char *NameEnd) { + // Note that we are loading an identifier. + Deserializing AnIdentifier(this); + IdentifierLookupVisitor Visitor(StringRef(NameStart, NameEnd - NameStart), /*PriorGeneration=*/0); ModuleMgr.visit(IdentifierLookupVisitor::visit, &Visitor); @@ -5570,6 +5968,7 @@ void ASTReader::ReadPendingInstantiations( ValueDecl *D = cast<ValueDecl>(GetDecl(PendingInstantiations[Idx++])); SourceLocation Loc = SourceLocation::getFromRawEncoding(PendingInstantiations[Idx++]); + Pending.push_back(std::make_pair(D, Loc)); } PendingInstantiations.clear(); @@ -5682,8 +6081,37 @@ IdentifierID ASTReader::getGlobalIdentifierID(ModuleFile &M, unsigned LocalID) { return LocalID + I->second; } -bool ASTReader::ReadSLocEntry(int ID) { - return ReadSLocEntryRecord(ID) != Success; +MacroInfo *ASTReader::getMacro(MacroID ID, MacroInfo *Hint) { + if (ID == 0) + return 0; + + if (MacrosLoaded.empty()) { + Error("no macro table in AST file"); + return 0; + } + + ID -= NUM_PREDEF_MACRO_IDS; + if (!MacrosLoaded[ID]) { + GlobalMacroMapType::iterator I + = GlobalMacroMap.find(ID + NUM_PREDEF_MACRO_IDS); + assert(I != GlobalMacroMap.end() && "Corrupted global macro map"); + ModuleFile *M = I->second; + unsigned Index = ID - M->BaseMacroID; + ReadMacroRecord(*M, M->MacroOffsets[Index], Hint); + } + + return MacrosLoaded[ID]; +} + +MacroID ASTReader::getGlobalMacroID(ModuleFile &M, unsigned LocalID) { + if (LocalID < NUM_PREDEF_MACRO_IDS) + return LocalID; + + ContinuousRangeMap<uint32_t, int, 2>::iterator I + = M.MacroRemap.find(LocalID - NUM_PREDEF_MACRO_IDS); + assert(I != M.MacroRemap.end() && "Invalid index into macro index remap"); + + return LocalID + I->second; } serialization::SubmoduleID @@ -5694,7 +6122,7 @@ ASTReader::getGlobalSubmoduleID(ModuleFile &M, unsigned LocalID) { ContinuousRangeMap<uint32_t, int, 2>::iterator I = M.SubmoduleRemap.find(LocalID - NUM_PREDEF_SUBMODULE_IDS); assert(I != M.SubmoduleRemap.end() - && "Invalid index into identifier index remap"); + && "Invalid index into submodule index remap"); return LocalID + I->second; } @@ -5759,7 +6187,7 @@ ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const { ContinuousRangeMap<uint32_t, int, 2>::iterator I = M.SelectorRemap.find(LocalID - NUM_PREDEF_SELECTOR_IDS); assert(I != M.SelectorRemap.end() - && "Invalid index into identifier index remap"); + && "Invalid index into selector index remap"); return LocalID + I->second; } @@ -5926,8 +6354,13 @@ ASTReader::ReadTemplateArgument(ModuleFile &F, return TemplateArgument(); case TemplateArgument::Type: return TemplateArgument(readType(F, Record, Idx)); - case TemplateArgument::Declaration: - return TemplateArgument(ReadDecl(F, Record, Idx)); + case TemplateArgument::Declaration: { + ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx); + bool ForReferenceParam = Record[Idx++]; + return TemplateArgument(D, ForReferenceParam); + } + case TemplateArgument::NullPtr: + return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true); case TemplateArgument::Integral: { llvm::APSInt Value = ReadAPSInt(Record, Idx); QualType T = readType(F, Record, Idx); @@ -6340,7 +6773,8 @@ void ASTReader::ReadComments() { } void ASTReader::finishPendingActions() { - while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty()) { + while (!PendingIdentifierInfos.empty() || !PendingDeclChains.empty() || + !PendingMacroIDs.empty()) { // If any identifiers with corresponding top-level declarations have // been loaded, load those declarations now. while (!PendingIdentifierInfos.empty()) { @@ -6355,6 +6789,18 @@ void ASTReader::finishPendingActions() { PendingDeclChainsKnown.erase(PendingDeclChains[I]); } PendingDeclChains.clear(); + + // Load any pending macro definitions. + for (unsigned I = 0; I != PendingMacroIDs.size(); ++I) { + // FIXME: std::move here + SmallVector<MacroID, 2> GlobalIDs = PendingMacroIDs.begin()[I].second; + MacroInfo *Hint = 0; + for (unsigned IDIdx = 0, NumIDs = GlobalIDs.size(); IDIdx != NumIDs; + ++IDIdx) { + Hint = getMacro(GlobalIDs[IDIdx], Hint); + } + } + PendingMacroIDs.clear(); } // If we deserialized any C++ or Objective-C class definitions, any @@ -6408,9 +6854,29 @@ void ASTReader::finishPendingActions() { for (RedeclarableTemplateDecl::redecl_iterator R = RTD->redecls_begin(), REnd = RTD->redecls_end(); R != REnd; ++R) - R->Common = RTD->Common; + R->Common = RTD->Common; } PendingDefinitions.clear(); + + // Load the bodies of any functions or methods we've encountered. We do + // this now (delayed) so that we can be sure that the declaration chains + // have been fully wired up. + for (PendingBodiesMap::iterator PB = PendingBodies.begin(), + PBEnd = PendingBodies.end(); + PB != PBEnd; ++PB) { + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(PB->first)) { + // FIXME: Check for =delete/=default? + // FIXME: Complain about ODR violations here? + if (!getContext().getLangOpts().Modules || !FD->hasBody()) + FD->setLazyBody(PB->second); + continue; + } + + ObjCMethodDecl *MD = cast<ObjCMethodDecl>(PB->first); + if (!getContext().getLangOpts().Modules || !MD->hasBody()) + MD->setLazyBody(PB->second); + } + PendingBodies.clear(); } void ASTReader::FinishedDeserializing() { @@ -6442,17 +6908,14 @@ void ASTReader::FinishedDeserializing() { ASTReader::ASTReader(Preprocessor &PP, ASTContext &Context, StringRef isysroot, bool DisableValidation, - bool DisableStatCache, bool AllowASTWithCompilerErrors) + bool AllowASTWithCompilerErrors) : Listener(new PCHValidator(PP, *this)), DeserializationListener(0), SourceMgr(PP.getSourceManager()), FileMgr(PP.getFileManager()), Diags(PP.getDiagnostics()), SemaObj(0), PP(PP), Context(Context), - Consumer(0), ModuleMgr(FileMgr.getFileSystemOptions()), - RelocatablePCH(false), isysroot(isysroot), - DisableValidation(DisableValidation), - DisableStatCache(DisableStatCache), + Consumer(0), ModuleMgr(PP.getFileManager()), + isysroot(isysroot), DisableValidation(DisableValidation), AllowASTWithCompilerErrors(AllowASTWithCompilerErrors), CurrentGeneration(0), CurrSwitchCaseStmts(&SwitchCaseStmts), - NumStatHits(0), NumStatMisses(0), NumSLocEntriesRead(0), TotalNumSLocEntries(0), NumStatementsRead(0), TotalNumStatements(0), NumMacrosRead(0), TotalNumMacros(0), NumSelectorsRead(0), NumMethodPoolEntriesRead(0), diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index cb21f82600e0..c42944df6344 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -37,7 +37,6 @@ namespace clang { class ASTDeclReader : public DeclVisitor<ASTDeclReader, void> { ASTReader &Reader; ModuleFile &F; - llvm::BitstreamCursor &Cursor; const DeclID ThisDeclID; const unsigned RawLocation; typedef ASTReader::RecordData RecordData; @@ -48,6 +47,8 @@ namespace clang { DeclID DeclContextIDForTemplateParmDecl; DeclID LexicalDeclContextIDForTemplateParmDecl; + bool HasPendingBody; + uint64_t GetCurrentCursorOffset(); SourceLocation ReadSourceLocation(const RecordData &R, unsigned &I) { @@ -116,7 +117,7 @@ namespace clang { GlobalDeclID FirstID; mutable bool Owning; - RedeclarableResult &operator=(RedeclarableResult&); // DO NOT IMPLEMENT + void operator=(RedeclarableResult &) LLVM_DELETED_FUNCTION; public: RedeclarableResult(ASTReader &Reader, GlobalDeclID FirstID) @@ -162,7 +163,7 @@ namespace clang { NamedDecl *Existing; mutable bool AddResult; - FindExistingResult &operator=(FindExistingResult&); // DO NOT IMPLEMENT + void operator=(FindExistingResult&) LLVM_DELETED_FUNCTION; public: FindExistingResult(ASTReader &Reader) @@ -194,16 +195,19 @@ namespace clang { public: ASTDeclReader(ASTReader &Reader, ModuleFile &F, - llvm::BitstreamCursor &Cursor, DeclID thisDeclID, + DeclID thisDeclID, unsigned RawLocation, const RecordData &Record, unsigned &Idx) - : Reader(Reader), F(F), Cursor(Cursor), ThisDeclID(thisDeclID), + : Reader(Reader), F(F), ThisDeclID(thisDeclID), RawLocation(RawLocation), Record(Record), Idx(Idx), - TypeIDForTypeDecl(0) { } + TypeIDForTypeDecl(0), HasPendingBody(false) { } static void attachPreviousDecl(Decl *D, Decl *previous); static void attachLatestDecl(Decl *D, Decl *latest); + /// \brief Determine whether this declaration has a pending body. + bool hasPendingBody() const { return HasPendingBody; } + void Visit(Decl *D); void UpdateDecl(Decl *D, ModuleFile &ModuleFile, @@ -321,8 +325,14 @@ void ASTDeclReader::Visit(Decl *D) { ID->TypeForDecl = Reader.GetType(TypeIDForTypeDecl).getTypePtrOrNull(); } else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // FunctionDecl's body was written last after all other Stmts/Exprs. - if (Record[Idx++]) - FD->setLazyBody(GetCurrentCursorOffset()); + // We only read it if FD doesn't already have a body (e.g., from another + // module). + // FIXME: Also consider = default and = delete. + // FIXME: Can we diagnose ODR violations somehow? + if (Record[Idx++]) { + Reader.PendingBodies[FD] = GetCurrentCursorOffset(); + HasPendingBody = true; + } } else if (D->isTemplateParameter()) { // If we have a fully initialized template parameter, we can now // set its DeclContext. @@ -590,8 +600,10 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { TemplArgs.size(), C); void *InsertPos = 0; CanonTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); - assert(InsertPos && "Another specialization already inserted!"); - CanonTemplate->getSpecializations().InsertNode(FTInfo, InsertPos); + if (InsertPos) + CanonTemplate->getSpecializations().InsertNode(FTInfo, InsertPos); + else + assert(0 && "Another specialization already inserted!"); } break; } @@ -628,19 +640,16 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { VisitNamedDecl(MD); if (Record[Idx++]) { - // In practice, this won't be executed (since method definitions - // don't occur in header files). - // Switch case IDs for this method body. - ASTReader::SwitchCaseMapTy SwitchCaseStmtsForObjCMethod; - SaveAndRestore<ASTReader::SwitchCaseMapTy *> - SCFOM(Reader.CurrSwitchCaseStmts, &SwitchCaseStmtsForObjCMethod); - MD->setBody(Reader.ReadStmt(F)); + // Load the body on-demand. Most clients won't care, because method + // definitions rarely show up in headers. + Reader.PendingBodies[MD] = GetCurrentCursorOffset(); + HasPendingBody = true; MD->setSelfDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx)); MD->setCmdDecl(ReadDeclAs<ImplicitParamDecl>(Record, Idx)); } MD->setInstanceMethod(Record[Idx++]); MD->setVariadic(Record[Idx++]); - MD->setSynthesized(Record[Idx++]); + MD->setPropertyAccessor(Record[Idx++]); MD->setDefined(Record[Idx++]); MD->IsOverriding = Record[Idx++]; @@ -846,6 +855,8 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>(Record, Idx)); D->setIvarLBraceLoc(ReadSourceLocation(Record, Idx)); D->setIvarRBraceLoc(ReadSourceLocation(Record, Idx)); + D->setHasNonZeroConstructors(Record[Idx++]); + D->setHasDestructors(Record[Idx++]); llvm::tie(D->IvarInitializers, D->NumIvarInitializers) = Reader.ReadCXXCtorInitializers(F, Record, Idx); } @@ -897,7 +908,8 @@ void ASTDeclReader::VisitVarDecl(VarDecl *VD) { VD->VarDeclBits.NRVOVariable = Record[Idx++]; VD->VarDeclBits.CXXForRangeDecl = Record[Idx++]; VD->VarDeclBits.ARCPseudoStrong = Record[Idx++]; - + VD->VarDeclBits.IsConstexpr = Record[Idx++]; + // Only true variables (not parameters or implicit parameters) can be merged. if (VD->getKind() == Decl::Var) mergeRedeclarable(VD, Redecl); @@ -1135,6 +1147,7 @@ void ASTDeclReader::ReadCXXDefinitionData( Lambda.Captures = (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures); Capture *ToCapture = Lambda.Captures; + Lambda.MethodTyInfo = GetTypeSourceInfo(Record, Idx); for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { SourceLocation Loc = ReadSourceLocation(Record, Idx); bool IsImplicit = Record[Idx++]; @@ -1155,7 +1168,8 @@ void ASTDeclReader::VisitCXXRecordDecl(CXXRecordDecl *D) { // allocate the appropriate DefinitionData structure. bool IsLambda = Record[Idx++]; if (IsLambda) - D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, false); + D->DefinitionData = new (C) CXXRecordDecl::LambdaDefinitionData(D, 0, + false); else D->DefinitionData = new (C) struct CXXRecordDecl::DefinitionData(D); @@ -1242,6 +1256,7 @@ void ASTDeclReader::VisitImportDecl(ImportDecl *D) { SourceLocation *StoredLocs = reinterpret_cast<SourceLocation *>(D + 1); for (unsigned I = 0, N = Record.back(); I != N; ++I) StoredLocs[I] = ReadSourceLocation(Record, Idx); + ++Idx; // The number of stored source locations. } void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) { @@ -1308,10 +1323,12 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { D->setMemberSpecialization(); } } - + VisitTemplateDecl(D); D->IdentifierNamespace = Record[Idx++]; - + + mergeRedeclarable(D, Redecl); + return Redecl; } @@ -1336,10 +1353,10 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { for (unsigned I = 0; I != Size; ++I) SpecIDs.push_back(ReadDeclID(Record, Idx)); + ClassTemplateDecl::Common *CommonPtr = D->getCommonPtr(); if (SpecIDs[0]) { typedef serialization::DeclID DeclID; - ClassTemplateDecl::Common *CommonPtr = D->getCommonPtr(); // FIXME: Append specializations! CommonPtr->LazySpecializations = new (Reader.getContext()) DeclID [SpecIDs.size()]; @@ -1347,7 +1364,7 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { SpecIDs.size() * sizeof(DeclID)); } - // InjectedClassNameType is computed. + CommonPtr->InjectedClassNameType = Reader.readType(F, Record, Idx); } } @@ -1391,14 +1408,17 @@ void ASTDeclReader::VisitClassTemplateSpecializationDecl( TemplArgs.size()); D->PointOfInstantiation = ReadSourceLocation(Record, Idx); D->SpecializationKind = (TemplateSpecializationKind)Record[Idx++]; - - if (D->isCanonicalDecl()) { // It's kept in the folding set. + + bool writtenAsCanonicalDecl = Record[Idx++]; + if (writtenAsCanonicalDecl) { ClassTemplateDecl *CanonPattern = ReadDeclAs<ClassTemplateDecl>(Record,Idx); - if (ClassTemplatePartialSpecializationDecl *Partial - = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) { - CanonPattern->getCommonPtr()->PartialSpecializations.InsertNode(Partial); - } else { - CanonPattern->getCommonPtr()->Specializations.InsertNode(D); + if (D->isCanonicalDecl()) { // It's kept in the folding set. + if (ClassTemplatePartialSpecializationDecl *Partial + = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) { + CanonPattern->getCommonPtr()->PartialSpecializations.GetOrInsertNode(Partial); + } else { + CanonPattern->getCommonPtr()->Specializations.GetOrInsertNode(D); + } } } } @@ -1486,11 +1506,18 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { // TemplateParmPosition. D->setDepth(Record[Idx++]); D->setPosition(Record[Idx++]); - // Rest of TemplateTemplateParmDecl. - TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx); - bool IsInherited = Record[Idx++]; - D->setDefaultArgument(Arg, IsInherited); - D->ParameterPack = Record[Idx++]; + if (D->isExpandedParameterPack()) { + void **Data = reinterpret_cast<void **>(D + 1); + for (unsigned I = 0, N = D->getNumExpansionTemplateParameters(); + I != N; ++I) + Data[I] = Reader.ReadTemplateParameterList(F, Record, Idx); + } else { + // Rest of TemplateTemplateParmDecl. + TemplateArgumentLoc Arg = Reader.ReadTemplateArgumentLoc(F, Record, Idx); + bool IsInherited = Record[Idx++]; + D->setDefaultArgument(Arg, IsInherited); + D->ParameterPack = Record[Idx++]; + } } void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { @@ -1640,7 +1667,7 @@ inline void ASTReader::LoadedDecl(unsigned Index, Decl *D) { /// This routine should return true for anything that might affect /// code generation, e.g., inline function definitions, Objective-C /// declarations with metadata, etc. -static bool isConsumerInterestedIn(Decl *D) { +static bool isConsumerInterestedIn(Decl *D, bool HasBody) { // An ObjCMethodDecl is never considered as "interesting" because its // implementation container always is. @@ -1652,7 +1679,7 @@ static bool isConsumerInterestedIn(Decl *D) { return Var->isFileVarDecl() && Var->isThisDeclarationADefinition() == VarDecl::Definition; if (FunctionDecl *Func = dyn_cast<FunctionDecl>(D)) - return Func->doesThisDeclarationHaveABody(); + return Func->doesThisDeclarationHaveABody() || HasBody; return false; } @@ -1719,8 +1746,10 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { if (TagDecl *TagX = dyn_cast<TagDecl>(X)) { TagDecl *TagY = cast<TagDecl>(Y); return (TagX->getTagKind() == TagY->getTagKind()) || - ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class) && - (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class)); + ((TagX->getTagKind() == TTK_Struct || TagX->getTagKind() == TTK_Class || + TagX->getTagKind() == TTK_Interface) && + (TagY->getTagKind() == TTK_Struct || TagY->getTagKind() == TTK_Class || + TagY->getTagKind() == TTK_Interface)); } // Functions with the same type and linkage match. @@ -1731,7 +1760,7 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { return (FuncX->getLinkage() == FuncY->getLinkage()) && FuncX->getASTContext().hasSameType(FuncX->getType(), FuncY->getType()); } - + // Variables with the same type and linkage match. if (VarDecl *VarX = dyn_cast<VarDecl>(X)) { VarDecl *VarY = cast<VarDecl>(Y); @@ -1744,7 +1773,11 @@ static bool isSameEntity(NamedDecl *X, NamedDecl *Y) { NamespaceDecl *NamespaceY = cast<NamespaceDecl>(Y); return NamespaceX->isInline() == NamespaceY->isInline(); } - + + // Identical template names and kinds match. + if (isa<TemplateDecl>(X)) + return true; + // FIXME: Many other cases to implement. return false; } @@ -1753,11 +1786,13 @@ ASTDeclReader::FindExistingResult::~FindExistingResult() { if (!AddResult || Existing) return; - DeclContext *DC = New->getDeclContext()->getRedeclContext(); - if (DC->isTranslationUnit() && Reader.SemaObj) { + if (New->getDeclContext()->getRedeclContext()->isTranslationUnit() + && Reader.SemaObj) { Reader.SemaObj->IdResolver.tryAddTopLevelDecl(New, New->getDeclName()); - } else if (DC->isNamespace()) { - DC->addDecl(New); + } else { + DeclContext *DC = New->getLexicalDeclContext(); + if (DC->isNamespace()) + DC->addDecl(New); } } @@ -1899,7 +1934,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { RecordData Record; unsigned Code = DeclsCursor.ReadCode(); unsigned Idx = 0; - ASTDeclReader Reader(*this, *Loc.F, DeclsCursor, ID, RawLocation, Record,Idx); + ASTDeclReader Reader(*this, *Loc.F, ID, RawLocation, Record,Idx); Decl *D = 0; switch ((DeclCode)DeclsCursor.ReadRecord(Code, Record)) { @@ -2002,6 +2037,10 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_TEMPLATE_TEMPLATE_PARM: D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID); break; + case DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK: + D = TemplateTemplateParmDecl::CreateDeserialized(Context, ID, + Record[Idx++]); + break; case DECL_TYPE_ALIAS_TEMPLATE: D = TypeAliasTemplateDecl::CreateDeserialized(Context, ID); break; @@ -2110,6 +2149,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { } PendingVisibleUpdates.erase(I); } + + if (!DC->hasExternalVisibleStorage() && DC->hasExternalLexicalStorage()) + DC->setMustBuildLookupTable(); } assert(Idx == Record.size()); @@ -2125,9 +2167,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { // AST consumer might need to know about, queue it. // We don't pass it to the consumer immediately because we may be in recursive // loading, and some declarations may still be initializing. - if (isConsumerInterestedIn(D)) + if (isConsumerInterestedIn(D, Reader.hasPendingBody())) InterestingDecls.push_back(D); - + return D; } @@ -2152,7 +2194,7 @@ void ASTReader::loadDeclUpdateRecords(serialization::DeclID ID, Decl *D) { assert(RecCode == DECL_UPDATES && "Expected DECL_UPDATES record!"); unsigned Idx = 0; - ASTDeclReader Reader(*this, *F, Cursor, ID, 0, Record, Idx); + ASTDeclReader Reader(*this, *F, ID, 0, Record, Idx); Reader.UpdateDecl(D, *F, Record); } } @@ -2207,10 +2249,8 @@ namespace { if (!D) return; - if (Deserialized.count(D)) { - Deserialized.erase(D); + if (Deserialized.erase(D)) Chain.push_back(D); - } } void searchForID(ModuleFile &M, GlobalDeclID GlobalID) { @@ -2275,7 +2315,7 @@ void ASTReader::loadPendingDeclChain(serialization::GlobalDeclID ID) { } MergedDeclsMap::iterator MergedPos = combineStoredMergedDecls(CanonDecl, ID); if (MergedPos != MergedDecls.end()) - SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end()); + SearchDecls.append(MergedPos->second.begin(), MergedPos->second.end()); // Build up the list of redeclarations. RedeclChainVisitor Visitor(*this, SearchDecls, RedeclsDeserialized, CanonID); @@ -2331,9 +2371,8 @@ namespace { void add(ObjCCategoryDecl *Cat) { // Only process each category once. - if (!Deserialized.count(Cat)) + if (!Deserialized.erase(Cat)) return; - Deserialized.erase(Cat); // Check for duplicate categories. if (Cat->getDeclName()) { diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index c5325b5f7837..367f75f55eb0 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -288,7 +288,7 @@ void ASTStmtReader::VisitDeclStmt(DeclStmt *S) { } } -void ASTStmtReader::VisitAsmStmt(AsmStmt *S) { +void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) { VisitStmt(S); unsigned NumOutputs = Record[Idx++]; unsigned NumInputs = Record[Idx++]; @@ -297,7 +297,6 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) { S->setRParenLoc(ReadSourceLocation(Record, Idx)); S->setVolatile(Record[Idx++]); S->setSimple(Record[Idx++]); - S->setMSAsm(Record[Idx++]); S->setAsmString(cast_or_null<StringLiteral>(Reader.ReadSubStmt())); @@ -566,6 +565,7 @@ void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) { E->setRHS(Reader.ReadSubExpr()); E->setOpcode((BinaryOperator::Opcode)Record[Idx++]); E->setOperatorLoc(ReadSourceLocation(Record, Idx)); + E->setFPContractable((bool)Record[Idx++]); } void ASTStmtReader::VisitCompoundAssignOperator(CompoundAssignOperator *E) { @@ -627,7 +627,8 @@ void ASTStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { void ASTStmtReader::VisitInitListExpr(InitListExpr *E) { VisitExpr(E); - E->setSyntacticForm(cast_or_null<InitListExpr>(Reader.ReadSubStmt())); + if (InitListExpr *SyntForm = cast_or_null<InitListExpr>(Reader.ReadSubStmt())) + E->setSyntacticForm(SyntForm); E->setLBraceLoc(ReadSourceLocation(Record, Idx)); E->setRBraceLoc(ReadSourceLocation(Record, Idx)); bool isArrayFiller = Record[Idx++]; @@ -1087,6 +1088,7 @@ void ASTStmtReader::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { VisitCallExpr(E); E->Operator = (OverloadedOperatorKind)Record[Idx++]; E->Range = Reader.ReadSourceRange(F, Record, Idx); + E->setFPContractable((bool)Record[Idx++]); } void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { @@ -1242,7 +1244,7 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) { E->setOperatorDelete(ReadDeclAs<FunctionDecl>(Record, Idx)); E->AllocatedTypeInfo = GetTypeSourceInfo(Record, Idx); E->TypeIdParens = ReadSourceRange(Record, Idx); - E->StartLoc = ReadSourceLocation(Record, Idx); + E->Range = ReadSourceRange(Record, Idx); E->DirectInitRange = ReadSourceRange(Record, Idx); E->AllocateArgsArray(Reader.getContext(), isArray, NumPlacementArgs, @@ -1367,8 +1369,6 @@ void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { VisitOverloadExpr(E); E->RequiresADL = Record[Idx++]; - if (E->RequiresADL) - E->StdIsAssociatedNamespace = Record[Idx++]; E->Overloaded = Record[Idx++]; E->NamingClass = ReadDeclAs<CXXRecordDecl>(Record, Idx); } @@ -1469,6 +1469,16 @@ void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr( E->NameLoc = ReadSourceLocation(Record, Idx); } +void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { + VisitExpr(E); + E->NumParameters = Record[Idx++]; + E->ParamPack = ReadDeclAs<ParmVarDecl>(Record, Idx); + E->NameLoc = ReadSourceLocation(Record, Idx); + ParmVarDecl **Parms = reinterpret_cast<ParmVarDecl**>(E+1); + for (unsigned i = 0, n = E->NumParameters; i != n; ++i) + Parms[i] = ReadDeclAs<ParmVarDecl>(Record, Idx); +} + void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { VisitExpr(E); E->Temporary = Reader.ReadSubExpr(); @@ -1701,8 +1711,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { S = new (Context) DeclStmt(Empty); break; - case STMT_ASM: - S = new (Context) AsmStmt(Empty); + case STMT_GCCASM: + S = new (Context) GCCAsmStmt(Empty); + break; + + case STMT_MSASM: + S = new (Context) MSAsmStmt(Empty); break; case EXPR_PREDEFINED: @@ -2180,6 +2194,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { case EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK: S = new (Context) SubstNonTypeTemplateParmPackExpr(Empty); break; + + case EXPR_FUNCTION_PARM_PACK: + S = FunctionParmPackExpr::CreateEmpty(Context, + Record[ASTStmtReader::NumExprFields]); + break; case EXPR_MATERIALIZE_TEMPORARY: S = new (Context) MaterializeTemporaryExpr(Empty); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 425d2e32a7b1..a2e8b71123b1 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -25,9 +25,11 @@ #include "clang/AST/Type.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Serialization/ASTReader.h" +#include "clang/Lex/HeaderSearchOptions.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PreprocessingRecord.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemStatCache.h" @@ -35,6 +37,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/SourceManagerInternals.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TargetOptions.h" #include "clang/Basic/Version.h" #include "clang/Basic/VersionTuple.h" #include "llvm/ADT/APFloat.h" @@ -485,6 +488,8 @@ void TypeLocWriter::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { } void TypeLocWriter::VisitFunctionTypeLoc(FunctionTypeLoc TL) { Writer.AddSourceLocation(TL.getLocalRangeBegin(), Record); + Writer.AddSourceLocation(TL.getLParenLoc(), Record); + Writer.AddSourceLocation(TL.getRParenLoc(), Record); Writer.AddSourceLocation(TL.getLocalRangeEnd(), Record); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) Writer.AddDeclRef(TL.getArg(i), Record); @@ -667,7 +672,8 @@ static void AddStmtsExprs(llvm::BitstreamWriter &Stream, RECORD(STMT_BREAK); RECORD(STMT_RETURN); RECORD(STMT_DECL); - RECORD(STMT_ASM); + RECORD(STMT_GCCASM); + RECORD(STMT_MSASM); RECORD(EXPR_PREDEFINED); RECORD(EXPR_DECL_REF); RECORD(EXPR_INTEGER_LITERAL); @@ -763,14 +769,27 @@ void ASTWriter::WriteBlockInfoBlock() { #define BLOCK(X) EmitBlockID(X ## _ID, #X, Stream, Record) #define RECORD(X) EmitRecordID(X, #X, Stream, Record) + // Control Block. + BLOCK(CONTROL_BLOCK); + RECORD(METADATA); + RECORD(IMPORTS); + RECORD(LANGUAGE_OPTIONS); + RECORD(TARGET_OPTIONS); + RECORD(ORIGINAL_FILE); + RECORD(ORIGINAL_PCH_DIR); + RECORD(INPUT_FILE_OFFSETS); + RECORD(DIAGNOSTIC_OPTIONS); + RECORD(FILE_SYSTEM_OPTIONS); + RECORD(HEADER_SEARCH_OPTIONS); + RECORD(PREPROCESSOR_OPTIONS); + + BLOCK(INPUT_FILES_BLOCK); + RECORD(INPUT_FILE); + // AST Top-Level Block. BLOCK(AST_BLOCK); - RECORD(ORIGINAL_FILE_NAME); - RECORD(ORIGINAL_FILE_ID); RECORD(TYPE_OFFSET); RECORD(DECL_OFFSET); - RECORD(LANGUAGE_OPTIONS); - RECORD(METADATA); RECORD(IDENTIFIER_OFFSET); RECORD(IDENTIFIER_TABLE); RECORD(EXTERNAL_DEFINITIONS); @@ -784,11 +803,8 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(PP_COUNTER_VALUE); RECORD(SOURCE_LOCATION_OFFSETS); RECORD(SOURCE_LOCATION_PRELOADS); - RECORD(STAT_CACHE); RECORD(EXT_VECTOR_DECLS); - RECORD(VERSION_CONTROL_BRANCH_REVISION); RECORD(PPD_ENTITIES_OFFSETS); - RECORD(IMPORTS); RECORD(REFERENCED_SELECTOR_POOL); RECORD(TU_UPDATE_LEXICAL); RECORD(LOCAL_REDECLARATIONS_MAP); @@ -803,11 +819,9 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(DIAG_PRAGMA_MAPPINGS); RECORD(CUDA_SPECIAL_DECL_REFS); RECORD(HEADER_SEARCH_TABLE); - RECORD(ORIGINAL_PCH_DIR); RECORD(FP_PRAGMA_OPTIONS); RECORD(OPENCL_EXTENSIONS); RECORD(DELEGATING_CTORS); - RECORD(FILE_SOURCE_LOCATION_OFFSETS); RECORD(KNOWN_NAMESPACES); RECORD(MODULE_OFFSET_MAP); RECORD(SOURCE_MANAGER_LINE_TABLE); @@ -817,6 +831,8 @@ void ASTWriter::WriteBlockInfoBlock() { RECORD(MERGED_DECLARATIONS); RECORD(LOCAL_REDECLARATIONS); RECORD(OBJC_CATEGORIES); + RECORD(MACRO_OFFSET); + RECORD(MACRO_UPDATES); // SourceManager Block. BLOCK(SOURCE_MANAGER_BLOCK); @@ -972,25 +988,25 @@ adjustFilenameForRelocatablePCH(const char *Filename, StringRef isysroot) { return Filename + Pos; } -/// \brief Write the AST metadata (e.g., i686-apple-darwin9). -void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot, - const std::string &OutputFile) { +/// \brief Write the control block. +void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, + StringRef isysroot, + const std::string &OutputFile) { using namespace llvm; - - // Metadata - const TargetInfo &Target = Context.getTargetInfo(); - BitCodeAbbrev *MetaAbbrev = new BitCodeAbbrev(); - MetaAbbrev->Add(BitCodeAbbrevOp(METADATA)); - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST major - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // AST minor - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang major - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang minor - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Has errors - MetaAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Target triple - unsigned MetaAbbrevCode = Stream.EmitAbbrev(MetaAbbrev); - + Stream.EnterSubblock(CONTROL_BLOCK_ID, 5); RecordData Record; + + // Metadata + BitCodeAbbrev *MetadataAbbrev = new BitCodeAbbrev(); + MetadataAbbrev->Add(BitCodeAbbrevOp(METADATA)); + MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Major + MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Minor + MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang maj. + MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 16)); // Clang min. + MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Relocatable + MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Errors + MetadataAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag + unsigned MetadataAbbrevCode = Stream.EmitAbbrev(MetadataAbbrev); Record.push_back(METADATA); Record.push_back(VERSION_MAJOR); Record.push_back(VERSION_MINOR); @@ -998,9 +1014,10 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot, Record.push_back(CLANG_VERSION_MINOR); Record.push_back(!isysroot.empty()); Record.push_back(ASTHasCompilerErrors); - const std::string &Triple = Target.getTriple().getTriple(); - Stream.EmitRecordWithBlob(MetaAbbrevCode, Record, Triple); + Stream.EmitRecordWithBlob(MetadataAbbrevCode, Record, + getClangFullRepositoryVersion()); + // Imports if (Chain) { serialization::ModuleManager &Mgr = Chain->getModuleManager(); llvm::SmallVector<char, 128> ModulePaths; @@ -1022,11 +1039,131 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot, Stream.EmitRecord(IMPORTS, Record); } + // Language options. + Record.clear(); + const LangOptions &LangOpts = Context.getLangOpts(); +#define LANGOPT(Name, Bits, Default, Description) \ + Record.push_back(LangOpts.Name); +#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ + Record.push_back(static_cast<unsigned>(LangOpts.get##Name())); +#include "clang/Basic/LangOptions.def" + + Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind()); + AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record); + + Record.push_back(LangOpts.CurrentModule.size()); + Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end()); + Stream.EmitRecord(LANGUAGE_OPTIONS, Record); + + // Target options. + Record.clear(); + const TargetInfo &Target = Context.getTargetInfo(); + const TargetOptions &TargetOpts = Target.getTargetOpts(); + AddString(TargetOpts.Triple, Record); + AddString(TargetOpts.CPU, Record); + AddString(TargetOpts.ABI, Record); + AddString(TargetOpts.CXXABI, Record); + AddString(TargetOpts.LinkerVersion, Record); + Record.push_back(TargetOpts.FeaturesAsWritten.size()); + for (unsigned I = 0, N = TargetOpts.FeaturesAsWritten.size(); I != N; ++I) { + AddString(TargetOpts.FeaturesAsWritten[I], Record); + } + Record.push_back(TargetOpts.Features.size()); + for (unsigned I = 0, N = TargetOpts.Features.size(); I != N; ++I) { + AddString(TargetOpts.Features[I], Record); + } + Stream.EmitRecord(TARGET_OPTIONS, Record); + + // Diagnostic options. + Record.clear(); + const DiagnosticOptions &DiagOpts + = Context.getDiagnostics().getDiagnosticOptions(); +#define DIAGOPT(Name, Bits, Default) Record.push_back(DiagOpts.Name); +#define ENUM_DIAGOPT(Name, Type, Bits, Default) \ + Record.push_back(static_cast<unsigned>(DiagOpts.get##Name())); +#include "clang/Basic/DiagnosticOptions.def" + Record.push_back(DiagOpts.Warnings.size()); + for (unsigned I = 0, N = DiagOpts.Warnings.size(); I != N; ++I) + AddString(DiagOpts.Warnings[I], Record); + // Note: we don't serialize the log or serialization file names, because they + // are generally transient files and will almost always be overridden. + Stream.EmitRecord(DIAGNOSTIC_OPTIONS, Record); + + // File system options. + Record.clear(); + const FileSystemOptions &FSOpts + = Context.getSourceManager().getFileManager().getFileSystemOptions(); + AddString(FSOpts.WorkingDir, Record); + Stream.EmitRecord(FILE_SYSTEM_OPTIONS, Record); + + // Header search options. + Record.clear(); + const HeaderSearchOptions &HSOpts + = PP.getHeaderSearchInfo().getHeaderSearchOpts(); + AddString(HSOpts.Sysroot, Record); + + // Include entries. + Record.push_back(HSOpts.UserEntries.size()); + for (unsigned I = 0, N = HSOpts.UserEntries.size(); I != N; ++I) { + const HeaderSearchOptions::Entry &Entry = HSOpts.UserEntries[I]; + AddString(Entry.Path, Record); + Record.push_back(static_cast<unsigned>(Entry.Group)); + Record.push_back(Entry.IsUserSupplied); + Record.push_back(Entry.IsFramework); + Record.push_back(Entry.IgnoreSysRoot); + Record.push_back(Entry.IsInternal); + Record.push_back(Entry.ImplicitExternC); + } + + // System header prefixes. + Record.push_back(HSOpts.SystemHeaderPrefixes.size()); + for (unsigned I = 0, N = HSOpts.SystemHeaderPrefixes.size(); I != N; ++I) { + AddString(HSOpts.SystemHeaderPrefixes[I].Prefix, Record); + Record.push_back(HSOpts.SystemHeaderPrefixes[I].IsSystemHeader); + } + + AddString(HSOpts.ResourceDir, Record); + AddString(HSOpts.ModuleCachePath, Record); + Record.push_back(HSOpts.DisableModuleHash); + Record.push_back(HSOpts.UseBuiltinIncludes); + Record.push_back(HSOpts.UseStandardSystemIncludes); + Record.push_back(HSOpts.UseStandardCXXIncludes); + Record.push_back(HSOpts.UseLibcxx); + Stream.EmitRecord(HEADER_SEARCH_OPTIONS, Record); + + // Preprocessor options. + Record.clear(); + const PreprocessorOptions &PPOpts = PP.getPreprocessorOpts(); + + // Macro definitions. + Record.push_back(PPOpts.Macros.size()); + for (unsigned I = 0, N = PPOpts.Macros.size(); I != N; ++I) { + AddString(PPOpts.Macros[I].first, Record); + Record.push_back(PPOpts.Macros[I].second); + } + + // Includes + Record.push_back(PPOpts.Includes.size()); + for (unsigned I = 0, N = PPOpts.Includes.size(); I != N; ++I) + AddString(PPOpts.Includes[I], Record); + + // Macro includes + Record.push_back(PPOpts.MacroIncludes.size()); + for (unsigned I = 0, N = PPOpts.MacroIncludes.size(); I != N; ++I) + AddString(PPOpts.MacroIncludes[I], Record); + + Record.push_back(PPOpts.UsePredefines); + AddString(PPOpts.ImplicitPCHInclude, Record); + AddString(PPOpts.ImplicitPTHInclude, Record); + Record.push_back(static_cast<unsigned>(PPOpts.ObjCXXARCStandardLibrary)); + Stream.EmitRecord(PREPROCESSOR_OPTIONS, Record); + // Original file name and file ID SourceManager &SM = Context.getSourceManager(); if (const FileEntry *MainFile = SM.getFileEntryForID(SM.getMainFileID())) { BitCodeAbbrev *FileAbbrev = new BitCodeAbbrev(); - FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE_NAME)); + FileAbbrev->Add(BitCodeAbbrevOp(ORIGINAL_FILE)); + FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // File ID FileAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name unsigned FileAbbrevCode = Stream.EmitAbbrev(FileAbbrev); @@ -1037,13 +1174,10 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot, const char *MainFileNameStr = MainFilePath.c_str(); MainFileNameStr = adjustFilenameForRelocatablePCH(MainFileNameStr, isysroot); - RecordData Record; - Record.push_back(ORIGINAL_FILE_NAME); - Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr); - Record.clear(); + Record.push_back(ORIGINAL_FILE); Record.push_back(SM.getMainFileID().getOpaqueValue()); - Stream.EmitRecord(ORIGINAL_FILE_ID, Record); + Stream.EmitRecordWithBlob(FileAbbrevCode, Record, MainFileNameStr); } // Original PCH directory @@ -1063,32 +1197,86 @@ void ASTWriter::WriteMetadata(ASTContext &Context, StringRef isysroot, Stream.EmitRecordWithBlob(AbbrevCode, Record, origDir); } - // Repository branch/version information. - BitCodeAbbrev *RepoAbbrev = new BitCodeAbbrev(); - RepoAbbrev->Add(BitCodeAbbrevOp(VERSION_CONTROL_BRANCH_REVISION)); - RepoAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // SVN branch/tag - unsigned RepoAbbrevCode = Stream.EmitAbbrev(RepoAbbrev); - Record.clear(); - Record.push_back(VERSION_CONTROL_BRANCH_REVISION); - Stream.EmitRecordWithBlob(RepoAbbrevCode, Record, - getClangFullRepositoryVersion()); + WriteInputFiles(Context.SourceMgr, isysroot); + Stream.ExitBlock(); } -/// \brief Write the LangOptions structure. -void ASTWriter::WriteLanguageOptions(const LangOptions &LangOpts) { +void ASTWriter::WriteInputFiles(SourceManager &SourceMgr, StringRef isysroot) { + using namespace llvm; + Stream.EnterSubblock(INPUT_FILES_BLOCK_ID, 4); RecordData Record; -#define LANGOPT(Name, Bits, Default, Description) \ - Record.push_back(LangOpts.Name); -#define ENUM_LANGOPT(Name, Type, Bits, Default, Description) \ - Record.push_back(static_cast<unsigned>(LangOpts.get##Name())); -#include "clang/Basic/LangOptions.def" + + // Create input-file abbreviation. + BitCodeAbbrev *IFAbbrev = new BitCodeAbbrev(); + IFAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE)); + IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ID + IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size + IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time + IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Overridden + IFAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name + unsigned IFAbbrevCode = Stream.EmitAbbrev(IFAbbrev); + + // Write out all of the input files. + std::vector<uint32_t> InputFileOffsets; + for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) { + // Get this source location entry. + const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I); + assert(&SourceMgr.getSLocEntry(FileID::get(I)) == SLoc); - Record.push_back((unsigned) LangOpts.ObjCRuntime.getKind()); - AddVersionTuple(LangOpts.ObjCRuntime.getVersion(), Record); + // We only care about file entries that were not overridden. + if (!SLoc->isFile()) + continue; + const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache(); + if (!Cache->OrigEntry) + continue; + + // Record this entry's offset. + InputFileOffsets.push_back(Stream.GetCurrentBitNo()); + InputFileIDs[Cache->OrigEntry] = InputFileOffsets.size(); + + Record.clear(); + Record.push_back(INPUT_FILE); + Record.push_back(InputFileOffsets.size()); + + // Emit size/modification time for this file. + Record.push_back(Cache->OrigEntry->getSize()); + Record.push_back(Cache->OrigEntry->getModificationTime()); + + // Whether this file was overridden. + Record.push_back(Cache->BufferOverridden); + + // Turn the file name into an absolute path, if it isn't already. + const char *Filename = Cache->OrigEntry->getName(); + SmallString<128> FilePath(Filename); + + // Ask the file manager to fixup the relative path for us. This will + // honor the working directory. + SourceMgr.getFileManager().FixupRelativePath(FilePath); + + // FIXME: This call to make_absolute shouldn't be necessary, the + // call to FixupRelativePath should always return an absolute path. + llvm::sys::fs::make_absolute(FilePath); + Filename = FilePath.c_str(); + + Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); + + Stream.EmitRecordWithBlob(IFAbbrevCode, Record, Filename); + } - Record.push_back(LangOpts.CurrentModule.size()); - Record.append(LangOpts.CurrentModule.begin(), LangOpts.CurrentModule.end()); - Stream.EmitRecord(LANGUAGE_OPTIONS, Record); + Stream.ExitBlock(); + + // Create input file offsets abbreviation. + BitCodeAbbrev *OffsetsAbbrev = new BitCodeAbbrev(); + OffsetsAbbrev->Add(BitCodeAbbrevOp(INPUT_FILE_OFFSETS)); + OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // # input files + OffsetsAbbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Array + unsigned OffsetsAbbrevCode = Stream.EmitAbbrev(OffsetsAbbrev); + + // Write input file offsets. + Record.clear(); + Record.push_back(INPUT_FILE_OFFSETS); + Record.push_back(InputFileOffsets.size()); + Stream.EmitRecordWithBlob(OffsetsAbbrevCode, Record, data(InputFileOffsets)); } //===----------------------------------------------------------------------===// @@ -1139,46 +1327,6 @@ public: }; } // end anonymous namespace -/// \brief Write the stat() system call cache to the AST file. -void ASTWriter::WriteStatCache(MemorizeStatCalls &StatCalls) { - // Build the on-disk hash table containing information about every - // stat() call. - OnDiskChainedHashTableGenerator<ASTStatCacheTrait> Generator; - unsigned NumStatEntries = 0; - for (MemorizeStatCalls::iterator Stat = StatCalls.begin(), - StatEnd = StatCalls.end(); - Stat != StatEnd; ++Stat, ++NumStatEntries) { - StringRef Filename = Stat->first(); - Generator.insert(Filename.data(), Stat->second); - } - - // Create the on-disk hash table in a buffer. - SmallString<4096> StatCacheData; - uint32_t BucketOffset; - { - llvm::raw_svector_ostream Out(StatCacheData); - // Make sure that no bucket is at offset 0 - clang::io::Emit32(Out, 0); - BucketOffset = Generator.Emit(Out); - } - - // Create a blob abbreviation - using namespace llvm; - BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(STAT_CACHE)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); - unsigned StatCacheAbbrev = Stream.EmitAbbrev(Abbrev); - - // Write the stat cache - RecordData Record; - Record.push_back(STAT_CACHE); - Record.push_back(BucketOffset); - Record.push_back(NumStatEntries); - Stream.EmitRecordWithBlob(StatCacheAbbrev, Record, StatCacheData.str()); -} - //===----------------------------------------------------------------------===// // Source Manager Serialization //===----------------------------------------------------------------------===// @@ -1194,13 +1342,10 @@ static unsigned CreateSLocFileAbbrev(llvm::BitstreamWriter &Stream) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // Characteristic Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // Line directives // FileEntry fields. - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 12)); // Size - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 32)); // Modification time - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // BufferOverridden + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Input File ID Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumCreatedFIDs Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 24)); // FirstDeclIndex Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 8)); // NumDecls - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // File name return Stream.EmitAbbrev(Abbrev); } @@ -1329,8 +1474,6 @@ namespace { /// \brief Write the header search block for the list of files that /// /// \param HS The header search structure to save. -/// -/// \param Chain Whether we're creating a chained AST file. void ASTWriter::WriteHeaderSearch(const HeaderSearch &HS, StringRef isysroot) { SmallVector<const FileEntry *, 16> FilesByUID; HS.getFileMgr().GetUniqueIDMapping(FilesByUID); @@ -1427,15 +1570,14 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, // Write out the source location entry table. We skip the first // entry, which is always the same dummy entry. std::vector<uint32_t> SLocEntryOffsets; - // Write out the offsets of only source location file entries. - // We will go through them in ASTReader::validateFileEntries(). - std::vector<uint32_t> SLocFileEntryOffsets; RecordData PreloadSLocs; SLocEntryOffsets.reserve(SourceMgr.local_sloc_entry_size() - 1); for (unsigned I = 1, N = SourceMgr.local_sloc_entry_size(); I != N; ++I) { // Get this source location entry. const SrcMgr::SLocEntry *SLoc = &SourceMgr.getLocalSLocEntry(I); + FileID FID = FileID::get(I); + assert(&SourceMgr.getSLocEntry(FID) == SLoc); // Record the offset of this source-location entry. SLocEntryOffsets.push_back(Stream.GetCurrentBitNo()); @@ -1446,7 +1588,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, const SrcMgr::ContentCache *Cache = SLoc->getFile().getContentCache(); if (Cache->OrigEntry) { Code = SM_SLOC_FILE_ENTRY; - SLocFileEntryOffsets.push_back(Stream.GetCurrentBitNo()); } else Code = SM_SLOC_BUFFER_ENTRY; } else @@ -1467,16 +1608,13 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, assert(Content->OrigEntry == Content->ContentsEntry && "Writing to AST an overridden file is not supported"); - // The source location entry is a file. The blob associated - // with this entry is the file name. + // The source location entry is a file. Emit input file ID. + assert(InputFileIDs[Content->OrigEntry] != 0 && "Missed file entry"); + Record.push_back(InputFileIDs[Content->OrigEntry]); - // Emit size/modification time for this file. - Record.push_back(Content->OrigEntry->getSize()); - Record.push_back(Content->OrigEntry->getModificationTime()); - Record.push_back(Content->BufferOverridden); Record.push_back(File.NumCreatedFIDs); - FileDeclIDsTy::iterator FDI = FileDeclIDs.find(SLoc); + FileDeclIDsTy::iterator FDI = FileDeclIDs.find(FID); if (FDI != FileDeclIDs.end()) { Record.push_back(FDI->second->FirstDeclIndex); Record.push_back(FDI->second->DeclIDs.size()); @@ -1485,21 +1623,7 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Record.push_back(0); } - // Turn the file name into an absolute path, if it isn't already. - const char *Filename = Content->OrigEntry->getName(); - SmallString<128> FilePath(Filename); - - // Ask the file manager to fixup the relative path for us. This will - // honor the working directory. - SourceMgr.getFileManager().FixupRelativePath(FilePath); - - // FIXME: This call to make_absolute shouldn't be necessary, the - // call to FixupRelativePath should always return an absolute path. - llvm::sys::fs::make_absolute(FilePath); - Filename = FilePath.c_str(); - - Filename = adjustFilenameForRelocatablePCH(Filename, isysroot); - Stream.EmitRecordWithBlob(SLocFileAbbrv, Record, Filename); + Stream.EmitRecordWithAbbrev(SLocFileAbbrv, Record); if (Content->BufferOverridden) { Record.clear(); @@ -1570,18 +1694,6 @@ void ASTWriter::WriteSourceManagerBlock(SourceManager &SourceMgr, Record.push_back(SourceMgr.getNextLocalOffset() - 1); // skip dummy Stream.EmitRecordWithBlob(SLocOffsetsAbbrev, Record, data(SLocEntryOffsets)); - Abbrev = new BitCodeAbbrev(); - Abbrev->Add(BitCodeAbbrevOp(FILE_SOURCE_LOCATION_OFFSETS)); - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 16)); // # of slocs - Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // offsets - unsigned SLocFileOffsetsAbbrev = Stream.EmitAbbrev(Abbrev); - - Record.clear(); - Record.push_back(FILE_SOURCE_LOCATION_OFFSETS); - Record.push_back(SLocFileEntryOffsets.size()); - Stream.EmitRecordWithBlob(SLocFileOffsetsAbbrev, Record, - data(SLocFileEntryOffsets)); - // Write the source location entry preloads array, telling the AST // reader which source locations entries it should load eagerly. Stream.EmitRecord(SOURCE_LOCATION_PRELOADS, PreloadSLocs); @@ -1675,102 +1787,129 @@ void ASTWriter::WritePreprocessor(const Preprocessor &PP, bool IsModule) { SmallVector<std::pair<const IdentifierInfo *, MacroInfo *>, 2> MacrosToEmit; llvm::SmallPtrSet<const IdentifierInfo*, 4> MacroDefinitionsSeen; - for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0), + for (Preprocessor::macro_iterator I = PP.macro_begin(Chain == 0), E = PP.macro_end(Chain == 0); I != E; ++I) { - const IdentifierInfo *Name = I->first; if (!IsModule || I->second->isPublic()) { - MacroDefinitionsSeen.insert(Name); + MacroDefinitionsSeen.insert(I->first); MacrosToEmit.push_back(std::make_pair(I->first, I->second)); } } - + // Sort the set of macro definitions that need to be serialized by the // name of the macro, to provide a stable ordering. - llvm::array_pod_sort(MacrosToEmit.begin(), MacrosToEmit.end(), + llvm::array_pod_sort(MacrosToEmit.begin(), MacrosToEmit.end(), &compareMacroDefinitions); - - // Resolve any identifiers that defined macros at the time they were - // deserialized, adding them to the list of macros to emit (if appropriate). - for (unsigned I = 0, N = DeserializedMacroNames.size(); I != N; ++I) { - IdentifierInfo *Name - = const_cast<IdentifierInfo *>(DeserializedMacroNames[I]); - if (Name->hasMacroDefinition() && MacroDefinitionsSeen.insert(Name)) - MacrosToEmit.push_back(std::make_pair(Name, PP.getMacroInfo(Name))); - } - + + /// \brief Offsets of each of the macros into the bitstream, indexed by + /// the local macro ID + /// + /// For each identifier that is associated with a macro, this map + /// provides the offset into the bitstream where that macro is + /// defined. + std::vector<uint32_t> MacroOffsets; + for (unsigned I = 0, N = MacrosToEmit.size(); I != N; ++I) { const IdentifierInfo *Name = MacrosToEmit[I].first; - MacroInfo *MI = MacrosToEmit[I].second; - if (!MI) - continue; - - // Don't emit builtin macros like __LINE__ to the AST file unless they have - // been redefined by the header (in which case they are not isBuiltinMacro). - // Also skip macros from a AST file if we're chaining. - - // FIXME: There is a (probably minor) optimization we could do here, if - // the macro comes from the original PCH but the identifier comes from a - // chained PCH, by storing the offset into the original PCH rather than - // writing the macro definition a second time. - if (MI->isBuiltinMacro() || - (Chain && - Name->isFromAST() && !Name->hasChangedSinceDeserialization() && - MI->isFromAST() && !MI->hasChangedAfterLoad())) - continue; - AddIdentifierRef(Name, Record); - MacroOffsets[Name] = Stream.GetCurrentBitNo(); - Record.push_back(MI->getDefinitionLoc().getRawEncoding()); - Record.push_back(MI->isUsed()); - Record.push_back(MI->isPublic()); - AddSourceLocation(MI->getVisibilityLocation(), Record); - unsigned Code; - if (MI->isObjectLike()) { - Code = PP_MACRO_OBJECT_LIKE; - } else { - Code = PP_MACRO_FUNCTION_LIKE; + for (MacroInfo *MI = MacrosToEmit[I].second; MI; + MI = MI->getPreviousDefinition()) { + MacroID ID = getMacroRef(MI); + if (!ID) + continue; - Record.push_back(MI->isC99Varargs()); - Record.push_back(MI->isGNUVarargs()); - Record.push_back(MI->getNumArgs()); - for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end(); - I != E; ++I) - AddIdentifierRef(*I, Record); - } + // Skip macros from a AST file if we're chaining. + if (Chain && MI->isFromAST() && !MI->hasChangedAfterLoad()) + continue; - // If we have a detailed preprocessing record, record the macro definition - // ID that corresponds to this macro. - if (PPRec) - Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]); + if (ID < FirstMacroID) { + // This will have been dealt with via an update record. + assert(MacroUpdates.count(MI) > 0 && "Missing macro update"); + continue; + } - Stream.EmitRecord(Code, Record); - Record.clear(); + // Record the local offset of this macro. + unsigned Index = ID - FirstMacroID; + if (Index == MacroOffsets.size()) + MacroOffsets.push_back(Stream.GetCurrentBitNo()); + else { + if (Index > MacroOffsets.size()) + MacroOffsets.resize(Index + 1); - // Emit the tokens array. - for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) { - // Note that we know that the preprocessor does not have any annotation - // tokens in it because they are created by the parser, and thus can't be - // in a macro definition. - const Token &Tok = MI->getReplacementToken(TokNo); - - Record.push_back(Tok.getLocation().getRawEncoding()); - Record.push_back(Tok.getLength()); - - // FIXME: When reading literal tokens, reconstruct the literal pointer if - // it is needed. - AddIdentifierRef(Tok.getIdentifierInfo(), Record); - // FIXME: Should translate token kind to a stable encoding. - Record.push_back(Tok.getKind()); - // FIXME: Should translate token flags to a stable encoding. - Record.push_back(Tok.getFlags()); - - Stream.EmitRecord(PP_TOKEN, Record); + MacroOffsets[Index] = Stream.GetCurrentBitNo(); + } + + AddIdentifierRef(Name, Record); + addMacroRef(MI, Record); + Record.push_back(inferSubmoduleIDFromLocation(MI->getDefinitionLoc())); + AddSourceLocation(MI->getDefinitionLoc(), Record); + AddSourceLocation(MI->getUndefLoc(), Record); + Record.push_back(MI->isUsed()); + Record.push_back(MI->isPublic()); + AddSourceLocation(MI->getVisibilityLocation(), Record); + unsigned Code; + if (MI->isObjectLike()) { + Code = PP_MACRO_OBJECT_LIKE; + } else { + Code = PP_MACRO_FUNCTION_LIKE; + + Record.push_back(MI->isC99Varargs()); + Record.push_back(MI->isGNUVarargs()); + Record.push_back(MI->getNumArgs()); + for (MacroInfo::arg_iterator I = MI->arg_begin(), E = MI->arg_end(); + I != E; ++I) + AddIdentifierRef(*I, Record); + } + + // If we have a detailed preprocessing record, record the macro definition + // ID that corresponds to this macro. + if (PPRec) + Record.push_back(MacroDefinitions[PPRec->findMacroDefinition(MI)]); + + Stream.EmitRecord(Code, Record); Record.clear(); + + // Emit the tokens array. + for (unsigned TokNo = 0, e = MI->getNumTokens(); TokNo != e; ++TokNo) { + // Note that we know that the preprocessor does not have any annotation + // tokens in it because they are created by the parser, and thus can't + // be in a macro definition. + const Token &Tok = MI->getReplacementToken(TokNo); + + Record.push_back(Tok.getLocation().getRawEncoding()); + Record.push_back(Tok.getLength()); + + // FIXME: When reading literal tokens, reconstruct the literal pointer + // if it is needed. + AddIdentifierRef(Tok.getIdentifierInfo(), Record); + // FIXME: Should translate token kind to a stable encoding. + Record.push_back(Tok.getKind()); + // FIXME: Should translate token flags to a stable encoding. + Record.push_back(Tok.getFlags()); + + Stream.EmitRecord(PP_TOKEN, Record); + Record.clear(); + } + ++NumMacros; } - ++NumMacros; } Stream.ExitBlock(); + + // Write the offsets table for macro IDs. + using namespace llvm; + BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(MACRO_OFFSET)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // # of macros + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // first ID + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); + + unsigned MacroOffsetAbbrev = Stream.EmitAbbrev(Abbrev); + Record.clear(); + Record.push_back(MACRO_OFFSET); + Record.push_back(MacroOffsets.size()); + Record.push_back(FirstMacroID - NUM_PREDEF_MACRO_IDS); + Stream.EmitRecordWithBlob(MacroOffsetAbbrev, Record, + data(MacroOffsets)); } void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { @@ -1794,6 +1933,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); // filename length Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // in quotes Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // kind + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // imported module Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); InclusionAbbrev = Stream.EmitAbbrev(Abbrev); } @@ -1836,6 +1976,7 @@ void ASTWriter::WritePreprocessorDetail(PreprocessingRecord &PPRec) { Record.push_back(ID->getFileName().size()); Record.push_back(ID->wasInQuotes()); Record.push_back(static_cast<unsigned>(ID->getKind())); + Record.push_back(ID->importedModule()); SmallString<64> Buffer; Buffer += ID->getFileName(); // Check that the FileEntry is not null because it was not resolved and @@ -1935,6 +2076,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { unsigned HeaderAbbrev = Stream.EmitAbbrev(Abbrev); Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_TOPHEADER)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned TopHeaderAbbrev = Stream.EmitAbbrev(Abbrev); + + Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_UMBRELLA_DIR)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name unsigned UmbrellaDirAbbrev = Stream.EmitAbbrev(Abbrev); @@ -1944,6 +2090,11 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Feature unsigned RequiresAbbrev = Stream.EmitAbbrev(Abbrev); + Abbrev = new BitCodeAbbrev(); + Abbrev->Add(BitCodeAbbrevOp(SUBMODULE_EXCLUDED_HEADER)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); // Name + unsigned ExcludedHeaderAbbrev = Stream.EmitAbbrev(Abbrev); + // Write the submodule metadata block. RecordData Record; Record.push_back(getNumberOfModules(WritingModule)); @@ -2005,6 +2156,19 @@ void ASTWriter::WriteSubmodules(Module *WritingModule) { Stream.EmitRecordWithBlob(HeaderAbbrev, Record, Mod->Headers[I]->getName()); } + // Emit the excluded headers. + for (unsigned I = 0, N = Mod->ExcludedHeaders.size(); I != N; ++I) { + Record.clear(); + Record.push_back(SUBMODULE_EXCLUDED_HEADER); + Stream.EmitRecordWithBlob(ExcludedHeaderAbbrev, Record, + Mod->ExcludedHeaders[I]->getName()); + } + for (unsigned I = 0, N = Mod->TopHeaders.size(); I != N; ++I) { + Record.clear(); + Record.push_back(SUBMODULE_TOPHEADER); + Stream.EmitRecordWithBlob(TopHeaderAbbrev, Record, + Mod->TopHeaders[I]->getName()); + } // Emit the imports. if (!Mod->Imports.empty()) { @@ -2067,24 +2231,35 @@ ASTWriter::inferSubmoduleIDFromLocation(SourceLocation Loc) { } void ASTWriter::WritePragmaDiagnosticMappings(const DiagnosticsEngine &Diag) { + // FIXME: Make it work properly with modules. + llvm::SmallDenseMap<const DiagnosticsEngine::DiagState *, unsigned, 64> + DiagStateIDMap; + unsigned CurrID = 0; + DiagStateIDMap[&Diag.DiagStates.front()] = ++CurrID; // the command-line one. RecordData Record; for (DiagnosticsEngine::DiagStatePointsTy::const_iterator I = Diag.DiagStatePoints.begin(), E = Diag.DiagStatePoints.end(); I != E; ++I) { - const DiagnosticsEngine::DiagStatePoint &point = *I; + const DiagnosticsEngine::DiagStatePoint &point = *I; if (point.Loc.isInvalid()) continue; Record.push_back(point.Loc.getRawEncoding()); - for (DiagnosticsEngine::DiagState::const_iterator - I = point.State->begin(), E = point.State->end(); I != E; ++I) { - if (I->second.isPragma()) { - Record.push_back(I->first); - Record.push_back(I->second.getMapping()); + unsigned &DiagStateID = DiagStateIDMap[point.State]; + Record.push_back(DiagStateID); + + if (DiagStateID == 0) { + DiagStateID = ++CurrID; + for (DiagnosticsEngine::DiagState::const_iterator + I = point.State->begin(), E = point.State->end(); I != E; ++I) { + if (I->second.isPragma()) { + Record.push_back(I->first); + Record.push_back(I->second.getMapping()); + } } + Record.push_back(-1); // mark the end of the diag/map pairs for this + // location. } - Record.push_back(-1); // mark the end of the diag/map pairs for this - // location. } if (!Record.empty()) @@ -2238,9 +2413,11 @@ void ASTWriter::WriteFileDeclIDsMap() { BitCodeAbbrev *Abbrev = new BitCodeAbbrev(); Abbrev->Add(BitCodeAbbrevOp(FILE_SORTED_DECLS)); + Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 32)); Abbrev->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Blob)); unsigned AbbrevCode = Stream.EmitAbbrev(Abbrev); Record.push_back(FILE_SORTED_DECLS); + Record.push_back(FileSortedIDs.size()); Stream.EmitRecordWithBlob(AbbrevCode, Record, data(FileSortedIDs)); } @@ -2495,17 +2672,17 @@ class ASTIdentifierTableTrait { II->getFETokenInfo<void>()) return true; - return hasMacroDefinition(II, Macro); + return hadMacroDefinition(II, Macro); } - - bool hasMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) { - if (!II->hasMacroDefinition()) + + bool hadMacroDefinition(IdentifierInfo *II, MacroInfo *&Macro) { + if (!II->hadMacroDefinition()) return false; - - if (Macro || (Macro = PP.getMacroInfo(II))) + + if (Macro || (Macro = PP.getMacroInfoHistory(II))) return !Macro->isBuiltinMacro() && (!IsModule || Macro->isPublic()); - - return false; + + return false; } public: @@ -2529,10 +2706,17 @@ public: unsigned DataLen = 4; // 4 bytes for the persistent ID << 1 MacroInfo *Macro = 0; if (isInterestingIdentifier(II, Macro)) { - DataLen += 2; // 2 bytes for builtin ID, flags - if (hasMacroDefinition(II, Macro)) - DataLen += 8; - + DataLen += 2; // 2 bytes for builtin ID + DataLen += 2; // 2 bytes for flags + if (hadMacroDefinition(II, Macro)) { + for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) { + if (Writer.getMacroRef(M) != 0) + DataLen += 4; + } + + DataLen += 4; + } + for (IdentifierResolver::iterator D = IdResolver.begin(II), DEnd = IdResolver.end(); D != DEnd; ++D) @@ -2563,23 +2747,28 @@ public: } clang::io::Emit32(Out, (ID << 1) | 0x01); - uint32_t Bits = 0; - bool HasMacroDefinition = hasMacroDefinition(II, Macro); - Bits = (uint32_t)II->getObjCOrBuiltinID(); - assert((Bits & 0x7ff) == Bits && "ObjCOrBuiltinID too big for ASTReader."); - Bits = (Bits << 1) | unsigned(HasMacroDefinition); + uint32_t Bits = (uint32_t)II->getObjCOrBuiltinID(); + assert((Bits & 0xffff) == Bits && "ObjCOrBuiltinID too big for ASTReader."); + clang::io::Emit16(Out, Bits); + Bits = 0; + bool HadMacroDefinition = hadMacroDefinition(II, Macro); + Bits = (Bits << 1) | unsigned(HadMacroDefinition); Bits = (Bits << 1) | unsigned(II->isExtensionToken()); Bits = (Bits << 1) | unsigned(II->isPoisoned()); Bits = (Bits << 1) | unsigned(II->hasRevertedTokenIDToIdentifier()); Bits = (Bits << 1) | unsigned(II->isCPlusPlusOperatorKeyword()); clang::io::Emit16(Out, Bits); - if (HasMacroDefinition) { - clang::io::Emit32(Out, Writer.getMacroOffset(II)); - clang::io::Emit32(Out, - Writer.inferSubmoduleIDFromLocation(Macro->getDefinitionLoc())); + if (HadMacroDefinition) { + // Write all of the macro IDs associated with this identifier. + for (MacroInfo *M = Macro; M; M = M->getPreviousDefinition()) { + if (MacroID ID = Writer.getMacroRef(M)) + clang::io::Emit32(Out, ID); + } + + clang::io::Emit32(Out, 0); } - + // Emit the declaration IDs in reverse order, because the // IdentifierResolver provides the declarations as they would be // visible (e.g., the function "stat" would come before the struct @@ -2756,30 +2945,32 @@ public: void EmitKey(raw_ostream& Out, DeclarationName Name, unsigned) { using namespace clang::io; - assert(Name.getNameKind() < 0x100 && "Invalid name kind ?"); Emit8(Out, Name.getNameKind()); switch (Name.getNameKind()) { case DeclarationName::Identifier: Emit32(Out, Writer.getIdentifierRef(Name.getAsIdentifierInfo())); - break; + return; case DeclarationName::ObjCZeroArgSelector: case DeclarationName::ObjCOneArgSelector: case DeclarationName::ObjCMultiArgSelector: Emit32(Out, Writer.getSelectorRef(Name.getObjCSelector())); - break; + return; case DeclarationName::CXXOperatorName: - assert(Name.getCXXOverloadedOperator() < 0x100 && "Invalid operator ?"); + assert(Name.getCXXOverloadedOperator() < NUM_OVERLOADED_OPERATORS && + "Invalid operator?"); Emit8(Out, Name.getCXXOverloadedOperator()); - break; + return; case DeclarationName::CXXLiteralOperatorName: Emit32(Out, Writer.getIdentifierRef(Name.getCXXLiteralIdentifier())); - break; + return; case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXUsingDirective: - break; + return; } + + llvm_unreachable("Invalid name kind?"); } void EmitData(raw_ostream& Out, key_type_ref, @@ -3147,7 +3338,8 @@ ASTWriter::ASTWriter(llvm::BitstreamWriter &Stream) ASTHasCompilerErrors(false), FirstDeclID(NUM_PREDEF_DECL_IDS), NextDeclID(FirstDeclID), FirstTypeID(NUM_PREDEF_TYPE_IDS), NextTypeID(FirstTypeID), - FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID), + FirstIdentID(NUM_PREDEF_IDENT_IDS), NextIdentID(FirstIdentID), + FirstMacroID(NUM_PREDEF_MACRO_IDS), NextMacroID(FirstMacroID), FirstSubmoduleID(NUM_PREDEF_SUBMODULE_IDS), NextSubmoduleID(FirstSubmoduleID), FirstSelectorID(NUM_PREDEF_SELECTOR_IDS), NextSelectorID(FirstSelectorID), @@ -3171,7 +3363,7 @@ ASTWriter::~ASTWriter() { delete I->second; } -void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls, +void ASTWriter::WriteAST(Sema &SemaRef, const std::string &OutputFile, Module *WritingModule, StringRef isysroot, bool hasErrors) { @@ -3190,7 +3382,7 @@ void ASTWriter::WriteAST(Sema &SemaRef, MemorizeStatCalls *StatCalls, Context = &SemaRef.Context; PP = &SemaRef.PP; this->WritingModule = WritingModule; - WriteASTCore(SemaRef, StatCalls, isysroot, OutputFile, WritingModule); + WriteASTCore(SemaRef, isysroot, OutputFile, WritingModule); Context = 0; PP = 0; this->WritingModule = 0; @@ -3207,7 +3399,7 @@ static void AddLazyVectorDecls(ASTWriter &Writer, Vector &Vec, } } -void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, +void ASTWriter::WriteASTCore(Sema &SemaRef, StringRef isysroot, const std::string &OutputFile, Module *WritingModule) { @@ -3357,14 +3549,13 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, if (!I->second) AddDeclRef(I->first, KnownNamespaces); } - + + // Write the control block + WriteControlBlock(PP, Context, isysroot, OutputFile); + // Write the remaining AST contents. RecordData Record; Stream.EnterSubblock(AST_BLOCK_ID, 5); - WriteMetadata(Context, isysroot, OutputFile); - WriteLanguageOptions(Context.getLangOpts()); - if (StatCalls && isysroot.empty()) - WriteStatCache(*StatCalls); // Create a lexical update block containing all of the declarations in the // translation unit that do not come from other AST files. @@ -3482,6 +3673,7 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, Out.write(FileName.data(), FileName.size()); io::Emit32(Out, (*M)->SLocEntryBaseOffset); io::Emit32(Out, (*M)->BaseIdentifierID); + io::Emit32(Out, (*M)->BaseMacroID); io::Emit32(Out, (*M)->BasePreprocessedEntityID); io::Emit32(Out, (*M)->BaseSubmoduleID); io::Emit32(Out, (*M)->BaseSelectorID); @@ -3595,7 +3787,8 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, Stream.EmitRecord(IMPORTED_MODULES, ImportedModules); } } - + + WriteMacroUpdates(); WriteDeclUpdatesBlocks(); WriteDeclReplacementsBlock(); WriteMergedDecls(); @@ -3612,6 +3805,21 @@ void ASTWriter::WriteASTCore(Sema &SemaRef, MemorizeStatCalls *StatCalls, Stream.ExitBlock(); } +void ASTWriter::WriteMacroUpdates() { + if (MacroUpdates.empty()) + return; + + RecordData Record; + for (MacroUpdatesMap::iterator I = MacroUpdates.begin(), + E = MacroUpdates.end(); + I != E; ++I) { + addMacroRef(I->first, Record); + AddSourceLocation(I->second.UndefLoc, Record); + Record.push_back(inferSubmoduleIDFromLocation(I->second.UndefLoc)); + } + Stream.EmitRecord(MACRO_UPDATES, Record); +} + /// \brief Go through the declaration update blocks and resolve declaration /// pointers into declaration IDs. void ASTWriter::ResolveDeclUpdatesBlocks() { @@ -3707,6 +3915,10 @@ void ASTWriter::AddIdentifierRef(const IdentifierInfo *II, RecordDataImpl &Recor Record.push_back(getIdentifierRef(II)); } +void ASTWriter::addMacroRef(MacroInfo *MI, RecordDataImpl &Record) { + Record.push_back(getMacroRef(MI)); +} + IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) { if (II == 0) return 0; @@ -3717,6 +3929,19 @@ IdentID ASTWriter::getIdentifierRef(const IdentifierInfo *II) { return ID; } +MacroID ASTWriter::getMacroRef(MacroInfo *MI) { + // Don't emit builtin macros like __LINE__ to the AST file unless they + // have been redefined by the header (in which case they are not + // isBuiltinMacro). + if (MI == 0 || MI->isBuiltinMacro()) + return 0; + + MacroID &ID = MacroIDs[MI]; + if (ID == 0) + ID = NextMacroID++; + return ID; +} + void ASTWriter::AddSelectorRef(const Selector SelRef, RecordDataImpl &Record) { Record.push_back(getSelectorRef(SelRef)); } @@ -3774,7 +3999,9 @@ void ASTWriter::AddTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind, case TemplateArgument::Null: case TemplateArgument::Integral: case TemplateArgument::Declaration: + case TemplateArgument::NullPtr: case TemplateArgument::Pack: + // FIXME: Is this right? break; } } @@ -3931,10 +4158,9 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) { llvm::tie(FID, Offset) = SM.getDecomposedLoc(FileLoc); if (FID.isInvalid()) return; - const SrcMgr::SLocEntry *Entry = &SM.getSLocEntry(FID); - assert(Entry->isFile()); + assert(SM.getSLocEntry(FID).isFile()); - DeclIDInFileInfo *&Info = FileDeclIDs[Entry]; + DeclIDInFileInfo *&Info = FileDeclIDs[FID]; if (!Info) Info = new DeclIDInFileInfo(); @@ -4191,6 +4417,10 @@ void ASTWriter::AddTemplateArgument(const TemplateArgument &Arg, break; case TemplateArgument::Declaration: AddDeclRef(Arg.getAsDecl(), Record); + Record.push_back(Arg.isDeclForReferenceParam()); + break; + case TemplateArgument::NullPtr: + AddTypeRef(Arg.getNullPtrType(), Record); break; case TemplateArgument::Integral: AddAPSInt(Arg.getAsIntegral(), Record); @@ -4403,6 +4633,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec Record.push_back(Lambda.NumExplicitCaptures); Record.push_back(Lambda.ManglingNumber); AddDeclRef(Lambda.ContextDecl, Record); + AddTypeSourceInfo(Lambda.MethodTyInfo, Record); for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { LambdaExpr::Capture &Capture = Lambda.Captures[I]; AddSourceLocation(Capture.getLocation(), Record); @@ -4423,6 +4654,7 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) { assert(FirstDeclID == NextDeclID && FirstTypeID == NextTypeID && FirstIdentID == NextIdentID && + FirstMacroID == NextMacroID && FirstSubmoduleID == NextSubmoduleID && FirstSelectorID == NextSelectorID && "Setting chain after writing has started."); @@ -4432,19 +4664,23 @@ void ASTWriter::ReaderInitialized(ASTReader *Reader) { FirstDeclID = NUM_PREDEF_DECL_IDS + Chain->getTotalNumDecls(); FirstTypeID = NUM_PREDEF_TYPE_IDS + Chain->getTotalNumTypes(); FirstIdentID = NUM_PREDEF_IDENT_IDS + Chain->getTotalNumIdentifiers(); + FirstMacroID = NUM_PREDEF_MACRO_IDS + Chain->getTotalNumMacros(); FirstSubmoduleID = NUM_PREDEF_SUBMODULE_IDS + Chain->getTotalNumSubmodules(); FirstSelectorID = NUM_PREDEF_SELECTOR_IDS + Chain->getTotalNumSelectors(); NextDeclID = FirstDeclID; NextTypeID = FirstTypeID; NextIdentID = FirstIdentID; + NextMacroID = FirstMacroID; NextSelectorID = FirstSelectorID; NextSubmoduleID = FirstSubmoduleID; } void ASTWriter::IdentifierRead(IdentID ID, IdentifierInfo *II) { IdentifierIDs[II] = ID; - if (II->hasMacroDefinition()) - DeserializedMacroNames.push_back(II); +} + +void ASTWriter::MacroRead(serialization::MacroID ID, MacroInfo *MI) { + MacroIDs[MI] = ID; } void ASTWriter::TypeRead(TypeIdx Idx, QualType T) { @@ -4468,15 +4704,15 @@ void ASTWriter::MacroDefinitionRead(serialization::PreprocessedEntityID ID, MacroDefinitions[MD] = ID; } -void ASTWriter::MacroVisible(IdentifierInfo *II) { - DeserializedMacroNames.push_back(II); -} - void ASTWriter::ModuleRead(serialization::SubmoduleID ID, Module *Mod) { assert(SubmoduleIDs.find(Mod) == SubmoduleIDs.end()); SubmoduleIDs[Mod] = ID; } +void ASTWriter::UndefinedMacro(MacroInfo *MI) { + MacroUpdates[MI].UndefLoc = MI->getUndefLoc(); +} + void ASTWriter::CompletedTagDefinition(const TagDecl *D) { assert(D->isCompleteDefinition()); assert(!WritingAST && "Already writing the AST!"); @@ -4490,6 +4726,7 @@ void ASTWriter::CompletedTagDefinition(const TagDecl *D) { } } } + void ASTWriter::AddedVisibleDecl(const DeclContext *DC, const Decl *D) { assert(!WritingAST && "Already writing the AST!"); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 602943b9ba58..74865657637c 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -416,7 +416,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { } Record.push_back(D->isInstanceMethod()); Record.push_back(D->isVariadic()); - Record.push_back(D->isSynthesized()); + Record.push_back(D->isPropertyAccessor()); Record.push_back(D->isDefined()); Record.push_back(D->IsOverriding); @@ -606,6 +606,8 @@ void ASTDeclWriter::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { Writer.AddDeclRef(D->getSuperClass(), Record); Writer.AddSourceLocation(D->getIvarLBraceLoc(), Record); Writer.AddSourceLocation(D->getIvarRBraceLoc(), Record); + Record.push_back(D->hasNonZeroConstructors()); + Record.push_back(D->hasDestructors()); Writer.AddCXXCtorInitializers(D->IvarInitializers, D->NumIvarInitializers, Record); Code = serialization::DECL_OBJC_IMPLEMENTATION; @@ -675,6 +677,8 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { Record.push_back(D->isNRVOVariable()); Record.push_back(D->isCXXForRangeDecl()); Record.push_back(D->isARCPseudoStrong()); + Record.push_back(D->isConstexpr()); + if (D->getInit()) { Record.push_back(!D->isInitKnownICE() ? 1 : (D->isInitICE() ? 3 : 2)); Writer.AddStmt(D->getInit()); @@ -705,6 +709,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { D->getInitStyle() == VarDecl::CInit && D->getInit() == 0 && !isa<ParmVarDecl>(D) && + !D->isConstexpr() && !SpecInfo) AbbrevToUse = Writer.getDeclVarAbbrev(); @@ -945,11 +950,16 @@ void ASTDeclWriter::VisitCXXRecordDecl(CXXRecordDecl *D) { void ASTDeclWriter::VisitCXXMethodDecl(CXXMethodDecl *D) { VisitFunctionDecl(D); - Record.push_back(D->size_overridden_methods()); - for (CXXMethodDecl::method_iterator - I = D->begin_overridden_methods(), E = D->end_overridden_methods(); - I != E; ++I) - Writer.AddDeclRef(*I, Record); + if (D->isCanonicalDecl()) { + Record.push_back(D->size_overridden_methods()); + for (CXXMethodDecl::method_iterator + I = D->begin_overridden_methods(), E = D->end_overridden_methods(); + I != E; ++I) + Writer.AddDeclRef(*I, Record); + } else { + // We only need to record overridden methods once for the canonical decl. + Record.push_back(0); + } Code = serialization::DECL_CXX_METHOD; } @@ -981,6 +991,7 @@ void ASTDeclWriter::VisitCXXConversionDecl(CXXConversionDecl *D) { void ASTDeclWriter::VisitImportDecl(ImportDecl *D) { VisitDecl(D); + Record.push_back(Writer.getSubmoduleID(D->getImportedModule())); ArrayRef<SourceLocation> IdentifierLocs = D->getIdentifierLocs(); Record.push_back(!IdentifierLocs.empty()); if (IdentifierLocs.empty()) { @@ -1073,7 +1084,7 @@ void ASTDeclWriter::VisitClassTemplateDecl(ClassTemplateDecl *D) { Writer.AddDeclRef(&*I, Record); } - // InjectedClassNameType is computed, no need to write it. + Writer.AddTypeRef(D->getCommonPtr()->InjectedClassNameType, Record); } Code = serialization::DECL_CLASS_TEMPLATE; } @@ -1103,6 +1114,7 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl( Writer.AddTemplateArgumentList(&D->getTemplateArgs(), Record); Writer.AddSourceLocation(D->getPointOfInstantiation(), Record); Record.push_back(D->getSpecializationKind()); + Record.push_back(D->isCanonicalDecl()); if (D->isCanonicalDecl()) { // When reading, we'll add it to the folding set of the following template. @@ -1172,7 +1184,8 @@ void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { // For an expanded parameter pack, record the number of expansion types here - // so that it's easier for + // so that it's easier for deserialization to allocate the right amount of + // memory. if (D->isExpandedParameterPack()) Record.push_back(D->getNumExpansionTypes()); @@ -1201,15 +1214,30 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { } void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + // For an expanded parameter pack, record the number of expansion types here + // so that it's easier for deserialization to allocate the right amount of + // memory. + if (D->isExpandedParameterPack()) + Record.push_back(D->getNumExpansionTemplateParameters()); + VisitTemplateDecl(D); // TemplateParmPosition. Record.push_back(D->getDepth()); Record.push_back(D->getPosition()); - // Rest of TemplateTemplateParmDecl. - Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record); - Record.push_back(D->defaultArgumentWasInherited()); - Record.push_back(D->isParameterPack()); - Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM; + + if (D->isExpandedParameterPack()) { + for (unsigned I = 0, N = D->getNumExpansionTemplateParameters(); + I != N; ++I) + Writer.AddTemplateParameterList(D->getExpansionTemplateParameters(I), + Record); + Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK; + } else { + // Rest of TemplateTemplateParmDecl. + Writer.AddTemplateArgumentLoc(D->getDefaultArgument(), Record); + Record.push_back(D->defaultArgumentWasInherited()); + Record.push_back(D->isParameterPack()); + Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM; + } } void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { @@ -1462,6 +1490,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(0)); // isNRVOVariable Abv->Add(BitCodeAbbrevOp(0)); // isCXXForRangeDecl Abv->Add(BitCodeAbbrevOp(0)); // isARCPseudoStrong + Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr Abv->Add(BitCodeAbbrevOp(0)); // HasInit Abv->Add(BitCodeAbbrevOp(0)); // HasMemberSpecializationInfo // ParmVarDecl @@ -1540,6 +1569,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isNRVOVariable Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isCXXForRangeDecl Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // isARCPseudoStrong + Abv->Add(BitCodeAbbrevOp(0)); // isConstexpr Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasInit Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); // HasMemberSpecInfo // Type Source Info @@ -1603,7 +1633,7 @@ void ASTWriter::WriteDeclsBlockAbbrevs() { //Character Literal Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // getValue Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // Location - Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 1)); //IsWide + Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, 2)); // getKind CharacterLiteralAbbrev = Stream.EmitAbbrev(Abv); Abv = new BitCodeAbbrev(); diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index f63388fa2fd1..7e8ce42d7caf 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -218,7 +218,7 @@ void ASTStmtWriter::VisitDeclStmt(DeclStmt *S) { Code = serialization::STMT_DECL; } -void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) { +void ASTStmtWriter::VisitGCCAsmStmt(GCCAsmStmt *S) { VisitStmt(S); Record.push_back(S->getNumOutputs()); Record.push_back(S->getNumInputs()); @@ -227,7 +227,6 @@ void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) { Writer.AddSourceLocation(S->getRParenLoc(), Record); Record.push_back(S->isVolatile()); Record.push_back(S->isSimple()); - Record.push_back(S->isMSAsm()); Writer.AddStmt(S->getAsmString()); // Outputs @@ -246,14 +245,16 @@ void ASTStmtWriter::VisitAsmStmt(AsmStmt *S) { // Clobbers for (unsigned I = 0, N = S->getNumClobbers(); I != N; ++I) - Writer.AddStmt(S->getClobber(I)); + Writer.AddStmt(S->getClobberStringLiteral(I)); - Code = serialization::STMT_ASM; + Code = serialization::STMT_GCCASM; } void ASTStmtWriter::VisitMSAsmStmt(MSAsmStmt *S) { // FIXME: Statement writer not yet implemented for MS style inline asm. VisitStmt(S); + + Code = serialization::STMT_MSASM; } void ASTStmtWriter::VisitExpr(Expr *E) { @@ -535,6 +536,7 @@ void ASTStmtWriter::VisitBinaryOperator(BinaryOperator *E) { Writer.AddStmt(E->getRHS()); Record.push_back(E->getOpcode()); // FIXME: stable encoding Writer.AddSourceLocation(E->getOperatorLoc(), Record); + Record.push_back(E->isFPContractable()); Code = serialization::EXPR_BINARY_OPERATOR; } @@ -604,6 +606,8 @@ void ASTStmtWriter::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { void ASTStmtWriter::VisitInitListExpr(InitListExpr *E) { VisitExpr(E); + // NOTE: only add the (possibly null) syntactic form. + // No need to serialize the isSemanticForm flag and the semantic form. Writer.AddStmt(E->getSyntacticForm()); Writer.AddSourceLocation(E->getLBraceLoc(), Record); Writer.AddSourceLocation(E->getRBraceLoc(), Record); @@ -1054,6 +1058,7 @@ void ASTStmtWriter::VisitCXXOperatorCallExpr(CXXOperatorCallExpr *E) { VisitCallExpr(E); Record.push_back(E->getOperator()); Writer.AddSourceRange(E->Range, Record); + Record.push_back(E->isFPContractable()); Code = serialization::EXPR_CXX_OPERATOR_CALL; } @@ -1233,7 +1238,7 @@ void ASTStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) { Writer.AddDeclRef(E->getOperatorDelete(), Record); Writer.AddTypeSourceInfo(E->getAllocatedTypeSourceInfo(), Record); Writer.AddSourceRange(E->getTypeIdParens(), Record); - Writer.AddSourceLocation(E->getStartLoc(), Record); + Writer.AddSourceRange(E->getSourceRange(), Record); Writer.AddSourceRange(E->getDirectInitRange(), Record); for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), e = E->raw_arg_end(); I != e; ++I) @@ -1382,8 +1387,6 @@ void ASTStmtWriter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { void ASTStmtWriter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { VisitOverloadExpr(E); Record.push_back(E->requiresADL()); - if (E->requiresADL()) - Record.push_back(E->isStdAssociatedNamespace()); Record.push_back(E->isOverloaded()); Writer.AddDeclRef(E->getNamingClass(), Record); Code = serialization::EXPR_CXX_UNRESOLVED_LOOKUP; @@ -1480,6 +1483,17 @@ void ASTStmtWriter::VisitSubstNonTypeTemplateParmPackExpr( Code = serialization::EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK; } +void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { + VisitExpr(E); + Record.push_back(E->getNumExpansions()); + Writer.AddDeclRef(E->getParameterPack(), Record); + Writer.AddSourceLocation(E->getParameterPackLocation(), Record); + for (FunctionParmPackExpr::iterator I = E->begin(), End = E->end(); + I != End; ++I) + Writer.AddDeclRef(*I, Record); + Code = serialization::EXPR_FUNCTION_PARM_PACK; +} + void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { VisitExpr(E); Writer.AddStmt(E->Temporary); diff --git a/lib/Serialization/GeneratePCH.cpp b/lib/Serialization/GeneratePCH.cpp index 02aed103f1bf..870d65489584 100644 --- a/lib/Serialization/GeneratePCH.cpp +++ b/lib/Serialization/GeneratePCH.cpp @@ -18,7 +18,6 @@ #include "clang/AST/ASTConsumer.h" #include "clang/Lex/Preprocessor.h" #include "clang/Basic/FileManager.h" -#include "clang/Basic/FileSystemStatCache.h" #include "llvm/Bitcode/BitstreamWriter.h" #include "llvm/Support/raw_ostream.h" #include <string> @@ -32,11 +31,7 @@ PCHGenerator::PCHGenerator(const Preprocessor &PP, raw_ostream *OS) : PP(PP), OutputFile(OutputFile), Module(Module), isysroot(isysroot.str()), Out(OS), - SemaPtr(0), StatCalls(0), Stream(Buffer), Writer(Stream) { - // Install a stat() listener to keep track of all of the stat() - // calls. - StatCalls = new MemorizeStatCalls(); - PP.getFileManager().addStatCache(StatCalls, /*AtBeginning=*/false); + SemaPtr(0), Stream(Buffer), Writer(Stream) { } PCHGenerator::~PCHGenerator() { @@ -48,7 +43,7 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { // Emit the PCH file assert(SemaPtr && "No Sema?"); - Writer.WriteAST(*SemaPtr, StatCalls, OutputFile, Module, isysroot); + Writer.WriteAST(*SemaPtr, OutputFile, Module, isysroot); // Write the generated bitstream to "Out". Out->write((char *)&Buffer.front(), Buffer.size()); @@ -60,6 +55,10 @@ void PCHGenerator::HandleTranslationUnit(ASTContext &Ctx) { Buffer.clear(); } +PPMutationListener *PCHGenerator::GetPPMutationListener() { + return &Writer; +} + ASTMutationListener *PCHGenerator::GetASTMutationListener() { return &Writer; } diff --git a/lib/Serialization/Module.cpp b/lib/Serialization/Module.cpp index ff241d3d4105..5e42ab4211fa 100644 --- a/lib/Serialization/Module.cpp +++ b/lib/Serialization/Module.cpp @@ -21,12 +21,15 @@ using namespace serialization; using namespace reader; ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation) - : Kind(Kind), DirectlyImported(false), Generation(Generation), SizeInBits(0), + : Kind(Kind), File(0), DirectlyImported(false), + Generation(Generation), SizeInBits(0), LocalNumSLocEntries(0), SLocEntryBaseID(0), SLocEntryBaseOffset(0), SLocEntryOffsets(0), - SLocFileOffsets(0), LocalNumIdentifiers(0), + LocalNumIdentifiers(0), IdentifierOffsets(0), BaseIdentifierID(0), IdentifierTableData(0), - IdentifierLookupTable(0), BasePreprocessedEntityID(0), + IdentifierLookupTable(0), + LocalNumMacros(0), MacroOffsets(0), + BasePreprocessedEntityID(0), PreprocessedEntityOffsets(0), NumPreprocessedEntities(0), LocalNumHeaderFileInfos(0), HeaderFileInfoTableData(0), HeaderFileInfoTable(0), @@ -35,9 +38,10 @@ ModuleFile::ModuleFile(ModuleKind Kind, unsigned Generation) SelectorLookupTableData(0), SelectorLookupTable(0), LocalNumDecls(0), DeclOffsets(0), BaseDeclID(0), LocalNumCXXBaseSpecifiers(0), CXXBaseSpecifiersOffsets(0), - FileSortedDecls(0), RedeclarationsMap(0), LocalNumRedeclarationsInMap(0), + FileSortedDecls(0), NumFileSortedDecls(0), + RedeclarationsMap(0), LocalNumRedeclarationsInMap(0), ObjCCategoriesMap(0), LocalNumObjCCategoriesInMap(0), - LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0), StatCache(0) + LocalNumTypes(0), TypeOffsets(0), BaseTypeIndex(0) {} ModuleFile::~ModuleFile() { @@ -89,6 +93,10 @@ void ModuleFile::dump() { << " Number of identifiers: " << LocalNumIdentifiers << '\n'; dumpLocalRemap("Identifier ID local -> global map", IdentifierRemap); + llvm::errs() << " Base macro ID: " << BaseMacroID << '\n' + << " Number of macros: " << LocalNumMacros << '\n'; + dumpLocalRemap("Macro ID local -> global map", MacroRemap); + llvm::errs() << " Base submodule ID: " << BaseSubmoduleID << '\n' << " Number of submodules: " << LocalNumSubmodules << '\n'; dumpLocalRemap("Submodule ID local -> global map", SubmoduleRemap); diff --git a/lib/Serialization/ModuleManager.cpp b/lib/Serialization/ModuleManager.cpp index ab364b7ebd2c..efe442101bb6 100644 --- a/lib/Serialization/ModuleManager.cpp +++ b/lib/Serialization/ModuleManager.cpp @@ -50,6 +50,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, // Allocate a new module. ModuleFile *New = new ModuleFile(Type, Generation); New->FileName = FileName.str(); + New->File = Entry; Chain.push_back(New); NewModule = true; ModuleEntry = New; @@ -87,6 +88,45 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, return std::make_pair(ModuleEntry, NewModule); } +namespace { + /// \brief Predicate that checks whether a module file occurs within + /// the given set. + class IsInModuleFileSet : public std::unary_function<ModuleFile *, bool> { + llvm::SmallPtrSet<ModuleFile *, 4> &Removed; + + public: + IsInModuleFileSet(llvm::SmallPtrSet<ModuleFile *, 4> &Removed) + : Removed(Removed) { } + + bool operator()(ModuleFile *MF) const { + return Removed.count(MF); + } + }; +} + +void ModuleManager::removeModules(ModuleIterator first, ModuleIterator last) { + if (first == last) + return; + + // Collect the set of module file pointers that we'll be removing. + llvm::SmallPtrSet<ModuleFile *, 4> victimSet(first, last); + + // Remove any references to the now-destroyed modules. + IsInModuleFileSet checkInSet(victimSet); + for (unsigned i = 0, n = Chain.size(); i != n; ++i) { + Chain[i]->ImportedBy.remove_if(checkInSet); + } + + // Delete the modules and erase them from the various structures. + for (ModuleIterator victim = first; victim != last; ++victim) { + Modules.erase((*victim)->File); + delete *victim; + } + + // Remove the modules from the chain. + Chain.erase(first, last); +} + void ModuleManager::addInMemoryBuffer(StringRef FileName, llvm::MemoryBuffer *Buffer) { @@ -95,7 +135,7 @@ void ModuleManager::addInMemoryBuffer(StringRef FileName, InMemoryBuffers[Entry] = Buffer; } -ModuleManager::ModuleManager(const FileSystemOptions &FSO) : FileMgr(FSO) { } +ModuleManager::ModuleManager(FileManager &FileMgr) : FileMgr(FileMgr) { } ModuleManager::~ModuleManager() { for (unsigned i = 0, e = Chain.size(); i != e; ++i) diff --git a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp b/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp deleted file mode 100644 index 84ea8c709dd9..000000000000 --- a/lib/StaticAnalyzer/Checkers/AdjustedReturnValueChecker.cpp +++ /dev/null @@ -1,92 +0,0 @@ -//== AdjustedReturnValueChecker.cpp -----------------------------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines AdjustedReturnValueChecker, a simple check to see if the -// return value of a function call is different than the one the caller thinks -// it is. -// -//===----------------------------------------------------------------------===// - -#include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" - -using namespace clang; -using namespace ento; - -namespace { -class AdjustedReturnValueChecker : - public Checker< check::PostStmt<CallExpr> > { -public: - void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; -}; -} - -void AdjustedReturnValueChecker::checkPostStmt(const CallExpr *CE, - CheckerContext &C) const { - - // Get the result type of the call. - QualType expectedResultTy = CE->getType(); - - // Fetch the signature of the called function. - ProgramStateRef state = C.getState(); - const LocationContext *LCtx = C.getLocationContext(); - - SVal V = state->getSVal(CE, LCtx); - - if (V.isUnknown()) - return; - - // Casting to void? Discard the value. - if (expectedResultTy->isVoidType()) { - C.addTransition(state->BindExpr(CE, LCtx, UnknownVal())); - return; - } - - const MemRegion *callee = state->getSVal(CE->getCallee(), LCtx).getAsRegion(); - if (!callee) - return; - - QualType actualResultTy; - - if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) { - const FunctionDecl *FD = FT->getDecl(); - actualResultTy = FD->getResultType(); - } - else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) { - const BlockTextRegion *BR = BD->getCodeRegion(); - const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>(); - const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>(); - actualResultTy = FT->getResultType(); - } - - // Can this happen? - if (actualResultTy.isNull()) - return; - - // For now, ignore references. - if (actualResultTy->getAs<ReferenceType>()) - return; - - - // Are they the same? - if (expectedResultTy != actualResultTy) { - // FIXME: Do more checking and actual emit an error. At least performing - // the cast avoids some assertion failures elsewhere. - SValBuilder &svalBuilder = C.getSValBuilder(); - V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy); - C.addTransition(state->BindExpr(CE, LCtx, V)); - } -} - -void ento::registerAdjustedReturnValueChecker(CheckerManager &mgr) { - mgr.registerChecker<AdjustedReturnValueChecker>(); -} diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp index b2ad18472e06..535d8eede46a 100644 --- a/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ArrayBoundChecker.cpp @@ -78,7 +78,7 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS, new BugReport(*BT, BT->getDescription(), N); report->addRange(LoadS->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); return; } diff --git a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp index c6efe941ec21..457c870943dd 100644 --- a/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp +++ b/lib/StaticAnalyzer/Checkers/ArrayBoundCheckerV2.cpp @@ -208,7 +208,7 @@ void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext, break; } - checkerContext.EmitReport(new BugReport(*BT, os.str(), errorNode)); + checkerContext.emitReport(new BugReport(*BT, os.str(), errorNode)); } void RegionRawOffsetV2::dump() const { diff --git a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp index c582cfc4a81b..81e8dd885a34 100644 --- a/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/AttrNonNullChecker.cpp @@ -105,9 +105,9 @@ void AttrNonNullChecker::checkPreCall(const CallEvent &Call, // Highlight the range of the argument that was null. R->addRange(Call.getArgSourceRange(idx)); if (const Expr *ArgE = Call.getArgExpr(idx)) - bugreporter::addTrackNullOrUndefValueVisitor(errorNode, ArgE, R); + bugreporter::trackNullOrUndefValue(errorNode, ArgE, *R); // Emit the bug report. - C.EmitReport(R); + C.emitReport(R); } // Always return. Either we cached out or we just emitted an error. diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp index 955e79ae4661..eba534e08f6b 100644 --- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp +++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp @@ -117,7 +117,7 @@ void NilArgChecker::WarnNilArg(CheckerContext &C, BugReport *R = new BugReport(*BT, os.str(), N); R->addRange(msg.getArgSourceRange(Arg)); - C.EmitReport(R); + C.emitReport(R); } } @@ -358,20 +358,20 @@ void CFNumberCreateChecker::checkPreStmt(const CallExpr *CE, BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(CE->getArg(2)->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); } } //===----------------------------------------------------------------------===// -// CFRetain/CFRelease checking for null arguments. +// CFRetain/CFRelease/CFMakeCollectable checking for null arguments. //===----------------------------------------------------------------------===// namespace { class CFRetainReleaseChecker : public Checker< check::PreStmt<CallExpr> > { mutable OwningPtr<APIMisuse> BT; - mutable IdentifierInfo *Retain, *Release; + mutable IdentifierInfo *Retain, *Release, *MakeCollectable; public: - CFRetainReleaseChecker(): Retain(0), Release(0) {} + CFRetainReleaseChecker(): Retain(0), Release(0), MakeCollectable(0) {} void checkPreStmt(const CallExpr *CE, CheckerContext &C) const; }; } // end anonymous namespace @@ -392,12 +392,14 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, ASTContext &Ctx = C.getASTContext(); Retain = &Ctx.Idents.get("CFRetain"); Release = &Ctx.Idents.get("CFRelease"); - BT.reset(new APIMisuse("null passed to CFRetain/CFRelease")); + MakeCollectable = &Ctx.Idents.get("CFMakeCollectable"); + BT.reset( + new APIMisuse("null passed to CFRetain/CFRelease/CFMakeCollectable")); } - // Check if we called CFRetain/CFRelease. + // Check if we called CFRetain/CFRelease/CFMakeCollectable. const IdentifierInfo *FuncII = FD->getIdentifier(); - if (!(FuncII == Retain || FuncII == Release)) + if (!(FuncII == Retain || FuncII == Release || FuncII == MakeCollectable)) return; // FIXME: The rest of this just checks that the argument is non-null. @@ -426,14 +428,20 @@ void CFRetainReleaseChecker::checkPreStmt(const CallExpr *CE, if (!N) return; - const char *description = (FuncII == Retain) - ? "Null pointer argument in call to CFRetain" - : "Null pointer argument in call to CFRelease"; + const char *description; + if (FuncII == Retain) + description = "Null pointer argument in call to CFRetain"; + else if (FuncII == Release) + description = "Null pointer argument in call to CFRelease"; + else if (FuncII == MakeCollectable) + description = "Null pointer argument in call to CFMakeCollectable"; + else + llvm_unreachable("impossible case"); BugReport *report = new BugReport(*BT, description, N); report->addRange(Arg->getSourceRange()); - bugreporter::addTrackNullOrUndefValueVisitor(N, Arg, report); - C.EmitReport(report); + bugreporter::trackNullOrUndefValue(N, Arg, *report); + C.emitReport(report); return; } @@ -491,7 +499,7 @@ void ClassReleaseChecker::checkPreObjCMessage(const ObjCMethodCall &msg, BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(msg.getSourceRange()); - C.EmitReport(report); + C.emitReport(report); } } @@ -644,7 +652,7 @@ void VariadicMethodTypeChecker::checkPreObjCMessage(const ObjCMethodCall &msg, BugReport *R = new BugReport(*BT, os.str(), errorNode.getValue()); R->addRange(msg.getArgSourceRange(I)); - C.EmitReport(R); + C.emitReport(R); } } @@ -716,6 +724,73 @@ void ObjCLoopChecker::checkPostStmt(const ObjCForCollectionStmt *FCS, C.addTransition(State); } +namespace { +/// \class ObjCNonNilReturnValueChecker +/// \brief The checker restricts the return values of APIs known to +/// never (or almost never) return 'nil'. +class ObjCNonNilReturnValueChecker + : public Checker<check::PostObjCMessage> { + mutable bool Initialized; + mutable Selector ObjectAtIndex; + mutable Selector ObjectAtIndexedSubscript; + +public: + ObjCNonNilReturnValueChecker() : Initialized(false) {} + void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const; +}; +} + +static ProgramStateRef assumeExprIsNonNull(const Expr *NonNullExpr, + ProgramStateRef State, + CheckerContext &C) { + SVal Val = State->getSVal(NonNullExpr, C.getLocationContext()); + if (DefinedOrUnknownSVal *DV = dyn_cast<DefinedOrUnknownSVal>(&Val)) + return State->assume(*DV, true); + return State; +} + +void ObjCNonNilReturnValueChecker::checkPostObjCMessage(const ObjCMethodCall &M, + CheckerContext &C) + const { + ProgramStateRef State = C.getState(); + + if (!Initialized) { + ASTContext &Ctx = C.getASTContext(); + ObjectAtIndex = GetUnarySelector("objectAtIndex", Ctx); + ObjectAtIndexedSubscript = GetUnarySelector("objectAtIndexedSubscript", Ctx); + } + + // Check the receiver type. + if (const ObjCInterfaceDecl *Interface = M.getReceiverInterface()) { + + // Assume that object returned from '[self init]' or '[super init]' is not + // 'nil' if we are processing an inlined function/method. + // + // A defensive callee will (and should) check if the object returned by + // '[super init]' is 'nil' before doing it's own initialization. However, + // since 'nil' is rarely returned in practice, we should not warn when the + // caller to the defensive constructor uses the object in contexts where + // 'nil' is not accepted. + if (!C.inTopFrame() && M.getDecl() && + M.getDecl()->getMethodFamily() == OMF_init && + M.isReceiverSelfOrSuper()) { + State = assumeExprIsNonNull(M.getOriginExpr(), State, C); + } + + // Objects returned from + // [NSArray|NSOrderedSet]::[ObjectAtIndex|ObjectAtIndexedSubscript] + // are never 'nil'. + FoundationClass Cl = findKnownClass(Interface); + if (Cl == FC_NSArray || Cl == FC_NSOrderedSet) { + Selector Sel = M.getSelector(); + if (Sel == ObjectAtIndex || Sel == ObjectAtIndexedSubscript) { + // Go ahead and assume the value is non-nil. + State = assumeExprIsNonNull(M.getOriginExpr(), State, C); + } + } + } + C.addTransition(State); +} //===----------------------------------------------------------------------===// // Check registration. @@ -744,3 +819,7 @@ void ento::registerVariadicMethodTypeChecker(CheckerManager &mgr) { void ento::registerObjCLoopChecker(CheckerManager &mgr) { mgr.registerChecker<ObjCLoopChecker>(); } + +void ento::registerObjCNonNilReturnValueChecker(CheckerManager &mgr) { + mgr.registerChecker<ObjCNonNilReturnValueChecker>(); +} diff --git a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp index a4fc396c3edc..92edefe7b170 100644 --- a/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/BoolAssignmentChecker.cpp @@ -35,7 +35,7 @@ void BoolAssignmentChecker::emitReport(ProgramStateRef state, if (ExplodedNode *N = C.addTransition(state)) { if (!BT) BT.reset(new BuiltinBug("Assignment of a non-Boolean value")); - C.EmitReport(new BugReport(*BT, BT->getDescription(), N)); + C.emitReport(new BugReport(*BT, BT->getDescription(), N)); } } diff --git a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp index 509bc796fc3c..6ef022b60925 100644 --- a/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/BuiltinFunctionChecker.cpp @@ -55,7 +55,7 @@ bool BuiltinFunctionChecker::evalCall(const CallExpr *CE, // FIXME: Refactor into StoreManager itself? MemRegionManager& RM = C.getStoreManager().getRegionManager(); const AllocaRegion* R = - RM.getAllocaRegion(CE, C.getCurrentBlockCount(), C.getLocationContext()); + RM.getAllocaRegion(CE, C.blockCount(), C.getLocationContext()); // Set the extent of the region in bytes. This enables us to use the // SVal of the argument directly. If we save the extent in bits, we diff --git a/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/lib/StaticAnalyzer/Checkers/CMakeLists.txt index 7fe51d3a4ce3..8e455de3bf46 100644 --- a/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -4,7 +4,6 @@ clang_tablegen(Checkers.inc -gen-clang-sa-checkers TARGET ClangSACheckers) add_clang_library(clangStaticAnalyzerCheckers - AdjustedReturnValueChecker.cpp AnalyzerStatsChecker.cpp ArrayBoundChecker.cpp ArrayBoundCheckerV2.cpp @@ -28,12 +27,15 @@ add_clang_library(clangStaticAnalyzerCheckers DeadStoresChecker.cpp DebugCheckers.cpp DereferenceChecker.cpp + DirectIvarAssignment.cpp DivZeroChecker.cpp DynamicTypePropagation.cpp ExprInspectionChecker.cpp + SimpleStreamChecker.cpp FixedAddressChecker.cpp GenericTaintChecker.cpp IdempotentOperationChecker.cpp + IvarInvalidationChecker.cpp LLVMConventionsChecker.cpp MacOSKeychainAPIChecker.cpp MacOSXAPIChecker.cpp @@ -43,10 +45,10 @@ add_clang_library(clangStaticAnalyzerCheckers NSAutoreleasePoolChecker.cpp NSErrorChecker.cpp NoReturnFunctionChecker.cpp - OSAtomicChecker.cpp ObjCAtSyncChecker.cpp ObjCContainersASTChecker.cpp ObjCContainersChecker.cpp + ObjCMissingSuperCallChecker.cpp ObjCSelfInitChecker.cpp ObjCUnusedIVarsChecker.cpp PointerArithChecker.cpp diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 483082a37f44..eae9ddfc05b9 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -188,21 +188,9 @@ public: NonLoc right) const; }; -class CStringLength { -public: - typedef llvm::ImmutableMap<const MemRegion *, SVal> EntryMap; -}; } //end anonymous namespace -namespace clang { -namespace ento { - template <> - struct ProgramStateTrait<CStringLength> - : public ProgramStatePartialTrait<CStringLength::EntryMap> { - static void *GDMIndex() { return CStringChecker::getTag(); } - }; -} -} +REGISTER_MAP_WITH_PROGRAMSTATE(CStringLength, const MemRegion *, SVal) //===----------------------------------------------------------------------===// // Individual checks and utility methods. @@ -252,8 +240,8 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(S->getSourceRange()); - bugreporter::addTrackNullOrUndefValueVisitor(N, S, report); - C.EmitReport(report); + bugreporter::trackNullOrUndefValue(N, S, *report); + C.emitReport(report); return NULL; } @@ -327,7 +315,7 @@ ProgramStateRef CStringChecker::CheckLocation(CheckerContext &C, // reference is outside the range. report->addRange(S->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); return NULL; } @@ -544,7 +532,7 @@ void CStringChecker::emitOverlapBug(CheckerContext &C, ProgramStateRef state, report->addRange(First->getSourceRange()); report->addRange(Second->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); } ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, @@ -607,7 +595,7 @@ ProgramStateRef CStringChecker::checkAdditionOverflow(CheckerContext &C, // Generate a report for this bug. BugReport *report = new BugReport(*BT_AdditionOverflow, warning, N); - C.EmitReport(report); + C.emitReport(report); return NULL; } @@ -673,11 +661,11 @@ SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C, } // Otherwise, get a new symbol and update the state. - unsigned Count = C.getCurrentBlockCount(); SValBuilder &svalBuilder = C.getSValBuilder(); QualType sizeTy = svalBuilder.getContext().getSizeType(); SVal strLength = svalBuilder.getMetadataSymbolVal(CStringChecker::getTag(), - MR, Ex, sizeTy, Count); + MR, Ex, sizeTy, + C.blockCount()); if (!hypothetical) state = state->set<CStringLength>(MR, strLength); @@ -714,7 +702,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, os.str(), N); report->addRange(Ex->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); } return UndefinedVal(); @@ -778,7 +766,7 @@ SVal CStringChecker::getCStringLength(CheckerContext &C, ProgramStateRef &state, os.str(), N); report->addRange(Ex->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); } return UndefinedVal(); @@ -826,15 +814,14 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C, } // Invalidate this region. - unsigned Count = C.getCurrentBlockCount(); const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); - return state->invalidateRegions(R, E, Count, LCtx); + return state->invalidateRegions(R, E, C.blockCount(), LCtx); } // If we have a non-region value by chance, just remove the binding. // FIXME: is this necessary or correct? This handles the non-Region // cases. Is it ever valid to store to these? - return state->unbindLoc(*L); + return state->killBinding(*L); } bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, @@ -843,7 +830,7 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, switch (MR->getKind()) { case MemRegion::FunctionTextRegionKind: { - const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl(); + const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl(); if (FD) os << "the address of the function '" << *FD << '\''; else @@ -957,9 +944,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, } else { // If we don't know how much we copied, we can at least // conjure a return value for later. - unsigned Count = C.getCurrentBlockCount(); - SVal result = - C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count); + SVal result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, + C.blockCount()); state = state->BindExpr(CE, LCtx, result); } @@ -1093,8 +1079,7 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { state = CheckBufferAccess(C, state, Size, Left, Right); if (state) { // The return value is the comparison result, which we don't know. - unsigned Count = C.getCurrentBlockCount(); - SVal CmpV = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count); + SVal CmpV = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount()); state = state->BindExpr(CE, LCtx, CmpV); C.addTransition(state); } @@ -1206,8 +1191,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, // no guarantee the full string length will actually be returned. // All we know is the return value is the min of the string length // and the limit. This is better than nothing. - unsigned Count = C.getCurrentBlockCount(); - result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count); + result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount()); NonLoc *resultNL = cast<NonLoc>(&result); if (strLengthNL) { @@ -1234,8 +1218,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, // If we don't know the length of the string, conjure a return // value, so it can be used in constraints, at least. if (result.isUnknown()) { - unsigned Count = C.getCurrentBlockCount(); - result = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, LCtx, Count); + result = C.getSValBuilder().conjureSymbolVal(0, CE, LCtx, C.blockCount()); } } @@ -1612,8 +1595,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // If this is a stpcpy-style copy, but we were unable to check for a buffer // overflow, we still need a result. Conjure a return value. if (returnEnd && Result.isUnknown()) { - unsigned Count = C.getCurrentBlockCount(); - Result = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count); + Result = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount()); } // Set the return value. @@ -1770,8 +1752,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, if (!canComputeResult) { // Conjure a symbolic value. It's the best we can do. - unsigned Count = C.getCurrentBlockCount(); - SVal resultVal = svalBuilder.getConjuredSymbolVal(NULL, CE, LCtx, Count); + SVal resultVal = svalBuilder.conjureSymbolVal(0, CE, LCtx, C.blockCount()); state = state->BindExpr(CE, LCtx, resultVal); } @@ -1885,7 +1866,7 @@ void CStringChecker::checkPreStmt(const DeclStmt *DS, CheckerContext &C) const { } bool CStringChecker::wantsRegionChangeUpdate(ProgramStateRef state) const { - CStringLength::EntryMap Entries = state->get<CStringLength>(); + CStringLengthTy Entries = state->get<CStringLength>(); return !Entries.isEmpty(); } @@ -1895,7 +1876,7 @@ CStringChecker::checkRegionChanges(ProgramStateRef state, ArrayRef<const MemRegion *> ExplicitRegions, ArrayRef<const MemRegion *> Regions, const CallEvent *Call) const { - CStringLength::EntryMap Entries = state->get<CStringLength>(); + CStringLengthTy Entries = state->get<CStringLength>(); if (Entries.isEmpty()) return state; @@ -1915,10 +1896,10 @@ CStringChecker::checkRegionChanges(ProgramStateRef state, } } - CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>(); + CStringLengthTy::Factory &F = state->get_context<CStringLength>(); // Then loop over the entries in the current state. - for (CStringLength::EntryMap::iterator I = Entries.begin(), + for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); I != E; ++I) { const MemRegion *MR = I.getKey(); @@ -1945,9 +1926,9 @@ CStringChecker::checkRegionChanges(ProgramStateRef state, void CStringChecker::checkLiveSymbols(ProgramStateRef state, SymbolReaper &SR) const { // Mark all symbols in our string length map as valid. - CStringLength::EntryMap Entries = state->get<CStringLength>(); + CStringLengthTy Entries = state->get<CStringLength>(); - for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end(); + for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); I != E; ++I) { SVal Len = I.getData(); @@ -1963,12 +1944,12 @@ void CStringChecker::checkDeadSymbols(SymbolReaper &SR, return; ProgramStateRef state = C.getState(); - CStringLength::EntryMap Entries = state->get<CStringLength>(); + CStringLengthTy Entries = state->get<CStringLength>(); if (Entries.isEmpty()) return; - CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>(); - for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end(); + CStringLengthTy::Factory &F = state->get_context<CStringLength>(); + for (CStringLengthTy::iterator I = Entries.begin(), E = Entries.end(); I != E; ++I) { SVal Len = I.getData(); if (SymbolRef Sym = Len.getAsSymbol()) { diff --git a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp index befc935d4f34..f1a3aacc7c4c 100644 --- a/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringSyntaxChecker.cpp @@ -33,7 +33,6 @@ namespace { class WalkAST: public StmtVisitor<WalkAST> { BugReporter &BR; AnalysisDeclContext* AC; - ASTContext &ASTC; /// Check if two expressions refer to the same declaration. inline bool sameDecl(const Expr *A1, const Expr *A2) { @@ -58,8 +57,8 @@ class WalkAST: public StmtVisitor<WalkAST> { const FunctionDecl *FD = CE->getDirectCallee(); if (!FD) return false; - return (CheckerContext::isCLibraryFunction(FD, "strlen", ASTC) - && sameDecl(CE->getArg(0), WithArg)); + return (CheckerContext::isCLibraryFunction(FD, "strlen") && + sameDecl(CE->getArg(0), WithArg)); } return false; } @@ -83,7 +82,7 @@ class WalkAST: public StmtVisitor<WalkAST> { public: WalkAST(BugReporter &br, AnalysisDeclContext* ac) : - BR(br), AC(ac), ASTC(AC->getASTContext()) { + BR(br), AC(ac) { } // Statement visitor methods. @@ -136,7 +135,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { if (!FD) return; - if (CheckerContext::isCLibraryFunction(FD, "strncat", ASTC)) { + if (CheckerContext::isCLibraryFunction(FD, "strncat")) { if (containsBadStrncatPattern(CE)) { const Expr *DstArg = CE->getArg(0); const Expr *LenArg = CE->getArg(2); diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp index 5edcf09f1150..82bc1361acfe 100644 --- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp @@ -75,13 +75,13 @@ void CallAndMessageChecker::emitBadCall(BugType *BT, CheckerContext &C, BugReport *R = new BugReport(*BT, BT->getName(), N); if (BadE) { R->addRange(BadE->getSourceRange()); - bugreporter::addTrackNullOrUndefValueVisitor(N, BadE, R); + bugreporter::trackNullOrUndefValue(N, BadE, *R); } - C.EmitReport(R); + C.emitReport(R); } -StringRef describeUninitializedArgumentInCall(const CallEvent &Call, - bool IsFirstArgument) { +static StringRef describeUninitializedArgumentInCall(const CallEvent &Call, + bool IsFirstArgument) { switch (Call.getKind()) { case CE_ObjCMessage: { const ObjCMethodCall &Msg = cast<ObjCMethodCall>(Call); @@ -122,8 +122,8 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, BugReport *R = new BugReport(*BT, Desc, N); R->addRange(argRange); if (argEx) - bugreporter::addTrackNullOrUndefValueVisitor(N, argEx, R); - C.EmitReport(R); + bugreporter::trackNullOrUndefValue(N, argEx, *R); + C.emitReport(R); } return true; } @@ -207,7 +207,7 @@ bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C, // FIXME: enhance track back for uninitialized value for arbitrary // memregions - C.EmitReport(R); + C.emitReport(R); } return true; } @@ -335,8 +335,8 @@ void CallAndMessageChecker::checkPreObjCMessage(const ObjCMethodCall &msg, // FIXME: getTrackNullOrUndefValueVisitor can't handle "super" yet. if (const Expr *ReceiverE = ME->getInstanceReceiver()) - bugreporter::addTrackNullOrUndefValueVisitor(N, ReceiverE, R); - C.EmitReport(R); + bugreporter::trackNullOrUndefValue(N, ReceiverE, *R); + C.emitReport(R); } return; } else { @@ -377,9 +377,9 @@ void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C, report->addRange(ME->getReceiverRange()); // FIXME: This won't track "self" in messages to super. if (const Expr *receiver = ME->getInstanceReceiver()) { - bugreporter::addTrackNullOrUndefValueVisitor(N, receiver, report); + bugreporter::trackNullOrUndefValue(N, receiver, *report); } - C.EmitReport(report); + C.emitReport(report); } static bool supportsNilWithFloatRet(const llvm::Triple &triple) { diff --git a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp index 2e184fbaf946..1cb8a8de7348 100644 --- a/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CastSizeChecker.cpp @@ -75,7 +75,7 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const { BugReport *R = new BugReport(*BT, BT->getDescription(), errorNode); R->addRange(CE->getSourceRange()); - C.EmitReport(R); + C.emitReport(R); } } } diff --git a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp index 1407638fcd69..d6d0e3c7b3b8 100644 --- a/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CastToStructChecker.cpp @@ -64,7 +64,7 @@ void CastToStructChecker::checkPreStmt(const CastExpr *CE, "errors or data corruption.")); BugReport *R = new BugReport(*BT,BT->getDescription(), N); R->addRange(CE->getSourceRange()); - C.EmitReport(R); + C.emitReport(R); } } } diff --git a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp index 7a2586557168..90872058af55 100644 --- a/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckObjCDealloc.cpp @@ -85,7 +85,7 @@ static bool scan_ivar_release(Stmt *S, ObjCIvarDecl *ID, Expr::NPC_ValueDependentIsNull)) { // This is only a 'release' if the property kind is not // 'assign'. - return PD->getSetterKind() != ObjCPropertyDecl::Assign;; + return PD->getSetterKind() != ObjCPropertyDecl::Assign; } // Recurse to children. diff --git a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index b8b7c367969c..5cd61941841d 100644 --- a/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -270,6 +270,7 @@ void WalkAST::checkLoopConditionForFloat(const ForStmt *FS) { // Emit the error. First figure out which DeclRefExpr in the condition // referenced the compared variable. + assert(drInc->getDecl()); const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS; SmallVector<SourceRange, 2> ranges; diff --git a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp index 0e9efaa5ade8..efaec2b3f1e3 100644 --- a/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp +++ b/lib/StaticAnalyzer/Checkers/CheckerDocumentation.cpp @@ -25,6 +25,7 @@ using namespace ento; // All checkers should be placed into anonymous namespace. // We place the CheckerDocumentation inside ento namespace to make the // it visible in doxygen. +namespace clang { namespace ento { /// This checker documents the callback functions checkers can use to implement @@ -33,8 +34,8 @@ namespace ento { /// checking. /// /// \sa CheckerContext -class CheckerDocumentation : public Checker< check::PreStmt<DeclStmt>, - check::PostStmt<CallExpr>, +class CheckerDocumentation : public Checker< check::PreStmt<ReturnStmt>, + check::PostStmt<DeclStmt>, check::PreObjCMessage, check::PostObjCMessage, check::PreCall, @@ -64,8 +65,8 @@ public: /// See checkBranchCondition() callback for performing custom processing of /// the branching statements. /// - /// check::PreStmt<DeclStmt> - void checkPreStmt(const DeclStmt *DS, CheckerContext &C) const {} + /// check::PreStmt<ReturnStmt> + void checkPreStmt(const ReturnStmt *DS, CheckerContext &C) const {} /// \brief Post-visit the Statement. /// @@ -74,8 +75,8 @@ public: /// which does not include the control flow statements such as IfStmt. The /// callback can be specialized to be called with any subclass of Stmt. /// - /// check::PostStmt<CallExpr> - void checkPostStmt(const CallExpr *DS, CheckerContext &C) const; + /// check::PostStmt<DeclStmt> + void checkPostStmt(const DeclStmt *DS, CheckerContext &C) const; /// \brief Pre-visit the Objective C message. /// @@ -98,8 +99,8 @@ public: /// behavior for functions and methods no matter how they are being invoked. /// /// Note that this includes ALL cross-body invocations, so if you want to - /// limit your checks to, say, function calls, you can either test for that - /// or fall back to the explicit callback (i.e. check::PreStmt). + /// limit your checks to, say, function calls, you should test for that at the + /// beginning of your callback function. /// /// check::PreCall void checkPreCall(const CallEvent &Call, CheckerContext &C) const {} @@ -151,9 +152,8 @@ public: /// check::DeadSymbols void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const {} - /// \brief Called when an end of path is reached in the ExplodedGraph. - /// - /// This callback should be used to check if the allocated resources are freed. + /// \brief Called when the analyzer core reaches the end of the top-level + /// function being analyzed. /// /// check::EndPath void checkEndPath(CheckerContext &Ctx) const {} @@ -213,21 +213,35 @@ public: /// check::LiveSymbols void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const {} - + /// \brief Called to determine if the checker currently needs to know if when + /// contents of any regions change. + /// + /// Since it is not necessarily cheap to compute which regions are being + /// changed, this allows the analyzer core to skip the more expensive + /// #checkRegionChanges when no checkers are tracking any state. bool wantsRegionChangeUpdate(ProgramStateRef St) const { return true; } - /// \brief Allows tracking regions which get invalidated. + /// \brief Called when the contents of one or more regions change. + /// + /// This can occur in many different ways: an explicit bind, a blanket + /// invalidation of the region contents, or by passing a region to a function + /// call whose behavior the analyzer cannot model perfectly. /// /// \param State The current program state. /// \param Invalidated A set of all symbols potentially touched by the change. /// \param ExplicitRegions The regions explicitly requested for invalidation. - /// For example, in the case of a function call, these would be arguments. - /// \param Regions The transitive closure of accessible regions, - /// i.e. all regions that may have been touched by this change. - /// \param Call The call expression wrapper if the regions are invalidated - /// by a call, 0 otherwise. - /// Note, in order to be notified, the checker should also implement the - /// wantsRegionChangeUpdate callback. + /// For a function call, this would be the arguments. For a bind, this + /// would be the region being bound to. + /// \param Regions The transitive closure of regions accessible from, + /// \p ExplicitRegions, i.e. all regions that may have been touched + /// by this change. For a simple bind, this list will be the same as + /// \p ExplicitRegions, since a bind does not affect the contents of + /// anything accessible through the base region. + /// \param Call The opaque call triggering this invalidation. Will be 0 if the + /// change was not triggered by a call. + /// + /// Note that this callback will not be invoked unless + /// #wantsRegionChangeUpdate returns \c true. /// /// check::RegionChanges ProgramStateRef @@ -256,9 +270,10 @@ public: }; -void CheckerDocumentation::checkPostStmt(const CallExpr *DS, +void CheckerDocumentation::checkPostStmt(const DeclStmt *DS, CheckerContext &C) const { return; } -} // end namespace +} // end namespace ento +} // end namespace clang diff --git a/lib/StaticAnalyzer/Checkers/Checkers.td b/lib/StaticAnalyzer/Checkers/Checkers.td index 8110bd0e18c2..235e63306f04 100644 --- a/lib/StaticAnalyzer/Checkers/Checkers.td +++ b/lib/StaticAnalyzer/Checkers/Checkers.td @@ -13,33 +13,33 @@ include "clang/StaticAnalyzer/Checkers/CheckerBase.td" // Packages. //===----------------------------------------------------------------------===// -def Experimental : Package<"experimental">; +def Alpha : Package<"alpha">; def Core : Package<"core">; def CoreBuiltin : Package<"builtin">, InPackage<Core>; def CoreUninitialized : Package<"uninitialized">, InPackage<Core>; -def CoreExperimental : Package<"core">, InPackage<Experimental>, Hidden; +def CoreAlpha : Package<"core">, InPackage<Alpha>, Hidden; def Cplusplus : Package<"cplusplus">; -def CplusplusExperimental : Package<"cplusplus">, InPackage<Experimental>, Hidden; +def CplusplusAlpha : Package<"cplusplus">, InPackage<Alpha>, Hidden; def DeadCode : Package<"deadcode">; -def DeadCodeExperimental : Package<"deadcode">, InPackage<Experimental>, Hidden; +def DeadCodeAlpha : Package<"deadcode">, InPackage<Alpha>, Hidden; def Security : Package <"security">; def InsecureAPI : Package<"insecureAPI">, InPackage<Security>; -def SecurityExperimental : Package<"security">, InPackage<Experimental>, Hidden; -def Taint : Package<"taint">, InPackage<SecurityExperimental>, Hidden; +def SecurityAlpha : Package<"security">, InPackage<Alpha>, Hidden; +def Taint : Package<"taint">, InPackage<SecurityAlpha>, Hidden; def Unix : Package<"unix">; -def UnixExperimental : Package<"unix">, InPackage<Experimental>, Hidden; +def UnixAlpha : Package<"unix">, InPackage<Alpha>, Hidden; def CString : Package<"cstring">, InPackage<Unix>, Hidden; -def CStringExperimental : Package<"cstring">, InPackage<UnixExperimental>, Hidden; +def CStringAlpha : Package<"cstring">, InPackage<UnixAlpha>, Hidden; def OSX : Package<"osx">; -def OSXExperimental : Package<"osx">, InPackage<Experimental>, Hidden; +def OSXAlpha : Package<"osx">, InPackage<Alpha>, Hidden; def Cocoa : Package<"cocoa">, InPackage<OSX>; -def CocoaExperimental : Package<"cocoa">, InPackage<OSXExperimental>, Hidden; +def CocoaAlpha : Package<"cocoa">, InPackage<OSXAlpha>, Hidden; def CoreFoundation : Package<"coreFoundation">, InPackage<OSX>; def Containers : Package<"containers">, InPackage<CoreFoundation>; @@ -60,10 +60,6 @@ def CallAndMessageChecker : Checker<"CallAndMessage">, HelpText<"Check for logical errors for function calls and Objective-C message expressions (e.g., uninitialized arguments, null function pointers)">, DescFile<"CallAndMessageChecker.cpp">; -def AdjustedReturnValueChecker : Checker<"AdjustedReturnValue">, - HelpText<"Check to see if the return value of a function call is different than the caller expects (e.g., from calls through function pointers)">, - DescFile<"AdjustedReturnValueChecker.cpp">; - def AttrNonNullChecker : Checker<"AttributeNonNull">, HelpText<"Check for null pointers passed as arguments to a function whose arguments are marked with the 'nonnull' attribute">, DescFile<"AttrNonNullChecker.cpp">; @@ -90,7 +86,7 @@ def DynamicTypePropagation : Checker<"DynamicTypePropagation">, } // end "core" -let ParentPackage = CoreExperimental in { +let ParentPackage = CoreAlpha in { def BoolAssignmentChecker : Checker<"BoolAssignment">, HelpText<"Warn about assigning non-{0,1} values to Boolean variables">, @@ -120,7 +116,7 @@ def SizeofPointerChecker : Checker<"SizeofPtr">, HelpText<"Warn about unintended use of sizeof() on pointer expressions">, DescFile<"CheckSizeofPointer.cpp">; -} // end "core.experimental" +} // end "alpha.core" //===----------------------------------------------------------------------===// // Evaluate "builtin" functions. @@ -170,13 +166,13 @@ def ReturnUndefChecker : Checker<"UndefReturn">, // C++ checkers. //===----------------------------------------------------------------------===// -let ParentPackage = CplusplusExperimental in { +let ParentPackage = CplusplusAlpha in { def VirtualCallChecker : Checker<"VirtualCall">, HelpText<"Check virtual function calls during construction or destruction">, DescFile<"VirtualCallChecker.cpp">; -} // end: "cplusplus.experimental" +} // end: "alpha.cplusplus" //===----------------------------------------------------------------------===// // Deadcode checkers. @@ -189,7 +185,7 @@ def DeadStoresChecker : Checker<"DeadStores">, DescFile<"DeadStoresChecker.cpp">; } // end DeadCode -let ParentPackage = DeadCodeExperimental in { +let ParentPackage = DeadCodeAlpha in { def IdempotentOperationChecker : Checker<"IdempotentOperations">, HelpText<"Warn about idempotent operations">, @@ -199,7 +195,7 @@ def UnreachableCodeChecker : Checker<"UnreachableCode">, HelpText<"Check unreachable code">, DescFile<"UnreachableCodeChecker.cpp">; -} // end "deadcode.experimental" +} // end "alpha.deadcode" //===----------------------------------------------------------------------===// // Security checkers. @@ -237,7 +233,7 @@ let ParentPackage = Security in { DescFile<"CheckSecuritySyntaxOnly.cpp">; } -let ParentPackage = SecurityExperimental in { +let ParentPackage = SecurityAlpha in { def ArrayBoundChecker : Checker<"ArrayBound">, HelpText<"Warn about buffer overflows (older checker)">, @@ -255,7 +251,7 @@ def MallocOverflowSecurityChecker : Checker<"MallocOverflow">, HelpText<"Check for overflows in the arguments to malloc()">, DescFile<"MallocOverflowSecurityChecker.cpp">; -} // end "security.experimental" +} // end "alpha.security" //===----------------------------------------------------------------------===// // Taint checkers. @@ -267,7 +263,7 @@ def GenericTaintChecker : Checker<"TaintPropagation">, HelpText<"Generate taint information used by other checkers">, DescFile<"GenericTaintChecker.cpp">; -} // end "experimental.security.taint" +} // end "alpha.security.taint" //===----------------------------------------------------------------------===// // Unix API checkers. @@ -289,7 +285,7 @@ def MallocSizeofChecker : Checker<"MallocSizeof">, } // end "unix" -let ParentPackage = UnixExperimental in { +let ParentPackage = UnixAlpha in { def ChrootChecker : Checker<"Chroot">, HelpText<"Check improper use of chroot">, @@ -307,7 +303,11 @@ def StreamChecker : Checker<"Stream">, HelpText<"Check stream handling functions">, DescFile<"StreamChecker.cpp">; -} // end "unix.experimental" +def SimpleStreamChecker : Checker<"SimpleStream">, + HelpText<"Check for misuses of stream APIs">, + DescFile<"SimpleStreamChecker.cpp">; + +} // end "alpha.unix" let ParentPackage = CString in { @@ -320,7 +320,7 @@ def CStringSyntaxChecker : Checker<"BadSizeArg">, DescFile<"CStringSyntaxChecker.cpp">; } -let ParentPackage = CStringExperimental in { +let ParentPackage = CStringAlpha in { def CStringOutOfBounds : Checker<"OutOfBounds">, HelpText<"Check for out-of-bounds access in string functions">, @@ -346,11 +346,6 @@ def MacOSXAPIChecker : Checker<"API">, HelpText<"Check for proper uses of various Mac OS X APIs">, DescFile<"MacOSXAPIChecker.cpp">; -def OSAtomicChecker : Checker<"AtomicCAS">, - InPackage<OSX>, - HelpText<"Evaluate calls to OSAtomic functions">, - DescFile<"OSAtomicChecker.cpp">; - def MacOSKeychainAPIChecker : Checker<"SecKeychainAPI">, InPackage<OSX>, HelpText<"Check for proper uses of Secure Keychain APIs">, @@ -397,6 +392,10 @@ def ObjCLoopChecker : Checker<"Loops">, HelpText<"Improved modeling of loops using Cocoa collection types">, DescFile<"BasicObjCFoundationChecks.cpp">; +def ObjCNonNilReturnValueChecker : Checker<"NonNilReturnValue">, + HelpText<"Model the APIs that are guaranteed to return a non-nil value">, + DescFile<"BasicObjCFoundationChecks.cpp">; + def NSErrorChecker : Checker<"NSError">, HelpText<"Check usage of NSError** parameters">, DescFile<"NSErrorChecker.cpp">; @@ -407,13 +406,25 @@ def RetainCountChecker : Checker<"RetainCount">, } // end "osx.cocoa" -let ParentPackage = CocoaExperimental in { +let ParentPackage = CocoaAlpha in { def ObjCDeallocChecker : Checker<"Dealloc">, HelpText<"Warn about Objective-C classes that lack a correct implementation of -dealloc">, DescFile<"CheckObjCDealloc.cpp">; -} // end "cocoa.experimental" +def IvarInvalidationChecker : Checker<"InstanceVariableInvalidation">, + HelpText<"Check that the invalidatable instance variables are invalidated in the methods annotated with objc_instance_variable_invalidator">, + DescFile<"IvarInvalidationChecker.cpp">; + +def DirectIvarAssignment : Checker<"DirectIvarAssignment">, + HelpText<"Check that the invalidatable instance variables are invalidated in the methods annotated with objc_instance_variable_invalidator">, + DescFile<"DirectIvarAssignment.cpp">; + +def ObjCSuperCallChecker : Checker<"MissingSuperCall">, + HelpText<"Warn about Objective-C methods that lack a necessary call to super">, + DescFile<"ObjCMissingSuperCallChecker.cpp">; + +} // end "alpha.osx.cocoa" let ParentPackage = CoreFoundation in { @@ -422,7 +433,7 @@ def CFNumberCreateChecker : Checker<"CFNumber">, DescFile<"BasicObjCFoundationChecks.cpp">; def CFRetainReleaseChecker : Checker<"CFRetainRelease">, - HelpText<"Check for null arguments to CFRetain/CFRelease">, + HelpText<"Check for null arguments to CFRetain/CFRelease/CFMakeCollectable">, DescFile<"BasicObjCFoundationChecks.cpp">; def CFErrorChecker : Checker<"CFError">, @@ -479,6 +490,10 @@ def CallGraphDumper : Checker<"DumpCallGraph">, HelpText<"Display Call Graph">, DescFile<"DebugCheckers.cpp">; +def ConfigDumper : Checker<"ConfigDumper">, + HelpText<"Dump config table">, + DescFile<"DebugCheckers.cpp">; + def TraversalDumper : Checker<"DumpTraversal">, HelpText<"Print branch conditions as they are traversed by the engine">, DescFile<"TraversalChecker.cpp">; diff --git a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp index 30d060996ea7..c8856162fe89 100644 --- a/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ChrootChecker.cpp @@ -147,7 +147,7 @@ void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { "after chroot")); BugReport *R = new BugReport(*BT_BreakJail, BT_BreakJail->getDescription(), N); - C.EmitReport(R); + C.emitReport(R); } return; diff --git a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp index 510e8cd8104b..59e03ecd5c61 100644 --- a/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp @@ -13,22 +13,54 @@ //===----------------------------------------------------------------------===// #include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/Analysis/Analyses/LiveVariables.h" -#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h" -#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" -#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" -#include "clang/Basic/Diagnostic.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ParentMap.h" -#include "llvm/ADT/SmallPtrSet.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Analysis/Analyses/LiveVariables.h" +#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/SaveAndRestore.h" using namespace clang; using namespace ento; -namespace { +namespace { + +/// A simple visitor to record what VarDecls occur in EH-handling code. +class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> { +public: + bool inEH; + llvm::DenseSet<const VarDecl *> &S; + + bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + SaveAndRestore<bool> inFinally(inEH, true); + return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S); + } + + bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) { + SaveAndRestore<bool> inCatch(inEH, true); + return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S); + } + + bool TraverseCXXCatchStmt(CXXCatchStmt *S) { + SaveAndRestore<bool> inCatch(inEH, true); + return TraverseStmt(S->getHandlerBlock()); + } + + bool VisitDeclRefExpr(DeclRefExpr *DR) { + if (inEH) + if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl())) + S.insert(D); + return true; + } + + EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) : + inEH(false), S(S) {} +}; // FIXME: Eventually migrate into its own file, and have it managed by // AnalysisManager. @@ -93,6 +125,7 @@ class DeadStoreObs : public LiveVariables::Observer { llvm::SmallPtrSet<const VarDecl*, 20> Escaped; OwningPtr<ReachableCode> reachableCode; const CFGBlock *currentBlock; + llvm::OwningPtr<llvm::DenseSet<const VarDecl *> > InEH; enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit }; @@ -105,6 +138,23 @@ public: virtual ~DeadStoreObs() {} + bool isLive(const LiveVariables::LivenessValues &Live, const VarDecl *D) { + if (Live.isLive(D)) + return true; + // Lazily construct the set that records which VarDecls are in + // EH code. + if (!InEH.get()) { + InEH.reset(new llvm::DenseSet<const VarDecl *>()); + EHCodeVisitor V(*InEH.get()); + V.TraverseStmt(AC->getBody()); + } + // Treat all VarDecls that occur in EH code as being "always live" + // when considering to suppress dead stores. Frequently stores + // are followed by reads in EH code, but we don't have the ability + // to analyze that yet. + return InEH->count(D); + } + void Report(const VarDecl *V, DeadStoreKind dsk, PathDiagnosticLocation L, SourceRange R) { if (Escaped.count(V)) @@ -159,7 +209,7 @@ public: if (VD->getType()->getAs<ReferenceType>()) return; - if (!Live.isLive(VD) && + if (!isLive(Live, VD) && !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>())) { PathDiagnosticLocation ExLoc = @@ -285,7 +335,7 @@ public: // A dead initialization is a variable that is dead after it // is initialized. We don't flag warnings for those variables // marked 'unused'. - if (!Live.isLive(V) && V->getAttr<UnusedAttr>() == 0) { + if (!isLive(Live, V) && V->getAttr<UnusedAttr>() == 0) { // Special case: check for initializations with constants. // // e.g. : int x = 0; diff --git a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp index 34053cdad638..7ad9c59a1bb2 100644 --- a/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp +++ b/lib/StaticAnalyzer/Checkers/DebugCheckers.cpp @@ -144,3 +144,38 @@ public: void ento::registerCallGraphDumper(CheckerManager &mgr) { mgr.registerChecker<CallGraphDumper>(); } + + +//===----------------------------------------------------------------------===// +// ConfigDumper +//===----------------------------------------------------------------------===// + +namespace { +class ConfigDumper : public Checker< check::EndOfTranslationUnit > { +public: + void checkEndOfTranslationUnit(const TranslationUnitDecl *TU, + AnalysisManager& mgr, + BugReporter &BR) const { + + const AnalyzerOptions::ConfigTable &Config = mgr.options.Config; + AnalyzerOptions::ConfigTable::const_iterator I = + Config.begin(), E = Config.end(); + + std::vector<StringRef> Keys; + for (; I != E ; ++I) { Keys.push_back(I->getKey()); } + sort(Keys.begin(), Keys.end()); + + llvm::errs() << "[config]\n"; + for (unsigned i = 0, n = Keys.size(); i < n ; ++i) { + StringRef Key = Keys[i]; + I = Config.find(Key); + llvm::errs() << Key << " = " << I->second << '\n'; + } + llvm::errs() << "[stats]\n" << "num-entries = " << Keys.size() << '\n'; + } +}; +} + +void ento::registerConfigDumper(CheckerManager &mgr) { + mgr.registerChecker<ConfigDumper>(); +} diff --git a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index e98c131ce97d..3ace4be44804 100644 --- a/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -39,7 +39,7 @@ public: CheckerContext &C) const; void checkBind(SVal L, SVal V, const Stmt *S, CheckerContext &C) const; - static const MemRegion *AddDerefSource(raw_ostream &os, + static void AddDerefSource(raw_ostream &os, SmallVectorImpl<SourceRange> &Ranges, const Expr *Ex, const ProgramState *state, const LocationContext *LCtx, @@ -47,7 +47,7 @@ public: }; } // end anonymous namespace -const MemRegion * +void DereferenceChecker::AddDerefSource(raw_ostream &os, SmallVectorImpl<SourceRange> &Ranges, const Expr *Ex, @@ -55,7 +55,6 @@ DereferenceChecker::AddDerefSource(raw_ostream &os, const LocationContext *LCtx, bool loadedFrom) { Ex = Ex->IgnoreParenLValueCasts(); - const MemRegion *sourceR = 0; switch (Ex->getStmtClass()) { default: break; @@ -65,7 +64,6 @@ DereferenceChecker::AddDerefSource(raw_ostream &os, os << " (" << (loadedFrom ? "loaded from" : "from") << " variable '" << VD->getName() << "')"; Ranges.push_back(DR->getSourceRange()); - sourceR = state->getLValue(VD, LCtx).getAsRegion(); } break; } @@ -78,7 +76,6 @@ DereferenceChecker::AddDerefSource(raw_ostream &os, break; } } - return sourceR; } void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, @@ -94,6 +91,8 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, BT_null.reset(new BuiltinBug("Dereference of null pointer")); SmallString<100> buf; + llvm::raw_svector_ostream os(buf); + SmallVector<SourceRange, 2> Ranges; // Walk through lvalue casts to get the original expression @@ -101,8 +100,6 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, if (const Expr *expr = dyn_cast<Expr>(S)) S = expr->IgnoreParenLValueCasts(); - const MemRegion *sourceR = 0; - if (IsBind) { if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S)) { if (BO->isAssignmentOp()) @@ -117,68 +114,55 @@ void DereferenceChecker::reportBug(ProgramStateRef State, const Stmt *S, switch (S->getStmtClass()) { case Stmt::ArraySubscriptExprClass: { - llvm::raw_svector_ostream os(buf); os << "Array access"; const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S); - sourceR = AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), - State.getPtr(), N->getLocationContext()); + AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts(), + State.getPtr(), N->getLocationContext()); os << " results in a null pointer dereference"; break; } case Stmt::UnaryOperatorClass: { - llvm::raw_svector_ostream os(buf); os << "Dereference of null pointer"; const UnaryOperator *U = cast<UnaryOperator>(S); - sourceR = AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), - State.getPtr(), N->getLocationContext(), true); + AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), + State.getPtr(), N->getLocationContext(), true); break; } case Stmt::MemberExprClass: { const MemberExpr *M = cast<MemberExpr>(S); - if (M->isArrow()) { - llvm::raw_svector_ostream os(buf); + if (M->isArrow() || bugreporter::isDeclRefExprToReference(M->getBase())) { os << "Access to field '" << M->getMemberNameInfo() << "' results in a dereference of a null pointer"; - sourceR = AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), - State.getPtr(), N->getLocationContext(), true); + AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), + State.getPtr(), N->getLocationContext(), true); } break; } case Stmt::ObjCIvarRefExprClass: { const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S); - if (const DeclRefExpr *DR = - dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) { - if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { - llvm::raw_svector_ostream os(buf); - os << "Instance variable access (via '" << VD->getName() - << "') results in a null pointer dereference"; - } - } - Ranges.push_back(IV->getSourceRange()); + os << "Access to instance variable '" << *IV->getDecl() + << "' results in a dereference of a null pointer"; + AddDerefSource(os, Ranges, IV->getBase()->IgnoreParenCasts(), + State.getPtr(), N->getLocationContext(), true); break; } default: break; } + os.flush(); BugReport *report = new BugReport(*BT_null, buf.empty() ? BT_null->getDescription() : buf.str(), N); - bugreporter::addTrackNullOrUndefValueVisitor(N, bugreporter::GetDerefExpr(N), - report); + bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N), *report); for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(), E = Ranges.end(); I!=E; ++I) report->addRange(*I); - if (sourceR) { - report->markInteresting(sourceR); - report->markInteresting(State->getRawSVal(loc::MemRegionVal(sourceR))); - } - - C.EmitReport(report); + C.emitReport(report); } void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, @@ -191,11 +175,9 @@ void DereferenceChecker::checkLocation(SVal l, bool isLoad, const Stmt* S, BugReport *report = new BugReport(*BT_undef, BT_undef->getDescription(), N); - bugreporter::addTrackNullOrUndefValueVisitor(N, - bugreporter::GetDerefExpr(N), - report); - report->disablePathPruning(); - C.EmitReport(report); + bugreporter::trackNullOrUndefValue(N, bugreporter::GetDerefExpr(N), + *report); + C.emitReport(report); } return; } diff --git a/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp new file mode 100644 index 000000000000..dc90b67e20fa --- /dev/null +++ b/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp @@ -0,0 +1,180 @@ +//=- DirectIvarAssignment.cpp - Check rules on ObjC properties -*- C++ ----*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Check that Objective C properties follow the following rules: +// - The property should be set with the setter, not though a direct +// assignment. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/StmtVisitor.h" +#include "llvm/ADT/DenseMap.h" + +using namespace clang; +using namespace ento; + +namespace { + +class DirectIvarAssignment : + public Checker<check::ASTDecl<ObjCImplementationDecl> > { + + typedef llvm::DenseMap<const ObjCIvarDecl*, + const ObjCPropertyDecl*> IvarToPropertyMapTy; + + /// A helper class, which walks the AST and locates all assignments to ivars + /// in the given function. + class MethodCrawler : public ConstStmtVisitor<MethodCrawler> { + const IvarToPropertyMapTy &IvarToPropMap; + const ObjCMethodDecl *MD; + const ObjCInterfaceDecl *InterfD; + BugReporter &BR; + LocationOrAnalysisDeclContext DCtx; + + public: + MethodCrawler(const IvarToPropertyMapTy &InMap, const ObjCMethodDecl *InMD, + const ObjCInterfaceDecl *InID, + BugReporter &InBR, AnalysisDeclContext *InDCtx) + : IvarToPropMap(InMap), MD(InMD), InterfD(InID), BR(InBR), DCtx(InDCtx) {} + + void VisitStmt(const Stmt *S) { VisitChildren(S); } + + void VisitBinaryOperator(const BinaryOperator *BO); + + void VisitChildren(const Stmt *S) { + for (Stmt::const_child_range I = S->children(); I; ++I) + if (*I) + this->Visit(*I); + } + }; + +public: + void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr, + BugReporter &BR) const; +}; + +static const ObjCIvarDecl *findPropertyBackingIvar(const ObjCPropertyDecl *PD, + const ObjCInterfaceDecl *InterD, + ASTContext &Ctx) { + // Check for synthesized ivars. + ObjCIvarDecl *ID = PD->getPropertyIvarDecl(); + if (ID) + return ID; + + ObjCInterfaceDecl *NonConstInterD = const_cast<ObjCInterfaceDecl*>(InterD); + + // Check for existing "_PropName". + ID = NonConstInterD->lookupInstanceVariable(PD->getDefaultSynthIvarName(Ctx)); + if (ID) + return ID; + + // Check for existing "PropName". + IdentifierInfo *PropIdent = PD->getIdentifier(); + ID = NonConstInterD->lookupInstanceVariable(PropIdent); + + return ID; +} + +void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D, + AnalysisManager& Mgr, + BugReporter &BR) const { + const ObjCInterfaceDecl *InterD = D->getClassInterface(); + + + IvarToPropertyMapTy IvarToPropMap; + + // Find all properties for this class. + for (ObjCInterfaceDecl::prop_iterator I = InterD->prop_begin(), + E = InterD->prop_end(); I != E; ++I) { + ObjCPropertyDecl *PD = *I; + + // Find the corresponding IVar. + const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterD, + Mgr.getASTContext()); + + if (!ID) + continue; + + // Store the IVar to property mapping. + IvarToPropMap[ID] = PD; + } + + if (IvarToPropMap.empty()) + return; + + for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), + E = D->instmeth_end(); I != E; ++I) { + + ObjCMethodDecl *M = *I; + AnalysisDeclContext *DCtx = Mgr.getAnalysisDeclContext(M); + + // Skip the init, dealloc functions and any functions that might be doing + // initialization based on their name. + if (M->getMethodFamily() == OMF_init || + M->getMethodFamily() == OMF_dealloc || + M->getMethodFamily() == OMF_copy || + M->getMethodFamily() == OMF_mutableCopy || + M->getSelector().getNameForSlot(0).find("init") != StringRef::npos || + M->getSelector().getNameForSlot(0).find("Init") != StringRef::npos) + continue; + + const Stmt *Body = M->getBody(); + assert(Body); + + MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, DCtx); + MC.VisitStmt(Body); + } +} + +void DirectIvarAssignment::MethodCrawler::VisitBinaryOperator( + const BinaryOperator *BO) { + if (!BO->isAssignmentOp()) + return; + + const ObjCIvarRefExpr *IvarRef = + dyn_cast<ObjCIvarRefExpr>(BO->getLHS()->IgnoreParenCasts()); + + if (!IvarRef) + return; + + if (const ObjCIvarDecl *D = IvarRef->getDecl()) { + IvarToPropertyMapTy::const_iterator I = IvarToPropMap.find(D); + if (I != IvarToPropMap.end()) { + const ObjCPropertyDecl *PD = I->second; + + ObjCMethodDecl *GetterMethod = + InterfD->getInstanceMethod(PD->getGetterName()); + ObjCMethodDecl *SetterMethod = + InterfD->getInstanceMethod(PD->getSetterName()); + + if (SetterMethod && SetterMethod->getCanonicalDecl() == MD) + return; + + if (GetterMethod && GetterMethod->getCanonicalDecl() == MD) + return; + + BR.EmitBasicReport(MD, + "Property access", + categories::CoreFoundationObjectiveC, + "Direct assignment to an instance variable backing a property; " + "use the setter instead", PathDiagnosticLocation(IvarRef, + BR.getSourceManager(), + DCtx)); + } + } +} +} + +void ento::registerDirectIvarAssignment(CheckerManager &mgr) { + mgr.registerChecker<DirectIvarAssignment>(); +} diff --git a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp index dcf6a8603ec7..76fb3f2b288e 100644 --- a/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/DivZeroChecker.cpp @@ -39,13 +39,9 @@ void DivZeroChecker::reportBug(const char *Msg, if (!BT) BT.reset(new BuiltinBug("Division by zero")); - BugReport *R = - new BugReport(*BT, Msg, N); - - bugreporter::addTrackNullOrUndefValueVisitor(N, - bugreporter::GetDenomExpr(N), - R); - C.EmitReport(R); + BugReport *R = new BugReport(*BT, Msg, N); + bugreporter::trackNullOrUndefValue(N, bugreporter::GetDenomExpr(N), *R); + C.emitReport(R); } } diff --git a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp index b636efbe35a1..b0a4bc67485e 100644 --- a/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp +++ b/lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp @@ -83,14 +83,14 @@ void DynamicTypePropagation::checkPreCall(const CallEvent &Call, if (const CXXDestructorCall *Dtor = dyn_cast<CXXDestructorCall>(&Call)) { // C++11 [class.cdtor]p4 (see above) + if (!Dtor->isBaseDestructor()) + return; const MemRegion *Target = Dtor->getCXXThisVal().getAsRegion(); if (!Target) return; - // FIXME: getRuntimeDefinition() can be expensive. It would be better to do - // this when we are entering the stack frame for the destructor. - const Decl *D = Dtor->getRuntimeDefinition().getDecl(); + const Decl *D = Dtor->getDecl(); if (!D) return; @@ -105,8 +105,7 @@ void DynamicTypePropagation::checkPostCall(const CallEvent &Call, if (const ObjCMethodCall *Msg = dyn_cast<ObjCMethodCall>(&Call)) { // Get the returned value if it's a region. - SVal Result = C.getSVal(Call.getOriginExpr()); - const MemRegion *RetReg = Result.getAsRegion(); + const MemRegion *RetReg = Call.getReturnValue().getAsRegion(); if (!RetReg) return; diff --git a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp index 7acf223e63d6..e7e316281faa 100644 --- a/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp @@ -93,7 +93,7 @@ void ExprInspectionChecker::analyzerEval(const CallExpr *CE, BT.reset(new BugType("Checking analyzer assumptions", "debug")); BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N); - C.EmitReport(R); + C.emitReport(R); } void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, @@ -113,7 +113,7 @@ void ExprInspectionChecker::analyzerCheckInlined(const CallExpr *CE, BT.reset(new BugType("Checking analyzer assumptions", "debug")); BugReport *R = new BugReport(*BT, getArgumentValueString(CE, C), N); - C.EmitReport(R); + C.emitReport(R); } void ento::registerExprInspectionChecker(CheckerManager &Mgr) { diff --git a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp index a1f2f3b2ba98..7fde68923124 100644 --- a/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/FixedAddressChecker.cpp @@ -58,7 +58,7 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B, "environments or platforms.")); BugReport *R = new BugReport(*BT, BT->getDescription(), N); R->addRange(B->getRHS()->getSourceRange()); - C.EmitReport(R); + C.emitReport(R); } } diff --git a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp index afb862cd6c9a..a9e02173c3a9 100644 --- a/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -192,13 +192,7 @@ const char GenericTaintChecker::MsgTaintedBufferSize[] = /// to the call post-visit. The values are unsigned integers, which are either /// ReturnValueIndex, or indexes of the pointer/reference argument, which /// points to data, which should be tainted on return. -namespace { struct TaintArgsOnPostVisit{}; } -namespace clang { namespace ento { -template<> struct ProgramStateTrait<TaintArgsOnPostVisit> - : public ProgramStatePartialTrait<llvm::ImmutableSet<unsigned> > { - static void *GDMIndex() { return GenericTaintChecker::getTag(); } -}; -}} +REGISTER_SET_WITH_PROGRAMSTATE(TaintArgsOnPostVisit, unsigned) GenericTaintChecker::TaintPropagationRule GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( @@ -337,7 +331,7 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE, // Depending on what was tainted at pre-visit, we determined a set of // arguments which should be tainted after the function returns. These are // stored in the state as TaintArgsOnPostVisit set. - llvm::ImmutableSet<unsigned> TaintArgs = State->get<TaintArgsOnPostVisit>(); + TaintArgsOnPostVisitTy TaintArgs = State->get<TaintArgsOnPostVisit>(); if (TaintArgs.isEmpty()) return false; @@ -653,7 +647,7 @@ bool GenericTaintChecker::generateReportIfTainted(const Expr *E, initBugType(); BugReport *report = new BugReport(*BT, Msg, N); report->addRange(E->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); return true; } return false; diff --git a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp index 9d0b83f40b34..ffbbb8b68d8a 100644 --- a/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/IdempotentOperationChecker.cpp @@ -430,7 +430,7 @@ void IdempotentOperationChecker::checkEndAnalysis(ExplodedGraph &G, FindLastStoreBRVisitor::registerStatementVarDecls(*report, RHS); } - BR.EmitReport(report); + BR.emitReport(report); } } diff --git a/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp new file mode 100644 index 000000000000..bf256cd9fa45 --- /dev/null +++ b/lib/StaticAnalyzer/Checkers/IvarInvalidationChecker.cpp @@ -0,0 +1,550 @@ +//=- IvarInvalidationChecker.cpp - -*- C++ -------------------------------*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This checker implements annotation driven invalidation checking. If a class +// contains a method annotated with 'objc_instance_variable_invalidator', +// - (void) foo +// __attribute__((annotate("objc_instance_variable_invalidator"))); +// all the "ivalidatable" instance variables of this class should be +// invalidated. We call an instance variable ivalidatable if it is an object of +// a class which contains an invalidation method. There could be multiple +// methods annotated with such annotations per class, either one can be used +// to invalidate the ivar. An ivar or property are considered to be +// invalidated if they are being assigned 'nil' or an invalidation method has +// been called on them. An invalidation method should either invalidate all +// the ivars or call another invalidation method (on self). +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/StmtVisitor.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" + +using namespace clang; +using namespace ento; + +namespace { +class IvarInvalidationChecker : + public Checker<check::ASTDecl<ObjCMethodDecl> > { + + typedef llvm::DenseSet<const ObjCMethodDecl*> MethodSet; + typedef llvm::DenseMap<const ObjCMethodDecl*, + const ObjCIvarDecl*> MethToIvarMapTy; + typedef llvm::DenseMap<const ObjCPropertyDecl*, + const ObjCIvarDecl*> PropToIvarMapTy; + typedef llvm::DenseMap<const ObjCIvarDecl*, + const ObjCPropertyDecl*> IvarToPropMapTy; + + + struct IvarInfo { + /// Has the ivar been invalidated? + bool IsInvalidated; + + /// The methods which can be used to invalidate the ivar. + MethodSet InvalidationMethods; + + IvarInfo() : IsInvalidated(false) {} + void addInvalidationMethod(const ObjCMethodDecl *MD) { + InvalidationMethods.insert(MD); + } + + bool needsInvalidation() const { + return !InvalidationMethods.empty(); + } + + void markInvalidated() { + IsInvalidated = true; + } + + bool markInvalidated(const ObjCMethodDecl *MD) { + if (IsInvalidated) + return true; + for (MethodSet::iterator I = InvalidationMethods.begin(), + E = InvalidationMethods.end(); I != E; ++I) { + if (*I == MD) { + IsInvalidated = true; + return true; + } + } + return false; + } + + bool isInvalidated() const { + return IsInvalidated; + } + }; + + typedef llvm::DenseMap<const ObjCIvarDecl*, IvarInfo> IvarSet; + + /// Statement visitor, which walks the method body and flags the ivars + /// referenced in it (either directly or via property). + class MethodCrawler : public ConstStmtVisitor<MethodCrawler> { + /// The set of Ivars which need to be invalidated. + IvarSet &IVars; + + /// Flag is set as the result of a message send to another + /// invalidation method. + bool &CalledAnotherInvalidationMethod; + + /// Property setter to ivar mapping. + const MethToIvarMapTy &PropertySetterToIvarMap; + + /// Property getter to ivar mapping. + const MethToIvarMapTy &PropertyGetterToIvarMap; + + /// Property to ivar mapping. + const PropToIvarMapTy &PropertyToIvarMap; + + /// The invalidation method being currently processed. + const ObjCMethodDecl *InvalidationMethod; + + ASTContext &Ctx; + + /// Peel off parens, casts, OpaqueValueExpr, and PseudoObjectExpr. + const Expr *peel(const Expr *E) const; + + /// Does this expression represent zero: '0'? + bool isZero(const Expr *E) const; + + /// Mark the given ivar as invalidated. + void markInvalidated(const ObjCIvarDecl *Iv); + + /// Checks if IvarRef refers to the tracked IVar, if yes, marks it as + /// invalidated. + void checkObjCIvarRefExpr(const ObjCIvarRefExpr *IvarRef); + + /// Checks if ObjCPropertyRefExpr refers to the tracked IVar, if yes, marks + /// it as invalidated. + void checkObjCPropertyRefExpr(const ObjCPropertyRefExpr *PA); + + /// Checks if ObjCMessageExpr refers to (is a getter for) the tracked IVar, + /// if yes, marks it as invalidated. + void checkObjCMessageExpr(const ObjCMessageExpr *ME); + + /// Checks if the Expr refers to an ivar, if yes, marks it as invalidated. + void check(const Expr *E); + + public: + MethodCrawler(IvarSet &InIVars, + bool &InCalledAnotherInvalidationMethod, + const MethToIvarMapTy &InPropertySetterToIvarMap, + const MethToIvarMapTy &InPropertyGetterToIvarMap, + const PropToIvarMapTy &InPropertyToIvarMap, + ASTContext &InCtx) + : IVars(InIVars), + CalledAnotherInvalidationMethod(InCalledAnotherInvalidationMethod), + PropertySetterToIvarMap(InPropertySetterToIvarMap), + PropertyGetterToIvarMap(InPropertyGetterToIvarMap), + PropertyToIvarMap(InPropertyToIvarMap), + InvalidationMethod(0), + Ctx(InCtx) {} + + void VisitStmt(const Stmt *S) { VisitChildren(S); } + + void VisitBinaryOperator(const BinaryOperator *BO); + + void VisitObjCMessageExpr(const ObjCMessageExpr *ME); + + void VisitChildren(const Stmt *S) { + for (Stmt::const_child_range I = S->children(); I; ++I) { + if (*I) + this->Visit(*I); + if (CalledAnotherInvalidationMethod) + return; + } + } + }; + + /// Check if the any of the methods inside the interface are annotated with + /// the invalidation annotation, update the IvarInfo accordingly. + static void containsInvalidationMethod(const ObjCContainerDecl *D, + IvarInfo &Out); + + /// Check if ivar should be tracked and add to TrackedIvars if positive. + /// Returns true if ivar should be tracked. + static bool trackIvar(const ObjCIvarDecl *Iv, IvarSet &TrackedIvars); + + /// Given the property declaration, and the list of tracked ivars, finds + /// the ivar backing the property when possible. Returns '0' when no such + /// ivar could be found. + static const ObjCIvarDecl *findPropertyBackingIvar( + const ObjCPropertyDecl *Prop, + const ObjCInterfaceDecl *InterfaceD, + IvarSet &TrackedIvars); + +public: + void checkASTDecl(const ObjCMethodDecl *D, AnalysisManager& Mgr, + BugReporter &BR) const; + + // TODO: We are currently ignoring the ivars coming from class extensions. +}; + +static bool isInvalidationMethod(const ObjCMethodDecl *M) { + for (specific_attr_iterator<AnnotateAttr> + AI = M->specific_attr_begin<AnnotateAttr>(), + AE = M->specific_attr_end<AnnotateAttr>(); AI != AE; ++AI) { + const AnnotateAttr *Ann = *AI; + if (Ann->getAnnotation() == "objc_instance_variable_invalidator") + return true; + } + return false; +} + +void IvarInvalidationChecker::containsInvalidationMethod( + const ObjCContainerDecl *D, IvarInfo &OutInfo) { + + // TODO: Cache the results. + + if (!D) + return; + + // Check all methods. + for (ObjCContainerDecl::method_iterator + I = D->meth_begin(), + E = D->meth_end(); I != E; ++I) { + const ObjCMethodDecl *MDI = *I; + if (isInvalidationMethod(MDI)) + OutInfo.addInvalidationMethod( + cast<ObjCMethodDecl>(MDI->getCanonicalDecl())); + } + + // If interface, check all parent protocols and super. + // TODO: Visit all categories in case the invalidation method is declared in + // a category. + if (const ObjCInterfaceDecl *InterfaceD = dyn_cast<ObjCInterfaceDecl>(D)) { + for (ObjCInterfaceDecl::protocol_iterator + I = InterfaceD->protocol_begin(), + E = InterfaceD->protocol_end(); I != E; ++I) { + containsInvalidationMethod(*I, OutInfo); + } + containsInvalidationMethod(InterfaceD->getSuperClass(), OutInfo); + return; + } + + // If protocol, check all parent protocols. + if (const ObjCProtocolDecl *ProtD = dyn_cast<ObjCProtocolDecl>(D)) { + for (ObjCInterfaceDecl::protocol_iterator + I = ProtD->protocol_begin(), + E = ProtD->protocol_end(); I != E; ++I) { + containsInvalidationMethod(*I, OutInfo); + } + return; + } + + llvm_unreachable("One of the casts above should have succeeded."); +} + +bool IvarInvalidationChecker::trackIvar(const ObjCIvarDecl *Iv, + IvarSet &TrackedIvars) { + QualType IvQTy = Iv->getType(); + const ObjCObjectPointerType *IvTy = IvQTy->getAs<ObjCObjectPointerType>(); + if (!IvTy) + return false; + const ObjCInterfaceDecl *IvInterf = IvTy->getInterfaceDecl(); + + IvarInfo Info; + containsInvalidationMethod(IvInterf, Info); + if (Info.needsInvalidation()) { + TrackedIvars[cast<ObjCIvarDecl>(Iv->getCanonicalDecl())] = Info; + return true; + } + return false; +} + +const ObjCIvarDecl *IvarInvalidationChecker::findPropertyBackingIvar( + const ObjCPropertyDecl *Prop, + const ObjCInterfaceDecl *InterfaceD, + IvarSet &TrackedIvars) { + const ObjCIvarDecl *IvarD = 0; + + // Lookup for the synthesized case. + IvarD = Prop->getPropertyIvarDecl(); + if (IvarD) { + if (TrackedIvars.count(IvarD)) { + return IvarD; + } + // If the ivar is synthesized we still want to track it. + if (trackIvar(IvarD, TrackedIvars)) + return IvarD; + } + + // Lookup IVars named "_PropName"or "PropName" among the tracked Ivars. + StringRef PropName = Prop->getIdentifier()->getName(); + for (IvarSet::const_iterator I = TrackedIvars.begin(), + E = TrackedIvars.end(); I != E; ++I) { + const ObjCIvarDecl *Iv = I->first; + StringRef IvarName = Iv->getName(); + + if (IvarName == PropName) + return Iv; + + SmallString<128> PropNameWithUnderscore; + { + llvm::raw_svector_ostream os(PropNameWithUnderscore); + os << '_' << PropName; + } + if (IvarName == PropNameWithUnderscore.str()) + return Iv; + } + + // Note, this is a possible source of false positives. We could look at the + // getter implementation to find the ivar when its name is not derived from + // the property name. + return 0; +} + +void IvarInvalidationChecker::checkASTDecl(const ObjCMethodDecl *D, + AnalysisManager& Mgr, + BugReporter &BR) const { + // We are only interested in checking the cleanup methods. + if (!D->hasBody() || !isInvalidationMethod(D)) + return; + + // Collect all ivars that need cleanup. + IvarSet Ivars; + const ObjCInterfaceDecl *InterfaceD = D->getClassInterface(); + + // Collect ivars declared in this class, its extensions and its implementation + ObjCInterfaceDecl *IDecl = const_cast<ObjCInterfaceDecl *>(InterfaceD); + for (const ObjCIvarDecl *Iv = IDecl->all_declared_ivar_begin(); Iv; + Iv= Iv->getNextIvar()) + trackIvar(Iv, Ivars); + + // Construct Property/Property Accessor to Ivar maps to assist checking if an + // ivar which is backing a property has been reset. + MethToIvarMapTy PropSetterToIvarMap; + MethToIvarMapTy PropGetterToIvarMap; + PropToIvarMapTy PropertyToIvarMap; + IvarToPropMapTy IvarToPopertyMap; + + ObjCInterfaceDecl::PropertyMap PropMap; + InterfaceD->collectPropertiesToImplement(PropMap); + + for (ObjCInterfaceDecl::PropertyMap::iterator + I = PropMap.begin(), E = PropMap.end(); I != E; ++I) { + const ObjCPropertyDecl *PD = I->second; + + const ObjCIvarDecl *ID = findPropertyBackingIvar(PD, InterfaceD, Ivars); + if (!ID) { + continue; + } + + // Store the mappings. + PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl()); + PropertyToIvarMap[PD] = ID; + IvarToPopertyMap[ID] = PD; + + // Find the setter and the getter. + const ObjCMethodDecl *SetterD = PD->getSetterMethodDecl(); + if (SetterD) { + SetterD = cast<ObjCMethodDecl>(SetterD->getCanonicalDecl()); + PropSetterToIvarMap[SetterD] = ID; + } + + const ObjCMethodDecl *GetterD = PD->getGetterMethodDecl(); + if (GetterD) { + GetterD = cast<ObjCMethodDecl>(GetterD->getCanonicalDecl()); + PropGetterToIvarMap[GetterD] = ID; + } + } + + + // Check which ivars have been invalidated in the method body. + bool CalledAnotherInvalidationMethod = false; + MethodCrawler(Ivars, + CalledAnotherInvalidationMethod, + PropSetterToIvarMap, + PropGetterToIvarMap, + PropertyToIvarMap, + BR.getContext()).VisitStmt(D->getBody()); + + if (CalledAnotherInvalidationMethod) + return; + + // Warn on the ivars that were not accessed by the method. + for (IvarSet::const_iterator I = Ivars.begin(), E = Ivars.end(); I != E; ++I){ + if (!I->second.isInvalidated()) { + const ObjCIvarDecl *IvarDecl = I->first; + + PathDiagnosticLocation IvarDecLocation = + PathDiagnosticLocation::createEnd(D->getBody(), BR.getSourceManager(), + Mgr.getAnalysisDeclContext(D)); + + SmallString<128> sbuf; + llvm::raw_svector_ostream os(sbuf); + + // Construct the warning message. + if (IvarDecl->getSynthesize()) { + const ObjCPropertyDecl *PD = IvarToPopertyMap[IvarDecl]; + assert(PD && + "Do we synthesize ivars for something other than properties?"); + os << "Property "<< PD->getName() << + " needs to be invalidated or set to nil"; + } else { + os << "Instance variable "<< IvarDecl->getName() + << " needs to be invalidated or set to nil"; + } + + BR.EmitBasicReport(D, + "Incomplete invalidation", + categories::CoreFoundationObjectiveC, os.str(), + IvarDecLocation); + } + } +} + +void IvarInvalidationChecker::MethodCrawler::markInvalidated( + const ObjCIvarDecl *Iv) { + IvarSet::iterator I = IVars.find(Iv); + if (I != IVars.end()) { + // If InvalidationMethod is present, we are processing the message send and + // should ensure we are invalidating with the appropriate method, + // otherwise, we are processing setting to 'nil'. + if (InvalidationMethod) + I->second.markInvalidated(InvalidationMethod); + else + I->second.markInvalidated(); + } +} + +const Expr *IvarInvalidationChecker::MethodCrawler::peel(const Expr *E) const { + E = E->IgnoreParenCasts(); + if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) + E = POE->getSyntacticForm()->IgnoreParenCasts(); + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) + E = OVE->getSourceExpr()->IgnoreParenCasts(); + return E; +} + +void IvarInvalidationChecker::MethodCrawler::checkObjCIvarRefExpr( + const ObjCIvarRefExpr *IvarRef) { + if (const Decl *D = IvarRef->getDecl()) + markInvalidated(cast<ObjCIvarDecl>(D->getCanonicalDecl())); +} + +void IvarInvalidationChecker::MethodCrawler::checkObjCMessageExpr( + const ObjCMessageExpr *ME) { + const ObjCMethodDecl *MD = ME->getMethodDecl(); + if (MD) { + MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); + MethToIvarMapTy::const_iterator IvI = PropertyGetterToIvarMap.find(MD); + if (IvI != PropertyGetterToIvarMap.end()) + markInvalidated(IvI->second); + } +} + +void IvarInvalidationChecker::MethodCrawler::checkObjCPropertyRefExpr( + const ObjCPropertyRefExpr *PA) { + + if (PA->isExplicitProperty()) { + const ObjCPropertyDecl *PD = PA->getExplicitProperty(); + if (PD) { + PD = cast<ObjCPropertyDecl>(PD->getCanonicalDecl()); + PropToIvarMapTy::const_iterator IvI = PropertyToIvarMap.find(PD); + if (IvI != PropertyToIvarMap.end()) + markInvalidated(IvI->second); + return; + } + } + + if (PA->isImplicitProperty()) { + const ObjCMethodDecl *MD = PA->getImplicitPropertySetter(); + if (MD) { + MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); + MethToIvarMapTy::const_iterator IvI =PropertyGetterToIvarMap.find(MD); + if (IvI != PropertyGetterToIvarMap.end()) + markInvalidated(IvI->second); + return; + } + } +} + +bool IvarInvalidationChecker::MethodCrawler::isZero(const Expr *E) const { + E = peel(E); + + return (E->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNotNull) + != Expr::NPCK_NotNull); +} + +void IvarInvalidationChecker::MethodCrawler::check(const Expr *E) { + E = peel(E); + + if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(E)) { + checkObjCIvarRefExpr(IvarRef); + return; + } + + if (const ObjCPropertyRefExpr *PropRef = dyn_cast<ObjCPropertyRefExpr>(E)) { + checkObjCPropertyRefExpr(PropRef); + return; + } + + if (const ObjCMessageExpr *MsgExpr = dyn_cast<ObjCMessageExpr>(E)) { + checkObjCMessageExpr(MsgExpr); + return; + } +} + +void IvarInvalidationChecker::MethodCrawler::VisitBinaryOperator( + const BinaryOperator *BO) { + VisitStmt(BO); + + if (BO->getOpcode() != BO_Assign) + return; + + // Do we assign zero? + if (!isZero(BO->getRHS())) + return; + + // Check the variable we are assigning to. + check(BO->getLHS()); +} + +void IvarInvalidationChecker::MethodCrawler::VisitObjCMessageExpr( + const ObjCMessageExpr *ME) { + const ObjCMethodDecl *MD = ME->getMethodDecl(); + const Expr *Receiver = ME->getInstanceReceiver(); + + // Stop if we are calling '[self invalidate]'. + if (Receiver && isInvalidationMethod(MD)) + if (Receiver->isObjCSelfExpr()) { + CalledAnotherInvalidationMethod = true; + return; + } + + // Check if we call a setter and set the property to 'nil'. + if (MD && (ME->getNumArgs() == 1) && isZero(ME->getArg(0))) { + MD = cast<ObjCMethodDecl>(MD->getCanonicalDecl()); + MethToIvarMapTy::const_iterator IvI = PropertySetterToIvarMap.find(MD); + if (IvI != PropertySetterToIvarMap.end()) { + markInvalidated(IvI->second); + return; + } + } + + // Check if we call the 'invalidation' routine on the ivar. + if (Receiver) { + InvalidationMethod = MD; + check(Receiver->IgnoreParenCasts()); + InvalidationMethod = 0; + } + + VisitStmt(ME); +} +} + +// Register the checker. +void ento::registerIvarInvalidationChecker(CheckerManager &mgr) { + mgr.registerChecker<IvarInvalidationChecker>(); +} diff --git a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp index 969f2ddeb4ca..76f20b6e2e51 100644 --- a/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MacOSKeychainAPIChecker.cpp @@ -158,16 +158,9 @@ private: /// ProgramState traits to store the currently allocated (and not yet freed) /// symbols. This is a map from the allocated content symbol to the /// corresponding AllocationState. -typedef llvm::ImmutableMap<SymbolRef, - MacOSKeychainAPIChecker::AllocationState> AllocatedSetTy; - -namespace { struct AllocatedData {}; } -namespace clang { namespace ento { -template<> struct ProgramStateTrait<AllocatedData> - : public ProgramStatePartialTrait<AllocatedSetTy > { - static void *GDMIndex() { static int index = 0; return &index; } -}; -}} +REGISTER_MAP_WITH_PROGRAMSTATE(AllocatedData, + SymbolRef, + MacOSKeychainAPIChecker::AllocationState) static bool isEnclosingFunctionParam(const Expr *E) { E = E->IgnoreParenCasts(); @@ -282,7 +275,7 @@ void MacOSKeychainAPIChecker:: Report->addVisitor(new SecKeychainBugVisitor(AP.first)); Report->addRange(ArgExpr->getSourceRange()); markInteresting(Report, AP); - C.EmitReport(Report); + C.emitReport(Report); } void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, @@ -323,7 +316,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, Report->addVisitor(new SecKeychainBugVisitor(V)); Report->addRange(ArgExpr->getSourceRange()); Report->markInteresting(AS->Region); - C.EmitReport(Report); + C.emitReport(Report); } } return; @@ -376,7 +369,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, Report->addRange(ArgExpr->getSourceRange()); if (AS) Report->markInteresting(AS->Region); - C.EmitReport(Report); + C.emitReport(Report); return; } @@ -440,7 +433,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE, Report->addVisitor(new SecKeychainBugVisitor(ArgSM)); Report->addRange(ArgExpr->getSourceRange()); Report->markInteresting(AS->Region); - C.EmitReport(Report); + C.emitReport(Report); return; } @@ -571,13 +564,13 @@ BugReport *MacOSKeychainAPIChecker:: void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const { ProgramStateRef State = C.getState(); - AllocatedSetTy ASet = State->get<AllocatedData>(); + AllocatedDataTy ASet = State->get<AllocatedData>(); if (ASet.isEmpty()) return; bool Changed = false; AllocationPairVec Errors; - for (AllocatedSetTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) { + for (AllocatedDataTy::iterator I = ASet.begin(), E = ASet.end(); I != E; ++I) { if (SR.isLive(I->first)) continue; @@ -585,7 +578,9 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, State = State->remove<AllocatedData>(I->first); // If the allocated symbol is null or if the allocation call might have // returned an error, do not report. - if (State->getSymVal(I->first) || + ConstraintManager &CMgr = State->getConstraintManager(); + ConditionTruthVal AllocFailed = CMgr.isNull(State, I.getKey()); + if (AllocFailed.isConstrainedTrue() || definitelyReturnedError(I->second.Region, State, C.getSValBuilder())) continue; Errors.push_back(std::make_pair(I->first, &I->second)); @@ -602,7 +597,7 @@ void MacOSKeychainAPIChecker::checkDeadSymbols(SymbolReaper &SR, // Generate the error reports. for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end(); I != E; ++I) { - C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N, C)); + C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C)); } // Generate the new, cleaned up state. @@ -617,7 +612,7 @@ void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const { if (C.getLocationContext()->getParent() != 0) return; - AllocatedSetTy AS = state->get<AllocatedData>(); + AllocatedDataTy AS = state->get<AllocatedData>(); if (AS.isEmpty()) return; @@ -625,12 +620,14 @@ void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const { // found here, so report it. bool Changed = false; AllocationPairVec Errors; - for (AllocatedSetTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) { + for (AllocatedDataTy::iterator I = AS.begin(), E = AS.end(); I != E; ++I ) { Changed = true; state = state->remove<AllocatedData>(I->first); // If the allocated symbol is null or if error code was returned at // allocation, do not report. - if (state->getSymVal(I.getKey()) || + ConstraintManager &CMgr = state->getConstraintManager(); + ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey()); + if (AllocFailed.isConstrainedTrue() || definitelyReturnedError(I->second.Region, state, C.getSValBuilder())) { continue; @@ -650,7 +647,7 @@ void MacOSKeychainAPIChecker::checkEndPath(CheckerContext &C) const { // Generate the error reports. for (AllocationPairVec::iterator I = Errors.begin(), E = Errors.end(); I != E; ++I) { - C.EmitReport(generateAllocatedDataNotReleasedReport(*I, N, C)); + C.emitReport(generateAllocatedDataNotReleasedReport(*I, N, C)); } C.addTransition(state, N); diff --git a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp index cfdb55df730d..467b8b1d815c 100644 --- a/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp @@ -70,6 +70,16 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, BT_dispatchOnce.reset(new BugType("Improper use of 'dispatch_once'", "Mac OS X API")); + // Handle _dispatch_once. In some versions of the OS X SDK we have the case + // that dispatch_once is a macro that wraps a call to _dispatch_once. + // _dispatch_once is then a function which then calls the real dispatch_once. + // Users do not care; they just want the warning at the top-level call. + if (CE->getLocStart().isMacroID()) { + StringRef TrimmedFName = FName.ltrim("_"); + if (TrimmedFName != FName) + FName = TrimmedFName; + } + SmallString<256> S; llvm::raw_svector_ostream os(S); os << "Call to '" << FName << "' uses"; @@ -84,7 +94,7 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE, BugReport *report = new BugReport(*BT_dispatchOnce, os.str(), N); report->addRange(CE->getArg(0)->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); } //===----------------------------------------------------------------------===// @@ -99,7 +109,9 @@ void MacOSXAPIChecker::checkPreStmt(const CallExpr *CE, SubChecker SC = llvm::StringSwitch<SubChecker>(Name) - .Cases("dispatch_once", "dispatch_once_f", + .Cases("dispatch_once", + "_dispatch_once", + "dispatch_once_f", &MacOSXAPIChecker::CheckDispatchOnce) .Default(NULL); diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index dfcedf640821..caf70ca3706f 100644 --- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" #include <climits> using namespace clang; @@ -70,17 +71,31 @@ public: } }; +enum ReallocPairKind { + RPToBeFreedAfterFailure, + // The symbol has been freed when reallocation failed. + RPIsFreeOnFailure, + // The symbol does not need to be freed after reallocation fails. + RPDoNotTrackAfterFailure +}; + +/// \class ReallocPair +/// \brief Stores information about the symbol being reallocated by a call to +/// 'realloc' to allow modeling failed reallocation later in the path. struct ReallocPair { + // \brief The symbol which realloc reallocated. SymbolRef ReallocatedSym; - bool IsFreeOnFailure; - ReallocPair(SymbolRef S, bool F) : ReallocatedSym(S), IsFreeOnFailure(F) {} + ReallocPairKind Kind; + + ReallocPair(SymbolRef S, ReallocPairKind K) : + ReallocatedSym(S), Kind(K) {} void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddInteger(IsFreeOnFailure); + ID.AddInteger(Kind); ID.AddPointer(ReallocatedSym); } bool operator==(const ReallocPair &X) const { return ReallocatedSym == X.ReallocatedSym && - IsFreeOnFailure == X.IsFreeOnFailure; + Kind == X.Kind; } }; @@ -92,7 +107,7 @@ class MallocChecker : public Checker<check::DeadSymbols, check::PreStmt<CallExpr>, check::PostStmt<CallExpr>, check::PostStmt<BlockExpr>, - check::PreObjCMessage, + check::PostObjCMessage, check::Location, check::Bind, eval::Assume, @@ -120,7 +135,7 @@ public: void checkPreStmt(const CallExpr *S, CheckerContext &C) const; void checkPostStmt(const CallExpr *CE, CheckerContext &C) const; - void checkPreObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const; + void checkPostObjCMessage(const ObjCMethodCall &Call, CheckerContext &C) const; void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; void checkEndPath(CheckerContext &C) const; @@ -177,11 +192,15 @@ private: const OwnershipAttr* Att) const; ProgramStateRef FreeMemAux(CheckerContext &C, const CallExpr *CE, ProgramStateRef state, unsigned Num, - bool Hold) const; + bool Hold, + bool &ReleasedAllocated, + bool ReturnsNullOnFailure = false) const; ProgramStateRef FreeMemAux(CheckerContext &C, const Expr *Arg, const Expr *ParentExpr, - ProgramStateRef state, - bool Hold) const; + ProgramStateRef State, + bool Hold, + bool &ReleasedAllocated, + bool ReturnsNullOnFailure = false) const; ProgramStateRef ReallocMem(CheckerContext &C, const CallExpr *CE, bool FreesMemOnFailure) const; @@ -301,13 +320,14 @@ private: : StackHintGeneratorForSymbol(S, M) {} virtual std::string getMessageForArg(const Expr *ArgE, unsigned ArgIndex) { + // Printed parameters start at 1, not 0. + ++ArgIndex; + SmallString<200> buf; llvm::raw_svector_ostream os(buf); - os << "Reallocation of "; - // Printed parameters start at 1, not 0. - printOrdinal(++ArgIndex, os); - os << " parameter failed"; + os << "Reallocation of " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) + << " parameter failed"; return os.str(); } @@ -320,25 +340,12 @@ private: }; } // end anonymous namespace -typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy; -typedef llvm::ImmutableMap<SymbolRef, ReallocPair > ReallocMap; -class RegionState {}; -class ReallocPairs {}; -namespace clang { -namespace ento { - template <> - struct ProgramStateTrait<RegionState> - : public ProgramStatePartialTrait<RegionStateTy> { - static void *GDMIndex() { static int x; return &x; } - }; +REGISTER_MAP_WITH_PROGRAMSTATE(RegionState, SymbolRef, RefState) +REGISTER_MAP_WITH_PROGRAMSTATE(ReallocPairs, SymbolRef, ReallocPair) - template <> - struct ProgramStateTrait<ReallocPairs> - : public ProgramStatePartialTrait<ReallocMap> { - static void *GDMIndex() { static int x; return &x; } - }; -} -} +// A map from the freed symbol to the symbol representing the return value of +// the free function. +REGISTER_MAP_WITH_PROGRAMSTATE(FreeReturnValue, SymbolRef, SymbolRef) namespace { class StopTrackingCallback : public SymbolVisitor { @@ -426,11 +433,15 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const } void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { + if (C.wasInlined) + return; + const FunctionDecl *FD = C.getCalleeDecl(CE); if (!FD) return; ProgramStateRef State = C.getState(); + bool ReleasedAllocatedMemory = false; if (FD->getKind() == Decl::Function) { initIdentifierInfo(C.getASTContext()); @@ -447,7 +458,7 @@ void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { } else if (FunI == II_calloc) { State = CallocMem(C, CE); } else if (FunI == II_free) { - State = FreeMemAux(C, CE, State, 0, false); + State = FreeMemAux(C, CE, State, 0, false, ReleasedAllocatedMemory); } else if (FunI == II_strdup) { State = MallocUpdateRefState(C, CE, State); } else if (FunI == II_strndup) { @@ -487,21 +498,26 @@ static bool isFreeWhenDoneSetToZero(const ObjCMethodCall &Call) { return false; } -void MallocChecker::checkPreObjCMessage(const ObjCMethodCall &Call, - CheckerContext &C) const { +void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call, + CheckerContext &C) const { // If the first selector is dataWithBytesNoCopy, assume that the memory will // be released with 'free' by the new object. // Ex: [NSData dataWithBytesNoCopy:bytes length:10]; // Unless 'freeWhenDone' param set to 0. // TODO: Check that the memory was allocated with malloc. + bool ReleasedAllocatedMemory = false; Selector S = Call.getSelector(); if ((S.getNameForSlot(0) == "dataWithBytesNoCopy" || S.getNameForSlot(0) == "initWithBytesNoCopy" || S.getNameForSlot(0) == "initWithCharactersNoCopy") && !isFreeWhenDoneSetToZero(Call)){ unsigned int argIdx = 0; - C.addTransition(FreeMemAux(C, Call.getArgExpr(argIdx), - Call.getOriginExpr(), C.getState(), true)); + ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(argIdx), + Call.getOriginExpr(), C.getState(), true, + ReleasedAllocatedMemory, + /* RetNullOnFailure*/ true); + + C.addTransition(State); } } @@ -526,7 +542,7 @@ ProgramStateRef MallocChecker::MallocMemAux(CheckerContext &C, // Bind the return value to the symbolic value from the heap region. // TODO: We could rewrite post visit to eval call; 'malloc' does not have // side effects other than what we model here. - unsigned Count = C.getCurrentBlockCount(); + unsigned Count = C.blockCount(); SValBuilder &svalBuilder = C.getSValBuilder(); const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); DefinedSVal RetVal = @@ -584,11 +600,13 @@ ProgramStateRef MallocChecker::FreeMemAttr(CheckerContext &C, return 0; ProgramStateRef State = C.getState(); + bool ReleasedAllocated = false; for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end(); I != E; ++I) { ProgramStateRef StateI = FreeMemAux(C, CE, State, *I, - Att->getOwnKind() == OwnershipAttr::Holds); + Att->getOwnKind() == OwnershipAttr::Holds, + ReleasedAllocated); if (StateI) State = StateI; } @@ -599,20 +617,40 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE, ProgramStateRef state, unsigned Num, - bool Hold) const { + bool Hold, + bool &ReleasedAllocated, + bool ReturnsNullOnFailure) const { if (CE->getNumArgs() < (Num + 1)) return 0; - return FreeMemAux(C, CE->getArg(Num), CE, state, Hold); + return FreeMemAux(C, CE->getArg(Num), CE, state, Hold, + ReleasedAllocated, ReturnsNullOnFailure); +} + +/// Checks if the previous call to free on the given symbol failed - if free +/// failed, returns true. Also, returns the corresponding return value symbol. +bool didPreviousFreeFail(ProgramStateRef State, + SymbolRef Sym, SymbolRef &RetStatusSymbol) { + const SymbolRef *Ret = State->get<FreeReturnValue>(Sym); + if (Ret) { + assert(*Ret && "We should not store the null return symbol"); + ConstraintManager &CMgr = State->getConstraintManager(); + ConditionTruthVal FreeFailed = CMgr.isNull(State, *Ret); + RetStatusSymbol = *Ret; + return FreeFailed.isConstrainedTrue(); + } + return false; } ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, const Expr *ArgExpr, const Expr *ParentExpr, - ProgramStateRef state, - bool Hold) const { + ProgramStateRef State, + bool Hold, + bool &ReleasedAllocated, + bool ReturnsNullOnFailure) const { - SVal ArgVal = state->getSVal(ArgExpr, C.getLocationContext()); + SVal ArgVal = State->getSVal(ArgExpr, C.getLocationContext()); if (!isa<DefinedOrUnknownSVal>(ArgVal)) return 0; DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(ArgVal); @@ -623,7 +661,7 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, // The explicit NULL case, no operation is performed. ProgramStateRef notNullState, nullState; - llvm::tie(notNullState, nullState) = state->assume(location); + llvm::tie(notNullState, nullState) = State->assume(location); if (nullState && !notNullState) return 0; @@ -672,10 +710,14 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, return 0; SymbolRef Sym = SR->getSymbol(); - const RefState *RS = state->get<RegionState>(Sym); + const RefState *RS = State->get<RegionState>(Sym); + SymbolRef PreviousRetStatusSymbol = 0; // Check double free. - if (RS && (RS->isReleased() || RS->isRelinquished())) { + if (RS && + (RS->isReleased() || RS->isRelinquished()) && + !didPreviousFreeFail(State, Sym, PreviousRetStatusSymbol)) { + if (ExplodedNode *N = C.generateSink()) { if (!BT_DoubleFree) BT_DoubleFree.reset( @@ -685,16 +727,34 @@ ProgramStateRef MallocChecker::FreeMemAux(CheckerContext &C, "Attempt to free non-owned memory"), N); R->addRange(ArgExpr->getSourceRange()); R->markInteresting(Sym); + if (PreviousRetStatusSymbol) + R->markInteresting(PreviousRetStatusSymbol); R->addVisitor(new MallocBugVisitor(Sym)); - C.EmitReport(R); + C.emitReport(R); } return 0; } + ReleasedAllocated = (RS != 0); + + // Clean out the info on previous call to free return info. + State = State->remove<FreeReturnValue>(Sym); + + // Keep track of the return value. If it is NULL, we will know that free + // failed. + if (ReturnsNullOnFailure) { + SVal RetVal = C.getSVal(ParentExpr); + SymbolRef RetStatusSymbol = RetVal.getAsSymbol(); + if (RetStatusSymbol) { + C.getSymbolManager().addSymbolDependency(Sym, RetStatusSymbol); + State = State->set<FreeReturnValue>(Sym, RetStatusSymbol); + } + } + // Normal free. if (Hold) - return state->set<RegionState>(Sym, RefState::getRelinquished(ParentExpr)); - return state->set<RegionState>(Sym, RefState::getReleased(ParentExpr)); + return State->set<RegionState>(Sym, RefState::getRelinquished(ParentExpr)); + return State->set<RegionState>(Sym, RefState::getReleased(ParentExpr)); } bool MallocChecker::SummarizeValue(raw_ostream &os, SVal V) { @@ -714,7 +774,7 @@ bool MallocChecker::SummarizeRegion(raw_ostream &os, const MemRegion *MR) { switch (MR->getKind()) { case MemRegion::FunctionTextRegionKind: { - const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl(); + const NamedDecl *FD = cast<FunctionTextRegion>(MR)->getDecl(); if (FD) os << "the address of the function '" << *FD << '\''; else @@ -819,7 +879,7 @@ void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal, BugReport *R = new BugReport(*BT_BadFree, os.str(), N); R->markInteresting(MR); R->addRange(range); - C.EmitReport(R); + C.emitReport(R); } } @@ -886,9 +946,12 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, if (!FromPtr || !ToPtr) return 0; + bool ReleasedAllocated = false; + // If the size is 0, free the memory. if (SizeIsZero) - if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero,0,false)){ + if (ProgramStateRef stateFree = FreeMemAux(C, CE, StateSizeIsZero, 0, + false, ReleasedAllocated)){ // The semantics of the return value are: // If size was equal to 0, either NULL or a pointer suitable to be passed // to free() is returned. We just free the input pointer and do not add @@ -897,14 +960,25 @@ ProgramStateRef MallocChecker::ReallocMem(CheckerContext &C, } // Default behavior. - if (ProgramStateRef stateFree = FreeMemAux(C, CE, state, 0, false)) { - // FIXME: We should copy the content of the original buffer. + if (ProgramStateRef stateFree = + FreeMemAux(C, CE, state, 0, false, ReleasedAllocated)) { + ProgramStateRef stateRealloc = MallocMemAux(C, CE, CE->getArg(1), UnknownVal(), stateFree); if (!stateRealloc) return 0; + + ReallocPairKind Kind = RPToBeFreedAfterFailure; + if (FreesOnFail) + Kind = RPIsFreeOnFailure; + else if (!ReleasedAllocated) + Kind = RPDoNotTrackAfterFailure; + + // Record the info about the reallocated symbol so that we could properly + // process failed reallocation. stateRealloc = stateRealloc->set<ReallocPairs>(ToPtr, - ReallocPair(FromPtr, FreesOnFail)); + ReallocPair(FromPtr, Kind)); + // The reallocated symbol should stay alive for as long as the new symbol. C.getSymbolManager().addSymbolDependency(ToPtr, FromPtr); return stateRealloc; } @@ -1004,7 +1078,7 @@ void MallocChecker::reportLeak(SymbolRef Sym, ExplodedNode *N, BugReport *R = new BugReport(*BT_Leak, os.str(), N, LocUsedForUniqueing); R->markInteresting(Sym); R->addVisitor(new MallocBugVisitor(Sym, true)); - C.EmitReport(R); + C.emitReport(R); } void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, @@ -1017,14 +1091,11 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, RegionStateTy RS = state->get<RegionState>(); RegionStateTy::Factory &F = state->get_context<RegionState>(); - bool generateReport = false; llvm::SmallVector<SymbolRef, 2> Errors; for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { if (SymReaper.isDead(I->first)) { - if (I->second.isAllocated()) { - generateReport = true; + if (I->second.isAllocated()) Errors.push_back(I->first); - } // Remove the dead symbol from the map. RS = F.remove(RS, I->first); @@ -1032,24 +1103,34 @@ void MallocChecker::checkDeadSymbols(SymbolReaper &SymReaper, } // Cleanup the Realloc Pairs Map. - ReallocMap RP = state->get<ReallocPairs>(); - for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) { + ReallocPairsTy RP = state->get<ReallocPairs>(); + for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) { if (SymReaper.isDead(I->first) || SymReaper.isDead(I->second.ReallocatedSym)) { state = state->remove<ReallocPairs>(I->first); } } - // Generate leak node. - static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak"); - ExplodedNode *N = C.addTransition(C.getState(), C.getPredecessor(), &Tag); + // Cleanup the FreeReturnValue Map. + FreeReturnValueTy FR = state->get<FreeReturnValue>(); + for (FreeReturnValueTy::iterator I = FR.begin(), E = FR.end(); I != E; ++I) { + if (SymReaper.isDead(I->first) || + SymReaper.isDead(I->second)) { + state = state->remove<FreeReturnValue>(I->first); + } + } - if (generateReport) { + // Generate leak node. + ExplodedNode *N = C.getPredecessor(); + if (!Errors.empty()) { + static SimpleProgramPointTag Tag("MallocChecker : DeadSymbolsLeak"); + N = C.addTransition(C.getState(), C.getPredecessor(), &Tag); for (llvm::SmallVector<SymbolRef, 2>::iterator - I = Errors.begin(), E = Errors.end(); I != E; ++I) { + I = Errors.begin(), E = Errors.end(); I != E; ++I) { reportLeak(*I, N, C); } } + C.addTransition(state->set<RegionState>(RS), N); } @@ -1182,7 +1263,7 @@ bool MallocChecker::checkUseAfterFree(SymbolRef Sym, CheckerContext &C, R->addRange(S->getSourceRange()); R->markInteresting(Sym); R->addVisitor(new MallocBugVisitor(Sym)); - C.EmitReport(R); + C.emitReport(R); return true; } } @@ -1249,28 +1330,36 @@ ProgramStateRef MallocChecker::evalAssume(ProgramStateRef state, bool Assumption) const { RegionStateTy RS = state->get<RegionState>(); for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) { - // If the symbol is assumed to NULL or another constant, this will - // return an APSInt*. - if (state->getSymVal(I.getKey())) + // If the symbol is assumed to be NULL, remove it from consideration. + ConstraintManager &CMgr = state->getConstraintManager(); + ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey()); + if (AllocFailed.isConstrainedTrue()) state = state->remove<RegionState>(I.getKey()); } // Realloc returns 0 when reallocation fails, which means that we should // restore the state of the pointer being reallocated. - ReallocMap RP = state->get<ReallocPairs>(); - for (ReallocMap::iterator I = RP.begin(), E = RP.end(); I != E; ++I) { - // If the symbol is assumed to NULL or another constant, this will - // return an APSInt*. - if (state->getSymVal(I.getKey())) { - SymbolRef ReallocSym = I.getData().ReallocatedSym; - const RefState *RS = state->get<RegionState>(ReallocSym); - if (RS) { - if (RS->isReleased() && ! I.getData().IsFreeOnFailure) + ReallocPairsTy RP = state->get<ReallocPairs>(); + for (ReallocPairsTy::iterator I = RP.begin(), E = RP.end(); I != E; ++I) { + // If the symbol is assumed to be NULL, remove it from consideration. + ConstraintManager &CMgr = state->getConstraintManager(); + ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey()); + if (!AllocFailed.isConstrainedTrue()) + continue; + + SymbolRef ReallocSym = I.getData().ReallocatedSym; + if (const RefState *RS = state->get<RegionState>(ReallocSym)) { + if (RS->isReleased()) { + if (I.getData().Kind == RPToBeFreedAfterFailure) state = state->set<RegionState>(ReallocSym, - RefState::getAllocated(RS->getStmt())); + RefState::getAllocated(RS->getStmt())); + else if (I.getData().Kind == RPDoNotTrackAfterFailure) + state = state->remove<RegionState>(ReallocSym); + else + assert(I.getData().Kind == RPIsFreeOnFailure); } - state = state->remove<ReallocPairs>(I.getKey()); } + state = state->remove<ReallocPairs>(I.getKey()); } return state; @@ -1463,10 +1552,10 @@ MallocChecker::checkRegionChanges(ProgramStateRef State, static SymbolRef findFailedReallocSymbol(ProgramStateRef currState, ProgramStateRef prevState) { - ReallocMap currMap = currState->get<ReallocPairs>(); - ReallocMap prevMap = prevState->get<ReallocPairs>(); + ReallocPairsTy currMap = currState->get<ReallocPairs>(); + ReallocPairsTy prevMap = prevState->get<ReallocPairs>(); - for (ReallocMap::iterator I = prevMap.begin(), E = prevMap.end(); + for (ReallocPairsTy::iterator I = prevMap.begin(), E = prevMap.end(); I != E; ++I) { SymbolRef sym = I.getKey(); if (!currMap.lookup(sym)) diff --git a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp index 6292a4725128..fb40f222b846 100644 --- a/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/MallocSizeofChecker.cpp @@ -146,9 +146,9 @@ static bool typesCompatible(ASTContext &C, QualType A, QualType B) { if (const PointerType *ptrA = A->getAs<PointerType>()) if (const PointerType *ptrB = B->getAs<PointerType>()) { - A = ptrA->getPointeeType(); - B = ptrB->getPointeeType(); - continue; + A = ptrA->getPointeeType(); + B = ptrB->getPointeeType(); + continue; } break; @@ -157,6 +157,18 @@ static bool typesCompatible(ASTContext &C, QualType A, QualType B) { return false; } +static bool compatibleWithArrayType(ASTContext &C, QualType PT, QualType T) { + // Ex: 'int a[10][2]' is compatible with 'int', 'int[2]', 'int[10][2]'. + while (const ArrayType *AT = T->getAsArrayTypeUnsafe()) { + QualType ElemType = AT->getElementType(); + if (typesCompatible(C, PT, AT->getElementType())) + return true; + T = ElemType; + } + + return false; +} + class MallocSizeofChecker : public Checker<check::ASTCodeBody> { public: void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, @@ -184,38 +196,49 @@ public: continue; QualType SizeofType = SFinder.Sizeofs[0]->getTypeOfArgument(); - if (!typesCompatible(BR.getContext(), PointeeType, SizeofType)) { - const TypeSourceInfo *TSI = 0; - if (i->CastedExprParent.is<const VarDecl *>()) { - TSI = + + if (typesCompatible(BR.getContext(), PointeeType, SizeofType)) + continue; + + // If the argument to sizeof is an array, the result could be a + // pointer to any array element. + if (compatibleWithArrayType(BR.getContext(), PointeeType, SizeofType)) + continue; + + const TypeSourceInfo *TSI = 0; + if (i->CastedExprParent.is<const VarDecl *>()) { + TSI = i->CastedExprParent.get<const VarDecl *>()->getTypeSourceInfo(); - } else { - TSI = i->ExplicitCastType; - } - - SmallString<64> buf; - llvm::raw_svector_ostream OS(buf); - - OS << "Result of '" - << i->AllocCall->getDirectCallee()->getIdentifier()->getName() - << "' is converted to a pointer of type '" - << PointeeType.getAsString() << "', which is incompatible with " - << "sizeof operand type '" << SizeofType.getAsString() << "'"; - llvm::SmallVector<SourceRange, 4> Ranges; - Ranges.push_back(i->AllocCall->getCallee()->getSourceRange()); - Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange()); - if (TSI) - Ranges.push_back(TSI->getTypeLoc().getSourceRange()); - - PathDiagnosticLocation L = + } else { + TSI = i->ExplicitCastType; + } + + SmallString<64> buf; + llvm::raw_svector_ostream OS(buf); + + OS << "Result of "; + const FunctionDecl *Callee = i->AllocCall->getDirectCallee(); + if (Callee && Callee->getIdentifier()) + OS << '\'' << Callee->getIdentifier()->getName() << '\''; + else + OS << "call"; + OS << " is converted to a pointer of type '" + << PointeeType.getAsString() << "', which is incompatible with " + << "sizeof operand type '" << SizeofType.getAsString() << "'"; + llvm::SmallVector<SourceRange, 4> Ranges; + Ranges.push_back(i->AllocCall->getCallee()->getSourceRange()); + Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange()); + if (TSI) + Ranges.push_back(TSI->getTypeLoc().getSourceRange()); + + PathDiagnosticLocation L = PathDiagnosticLocation::createBegin(i->AllocCall->getCallee(), - BR.getSourceManager(), ADC); + BR.getSourceManager(), ADC); - BR.EmitBasicReport(D, "Allocator sizeof operand mismatch", - categories::UnixAPI, - OS.str(), - L, Ranges.data(), Ranges.size()); - } + BR.EmitBasicReport(D, "Allocator sizeof operand mismatch", + categories::UnixAPI, + OS.str(), + L, Ranges.data(), Ranges.size()); } } } diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp index aad3b0f5f277..3331bc8a9a8d 100644 --- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp @@ -71,7 +71,7 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg, BugReport *Report = new BugReport(*BT, "Use -drain instead of -release when " "using NSAutoreleasePool and garbage collection", N); Report->addRange(msg.getSourceRange()); - C.EmitReport(Report); + C.emitReport(Report); } void ento::registerNSAutoreleasePoolChecker(CheckerManager &mgr) { diff --git a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp index f826573c9ecb..7a66ec3a934f 100644 --- a/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/NSErrorChecker.cpp @@ -163,23 +163,9 @@ public: }; } -namespace { struct NSErrorOut {}; } -namespace { struct CFErrorOut {}; } - typedef llvm::ImmutableMap<SymbolRef, unsigned> ErrorOutFlag; - -namespace clang { -namespace ento { - template <> - struct ProgramStateTrait<NSErrorOut> : public ProgramStatePartialTrait<ErrorOutFlag> { - static void *GDMIndex() { static int index = 0; return &index; } - }; - template <> - struct ProgramStateTrait<CFErrorOut> : public ProgramStatePartialTrait<ErrorOutFlag> { - static void *GDMIndex() { static int index = 0; return &index; } - }; -} -} +REGISTER_TRAIT_WITH_PROGRAMSTATE(NSErrorOut, ErrorOutFlag) +REGISTER_TRAIT_WITH_PROGRAMSTATE(CFErrorOut, ErrorOutFlag) template <typename T> static bool hasFlag(SVal val, ProgramStateRef state) { @@ -285,7 +271,7 @@ void NSOrCFErrorDerefChecker::checkEvent(ImplicitNullDerefEvent event) const { bug = new CFErrorDerefBug(); BugReport *report = new BugReport(*bug, os.str(), event.SinkNode); - BR.EmitReport(report); + BR.emitReport(report); } static bool IsNSError(QualType T, IdentifierInfo *II) { diff --git a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp b/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp deleted file mode 100644 index 7b724d2be9b7..000000000000 --- a/lib/StaticAnalyzer/Checkers/OSAtomicChecker.cpp +++ /dev/null @@ -1,218 +0,0 @@ -//=== OSAtomicChecker.cpp - OSAtomic functions evaluator --------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This checker evaluates OSAtomic functions. -// -//===----------------------------------------------------------------------===// - -#include "ClangSACheckers.h" -#include "clang/StaticAnalyzer/Core/Checker.h" -#include "clang/StaticAnalyzer/Core/CheckerManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/Basic/Builtins.h" - -using namespace clang; -using namespace ento; - -namespace { - -class OSAtomicChecker : public Checker<eval::InlineCall> { -public: - bool inlineCall(const CallExpr *CE, ExprEngine &Eng, - ExplodedNode *Pred, ExplodedNodeSet &Dst) const; - -private: - bool evalOSAtomicCompareAndSwap(const CallExpr *CE, - ExprEngine &Eng, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) const; -}; -} - -static StringRef getCalleeName(ProgramStateRef State, - const CallExpr *CE, - const LocationContext *LCtx) { - const Expr *Callee = CE->getCallee(); - SVal L = State->getSVal(Callee, LCtx); - const FunctionDecl *funDecl = L.getAsFunctionDecl(); - if (!funDecl) - return StringRef(); - IdentifierInfo *funI = funDecl->getIdentifier(); - if (!funI) - return StringRef(); - return funI->getName(); -} - -bool OSAtomicChecker::inlineCall(const CallExpr *CE, - ExprEngine &Eng, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) const { - StringRef FName = getCalleeName(Pred->getState(), - CE, Pred->getLocationContext()); - if (FName.empty()) - return false; - - // Check for compare and swap. - if (FName.startswith("OSAtomicCompareAndSwap") || - FName.startswith("objc_atomicCompareAndSwap")) - return evalOSAtomicCompareAndSwap(CE, Eng, Pred, Dst); - - // FIXME: Other atomics. - return false; -} - -bool OSAtomicChecker::evalOSAtomicCompareAndSwap(const CallExpr *CE, - ExprEngine &Eng, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) const { - // Not enough arguments to match OSAtomicCompareAndSwap? - if (CE->getNumArgs() != 3) - return false; - - ASTContext &Ctx = Eng.getContext(); - const Expr *oldValueExpr = CE->getArg(0); - QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType()); - - const Expr *newValueExpr = CE->getArg(1); - QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType()); - - // Do the types of 'oldValue' and 'newValue' match? - if (oldValueType != newValueType) - return false; - - const Expr *theValueExpr = CE->getArg(2); - const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>(); - - // theValueType not a pointer? - if (!theValueType) - return false; - - QualType theValueTypePointee = - Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType(); - - // The pointee must match newValueType and oldValueType. - if (theValueTypePointee != newValueType) - return false; - - static SimpleProgramPointTag OSAtomicLoadTag("OSAtomicChecker : Load"); - static SimpleProgramPointTag OSAtomicStoreTag("OSAtomicChecker : Store"); - - // Load 'theValue'. - ProgramStateRef state = Pred->getState(); - const LocationContext *LCtx = Pred->getLocationContext(); - ExplodedNodeSet Tmp; - SVal location = state->getSVal(theValueExpr, LCtx); - // Here we should use the value type of the region as the load type, because - // we are simulating the semantics of the function, not the semantics of - // passing argument. So the type of theValue expr is not we are loading. - // But usually the type of the varregion is not the type we want either, - // we still need to do a CastRetrievedVal in store manager. So actually this - // LoadTy specifying can be omitted. But we put it here to emphasize the - // semantics. - QualType LoadTy; - if (const TypedValueRegion *TR = - dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) { - LoadTy = TR->getValueType(); - } - Eng.evalLoad(Tmp, CE, theValueExpr, Pred, - state, location, &OSAtomicLoadTag, LoadTy); - - if (Tmp.empty()) { - // If no nodes were generated, other checkers must have generated sinks. - // We return an empty Dst. - return true; - } - - for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); - I != E; ++I) { - - ExplodedNode *N = *I; - ProgramStateRef stateLoad = N->getState(); - - // Use direct bindings from the environment since we are forcing a load - // from a location that the Environment would typically not be used - // to bind a value. - SVal theValueVal_untested = stateLoad->getSVal(theValueExpr, LCtx, true); - - SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr, LCtx); - - // FIXME: Issue an error. - if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) { - return false; - } - - DefinedOrUnknownSVal theValueVal = - cast<DefinedOrUnknownSVal>(theValueVal_untested); - DefinedOrUnknownSVal oldValueVal = - cast<DefinedOrUnknownSVal>(oldValueVal_untested); - - SValBuilder &svalBuilder = Eng.getSValBuilder(); - - // Perform the comparison. - DefinedOrUnknownSVal Cmp = - svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal); - - ProgramStateRef stateEqual = stateLoad->assume(Cmp, true); - - // Were they equal? - if (stateEqual) { - // Perform the store. - ExplodedNodeSet TmpStore; - SVal val = stateEqual->getSVal(newValueExpr, LCtx); - - // Handle implicit value casts. - if (const TypedValueRegion *R = - dyn_cast_or_null<TypedValueRegion>(location.getAsRegion())) { - val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType()); - } - - Eng.evalStore(TmpStore, CE, theValueExpr, N, - stateEqual, location, val, &OSAtomicStoreTag); - - if (TmpStore.empty()) { - // If no nodes were generated, other checkers must have generated sinks. - // We return an empty Dst. - return true; - } - - StmtNodeBuilder B(TmpStore, Dst, Eng.getBuilderContext()); - // Now bind the result of the comparison. - for (ExplodedNodeSet::iterator I2 = TmpStore.begin(), - E2 = TmpStore.end(); I2 != E2; ++I2) { - ExplodedNode *predNew = *I2; - ProgramStateRef stateNew = predNew->getState(); - // Check for 'void' return type if we have a bogus function prototype. - SVal Res = UnknownVal(); - QualType T = CE->getType(); - if (!T->isVoidType()) - Res = Eng.getSValBuilder().makeTruthVal(true, T); - B.generateNode(CE, predNew, stateNew->BindExpr(CE, LCtx, Res), - false, this); - } - } - - // Were they not equal? - if (ProgramStateRef stateNotEqual = stateLoad->assume(Cmp, false)) { - // Check for 'void' return type if we have a bogus function prototype. - SVal Res = UnknownVal(); - QualType T = CE->getType(); - if (!T->isVoidType()) - Res = Eng.getSValBuilder().makeTruthVal(false, CE->getType()); - StmtNodeBuilder B(N, Dst, Eng.getBuilderContext()); - B.generateNode(CE, N, stateNotEqual->BindExpr(CE, LCtx, Res), - false, this); - } - } - - return true; -} - -void ento::registerOSAtomicChecker(CheckerManager &mgr) { - mgr.registerChecker<OSAtomicChecker>(); -} diff --git a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp index 4cc92ce9e958..9d84f52f934e 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCAtSyncChecker.cpp @@ -18,7 +18,6 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" -#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" using namespace clang; @@ -50,8 +49,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, "for @synchronized")); BugReport *report = new BugReport(*BT_undef, BT_undef->getDescription(), N); - bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, report); - C.EmitReport(report); + bugreporter::trackNullOrUndefValue(N, Ex, *report); + C.emitReport(report); } return; } @@ -73,9 +72,9 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S, "(no synchronization will occur)")); BugReport *report = new BugReport(*BT_null, BT_null->getDescription(), N); - bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, report); + bugreporter::trackNullOrUndefValue(N, Ex, *report); - C.EmitReport(report); + C.emitReport(report); return; } } diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp index f2929c03cc0b..63a84805e73e 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCContainersASTChecker.cpp @@ -31,8 +31,6 @@ class WalkAST : public StmtVisitor<WalkAST> { ASTContext &ASTC; uint64_t PtrWidth; - static const unsigned InvalidArgIndex = UINT_MAX; - /// Check if the type has pointer size (very conservative). inline bool isPointerSize(const Type *T) { if (!T) @@ -102,16 +100,18 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { return; const Expr *Arg = 0; - unsigned ArgNum = InvalidArgIndex; + unsigned ArgNum; if (Name.equals("CFArrayCreate") || Name.equals("CFSetCreate")) { + if (CE->getNumArgs() != 4) + return; ArgNum = 1; Arg = CE->getArg(ArgNum)->IgnoreParenCasts(); if (hasPointerToPointerSizedType(Arg)) return; - } - - if (Arg == 0 && Name.equals("CFDictionaryCreate")) { + } else if (Name.equals("CFDictionaryCreate")) { + if (CE->getNumArgs() != 6) + return; // Check first argument. ArgNum = 1; Arg = CE->getArg(ArgNum)->IgnoreParenCasts(); @@ -125,17 +125,18 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { } } - if (ArgNum != InvalidArgIndex) { + if (Arg) { assert(ArgNum == 1 || ArgNum == 2); - SmallString<256> BufName; + SmallString<64> BufName; llvm::raw_svector_ostream OsName(BufName); - assert(ArgNum == 1 || ArgNum == 2); OsName << " Invalid use of '" << Name << "'" ; SmallString<256> Buf; llvm::raw_svector_ostream Os(Buf); - Os << " The "<< ((ArgNum == 1) ? "first" : "second") << " argument to '" + // Use "second" and "third" since users will expect 1-based indexing + // for parameter names when mentioned in prose. + Os << " The "<< ((ArgNum == 1) ? "second" : "third") << " argument to '" << Name << "' must be a C array of pointer-sized values, not '" << Arg->getType().getAsString() << "'"; diff --git a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp index 2ab49ed12a14..999c994cb1c6 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCContainersChecker.cpp @@ -55,16 +55,8 @@ public: }; } // end anonymous namespace -// ProgramState trait - a map from array symbol to it's state. -typedef llvm::ImmutableMap<SymbolRef, DefinedSVal> ArraySizeM; - -namespace { struct ArraySizeMap {}; } -namespace clang { namespace ento { -template<> struct ProgramStateTrait<ArraySizeMap> - : public ProgramStatePartialTrait<ArraySizeM > { - static void *GDMIndex() { return ObjCContainersChecker::getTag(); } -}; -}} +// ProgramState trait - a map from array symbol to its state. +REGISTER_MAP_WITH_PROGRAMSTATE(ArraySizeMap, SymbolRef, DefinedSVal) void ObjCContainersChecker::addSizeInfo(const Expr *Array, const Expr *Size, CheckerContext &C) const { @@ -146,7 +138,7 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE, initBugType(); BugReport *R = new BugReport(*BT, "Index is out of bounds", N); R->addRange(IdxExpr->getSourceRange()); - C.EmitReport(R); + C.emitReport(R); return; } } diff --git a/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp new file mode 100644 index 000000000000..e906e8aa3016 --- /dev/null +++ b/lib/StaticAnalyzer/Checkers/ObjCMissingSuperCallChecker.cpp @@ -0,0 +1,203 @@ +//==- ObjCMissingSuperCallChecker.cpp - Check missing super-calls in ObjC --==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines a ObjCMissingSuperCallChecker, a checker that +// analyzes a UIViewController implementation to determine if it +// correctly calls super in the methods where this is mandatory. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" +#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" +#include "clang/AST/ExprObjC.h" +#include "clang/AST/Expr.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace ento; + +static bool isUIViewControllerSubclass(ASTContext &Ctx, + const ObjCImplementationDecl *D) { + IdentifierInfo *ViewControllerII = &Ctx.Idents.get("UIViewController"); + const ObjCInterfaceDecl *ID = D->getClassInterface(); + + for ( ; ID; ID = ID->getSuperClass()) + if (ID->getIdentifier() == ViewControllerII) + return true; + return false; +} + +//===----------------------------------------------------------------------===// +// FindSuperCallVisitor - Identify specific calls to the superclass. +//===----------------------------------------------------------------------===// + +class FindSuperCallVisitor : public RecursiveASTVisitor<FindSuperCallVisitor> { +public: + explicit FindSuperCallVisitor(Selector S) : DoesCallSuper(false), Sel(S) {} + + bool VisitObjCMessageExpr(ObjCMessageExpr *E) { + if (E->getSelector() == Sel) + if (E->getReceiverKind() == ObjCMessageExpr::SuperInstance) + DoesCallSuper = true; + + // Recurse if we didn't find the super call yet. + return !DoesCallSuper; + } + + bool DoesCallSuper; + +private: + Selector Sel; +}; + +//===----------------------------------------------------------------------===// +// ObjCSuperCallChecker +//===----------------------------------------------------------------------===// + +namespace { +class ObjCSuperCallChecker : public Checker< + check::ASTDecl<ObjCImplementationDecl> > { +public: + void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager &Mgr, + BugReporter &BR) const; +}; +} + +void ObjCSuperCallChecker::checkASTDecl(const ObjCImplementationDecl *D, + AnalysisManager &Mgr, + BugReporter &BR) const { + ASTContext &Ctx = BR.getContext(); + + if (!isUIViewControllerSubclass(Ctx, D)) + return; + + const char *SelectorNames[] = + {"addChildViewController", "viewDidAppear", "viewDidDisappear", + "viewWillAppear", "viewWillDisappear", "removeFromParentViewController", + "didReceiveMemoryWarning", "viewDidUnload", "viewWillUnload", + "viewDidLoad"}; + const unsigned SelectorArgumentCounts[] = + {1, 1, 1, 1, 1, 0, 0, 0, 0, 0}; + const size_t SelectorCount = llvm::array_lengthof(SelectorNames); + assert(llvm::array_lengthof(SelectorArgumentCounts) == SelectorCount); + + // Fill the Selectors SmallSet with all selectors we want to check. + llvm::SmallSet<Selector, 16> Selectors; + for (size_t i = 0; i < SelectorCount; i++) { + unsigned ArgumentCount = SelectorArgumentCounts[i]; + const char *SelectorCString = SelectorNames[i]; + + // Get the selector. + IdentifierInfo *II = &Ctx.Idents.get(SelectorCString); + Selectors.insert(Ctx.Selectors.getSelector(ArgumentCount, &II)); + } + + // Iterate over all instance methods. + for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(), + E = D->instmeth_end(); + I != E; ++I) { + Selector S = (*I)->getSelector(); + // Find out whether this is a selector that we want to check. + if (!Selectors.count(S)) + continue; + + ObjCMethodDecl *MD = *I; + + // Check if the method calls its superclass implementation. + if (MD->getBody()) + { + FindSuperCallVisitor Visitor(S); + Visitor.TraverseDecl(MD); + + // It doesn't call super, emit a diagnostic. + if (!Visitor.DoesCallSuper) { + PathDiagnosticLocation DLoc = + PathDiagnosticLocation::createEnd(MD->getBody(), + BR.getSourceManager(), + Mgr.getAnalysisDeclContext(D)); + + const char *Name = "Missing call to superclass"; + SmallString<256> Buf; + llvm::raw_svector_ostream os(Buf); + + os << "The '" << S.getAsString() + << "' instance method in UIViewController subclass '" << *D + << "' is missing a [super " << S.getAsString() << "] call"; + + BR.EmitBasicReport(MD, Name, categories::CoreFoundationObjectiveC, + os.str(), DLoc); + } + } + } +} + + +//===----------------------------------------------------------------------===// +// Check registration. +//===----------------------------------------------------------------------===// + +void ento::registerObjCSuperCallChecker(CheckerManager &Mgr) { + Mgr.registerChecker<ObjCSuperCallChecker>(); +} + + +/* + ToDo list for expanding this check in the future, the list is not exhaustive. + There are also cases where calling super is suggested but not "mandatory". + In addition to be able to check the classes and methods below, architectural + improvements like being able to allow for the super-call to be done in a called + method would be good too. + +*** trivial cases: +UIResponder subclasses +- resignFirstResponder + +NSResponder subclasses +- cursorUpdate + +*** more difficult cases: + +UIDocument subclasses +- finishedHandlingError:recovered: (is multi-arg) +- finishedHandlingError:recovered: (is multi-arg) + +UIViewController subclasses +- loadView (should *never* call super) +- transitionFromViewController:toViewController: + duration:options:animations:completion: (is multi-arg) + +UICollectionViewController subclasses +- loadView (take care because UIViewController subclasses should NOT call super + in loadView, but UICollectionViewController subclasses should) + +NSObject subclasses +- doesNotRecognizeSelector (it only has to call super if it doesn't throw) + +UIPopoverBackgroundView subclasses (some of those are class methods) +- arrowDirection (should *never* call super) +- arrowOffset (should *never* call super) +- arrowBase (should *never* call super) +- arrowHeight (should *never* call super) +- contentViewInsets (should *never* call super) + +UITextSelectionRect subclasses (some of those are properties) +- rect (should *never* call super) +- range (should *never* call super) +- writingDirection (should *never* call super) +- isVertical (should *never* call super) +- containsStart (should *never* call super) +- containsEnd (should *never* call super) +*/ diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp index be45da1be066..98d2a85ace36 100644 --- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp @@ -72,6 +72,8 @@ public: void checkPreCall(const CallEvent &CE, CheckerContext &C) const; void checkPostCall(const CallEvent &CE, CheckerContext &C) const; + void printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const; }; } // end anonymous namespace @@ -97,31 +99,14 @@ enum SelfFlagEnum { }; } -typedef llvm::ImmutableMap<SymbolRef, unsigned> SelfFlag; -namespace { struct CalledInit {}; } -namespace { struct PreCallSelfFlags {}; } - -namespace clang { -namespace ento { - template<> - struct ProgramStateTrait<SelfFlag> : public ProgramStatePartialTrait<SelfFlag> { - static void *GDMIndex() { static int index = 0; return &index; } - }; - template <> - struct ProgramStateTrait<CalledInit> : public ProgramStatePartialTrait<bool> { - static void *GDMIndex() { static int index = 0; return &index; } - }; - - /// \brief A call receiving a reference to 'self' invalidates the object that - /// 'self' contains. This keeps the "self flags" assigned to the 'self' - /// object before the call so we can assign them to the new object that 'self' - /// points to after the call. - template <> - struct ProgramStateTrait<PreCallSelfFlags> : public ProgramStatePartialTrait<unsigned> { - static void *GDMIndex() { static int index = 0; return &index; } - }; -} -} +REGISTER_MAP_WITH_PROGRAMSTATE(SelfFlag, SymbolRef, unsigned) +REGISTER_TRAIT_WITH_PROGRAMSTATE(CalledInit, bool) + +/// \brief A call receiving a reference to 'self' invalidates the object that +/// 'self' contains. This keeps the "self flags" assigned to the 'self' +/// object before the call so we can assign them to the new object that 'self' +/// points to after the call. +REGISTER_TRAIT_WITH_PROGRAMSTATE(PreCallSelfFlags, unsigned) static SelfFlagEnum getSelfFlags(SVal val, ProgramStateRef state) { if (SymbolRef sym = val.getAsSymbol()) @@ -138,7 +123,8 @@ static void addSelfFlag(ProgramStateRef state, SVal val, SelfFlagEnum flag, CheckerContext &C) { // We tag the symbol that the SVal wraps. if (SymbolRef sym = val.getAsSymbol()) - C.addTransition(state->set<SelfFlag>(sym, getSelfFlags(val, C) | flag)); + state = state->set<SelfFlag>(sym, getSelfFlags(val, state) | flag); + C.addTransition(state); } static bool hasSelfFlag(SVal val, SelfFlagEnum flag, CheckerContext &C) { @@ -176,7 +162,7 @@ static void checkForInvalidSelf(const Expr *E, CheckerContext &C, BugReport *report = new BugReport(*new InitSelfBug(), errorStr, N); - C.EmitReport(report); + C.emitReport(report); } void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg, @@ -305,13 +291,12 @@ void ObjCSelfInitChecker::checkPostCall(const CallEvent &CE, // returns 'self'. So assign the flags, which were set on 'self' to the // return value. // EX: self = performMoreInitialization(self) - const Expr *CallExpr = CE.getOriginExpr(); - if (CallExpr) - addSelfFlag(state, state->getSVal(CallExpr, C.getLocationContext()), - prevFlags, C); + addSelfFlag(state, CE.getReturnValue(), prevFlags, C); return; } } + + C.addTransition(state); } void ObjCSelfInitChecker::checkLocation(SVal location, bool isLoad, @@ -346,6 +331,53 @@ void ObjCSelfInitChecker::checkBind(SVal loc, SVal val, const Stmt *S, } } +void ObjCSelfInitChecker::printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const { + SelfFlagTy FlagMap = State->get<SelfFlag>(); + bool DidCallInit = State->get<CalledInit>(); + SelfFlagEnum PreCallFlags = (SelfFlagEnum)State->get<PreCallSelfFlags>(); + + if (FlagMap.isEmpty() && !DidCallInit && !PreCallFlags) + return; + + Out << Sep << NL << "ObjCSelfInitChecker:" << NL; + + if (DidCallInit) + Out << " An init method has been called." << NL; + + if (PreCallFlags != SelfFlag_None) { + if (PreCallFlags & SelfFlag_Self) { + Out << " An argument of the current call came from the 'self' variable." + << NL; + } + if (PreCallFlags & SelfFlag_InitRes) { + Out << " An argument of the current call came from an init method." + << NL; + } + } + + Out << NL; + for (SelfFlagTy::iterator I = FlagMap.begin(), E = FlagMap.end(); + I != E; ++I) { + Out << I->first << " : "; + + if (I->second == SelfFlag_None) + Out << "none"; + + if (I->second & SelfFlag_Self) + Out << "self variable"; + + if (I->second & SelfFlag_InitRes) { + if (I->second != SelfFlag_InitRes) + Out << " | "; + Out << "result of init method"; + } + + Out << NL; + } +} + + // FIXME: A callback should disable checkers at the start of functions. static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND) { if (!ND) diff --git a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp index fe4845bd8894..b5d9959b8531 100644 --- a/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/PointerArithChecker.cpp @@ -59,7 +59,7 @@ void PointerArithChecker::checkPreStmt(const BinaryOperator *B, "dangerous.")); BugReport *R = new BugReport(*BT, BT->getDescription(), N); R->addRange(B->getSourceRange()); - C.EmitReport(R); + C.emitReport(R); } } } diff --git a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp index fa5c6a30a683..47da87f0bcc6 100644 --- a/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/PointerSubChecker.cpp @@ -67,7 +67,7 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B, "the same memory chunk may cause incorrect result.")); BugReport *R = new BugReport(*BT, BT->getDescription(), N); R->addRange(B->getSourceRange()); - C.EmitReport(R); + C.emitReport(R); } } diff --git a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp index 2d018ef9264d..d9b638469525 100644 --- a/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/PthreadLockChecker.cpp @@ -43,15 +43,7 @@ public: } // end anonymous namespace // GDM Entry for tracking lock state. -namespace { class LockSet {}; } -namespace clang { -namespace ento { -template <> struct ProgramStateTrait<LockSet> : - public ProgramStatePartialTrait<llvm::ImmutableList<const MemRegion*> > { - static void *GDMIndex() { static int x = 0; return &x; } -}; -} // end of ento (ProgramState) namespace -} // end clang namespace +REGISTER_LIST_WITH_PROGRAMSTATE(LockSet, const MemRegion *) void PthreadLockChecker::checkPostStmt(const CallExpr *CE, @@ -118,7 +110,7 @@ void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE, "This lock has already " "been acquired", N); report->addRange(CE->getArg(0)->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); return; } @@ -163,7 +155,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, return; ProgramStateRef state = C.getState(); - llvm::ImmutableList<const MemRegion*> LS = state->get<LockSet>(); + LockSetTy LS = state->get<LockSet>(); // FIXME: Better analysis requires IPA for wrappers. // FIXME: check for double unlocks @@ -183,7 +175,7 @@ void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE, "Possible lock order " "reversal", N); report->addRange(CE->getArg(0)->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); return; } diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp index 3c00d9915b4a..304051c1394c 100644 --- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp @@ -40,24 +40,6 @@ using namespace clang; using namespace ento; using llvm::StrInStrNoCase; -namespace { -/// Wrapper around different kinds of node builder, so that helper functions -/// can have a common interface. -class GenericNodeBuilderRefCount { - CheckerContext *C; - const ProgramPointTag *tag; -public: - GenericNodeBuilderRefCount(CheckerContext &c, - const ProgramPointTag *t = 0) - : C(&c), tag(t){} - - ExplodedNode *MakeNode(ProgramStateRef state, ExplodedNode *Pred, - bool MarkAsSink = false) { - return C->addTransition(state, Pred, tag, MarkAsSink); - } -}; -} // end anonymous namespace - //===----------------------------------------------------------------------===// // Primitives used for constructing summaries for function/method calls. //===----------------------------------------------------------------------===// @@ -66,9 +48,23 @@ public: /// particular argument. enum ArgEffect { DoNothing, Autorelease, Dealloc, DecRef, DecRefMsg, DecRefBridgedTransfered, - DecRefAndStopTracking, DecRefMsgAndStopTracking, IncRefMsg, IncRef, MakeCollectable, MayEscape, - NewAutoreleasePool, StopTracking }; + NewAutoreleasePool, + + // Stop tracking the argument - the effect of the call is + // unknown. + StopTracking, + + // In some cases, we obtain a better summary for this checker + // by looking at the call site than by inlining the function. + // Signifies that we should stop tracking the symbol even if + // the function is inlined. + StopTrackingHard, + + // The function decrements the reference count and the checker + // should stop tracking the argument. + DecRefAndStopTrackingHard, DecRefMsgAndStopTrackingHard + }; namespace llvm { template <> struct FoldingSetTrait<ArgEffect> { @@ -90,7 +86,13 @@ class RetEffect { public: enum Kind { NoRet, OwnedSymbol, OwnedAllocatedSymbol, NotOwnedSymbol, GCNotOwnedSymbol, ARCNotOwnedSymbol, - OwnedWhenTrackedReceiver }; + OwnedWhenTrackedReceiver, + // Treat this function as returning a non-tracked symbol even if + // the function has been inlined. This is used where the call + // site summary is more presise than the summary indirectly produced + // by inlining the function + NoRetHard + }; enum ObjKind { CF, ObjC, AnyObj }; @@ -133,6 +135,9 @@ public: static RetEffect MakeNoRet() { return RetEffect(NoRet); } + static RetEffect MakeNoRetHard() { + return RetEffect(NoRetHard); + } void Profile(llvm::FoldingSetNodeID& ID) const { ID.AddInteger((unsigned) K); @@ -337,20 +342,7 @@ void RefVal::print(raw_ostream &Out) const { // RefBindings - State used to track object reference counts. //===----------------------------------------------------------------------===// -typedef llvm::ImmutableMap<SymbolRef, RefVal> RefBindings; - -namespace clang { -namespace ento { -template<> -struct ProgramStateTrait<RefBindings> - : public ProgramStatePartialTrait<RefBindings> { - static void *GDMIndex() { - static int RefBIndex = 0; - return &RefBIndex; - } -}; -} -} +REGISTER_MAP_WITH_PROGRAMSTATE(RefBindings, SymbolRef, RefVal) static inline const RefVal *getRefBinding(ProgramStateRef State, SymbolRef Sym) { @@ -893,7 +885,7 @@ static bool isMakeCollectable(const FunctionDecl *FD, StringRef FName) { return FName.find("MakeCollectable") != StringRef::npos; } -static ArgEffect getStopTrackingEquivalent(ArgEffect E) { +static ArgEffect getStopTrackingHardEquivalent(ArgEffect E) { switch (E) { case DoNothing: case Autorelease: @@ -904,13 +896,14 @@ static ArgEffect getStopTrackingEquivalent(ArgEffect E) { case MayEscape: case NewAutoreleasePool: case StopTracking: - return StopTracking; + case StopTrackingHard: + return StopTrackingHard; case DecRef: - case DecRefAndStopTracking: - return DecRefAndStopTracking; + case DecRefAndStopTrackingHard: + return DecRefAndStopTrackingHard; case DecRefMsg: - case DecRefMsgAndStopTracking: - return DecRefMsgAndStopTracking; + case DecRefMsgAndStopTrackingHard: + return DecRefMsgAndStopTrackingHard; case Dealloc: return Dealloc; } @@ -921,33 +914,65 @@ static ArgEffect getStopTrackingEquivalent(ArgEffect E) { void RetainSummaryManager::updateSummaryForCall(const RetainSummary *&S, const CallEvent &Call) { if (Call.hasNonZeroCallbackArg()) { - ArgEffect RecEffect = getStopTrackingEquivalent(S->getReceiverEffect()); - ArgEffect DefEffect = getStopTrackingEquivalent(S->getDefaultArgEffect()); + ArgEffect RecEffect = + getStopTrackingHardEquivalent(S->getReceiverEffect()); + ArgEffect DefEffect = + getStopTrackingHardEquivalent(S->getDefaultArgEffect()); ArgEffects CustomArgEffects = S->getArgEffects(); for (ArgEffects::iterator I = CustomArgEffects.begin(), E = CustomArgEffects.end(); I != E; ++I) { - ArgEffect Translated = getStopTrackingEquivalent(I->second); + ArgEffect Translated = getStopTrackingHardEquivalent(I->second); if (Translated != DefEffect) ScratchArgs = AF.add(ScratchArgs, I->first, Translated); } - RetEffect RE = RetEffect::MakeNoRet(); + RetEffect RE = RetEffect::MakeNoRetHard(); // Special cases where the callback argument CANNOT free the return value. // This can generally only happen if we know that the callback will only be // called when the return value is already being deallocated. if (const FunctionCall *FC = dyn_cast<FunctionCall>(&Call)) { - IdentifierInfo *Name = FC->getDecl()->getIdentifier(); - - // This callback frees the associated buffer. - if (Name->isStr("CGBitmapContextCreateWithData")) - RE = S->getRetEffect(); + if (IdentifierInfo *Name = FC->getDecl()->getIdentifier()) { + // When the CGBitmapContext is deallocated, the callback here will free + // the associated data buffer. + if (Name->isStr("CGBitmapContextCreateWithData")) + RE = S->getRetEffect(); + } } S = getPersistentSummary(RE, RecEffect, DefEffect); } + + // Special case '[super init];' and '[self init];' + // + // Even though calling '[super init]' without assigning the result to self + // and checking if the parent returns 'nil' is a bad pattern, it is common. + // Additionally, our Self Init checker already warns about it. To avoid + // overwhelming the user with messages from both checkers, we model the case + // of '[super init]' in cases when it is not consumed by another expression + // as if the call preserves the value of 'self'; essentially, assuming it can + // never fail and return 'nil'. + // Note, we don't want to just stop tracking the value since we want the + // RetainCount checker to report leaks and use-after-free if SelfInit checker + // is turned off. + if (const ObjCMethodCall *MC = dyn_cast<ObjCMethodCall>(&Call)) { + if (MC->getMethodFamily() == OMF_init && MC->isReceiverSelfOrSuper()) { + + // Check if the message is not consumed, we know it will not be used in + // an assignment, ex: "self = [super init]". + const Expr *ME = MC->getOriginExpr(); + const LocationContext *LCtx = MC->getLocationContext(); + ParentMap &PM = LCtx->getAnalysisDeclContext()->getParentMap(); + if (!PM.isConsumedExpr(ME)) { + RetainSummaryTemplate ModifiableSummaryTemplate(S, *this); + ModifiableSummaryTemplate->setReceiverEffect(DoNothing); + ModifiableSummaryTemplate->setRetEffect(RetEffect::MakeNoRet()); + } + } + + } } const RetainSummary * @@ -1036,6 +1061,8 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { // The headers on OS X 10.8 use cf_consumed/ns_returns_retained, // but we can fully model NSMakeCollectable ourselves. AllowAnnotations = false; + } else if (FName == "CFPlugInInstanceCreate") { + S = getPersistentSummary(RetEffect::MakeNoRet()); } else if (FName == "IOBSDNameMatching" || FName == "IOServiceMatching" || FName == "IOServiceNameMatching" || @@ -1108,6 +1135,11 @@ RetainSummaryManager::getFunctionSummary(const FunctionDecl *FD) { break; if (RetTy->isPointerType()) { + if (FD->getAttr<CFAuditedTransferAttr>()) { + S = getCFCreateGetRuleSummary(FD); + break; + } + // For CoreFoundation ('CF') types. if (cocoa::isRefType(RetTy, "CF", FName)) { if (isRetain(FD, FName)) @@ -1347,22 +1379,6 @@ RetainSummaryManager::updateSummaryFromAnnotations(const RetainSummary *&Summ, const RetainSummary * RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD, Selector S, QualType RetTy) { - - if (MD) { - // Scan the method decl for 'void*' arguments. These should be treated - // as 'StopTracking' because they are often used with delegates. - // Delegates are a frequent form of false positives with the retain - // count checker. - unsigned i = 0; - for (ObjCMethodDecl::param_const_iterator I = MD->param_begin(), - E = MD->param_end(); I != E; ++I, ++i) - if (const ParmVarDecl *PD = *I) { - QualType Ty = Ctx.getCanonicalType(PD->getType()); - if (Ty.getLocalUnqualifiedType() == Ctx.VoidPtrTy) - ScratchArgs = AF.add(ScratchArgs, i, StopTracking); - } - } - // Any special effects? ArgEffect ReceiverEff = DoNothing; RetEffect ResultEff = RetEffect::MakeNoRet(); @@ -1441,9 +1457,9 @@ RetainSummaryManager::getStandardMethodSummary(const ObjCMethodDecl *MD, StringRef Slot = S.getNameForSlot(i); if (Slot.substr(Slot.size() - 8).equals_lower("delegate")) { if (ResultEff == ObjCInitRetE) - ResultEff = RetEffect::MakeNoRet(); + ResultEff = RetEffect::MakeNoRetHard(); else - ReceiverEff = StopTracking; + ReceiverEff = StopTrackingHard; } } } @@ -2174,6 +2190,7 @@ GetAllocationSite(ProgramStateManager& StateMgr, const ExplodedNode *N, // If allocation happened in a function different from the leak node context, // do not report the binding. + assert(N && "Could not find allocation node"); if (N->getLocationContext() != LeakContext) { FirstBinding = 0; } @@ -2229,27 +2246,36 @@ CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC, // Get the retain count. const RefVal* RV = getRefBinding(EndN->getState(), Sym); + assert(RV); if (RV->getKind() == RefVal::ErrorLeakReturned) { // FIXME: Per comments in rdar://6320065, "create" only applies to CF // objects. Only "copy", "alloc", "retain" and "new" transfer ownership // to the caller for NS objects. const Decl *D = &EndN->getCodeDecl(); - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - os << " is returned from a method whose name ('" - << MD->getSelector().getAsString() - << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'." - " This violates the naming convention rules" - " given in the Memory Management Guide for Cocoa"; - } + + os << (isa<ObjCMethodDecl>(D) ? " is returned from a method " + : " is returned from a function "); + + if (D->getAttr<CFReturnsNotRetainedAttr>()) + os << "that is annotated as CF_RETURNS_NOT_RETAINED"; + else if (D->getAttr<NSReturnsNotRetainedAttr>()) + os << "that is annotated as NS_RETURNS_NOT_RETAINED"; else { - const FunctionDecl *FD = cast<FunctionDecl>(D); - os << " is returned from a function whose name ('" - << *FD - << "') does not contain 'Copy' or 'Create'. This violates the naming" - " convention rules given in the Memory Management Guide for Core" - " Foundation"; - } + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + os << "whose name ('" << MD->getSelector().getAsString() + << "') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'." + " This violates the naming convention rules" + " given in the Memory Management Guide for Cocoa"; + } + else { + const FunctionDecl *FD = cast<FunctionDecl>(D); + os << "whose name ('" << *FD + << "') does not contain 'Copy' or 'Create'. This violates the naming" + " convention rules given in the Memory Management Guide for Core" + " Foundation"; + } + } } else if (RV->getKind() == RefVal::ErrorGCLeakReturned) { ObjCMethodDecl &MD = cast<ObjCMethodDecl>(EndN->getCodeDecl()); @@ -2474,6 +2500,10 @@ public: void checkSummary(const RetainSummary &Summ, const CallEvent &Call, CheckerContext &C) const; + void processSummaryOfInlined(const RetainSummary &Summ, + const CallEvent &Call, + CheckerContext &C) const; + bool evalCall(const CallExpr *CE, CheckerContext &C) const; ProgramStateRef evalAssume(ProgramStateRef state, SVal Cond, @@ -2499,8 +2529,8 @@ public: void checkEndPath(CheckerContext &C) const; ProgramStateRef updateSymbol(ProgramStateRef state, SymbolRef sym, - RefVal V, ArgEffect E, RefVal::Kind &hasErr, - CheckerContext &C) const; + RefVal V, ArgEffect E, RefVal::Kind &hasErr, + CheckerContext &C) const; void processNonLeakError(ProgramStateRef St, SourceRange ErrorRange, RefVal::Kind ErrorKind, SymbolRef Sym, @@ -2515,13 +2545,12 @@ public: SmallVectorImpl<SymbolRef> &Leaked) const; std::pair<ExplodedNode *, ProgramStateRef > - handleAutoreleaseCounts(ProgramStateRef state, - GenericNodeBuilderRefCount Bd, ExplodedNode *Pred, - CheckerContext &Ctx, SymbolRef Sym, RefVal V) const; + handleAutoreleaseCounts(ProgramStateRef state, ExplodedNode *Pred, + const ProgramPointTag *Tag, CheckerContext &Ctx, + SymbolRef Sym, RefVal V) const; ExplodedNode *processLeaks(ProgramStateRef state, SmallVectorImpl<SymbolRef> &Leaked, - GenericNodeBuilderRefCount &Builder, CheckerContext &Ctx, ExplodedNode *Pred = 0) const; }; @@ -2685,11 +2714,13 @@ void RetainCountChecker::checkPostStmt(const ObjCBoxedExpr *Ex, void RetainCountChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { - if (C.wasInlined) - return; - RetainSummaryManager &Summaries = getSummaryManager(C); const RetainSummary *Summ = Summaries.getSummary(Call, C.getState()); + + if (C.wasInlined) { + processSummaryOfInlined(*Summ, Call, C); + return; + } checkSummary(*Summ, Call, C); } @@ -2721,6 +2752,45 @@ static QualType GetReturnType(const Expr *RetE, ASTContext &Ctx) { return RetTy; } +// We don't always get the exact modeling of the function with regards to the +// retain count checker even when the function is inlined. For example, we need +// to stop tracking the symbols which were marked with StopTrackingHard. +void RetainCountChecker::processSummaryOfInlined(const RetainSummary &Summ, + const CallEvent &CallOrMsg, + CheckerContext &C) const { + ProgramStateRef state = C.getState(); + + // Evaluate the effect of the arguments. + for (unsigned idx = 0, e = CallOrMsg.getNumArgs(); idx != e; ++idx) { + if (Summ.getArg(idx) == StopTrackingHard) { + SVal V = CallOrMsg.getArgSVal(idx); + if (SymbolRef Sym = V.getAsLocSymbol()) { + state = removeRefBinding(state, Sym); + } + } + } + + // Evaluate the effect on the message receiver. + const ObjCMethodCall *MsgInvocation = dyn_cast<ObjCMethodCall>(&CallOrMsg); + if (MsgInvocation) { + if (SymbolRef Sym = MsgInvocation->getReceiverSVal().getAsLocSymbol()) { + if (Summ.getReceiverEffect() == StopTrackingHard) { + state = removeRefBinding(state, Sym); + } + } + } + + // Consult the summary for the return value. + RetEffect RE = Summ.getRetEffect(); + if (RE.getKind() == RetEffect::NoRetHard) { + SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol(); + if (Sym) + state = removeRefBinding(state, Sym); + } + + C.addTransition(state); +} + void RetainCountChecker::checkSummary(const RetainSummary &Summ, const CallEvent &CallOrMsg, CheckerContext &C) const { @@ -2755,7 +2825,7 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ, if (const RefVal *T = getRefBinding(state, Sym)) { ReceiverIsTracked = true; state = updateSymbol(state, Sym, *T, Summ.getReceiverEffect(), - hasErr, C); + hasErr, C); if (hasErr) { ErrorRange = MsgInvocation->getOriginExpr()->getReceiverRange(); ErrorSym = Sym; @@ -2786,13 +2856,13 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ, llvm_unreachable("Unhandled RetEffect."); case RetEffect::NoRet: + case RetEffect::NoRetHard: // No work necessary. break; case RetEffect::OwnedAllocatedSymbol: case RetEffect::OwnedSymbol: { - SymbolRef Sym = state->getSVal(CallOrMsg.getOriginExpr(), - C.getLocationContext()).getAsSymbol(); + SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol(); if (!Sym) break; @@ -2811,10 +2881,10 @@ void RetainCountChecker::checkSummary(const RetainSummary &Summ, case RetEffect::ARCNotOwnedSymbol: case RetEffect::NotOwnedSymbol: { const Expr *Ex = CallOrMsg.getOriginExpr(); - SymbolRef Sym = state->getSVal(Ex, C.getLocationContext()).getAsSymbol(); + SymbolRef Sym = CallOrMsg.getReturnValue().getAsSymbol(); if (!Sym) break; - + assert(Ex); // Use GetReturnType in order to give [NSFoo alloc] the type NSFoo *. QualType ResultTy = GetReturnType(Ex, C.getASTContext()); state = setRefBinding(state, Sym, RefVal::makeNotOwned(RE.getObjKind(), @@ -2864,8 +2934,8 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym, case DecRefMsg: E = IgnoreRetainMsg ? DoNothing : DecRef; break; - case DecRefMsgAndStopTracking: - E = IgnoreRetainMsg ? StopTracking : DecRefAndStopTracking; + case DecRefMsgAndStopTrackingHard: + E = IgnoreRetainMsg ? StopTracking : DecRefAndStopTrackingHard; break; case MakeCollectable: E = C.isObjCGCEnabled() ? DecRef : DoNothing; @@ -2886,7 +2956,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym, case DecRefMsg: case IncRefMsg: case MakeCollectable: - case DecRefMsgAndStopTracking: + case DecRefMsgAndStopTrackingHard: llvm_unreachable("DecRefMsg/IncRefMsg/MakeCollectable already converted"); case Dealloc: @@ -2935,6 +3005,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym, break; case StopTracking: + case StopTrackingHard: return removeRefBinding(state, sym); case IncRef: @@ -2955,7 +3026,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym, case DecRef: case DecRefBridgedTransfered: - case DecRefAndStopTracking: + case DecRefAndStopTrackingHard: switch (V.getKind()) { default: // case 'RefVal::Released' handled above. @@ -2966,7 +3037,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym, if (V.getCount() == 1) V = V ^ (E == DecRefBridgedTransfered ? RefVal::NotOwned : RefVal::Released); - else if (E == DecRefAndStopTracking) + else if (E == DecRefAndStopTrackingHard) return removeRefBinding(state, sym); V = V - 1; @@ -2974,7 +3045,7 @@ RetainCountChecker::updateSymbol(ProgramStateRef state, SymbolRef sym, case RefVal::NotOwned: if (V.getCount() > 0) { - if (E == DecRefAndStopTracking) + if (E == DecRefAndStopTrackingHard) return removeRefBinding(state, sym); V = V - 1; } else { @@ -3035,7 +3106,7 @@ void RetainCountChecker::processNonLeakError(ProgramStateRef St, C.isObjCGCEnabled(), SummaryLog, N, Sym); report->addRange(ErrorRange); - C.EmitReport(report); + C.emitReport(report); } //===----------------------------------------------------------------------===// @@ -3090,8 +3161,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { if (RetVal.isUnknown()) { // If the receiver is unknown, conjure a return value. SValBuilder &SVB = C.getSValBuilder(); - unsigned Count = C.getCurrentBlockCount(); - RetVal = SVB.getConjuredSymbolVal(0, CE, LCtx, ResultTy, Count); + RetVal = SVB.conjureSymbolVal(0, CE, LCtx, ResultTy, C.blockCount()); } state = state->BindExpr(CE, LCtx, RetVal, false); @@ -3105,8 +3175,7 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { Binding = getRefBinding(state, Sym); // Invalidate the argument region. - unsigned Count = C.getCurrentBlockCount(); - state = state->invalidateRegions(ArgRegion, CE, Count, LCtx); + state = state->invalidateRegions(ArgRegion, CE, C.blockCount(), LCtx); // Restore the refcount status of the argument. if (Binding) @@ -3121,12 +3190,6 @@ bool RetainCountChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { // Handle return statements. //===----------------------------------------------------------------------===// -// Return true if the current LocationContext has no caller context. -static bool inTopFrame(CheckerContext &C) { - const LocationContext *LC = C.getLocationContext(); - return LC->getParent() == 0; -} - void RetainCountChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { @@ -3135,7 +3198,7 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S, // better checking even for inlined calls, and see if they match // with their expected semantics (e.g., the method should return a retained // object, etc.). - if (!inTopFrame(C)) + if (!C.inTopFrame()) return; const Expr *RetE = S->getRetValue(); @@ -3196,8 +3259,8 @@ void RetainCountChecker::checkPreStmt(const ReturnStmt *S, // Update the autorelease counts. static SimpleProgramPointTag AutoreleaseTag("RetainCountChecker : Autorelease"); - GenericNodeBuilderRefCount Bd(C, &AutoreleaseTag); - llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, C, Sym, X); + llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, &AutoreleaseTag, + C, Sym, X); // Did we cache out? if (!Pred) @@ -3267,7 +3330,7 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, new CFRefLeakReport(*getLeakAtReturnBug(LOpts, GCEnabled), LOpts, GCEnabled, SummaryLog, N, Sym, C); - C.EmitReport(report); + C.emitReport(report); } } } @@ -3288,7 +3351,7 @@ void RetainCountChecker::checkReturnWithRetEffect(const ReturnStmt *S, new CFRefReport(*returnNotOwnedForOwned, C.getASTContext().getLangOpts(), C.isObjCGCEnabled(), SummaryLog, N, Sym); - C.EmitReport(report); + C.emitReport(report); } } } @@ -3354,18 +3417,19 @@ ProgramStateRef RetainCountChecker::evalAssume(ProgramStateRef state, // too bad since the number of symbols we will track in practice are // probably small and evalAssume is only called at branches and a few // other places. - RefBindings B = state->get<RefBindings>(); + RefBindingsTy B = state->get<RefBindings>(); if (B.isEmpty()) return state; bool changed = false; - RefBindings::Factory &RefBFactory = state->get_context<RefBindings>(); + RefBindingsTy::Factory &RefBFactory = state->get_context<RefBindings>(); - for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { - // Check if the symbol is null (or equal to any constant). - // If this is the case, stop tracking the symbol. - if (state->getSymVal(I.getKey())) { + for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { + // Check if the symbol is null stop tracking the symbol. + ConstraintManager &CMgr = state->getConstraintManager(); + ConditionTruthVal AllocFailed = CMgr.isNull(state, I.getKey()); + if (AllocFailed.isConstrainedTrue()) { changed = true; B = RefBFactory.remove(B, I.getKey()); } @@ -3410,8 +3474,8 @@ RetainCountChecker::checkRegionChanges(ProgramStateRef state, std::pair<ExplodedNode *, ProgramStateRef > RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, - GenericNodeBuilderRefCount Bd, ExplodedNode *Pred, + const ProgramPointTag *Tag, CheckerContext &Ctx, SymbolRef Sym, RefVal V) const { unsigned ACnt = V.getAutoreleaseCount(); @@ -3440,7 +3504,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, V.setAutoreleaseCount(0); } state = setRefBinding(state, Sym, V); - ExplodedNode *N = Bd.MakeNode(state, Pred); + ExplodedNode *N = Ctx.addTransition(state, Pred, Tag); if (N == 0) state = 0; return std::make_pair(N, state); @@ -3451,7 +3515,8 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, V = V ^ RefVal::ErrorOverAutorelease; state = setRefBinding(state, Sym, V); - if (ExplodedNode *N = Bd.MakeNode(state, Pred, true)) { + ExplodedNode *N = Ctx.generateSink(state, Pred, Tag); + if (N) { SmallString<128> sbuf; llvm::raw_svector_ostream os(sbuf); os << "Object over-autoreleased: object was sent -autorelease "; @@ -3466,7 +3531,7 @@ RetainCountChecker::handleAutoreleaseCounts(ProgramStateRef state, CFRefReport *report = new CFRefReport(*overAutorelease, LOpts, /* GCEnabled = */ false, SummaryLog, N, Sym, os.str()); - Ctx.EmitReport(report); + Ctx.emitReport(report); } return std::make_pair((ExplodedNode *)0, (ProgramStateRef )0); @@ -3492,14 +3557,13 @@ RetainCountChecker::handleSymbolDeath(ProgramStateRef state, ExplodedNode * RetainCountChecker::processLeaks(ProgramStateRef state, SmallVectorImpl<SymbolRef> &Leaked, - GenericNodeBuilderRefCount &Builder, CheckerContext &Ctx, ExplodedNode *Pred) const { if (Leaked.empty()) return Pred; // Generate an intermediate node representing the leak point. - ExplodedNode *N = Builder.MakeNode(state, Pred); + ExplodedNode *N = Ctx.addTransition(state, Pred); if (N) { for (SmallVectorImpl<SymbolRef>::iterator @@ -3513,7 +3577,7 @@ RetainCountChecker::processLeaks(ProgramStateRef state, CFRefLeakReport *report = new CFRefLeakReport(*BT, LOpts, GCEnabled, SummaryLog, N, *I, Ctx); - Ctx.EmitReport(report); + Ctx.emitReport(report); } } @@ -3522,13 +3586,12 @@ RetainCountChecker::processLeaks(ProgramStateRef state, void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const { ProgramStateRef state = Ctx.getState(); - GenericNodeBuilderRefCount Bd(Ctx); - RefBindings B = state->get<RefBindings>(); + RefBindingsTy B = state->get<RefBindings>(); ExplodedNode *Pred = Ctx.getPredecessor(); - for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { - llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, Ctx, - I->first, I->second); + for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { + llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, /*Tag=*/0, + Ctx, I->first, I->second); if (!state) return; } @@ -3543,10 +3606,10 @@ void RetainCountChecker::checkEndPath(CheckerContext &Ctx) const { B = state->get<RefBindings>(); SmallVector<SymbolRef, 10> Leaked; - for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) + for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) state = handleSymbolDeath(state, I->first, I->second, Leaked); - processLeaks(state, Leaked, Bd, Ctx, Pred); + processLeaks(state, Leaked, Ctx, Pred); } const ProgramPointTag * @@ -3567,7 +3630,7 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper, ExplodedNode *Pred = C.getPredecessor(); ProgramStateRef state = C.getState(); - RefBindings B = state->get<RefBindings>(); + RefBindingsTy B = state->get<RefBindings>(); // Update counts from autorelease pools for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), @@ -3576,8 +3639,8 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper, if (const RefVal *T = B.lookup(Sym)){ // Use the symbol as the tag. // FIXME: This might not be as unique as we would like. - GenericNodeBuilderRefCount Bd(C, getDeadSymbolTag(Sym)); - llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Bd, Pred, C, + const ProgramPointTag *Tag = getDeadSymbolTag(Sym); + llvm::tie(Pred, state) = handleAutoreleaseCounts(state, Pred, Tag, C, Sym, *T); if (!state) return; @@ -3593,17 +3656,14 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper, state = handleSymbolDeath(state, *I, *T, Leaked); } - { - GenericNodeBuilderRefCount Bd(C, this); - Pred = processLeaks(state, Leaked, Bd, C, Pred); - } + Pred = processLeaks(state, Leaked, C, Pred); // Did we cache out? if (!Pred) return; // Now generate a new node that nukes the old bindings. - RefBindings::Factory &F = state->get_context<RefBindings>(); + RefBindingsTy::Factory &F = state->get_context<RefBindings>(); for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I != E; ++I) @@ -3616,12 +3676,12 @@ void RetainCountChecker::checkDeadSymbols(SymbolReaper &SymReaper, void RetainCountChecker::printState(raw_ostream &Out, ProgramStateRef State, const char *NL, const char *Sep) const { - RefBindings B = State->get<RefBindings>(); + RefBindingsTy B = State->get<RefBindings>(); if (!B.isEmpty()) Out << Sep << NL; - for (RefBindings::iterator I = B.begin(), E = B.end(); I != E; ++I) { + for (RefBindingsTy::iterator I = B.begin(), E = B.end(); I != E; ++I) { Out << I->first << " : "; I->second.print(Out); Out << NL; diff --git a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp index 6e565932d556..f3560aad8de2 100644 --- a/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ReturnPointerRangeChecker.cpp @@ -82,7 +82,7 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS, new BugReport(*BT, BT->getDescription(), N); report->addRange(RetE->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); } } diff --git a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp index ca2a55d1e7bb..37ec1aa7bea0 100644 --- a/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/ReturnUndefChecker.cpp @@ -16,6 +16,7 @@ #include "ClangSACheckers.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" @@ -41,6 +42,19 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, if (!C.getState()->getSVal(RetE, C.getLocationContext()).isUndef()) return; + // "return;" is modeled to evaluate to an UndefinedValue. Allow UndefinedValue + // to be returned in functions returning void to support the following pattern: + // void foo() { + // return; + // } + // void test() { + // return foo(); + // } + const StackFrameContext *SFC = C.getStackFrame(); + QualType RT = CallEvent::getDeclaredResultType(SFC->getDecl()); + if (!RT.isNull() && RT->isSpecificBuiltinType(BuiltinType::Void)) + return; + ExplodedNode *N = C.generateSink(); if (!N) @@ -53,11 +67,10 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS, BugReport *report = new BugReport(*BT, BT->getDescription(), N); - report->disablePathPruning(); report->addRange(RetE->getSourceRange()); - bugreporter::addTrackNullOrUndefValueVisitor(N, RetE, report); + bugreporter::trackNullOrUndefValue(N, RetE, *report); - C.EmitReport(report); + C.emitReport(report); } void ento::registerReturnUndefChecker(CheckerManager &mgr) { diff --git a/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp new file mode 100644 index 000000000000..ee055adf6e4d --- /dev/null +++ b/lib/StaticAnalyzer/Checkers/SimpleStreamChecker.cpp @@ -0,0 +1,348 @@ +//===-- SimpleStreamChecker.cpp -----------------------------------------*- C++ -*--// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Defines a checker for proper use of fopen/fclose APIs. +// - If a file has been closed with fclose, it should not be accessed again. +// Accessing a closed file results in undefined behavior. +// - If a file was opened with fopen, it must be closed with fclose before +// the execution ends. Failing to do so results in a resource leak. +// +//===----------------------------------------------------------------------===// + +#include "ClangSACheckers.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" + +using namespace clang; +using namespace ento; + +namespace { +typedef llvm::SmallVector<SymbolRef, 2> SymbolVector; + +struct StreamState { +private: + enum Kind { Opened, Closed } K; + StreamState(Kind InK) : K(InK) { } + +public: + bool isOpened() const { return K == Opened; } + bool isClosed() const { return K == Closed; } + + static StreamState getOpened() { return StreamState(Opened); } + static StreamState getClosed() { return StreamState(Closed); } + + bool operator==(const StreamState &X) const { + return K == X.K; + } + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(K); + } +}; + +class SimpleStreamChecker : public Checker<check::PostCall, + check::PreCall, + check::DeadSymbols, + check::Bind, + check::RegionChanges> { + + mutable IdentifierInfo *IIfopen, *IIfclose; + + OwningPtr<BugType> DoubleCloseBugType; + OwningPtr<BugType> LeakBugType; + + void initIdentifierInfo(ASTContext &Ctx) const; + + void reportDoubleClose(SymbolRef FileDescSym, + const CallEvent &Call, + CheckerContext &C) const; + + void reportLeaks(SymbolVector LeakedStreams, + CheckerContext &C, + ExplodedNode *ErrNode) const; + + bool guaranteedNotToCloseFile(const CallEvent &Call) const; + +public: + SimpleStreamChecker(); + + /// Process fopen. + void checkPostCall(const CallEvent &Call, CheckerContext &C) const; + /// Process fclose. + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + + void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; + + /// Deal with symbol escape as a byproduct of a bind. + void checkBind(SVal location, SVal val, const Stmt*S, + CheckerContext &C) const; + + /// Deal with symbol escape as a byproduct of a region change. + ProgramStateRef + checkRegionChanges(ProgramStateRef state, + const StoreManager::InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call) const; + bool wantsRegionChangeUpdate(ProgramStateRef state) const { + return true; + } +}; + +} // end anonymous namespace + +/// The state of the checker is a map from tracked stream symbols to their +/// state. Let's store it in the ProgramState. +REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState) + +namespace { +class StopTrackingCallback : public SymbolVisitor { + ProgramStateRef state; +public: + StopTrackingCallback(ProgramStateRef st) : state(st) {} + ProgramStateRef getState() const { return state; } + + bool VisitSymbol(SymbolRef sym) { + state = state->remove<StreamMap>(sym); + return true; + } +}; +} // end anonymous namespace + + +SimpleStreamChecker::SimpleStreamChecker() : IIfopen(0), IIfclose(0) { + // Initialize the bug types. + DoubleCloseBugType.reset(new BugType("Double fclose", + "Unix Stream API Error")); + + LeakBugType.reset(new BugType("Resource Leak", + "Unix Stream API Error")); + // Sinks are higher importance bugs as well as calls to assert() or exit(0). + LeakBugType->setSuppressOnSink(true); +} + +void SimpleStreamChecker::checkPostCall(const CallEvent &Call, + CheckerContext &C) const { + initIdentifierInfo(C.getASTContext()); + + if (!Call.isGlobalCFunction()) + return; + + if (Call.getCalleeIdentifier() != IIfopen) + return; + + // Get the symbolic value corresponding to the file handle. + SymbolRef FileDesc = Call.getReturnValue().getAsSymbol(); + if (!FileDesc) + return; + + // Generate the next transition (an edge in the exploded graph). + ProgramStateRef State = C.getState(); + State = State->set<StreamMap>(FileDesc, StreamState::getOpened()); + C.addTransition(State); +} + +void SimpleStreamChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + initIdentifierInfo(C.getASTContext()); + + if (!Call.isGlobalCFunction()) + return; + + if (Call.getCalleeIdentifier() != IIfclose) + return; + + if (Call.getNumArgs() != 1) + return; + + // Get the symbolic value corresponding to the file handle. + SymbolRef FileDesc = Call.getArgSVal(0).getAsSymbol(); + if (!FileDesc) + return; + + // Check if the stream has already been closed. + ProgramStateRef State = C.getState(); + const StreamState *SS = State->get<StreamMap>(FileDesc); + if (SS && SS->isClosed()) { + reportDoubleClose(FileDesc, Call, C); + return; + } + + // Generate the next transition, in which the stream is closed. + State = State->set<StreamMap>(FileDesc, StreamState::getClosed()); + C.addTransition(State); +} + +static bool isLeaked(SymbolRef Sym, const StreamState &SS, + bool IsSymDead, ProgramStateRef State) { + if (IsSymDead && SS.isOpened()) { + // If a symbol is NULL, assume that fopen failed on this path. + // A symbol should only be considered leaked if it is non-null. + ConstraintManager &CMgr = State->getConstraintManager(); + ConditionTruthVal OpenFailed = CMgr.isNull(State, Sym); + return !OpenFailed.isConstrainedTrue(); + } + return false; +} + +void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + SymbolVector LeakedStreams; + StreamMapTy TrackedStreams = State->get<StreamMap>(); + for (StreamMapTy::iterator I = TrackedStreams.begin(), + E = TrackedStreams.end(); I != E; ++I) { + SymbolRef Sym = I->first; + bool IsSymDead = SymReaper.isDead(Sym); + + // Collect leaked symbols. + if (isLeaked(Sym, I->second, IsSymDead, State)) + LeakedStreams.push_back(Sym); + + // Remove the dead symbol from the streams map. + if (IsSymDead) + State = State->remove<StreamMap>(Sym); + } + + ExplodedNode *N = C.addTransition(State); + reportLeaks(LeakedStreams, C, N); +} + +void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym, + const CallEvent &Call, + CheckerContext &C) const { + // We reached a bug, stop exploring the path here by generating a sink. + ExplodedNode *ErrNode = C.generateSink(); + // If we've already reached this node on another path, return. + if (!ErrNode) + return; + + // Generate the report. + BugReport *R = new BugReport(*DoubleCloseBugType, + "Closing a previously closed file stream", ErrNode); + R->addRange(Call.getSourceRange()); + R->markInteresting(FileDescSym); + C.emitReport(R); +} + +void SimpleStreamChecker::reportLeaks(SymbolVector LeakedStreams, + CheckerContext &C, + ExplodedNode *ErrNode) const { + // Attach bug reports to the leak node. + // TODO: Identify the leaked file descriptor. + for (llvm::SmallVector<SymbolRef, 2>::iterator + I = LeakedStreams.begin(), E = LeakedStreams.end(); I != E; ++I) { + BugReport *R = new BugReport(*LeakBugType, + "Opened file is never closed; potential resource leak", ErrNode); + R->markInteresting(*I); + C.emitReport(R); + } +} + +// Check various ways a symbol can be invalidated. +// Stop tracking symbols when a value escapes as a result of checkBind. +// A value escapes in three possible cases: +// (1) We are binding to something that is not a memory region. +// (2) We are binding to a MemRegion that does not have stack storage +// (3) We are binding to a MemRegion with stack storage that the store +// does not understand. +void SimpleStreamChecker::checkBind(SVal loc, SVal val, const Stmt *S, + CheckerContext &C) const { + // Are we storing to something that causes the value to "escape"? + bool escapes = true; + ProgramStateRef state = C.getState(); + + if (loc::MemRegionVal *regionLoc = dyn_cast<loc::MemRegionVal>(&loc)) { + escapes = !regionLoc->getRegion()->hasStackStorage(); + + if (!escapes) { + // To test (3), generate a new state with the binding added. If it is + // the same state, then it escapes (since the store cannot represent + // the binding). Do this only if we know that the store is not supposed + // to generate the same state. + SVal StoredVal = state->getSVal(regionLoc->getRegion()); + if (StoredVal != val) + escapes = (state == (state->bindLoc(*regionLoc, val))); + } + } + + // If our store can represent the binding and we aren't storing to something + // that doesn't have local storage then just return the state and + // continue as is. + if (!escapes) + return; + + // Otherwise, find all symbols referenced by 'val' that we are tracking + // and stop tracking them. + state = state->scanReachableSymbols<StopTrackingCallback>(val).getState(); + C.addTransition(state); +} + +bool SimpleStreamChecker::guaranteedNotToCloseFile(const CallEvent &Call) const{ + // If it's not in a system header, assume it might close a file. + if (!Call.isInSystemHeader()) + return false; + + // Handle cases where we know a buffer's /address/ can escape. + if (Call.argumentsMayEscape()) + return false; + + // Note, even though fclose closes the file, we do not list it here + // since the checker is modeling the call. + + return true; +} + +// If the symbol we are tracking is invalidated, do not track the symbol as +// we cannot reason about it anymore. +ProgramStateRef +SimpleStreamChecker::checkRegionChanges(ProgramStateRef State, + const StoreManager::InvalidatedSymbols *invalidated, + ArrayRef<const MemRegion *> ExplicitRegions, + ArrayRef<const MemRegion *> Regions, + const CallEvent *Call) const { + + if (!invalidated || invalidated->empty()) + return State; + + // If it's a call which might close the file, we assume that all regions + // (explicit and implicit) escaped. Otherwise, whitelist explicit pointers + // (the parameters to the call); we still can track them. + llvm::SmallPtrSet<SymbolRef, 8> WhitelistedSymbols; + if (!Call || guaranteedNotToCloseFile(*Call)) { + for (ArrayRef<const MemRegion *>::iterator I = ExplicitRegions.begin(), + E = ExplicitRegions.end(); I != E; ++I) { + if (const SymbolicRegion *R = (*I)->StripCasts()->getAs<SymbolicRegion>()) + WhitelistedSymbols.insert(R->getSymbol()); + } + } + + for (StoreManager::InvalidatedSymbols::const_iterator I=invalidated->begin(), + E = invalidated->end(); I!=E; ++I) { + SymbolRef sym = *I; + if (WhitelistedSymbols.count(sym)) + continue; + // The symbol escaped. Optimistically, assume that the corresponding file + // handle will be closed somewhere else. + State = State->remove<StreamMap>(sym); + } + return State; +} + +void SimpleStreamChecker::initIdentifierInfo(ASTContext &Ctx) const { + if (IIfopen) + return; + IIfopen = &Ctx.Idents.get("fopen"); + IIfclose = &Ctx.Idents.get("fclose"); +} + +void ento::registerSimpleStreamChecker(CheckerManager &mgr) { + mgr.registerChecker<SimpleStreamChecker>(); +} diff --git a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp index 54cf5690c9ea..0c2f26683745 100644 --- a/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/StackAddrEscapeChecker.cpp @@ -109,7 +109,7 @@ void StackAddrEscapeChecker::EmitStackError(CheckerContext &C, const MemRegion * if (range.isValid()) report->addRange(range); - C.EmitReport(report); + C.emitReport(report); } void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, @@ -118,8 +118,10 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, const Expr *RetE = RS->getRetValue(); if (!RetE) return; - - SVal V = C.getState()->getSVal(RetE, C.getLocationContext()); + RetE = RetE->IgnoreParens(); + + const LocationContext *LCtx = C.getLocationContext(); + SVal V = C.getState()->getSVal(RetE, LCtx); const MemRegion *R = V.getAsRegion(); if (!R) @@ -132,8 +134,9 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, return; // Return stack memory in an ancestor stack frame is fine. - const StackFrameContext *SFC = SS->getStackFrame(); - if (SFC != C.getLocationContext()->getCurrentStackFrame()) + const StackFrameContext *CurFrame = LCtx->getCurrentStackFrame(); + const StackFrameContext *MemFrame = SS->getStackFrame(); + if (MemFrame != CurFrame) return; // Automatic reference counting automatically copies blocks. @@ -141,6 +144,14 @@ void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS, isa<BlockDataRegion>(R)) return; + // Returning a record by value is fine. (In this case, the returned + // expression will be a copy-constructor, possibly wrapped in an + // ExprWithCleanups node.) + if (const ExprWithCleanups *Cleanup = dyn_cast<ExprWithCleanups>(RetE)) + RetE = Cleanup->getSubExpr(); + if (isa<CXXConstructExpr>(RetE) && RetE->getType()->isRecordType()) + return; + EmitStackError(C, R, RetE); } @@ -221,7 +232,7 @@ void StackAddrEscapeChecker::checkEndPath(CheckerContext &Ctx) const { if (range.isValid()) report->addRange(range); - Ctx.EmitReport(report); + Ctx.emitReport(report); } } diff --git a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 731dd66b460b..c06ba7c304e6 100644 --- a/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -104,15 +104,8 @@ private: } // end anonymous namespace -namespace clang { -namespace ento { - template <> - struct ProgramStateTrait<StreamState> - : public ProgramStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > { - static void *GDMIndex() { static int x; return &x; } - }; -} -} +REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState) + bool StreamChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { const FunctionDecl *FD = C.getCalleeDecl(CE); @@ -219,11 +212,11 @@ void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) const { void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const { ProgramStateRef state = C.getState(); - unsigned Count = C.getCurrentBlockCount(); SValBuilder &svalBuilder = C.getSValBuilder(); const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); DefinedSVal RetVal = - cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, LCtx, Count)); + cast<DefinedSVal>(svalBuilder.conjureSymbolVal(0, CE, LCtx, + C.blockCount())); state = state->BindExpr(CE, C.getLocationContext(), RetVal); ConstraintManager &CM = C.getConstraintManager(); @@ -235,9 +228,9 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const { if (SymbolRef Sym = RetVal.getAsSymbol()) { // if RetVal is not NULL, set the symbol's state to Opened. stateNotNull = - stateNotNull->set<StreamState>(Sym,StreamState::getOpened(CE)); + stateNotNull->set<StreamMap>(Sym,StreamState::getOpened(CE)); stateNull = - stateNull->set<StreamState>(Sym, StreamState::getOpenFailed(CE)); + stateNull->set<StreamMap>(Sym, StreamState::getOpenFailed(CE)); C.addTransition(stateNotNull); C.addTransition(stateNull); @@ -287,7 +280,7 @@ void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const { "SEEK_SET, SEEK_END, or SEEK_CUR.")); BugReport *R = new BugReport(*BT_illegalwhence, BT_illegalwhence->getDescription(), N); - C.EmitReport(R); + C.emitReport(R); } } @@ -363,7 +356,7 @@ ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state, BT_nullfp.reset(new BuiltinBug("NULL stream pointer", "Stream pointer might be NULL.")); BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N); - C.EmitReport(R); + C.emitReport(R); } return 0; } @@ -378,7 +371,7 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE, if (!Sym) return state; - const StreamState *SS = state->get<StreamState>(Sym); + const StreamState *SS = state->get<StreamMap>(Sym); // If the file stream is not tracked, return. if (!SS) @@ -395,22 +388,24 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE, " closed. Cause undefined behaviour.")); BugReport *R = new BugReport(*BT_doubleclose, BT_doubleclose->getDescription(), N); - C.EmitReport(R); + C.emitReport(R); } return NULL; } // Close the File Descriptor. - return state->set<StreamState>(Sym, StreamState::getClosed(CE)); + return state->set<StreamMap>(Sym, StreamState::getClosed(CE)); } void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { + // TODO: Clean up the state. for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(), E = SymReaper.dead_end(); I != E; ++I) { SymbolRef Sym = *I; ProgramStateRef state = C.getState(); - const StreamState *SS = state->get<StreamState>(Sym); + const StreamState *SS = state->get<StreamMap>(Sym); + // TODO: Shouldn't we have a continue here? if (!SS) return; @@ -422,7 +417,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, "Opened File never closed. Potential Resource leak.")); BugReport *R = new BugReport(*BT_ResourceLeak, BT_ResourceLeak->getDescription(), N); - C.EmitReport(R); + C.emitReport(R); } } } @@ -430,10 +425,9 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, void StreamChecker::checkEndPath(CheckerContext &Ctx) const { ProgramStateRef state = Ctx.getState(); - typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap; - SymMap M = state->get<StreamState>(); + StreamMapTy M = state->get<StreamMap>(); - for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) { + for (StreamMapTy::iterator I = M.begin(), E = M.end(); I != E; ++I) { StreamState SS = I->second; if (SS.isOpened()) { ExplodedNode *N = Ctx.addTransition(state); @@ -443,7 +437,7 @@ void StreamChecker::checkEndPath(CheckerContext &Ctx) const { "Opened File never closed. Potential Resource leak.")); BugReport *R = new BugReport(*BT_ResourceLeak, BT_ResourceLeak->getDescription(), N); - Ctx.EmitReport(R); + Ctx.emitReport(R); } } } @@ -460,12 +454,12 @@ void StreamChecker::checkPreStmt(const ReturnStmt *S, CheckerContext &C) const { if (!Sym) return; - const StreamState *SS = state->get<StreamState>(Sym); + const StreamState *SS = state->get<StreamMap>(Sym); if(!SS) return; if (SS->isOpened()) - state = state->set<StreamState>(Sym, StreamState::getEscaped(S)); + state = state->set<StreamMap>(Sym, StreamState::getEscaped(S)); C.addTransition(state); } diff --git a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp index 113368254d67..382be8475bb8 100644 --- a/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/TaintTesterChecker.cpp @@ -52,7 +52,7 @@ void TaintTesterChecker::checkPostStmt(const Expr *E, initBugType(); BugReport *report = new BugReport(*BT, "tainted",N); report->addRange(E->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); } } } diff --git a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp index 70a33c76db0c..70e141e574cd 100644 --- a/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefBranchChecker.cpp @@ -99,11 +99,10 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition, // Emit the bug report. BugReport *R = new BugReport(*BT, BT->getDescription(), N); - bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, R); + bugreporter::trackNullOrUndefValue(N, Ex, *R); R->addRange(Ex->getSourceRange()); - R->disablePathPruning(); - Ctx.EmitReport(R); + Ctx.emitReport(R); } } } diff --git a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp index 675b38a5df26..30ccffaab055 100644 --- a/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefCapturedBlockVarChecker.cpp @@ -96,7 +96,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE, R->addVisitor(new FindLastStoreBRVisitor(VRVal, VR)); R->disablePathPruning(); // need location of block - C.EmitReport(R); + C.emitReport(R); } } } diff --git a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp index e220499d73f4..415bab57287e 100644 --- a/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefResultChecker.cpp @@ -76,13 +76,12 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B, BugReport *report = new BugReport(*BT, OS.str(), N); if (Ex) { report->addRange(Ex->getSourceRange()); - bugreporter::addTrackNullOrUndefValueVisitor(N, Ex, report); + bugreporter::trackNullOrUndefValue(N, Ex, *report); } else - bugreporter::addTrackNullOrUndefValueVisitor(N, B, report); + bugreporter::trackNullOrUndefValue(N, B, *report); - report->disablePathPruning(); - C.EmitReport(report); + C.emitReport(report); } } diff --git a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp index 6ae3c1875fbf..b3a83e8e9179 100644 --- a/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefinedArraySubscriptChecker.cpp @@ -42,8 +42,8 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A, // Generate a report for this bug. BugReport *R = new BugReport(*BT, BT->getName(), N); R->addRange(A->getIdx()->getSourceRange()); - bugreporter::addTrackNullOrUndefValueVisitor(N, A->getIdx(), R); - C.EmitReport(R); + bugreporter::trackNullOrUndefValue(N, A->getIdx(), *R); + C.emitReport(R); } } } diff --git a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp index 14a884e01b64..410010a335c3 100644 --- a/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UndefinedAssignmentChecker.cpp @@ -78,10 +78,9 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val, BugReport *R = new BugReport(*BT, str, N); if (ex) { R->addRange(ex->getSourceRange()); - bugreporter::addTrackNullOrUndefValueVisitor(N, ex, R); + bugreporter::trackNullOrUndefValue(N, ex, *R); } - R->disablePathPruning(); - C.EmitReport(R); + C.emitReport(R); } void ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) { diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp index d35455c2191b..171e15b85ae7 100644 --- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp @@ -41,6 +41,7 @@ public: void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const; void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const; void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const; + void CheckReallocfZero(CheckerContext &C, const CallExpr *CE) const; void CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const; void CheckVallocZero(CheckerContext &C, const CallExpr *CE) const; @@ -138,7 +139,7 @@ void UnixAPIChecker::CheckOpen(CheckerContext &C, const CallExpr *CE) const { "Call to 'open' requires a third argument when " "the 'O_CREAT' flag is set", N); report->addRange(oflagsEx->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); } } @@ -183,11 +184,12 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C, BugReport *report = new BugReport(*BT_pthreadOnce, os.str(), N); report->addRange(CE->getArg(0)->getSourceRange()); - C.EmitReport(report); + C.emitReport(report); } //===----------------------------------------------------------------------===// -// "calloc", "malloc", "realloc", "alloca" and "valloc" with allocation size 0 +// "calloc", "malloc", "realloc", "reallocf", "alloca" and "valloc" +// with allocation size 0 //===----------------------------------------------------------------------===// // FIXME: Eventually these should be rolled into the MallocChecker, but right now // they're more basic and valuable for widespread use. @@ -224,8 +226,8 @@ bool UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C, BugReport *report = new BugReport(*BT_mallocZero, os.str(), N); report->addRange(arg->getSourceRange()); - bugreporter::addTrackNullOrUndefValueVisitor(N, arg, report); - C.EmitReport(report); + bugreporter::trackNullOrUndefValue(N, arg, *report); + C.emitReport(report); return true; } @@ -307,6 +309,11 @@ void UnixAPIChecker::CheckReallocZero(CheckerContext &C, BasicAllocationCheck(C, CE, 2, 1, "realloc"); } +void UnixAPIChecker::CheckReallocfZero(CheckerContext &C, + const CallExpr *CE) const { + BasicAllocationCheck(C, CE, 2, 1, "reallocf"); +} + void UnixAPIChecker::CheckAllocaZero(CheckerContext &C, const CallExpr *CE) const { BasicAllocationCheck(C, CE, 1, 0, "alloca"); @@ -339,6 +346,7 @@ void UnixAPIChecker::checkPreStmt(const CallExpr *CE, .Case("calloc", &UnixAPIChecker::CheckCallocZero) .Case("malloc", &UnixAPIChecker::CheckMallocZero) .Case("realloc", &UnixAPIChecker::CheckReallocZero) + .Case("reallocf", &UnixAPIChecker::CheckReallocfZero) .Cases("alloca", "__builtin_alloca", &UnixAPIChecker::CheckAllocaZero) .Case("valloc", &UnixAPIChecker::CheckVallocZero) .Default(NULL); diff --git a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp index fab4adf3e0e2..58f9ec0f9b9b 100644 --- a/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/VLASizeChecker.cpp @@ -69,8 +69,8 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind, BugReport *report = new BugReport(*BT, os.str(), N); report->addRange(SizeE->getSourceRange()); - bugreporter::addTrackNullOrUndefValueVisitor(N, SizeE, report); - C.EmitReport(report); + bugreporter::trackNullOrUndefValue(N, SizeE, *report); + C.emitReport(report); return; } diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp index efeba17a62ba..011d4c09a23f 100644 --- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -20,33 +20,19 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, StoreManagerCreator storemgr, ConstraintManagerCreator constraintmgr, CheckerManager *checkerMgr, - unsigned maxnodes, unsigned maxvisit, - bool vizdot, bool vizubi, - AnalysisPurgeMode purge, - bool eager, bool trim, - bool useUnoptimizedCFG, - bool addImplicitDtors, - bool eagerlyTrimEGraph, - AnalysisIPAMode ipa, - unsigned inlineMaxStack, - unsigned inlineMaxFunctionSize, - AnalysisInliningMode IMode, - bool NoRetry) - : AnaCtxMgr(useUnoptimizedCFG, addImplicitDtors, /*addInitializers=*/true), - Ctx(ctx), Diags(diags), LangOpts(lang), + AnalyzerOptions &Options) + : AnaCtxMgr(Options.UnoptimizedCFG, + /*AddImplicitDtors=*/true, + /*AddInitializers=*/true, + Options.includeTemporaryDtorsInCFG(), + Options.shouldSynthesizeBodies()), + Ctx(ctx), + Diags(diags), + LangOpts(lang), PathConsumers(PDC), CreateStoreMgr(storemgr), CreateConstraintMgr(constraintmgr), - CheckerMgr(checkerMgr), - MaxNodes(maxnodes), MaxVisit(maxvisit), - VisualizeEGDot(vizdot), VisualizeEGUbi(vizubi), PurgeDead(purge), - EagerlyAssume(eager), TrimGraph(trim), - EagerlyTrimEGraph(eagerlyTrimEGraph), - IPAMode(ipa), - InlineMaxStackDepth(inlineMaxStack), - InlineMaxFunctionSize(inlineMaxFunctionSize), - InliningMode(IMode), - NoRetryExhausted(NoRetry) -{ + CheckerMgr(checkerMgr), + options(Options) { AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); } diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp new file mode 100644 index 000000000000..da88589c8696 --- /dev/null +++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -0,0 +1,138 @@ +//===-- AnalyzerOptions.cpp - Analysis Engine Options -----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains special accessors for analyzer configuration options +// with string representations. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace llvm; + +bool +AnalyzerOptions::mayInlineCXXMemberFunction(CXXInlineableMemberKind K) { + if (IPAMode < Inlining) + return false; + + if (!CXXMemberInliningMode) { + static const char *ModeKey = "c++-inlining"; + + StringRef ModeStr(Config.GetOrCreateValue(ModeKey, + "methods").getValue()); + + CXXInlineableMemberKind &MutableMode = + const_cast<CXXInlineableMemberKind &>(CXXMemberInliningMode); + + MutableMode = llvm::StringSwitch<CXXInlineableMemberKind>(ModeStr) + .Case("constructors", CIMK_Constructors) + .Case("destructors", CIMK_Destructors) + .Case("none", CIMK_None) + .Case("methods", CIMK_MemberFunctions) + .Default(CXXInlineableMemberKind()); + + if (!MutableMode) { + // FIXME: We should emit a warning here about an unknown inlining kind, + // but the AnalyzerOptions doesn't have access to a diagnostic engine. + MutableMode = CIMK_None; + } + } + + return CXXMemberInliningMode >= K; +} + +static StringRef toString(bool b) { return b ? "true" : "false"; } + +bool AnalyzerOptions::getBooleanOption(StringRef Name, bool DefaultVal) { + // FIXME: We should emit a warning here if the value is something other than + // "true", "false", or the empty string (meaning the default value), + // but the AnalyzerOptions doesn't have access to a diagnostic engine. + StringRef V(Config.GetOrCreateValue(Name, toString(DefaultVal)).getValue()); + return llvm::StringSwitch<bool>(V) + .Case("true", true) + .Case("false", false) + .Default(DefaultVal); +} + +bool AnalyzerOptions::getBooleanOption(llvm::Optional<bool> &V, + StringRef Name, + bool DefaultVal) { + if (!V.hasValue()) + V = getBooleanOption(Name, DefaultVal); + return V.getValue(); +} + +bool AnalyzerOptions::includeTemporaryDtorsInCFG() { + return getBooleanOption(IncludeTemporaryDtorsInCFG, + "cfg-temporary-dtors", + /* Default = */ false); +} + +bool AnalyzerOptions::mayInlineCXXStandardLibrary() { + return getBooleanOption(InlineCXXStandardLibrary, + "c++-stdlib-inlining", + /*Default=*/true); +} + +bool AnalyzerOptions::mayInlineTemplateFunctions() { + return getBooleanOption(InlineTemplateFunctions, + "c++-template-inlining", + /*Default=*/true); +} + +bool AnalyzerOptions::mayInlineObjCMethod() { + return getBooleanOption(ObjCInliningMode, + "objc-inlining", + /* Default = */ true); +} + +bool AnalyzerOptions::shouldPruneNullReturnPaths() { + return getBooleanOption(PruneNullReturnPaths, + "suppress-null-return-paths", + /* Default = */ true); +} + +bool AnalyzerOptions::shouldAvoidSuppressingNullArgumentPaths() { + return getBooleanOption(AvoidSuppressingNullArgumentPaths, + "avoid-suppressing-null-argument-paths", + /* Default = */ false); +} + +int AnalyzerOptions::getOptionAsInteger(StringRef Name, int DefaultVal) { + llvm::SmallString<10> StrBuf; + llvm::raw_svector_ostream OS(StrBuf); + OS << DefaultVal; + + StringRef V(Config.GetOrCreateValue(Name, OS.str()).getValue()); + int Res = DefaultVal; + bool b = V.getAsInteger(10, Res); + assert(!b && "analyzer-config option should be numeric"); + (void) b; + return Res; +} + +unsigned AnalyzerOptions::getAlwaysInlineSize() { + if (!AlwaysInlineSize.hasValue()) + AlwaysInlineSize = getOptionAsInteger("ipa-always-inline-size", 3); + return AlwaysInlineSize.getValue(); +} + +unsigned AnalyzerOptions::getGraphTrimInterval() { + if (!GraphTrimInterval.hasValue()) + GraphTrimInterval = getOptionAsInteger("graph-trim-interval", 1000); + return GraphTrimInterval.getValue(); +} + +bool AnalyzerOptions::shouldSynthesizeBodies() { + return getBooleanOption("faux-bodies", true); +} diff --git a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp b/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp deleted file mode 100644 index 8897756a92d9..000000000000 --- a/lib/StaticAnalyzer/Core/BasicConstraintManager.cpp +++ /dev/null @@ -1,446 +0,0 @@ -//== BasicConstraintManager.cpp - Manage basic constraints.------*- C++ -*--==// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines BasicConstraintManager, a class that tracks simple -// equality and inequality constraints on symbolic values of ProgramState. -// -//===----------------------------------------------------------------------===// - -#include "SimpleConstraintManager.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" -#include "llvm/Support/raw_ostream.h" - -using namespace clang; -using namespace ento; - - -namespace { class ConstNotEq {}; } -namespace { class ConstEq {}; } - -typedef llvm::ImmutableMap<SymbolRef,ProgramState::IntSetTy> ConstNotEqTy; -typedef llvm::ImmutableMap<SymbolRef,const llvm::APSInt*> ConstEqTy; - -static int ConstEqIndex = 0; -static int ConstNotEqIndex = 0; - -namespace clang { -namespace ento { -template<> -struct ProgramStateTrait<ConstNotEq> : - public ProgramStatePartialTrait<ConstNotEqTy> { - static inline void *GDMIndex() { return &ConstNotEqIndex; } -}; - -template<> -struct ProgramStateTrait<ConstEq> : public ProgramStatePartialTrait<ConstEqTy> { - static inline void *GDMIndex() { return &ConstEqIndex; } -}; -} -} - -namespace { -// BasicConstraintManager only tracks equality and inequality constraints of -// constants and integer variables. -class BasicConstraintManager - : public SimpleConstraintManager { - ProgramState::IntSetTy::Factory ISetFactory; -public: - BasicConstraintManager(ProgramStateManager &statemgr, SubEngine &subengine) - : SimpleConstraintManager(subengine, statemgr.getBasicVals()), - ISetFactory(statemgr.getAllocator()) {} - - ProgramStateRef assumeSymEquality(ProgramStateRef State, SymbolRef Sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment, - bool Assumption); - - ProgramStateRef assumeSymNE(ProgramStateRef State, SymbolRef Sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) { - return assumeSymEquality(State, Sym, V, Adjustment, false); - } - - ProgramStateRef assumeSymEQ(ProgramStateRef State, SymbolRef Sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) { - return assumeSymEquality(State, Sym, V, Adjustment, true); - } - - ProgramStateRef assumeSymLT(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V, - const llvm::APSInt& Adjustment); - - ProgramStateRef assumeSymGT(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V, - const llvm::APSInt& Adjustment); - - ProgramStateRef assumeSymGE(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V, - const llvm::APSInt& Adjustment); - - ProgramStateRef assumeSymLE(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V, - const llvm::APSInt& Adjustment); - - ProgramStateRef AddEQ(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V); - - ProgramStateRef AddNE(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V); - - const llvm::APSInt* getSymVal(ProgramStateRef state, - SymbolRef sym) const; - - bool isNotEqual(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V) const; - - bool isEqual(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V) const; - - ProgramStateRef removeDeadBindings(ProgramStateRef state, - SymbolReaper& SymReaper); - - bool performTest(llvm::APSInt SymVal, llvm::APSInt Adjustment, - BinaryOperator::Opcode Op, llvm::APSInt ComparisonVal); - - void print(ProgramStateRef state, - raw_ostream &Out, - const char* nl, - const char *sep); -}; - -} // end anonymous namespace - -ConstraintManager* -ento::CreateBasicConstraintManager(ProgramStateManager& statemgr, - SubEngine &subengine) { - return new BasicConstraintManager(statemgr, subengine); -} - -// FIXME: This is a more general utility and should live somewhere else. -bool BasicConstraintManager::performTest(llvm::APSInt SymVal, - llvm::APSInt Adjustment, - BinaryOperator::Opcode Op, - llvm::APSInt ComparisonVal) { - APSIntType Type(Adjustment); - Type.apply(SymVal); - Type.apply(ComparisonVal); - SymVal += Adjustment; - - assert(BinaryOperator::isComparisonOp(Op)); - BasicValueFactory &BVF = getBasicVals(); - const llvm::APSInt *Result = BVF.evalAPSInt(Op, SymVal, ComparisonVal); - assert(Result && "Comparisons should always have valid results."); - - return Result->getBoolValue(); -} - -ProgramStateRef -BasicConstraintManager::assumeSymEquality(ProgramStateRef State, SymbolRef Sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment, - bool Assumption) { - // Before we do any real work, see if the value can even show up. - APSIntType AdjustmentType(Adjustment); - if (AdjustmentType.testInRange(V) != APSIntType::RTR_Within) - return Assumption ? NULL : State; - - // Get the symbol type. - BasicValueFactory &BVF = getBasicVals(); - ASTContext &Ctx = BVF.getContext(); - APSIntType SymbolType = BVF.getAPSIntType(Sym->getType(Ctx)); - - // First, see if the adjusted value is within range for the symbol. - llvm::APSInt Adjusted = AdjustmentType.convert(V) - Adjustment; - if (SymbolType.testInRange(Adjusted) != APSIntType::RTR_Within) - return Assumption ? NULL : State; - - // Now we can do things properly in the symbol space. - SymbolType.apply(Adjusted); - - // Second, determine if sym == X, where X+Adjustment != V. - if (const llvm::APSInt *X = getSymVal(State, Sym)) { - bool IsFeasible = (*X == Adjusted); - return (IsFeasible == Assumption) ? State : NULL; - } - - // Third, determine if we already know sym+Adjustment != V. - if (isNotEqual(State, Sym, Adjusted)) - return Assumption ? NULL : State; - - // If we reach here, sym is not a constant and we don't know if it is != V. - // Make the correct assumption. - if (Assumption) - return AddEQ(State, Sym, Adjusted); - else - return AddNE(State, Sym, Adjusted); -} - -// The logic for these will be handled in another ConstraintManager. -// Approximate it here anyway by handling some edge cases. -ProgramStateRef -BasicConstraintManager::assumeSymLT(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) { - APSIntType ComparisonType(V), AdjustmentType(Adjustment); - - // Is 'V' out of range above the type? - llvm::APSInt Max = AdjustmentType.getMaxValue(); - if (V > ComparisonType.convert(Max)) { - // This path is trivially feasible. - return state; - } - - // Is 'V' the smallest possible value, or out of range below the type? - llvm::APSInt Min = AdjustmentType.getMinValue(); - if (V <= ComparisonType.convert(Min)) { - // sym cannot be any value less than 'V'. This path is infeasible. - return NULL; - } - - // Reject a path if the value of sym is a constant X and !(X+Adj < V). - if (const llvm::APSInt *X = getSymVal(state, sym)) { - bool isFeasible = performTest(*X, Adjustment, BO_LT, V); - return isFeasible ? state : NULL; - } - - // FIXME: For now have assuming x < y be the same as assuming sym != V; - return assumeSymNE(state, sym, V, Adjustment); -} - -ProgramStateRef -BasicConstraintManager::assumeSymGT(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) { - APSIntType ComparisonType(V), AdjustmentType(Adjustment); - - // Is 'V' the largest possible value, or out of range above the type? - llvm::APSInt Max = AdjustmentType.getMaxValue(); - if (V >= ComparisonType.convert(Max)) { - // sym cannot be any value greater than 'V'. This path is infeasible. - return NULL; - } - - // Is 'V' out of range below the type? - llvm::APSInt Min = AdjustmentType.getMinValue(); - if (V < ComparisonType.convert(Min)) { - // This path is trivially feasible. - return state; - } - - // Reject a path if the value of sym is a constant X and !(X+Adj > V). - if (const llvm::APSInt *X = getSymVal(state, sym)) { - bool isFeasible = performTest(*X, Adjustment, BO_GT, V); - return isFeasible ? state : NULL; - } - - // FIXME: For now have assuming x > y be the same as assuming sym != V; - return assumeSymNE(state, sym, V, Adjustment); -} - -ProgramStateRef -BasicConstraintManager::assumeSymGE(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) { - APSIntType ComparisonType(V), AdjustmentType(Adjustment); - - // Is 'V' the largest possible value, or out of range above the type? - llvm::APSInt Max = AdjustmentType.getMaxValue(); - ComparisonType.apply(Max); - - if (V > Max) { - // sym cannot be any value greater than 'V'. This path is infeasible. - return NULL; - } else if (V == Max) { - // If the path is feasible then as a consequence we know that - // 'sym+Adjustment == V' because there are no larger values. - // Add this constraint. - return assumeSymEQ(state, sym, V, Adjustment); - } - - // Is 'V' out of range below the type? - llvm::APSInt Min = AdjustmentType.getMinValue(); - if (V < ComparisonType.convert(Min)) { - // This path is trivially feasible. - return state; - } - - // Reject a path if the value of sym is a constant X and !(X+Adj >= V). - if (const llvm::APSInt *X = getSymVal(state, sym)) { - bool isFeasible = performTest(*X, Adjustment, BO_GE, V); - return isFeasible ? state : NULL; - } - - return state; -} - -ProgramStateRef -BasicConstraintManager::assumeSymLE(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt &V, - const llvm::APSInt &Adjustment) { - APSIntType ComparisonType(V), AdjustmentType(Adjustment); - - // Is 'V' out of range above the type? - llvm::APSInt Max = AdjustmentType.getMaxValue(); - if (V > ComparisonType.convert(Max)) { - // This path is trivially feasible. - return state; - } - - // Is 'V' the smallest possible value, or out of range below the type? - llvm::APSInt Min = AdjustmentType.getMinValue(); - ComparisonType.apply(Min); - - if (V < Min) { - // sym cannot be any value less than 'V'. This path is infeasible. - return NULL; - } else if (V == Min) { - // If the path is feasible then as a consequence we know that - // 'sym+Adjustment == V' because there are no smaller values. - // Add this constraint. - return assumeSymEQ(state, sym, V, Adjustment); - } - - // Reject a path if the value of sym is a constant X and !(X+Adj >= V). - if (const llvm::APSInt *X = getSymVal(state, sym)) { - bool isFeasible = performTest(*X, Adjustment, BO_LE, V); - return isFeasible ? state : NULL; - } - - return state; -} - -ProgramStateRef BasicConstraintManager::AddEQ(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V) { - // Now that we have an actual value, we can throw out the NE-set. - // Create a new state with the old bindings replaced. - state = state->remove<ConstNotEq>(sym); - return state->set<ConstEq>(sym, &getBasicVals().getValue(V)); -} - -ProgramStateRef BasicConstraintManager::AddNE(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V) { - - // First, retrieve the NE-set associated with the given symbol. - ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym); - ProgramState::IntSetTy S = T ? *T : ISetFactory.getEmptySet(); - - // Now add V to the NE set. - S = ISetFactory.add(S, &getBasicVals().getValue(V)); - - // Create a new state with the old binding replaced. - return state->set<ConstNotEq>(sym, S); -} - -const llvm::APSInt* BasicConstraintManager::getSymVal(ProgramStateRef state, - SymbolRef sym) const { - const ConstEqTy::data_type* T = state->get<ConstEq>(sym); - return T ? *T : NULL; -} - -bool BasicConstraintManager::isNotEqual(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V) const { - - // Retrieve the NE-set associated with the given symbol. - const ConstNotEqTy::data_type* T = state->get<ConstNotEq>(sym); - - // See if V is present in the NE-set. - return T ? T->contains(&getBasicVals().getValue(V)) : false; -} - -bool BasicConstraintManager::isEqual(ProgramStateRef state, - SymbolRef sym, - const llvm::APSInt& V) const { - // Retrieve the EQ-set associated with the given symbol. - const ConstEqTy::data_type* T = state->get<ConstEq>(sym); - // See if V is present in the EQ-set. - return T ? **T == V : false; -} - -/// Scan all symbols referenced by the constraints. If the symbol is not alive -/// as marked in LSymbols, mark it as dead in DSymbols. -ProgramStateRef -BasicConstraintManager::removeDeadBindings(ProgramStateRef state, - SymbolReaper& SymReaper) { - - ConstEqTy CE = state->get<ConstEq>(); - ConstEqTy::Factory& CEFactory = state->get_context<ConstEq>(); - - for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) { - SymbolRef sym = I.getKey(); - if (SymReaper.maybeDead(sym)) - CE = CEFactory.remove(CE, sym); - } - state = state->set<ConstEq>(CE); - - ConstNotEqTy CNE = state->get<ConstNotEq>(); - ConstNotEqTy::Factory& CNEFactory = state->get_context<ConstNotEq>(); - - for (ConstNotEqTy::iterator I = CNE.begin(), E = CNE.end(); I != E; ++I) { - SymbolRef sym = I.getKey(); - if (SymReaper.maybeDead(sym)) - CNE = CNEFactory.remove(CNE, sym); - } - - return state->set<ConstNotEq>(CNE); -} - -void BasicConstraintManager::print(ProgramStateRef state, - raw_ostream &Out, - const char* nl, const char *sep) { - // Print equality constraints. - - ConstEqTy CE = state->get<ConstEq>(); - - if (!CE.isEmpty()) { - Out << nl << sep << "'==' constraints:"; - for (ConstEqTy::iterator I = CE.begin(), E = CE.end(); I!=E; ++I) - Out << nl << " $" << I.getKey() << " : " << *I.getData(); - } - - // Print != constraints. - - ConstNotEqTy CNE = state->get<ConstNotEq>(); - - if (!CNE.isEmpty()) { - Out << nl << sep << "'!=' constraints:"; - - for (ConstNotEqTy::iterator I = CNE.begin(), EI = CNE.end(); I!=EI; ++I) { - Out << nl << " $" << I.getKey() << " : "; - bool isFirst = true; - - ProgramState::IntSetTy::iterator J = I.getData().begin(), - EJ = I.getData().end(); - - for ( ; J != EJ; ++J) { - if (isFirst) isFirst = false; - else Out << ", "; - - Out << (*J)->getSExtValue(); // Hack: should print to raw_ostream. - } - } - } -} diff --git a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp index 20c73612c481..a6c400f3704d 100644 --- a/lib/StaticAnalyzer/Core/BasicValueFactory.cpp +++ b/lib/StaticAnalyzer/Core/BasicValueFactory.cpp @@ -101,11 +101,7 @@ const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, unsigned BitWidth, const llvm::APSInt& BasicValueFactory::getValue(uint64_t X, QualType T) { - unsigned bits = Ctx.getTypeSize(T); - llvm::APSInt V(bits, - T->isUnsignedIntegerOrEnumerationType() || Loc::isLocType(T)); - V = X; - return getValue(V); + return getValue(getAPSIntType(T).getValue(X)); } const CompoundValData* diff --git a/lib/StaticAnalyzer/Core/BugReporter.cpp b/lib/StaticAnalyzer/Core/BugReporter.cpp index 571baecd729d..c898d65a5f95 100644 --- a/lib/StaticAnalyzer/Core/BugReporter.cpp +++ b/lib/StaticAnalyzer/Core/BugReporter.cpp @@ -118,10 +118,82 @@ GetCurrentOrNextStmt(const ExplodedNode *N) { // Diagnostic cleanup. //===----------------------------------------------------------------------===// +static PathDiagnosticEventPiece * +eventsDescribeSameCondition(PathDiagnosticEventPiece *X, + PathDiagnosticEventPiece *Y) { + // Prefer diagnostics that come from ConditionBRVisitor over + // those that came from TrackConstraintBRVisitor. + const void *tagPreferred = ConditionBRVisitor::getTag(); + const void *tagLesser = TrackConstraintBRVisitor::getTag(); + + if (X->getLocation() != Y->getLocation()) + return 0; + + if (X->getTag() == tagPreferred && Y->getTag() == tagLesser) + return X; + + if (Y->getTag() == tagPreferred && X->getTag() == tagLesser) + return Y; + + return 0; +} + +/// An optimization pass over PathPieces that removes redundant diagnostics +/// generated by both ConditionBRVisitor and TrackConstraintBRVisitor. Both +/// BugReporterVisitors use different methods to generate diagnostics, with +/// one capable of emitting diagnostics in some cases but not in others. This +/// can lead to redundant diagnostic pieces at the same point in a path. +static void removeRedundantMsgs(PathPieces &path) { + unsigned N = path.size(); + if (N < 2) + return; + // NOTE: this loop intentionally is not using an iterator. Instead, we + // are streaming the path and modifying it in place. This is done by + // grabbing the front, processing it, and if we decide to keep it append + // it to the end of the path. The entire path is processed in this way. + for (unsigned i = 0; i < N; ++i) { + IntrusiveRefCntPtr<PathDiagnosticPiece> piece(path.front()); + path.pop_front(); + + switch (piece->getKind()) { + case clang::ento::PathDiagnosticPiece::Call: + removeRedundantMsgs(cast<PathDiagnosticCallPiece>(piece)->path); + break; + case clang::ento::PathDiagnosticPiece::Macro: + removeRedundantMsgs(cast<PathDiagnosticMacroPiece>(piece)->subPieces); + break; + case clang::ento::PathDiagnosticPiece::ControlFlow: + break; + case clang::ento::PathDiagnosticPiece::Event: { + if (i == N-1) + break; + + if (PathDiagnosticEventPiece *nextEvent = + dyn_cast<PathDiagnosticEventPiece>(path.front().getPtr())) { + PathDiagnosticEventPiece *event = + cast<PathDiagnosticEventPiece>(piece); + // Check to see if we should keep one of the two pieces. If we + // come up with a preference, record which piece to keep, and consume + // another piece from the path. + if (PathDiagnosticEventPiece *pieceToKeep = + eventsDescribeSameCondition(event, nextEvent)) { + piece = pieceToKeep; + path.pop_front(); + ++i; + } + } + break; + } + } + path.push_back(piece); + } +} + /// Recursively scan through a path and prune out calls and macros pieces /// that aren't needed. Return true if afterwards the path contains /// "interesting stuff" which means it should be pruned from the parent path. -static bool RemoveUneededCalls(PathPieces &pieces) { +bool BugReporter::RemoveUneededCalls(PathPieces &pieces, BugReport *R, + PathDiagnosticCallPiece *CallWithLoc) { bool containsSomethingInteresting = false; const unsigned N = pieces.size(); @@ -131,30 +203,49 @@ static bool RemoveUneededCalls(PathPieces &pieces) { IntrusiveRefCntPtr<PathDiagnosticPiece> piece(pieces.front()); pieces.pop_front(); + // Throw away pieces with invalid locations. + if (piece->getKind() != PathDiagnosticPiece::Call && + piece->getLocation().asLocation().isInvalid()) + continue; + switch (piece->getKind()) { case PathDiagnosticPiece::Call: { PathDiagnosticCallPiece *call = cast<PathDiagnosticCallPiece>(piece); + // Check if the location context is interesting. + assert(LocationContextMap.count(call)); + if (R->isInteresting(LocationContextMap[call])) { + containsSomethingInteresting = true; + break; + } // Recursively clean out the subclass. Keep this call around if // it contains any informative diagnostics. - if (!RemoveUneededCalls(call->path)) + PathDiagnosticCallPiece *NewCallWithLoc = + call->getLocation().asLocation().isValid() + ? call : CallWithLoc; + + if (!RemoveUneededCalls(call->path, R, NewCallWithLoc)) continue; + + if (NewCallWithLoc == CallWithLoc && CallWithLoc) { + call->callEnter = CallWithLoc->callEnter; + } + containsSomethingInteresting = true; break; } case PathDiagnosticPiece::Macro: { PathDiagnosticMacroPiece *macro = cast<PathDiagnosticMacroPiece>(piece); - if (!RemoveUneededCalls(macro->subPieces)) + if (!RemoveUneededCalls(macro->subPieces, R)) continue; containsSomethingInteresting = true; break; } case PathDiagnosticPiece::Event: { PathDiagnosticEventPiece *event = cast<PathDiagnosticEventPiece>(piece); + // We never throw away an event, but we do throw it away wholesale // as part of a path if we throw the entire path away. - if (event->isPrunable()) - continue; - containsSomethingInteresting = true; + containsSomethingInteresting |= !event->isPrunable(); break; } case PathDiagnosticPiece::ControlFlow: @@ -382,6 +473,35 @@ PathDiagnosticBuilder::getEnclosingStmtLocation(const Stmt *S) { } //===----------------------------------------------------------------------===// +// "Visitors only" path diagnostic generation algorithm. +//===----------------------------------------------------------------------===// +static bool GenerateVisitorsOnlyPathDiagnostic(PathDiagnostic &PD, + PathDiagnosticBuilder &PDB, + const ExplodedNode *N, + ArrayRef<BugReporterVisitor *> visitors) { + // All path generation skips the very first node (the error node). + // This is because there is special handling for the end-of-path note. + N = N->getFirstPred(); + if (!N) + return true; + + BugReport *R = PDB.getBugReport(); + while (const ExplodedNode *Pred = N->getFirstPred()) { + for (ArrayRef<BugReporterVisitor *>::iterator I = visitors.begin(), + E = visitors.end(); + I != E; ++I) { + // Visit all the node pairs, but throw the path pieces away. + PathDiagnosticPiece *Piece = (*I)->VisitNode(N, Pred, PDB, *R); + delete Piece; + } + + N = Pred; + } + + return R->isValid(); +} + +//===----------------------------------------------------------------------===// // "Minimal" path diagnostic generation algorithm. //===----------------------------------------------------------------------===// typedef std::pair<PathDiagnosticCallPiece*, const ExplodedNode*> StackDiagPair; @@ -412,7 +532,7 @@ static void updateStackPiecesWithMessage(PathDiagnosticPiece *P, static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM); -static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, +static bool GenerateMinimalPathDiagnostic(PathDiagnostic& PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, ArrayRef<BugReporterVisitor *> visitors) { @@ -430,55 +550,60 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, NextNode = GetPredecessorNode(N); ProgramPoint P = N->getLocation(); - - if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) { - PathDiagnosticCallPiece *C = - PathDiagnosticCallPiece::construct(N, *CE, SMgr); - PD.getActivePath().push_front(C); - PD.pushActivePath(&C->path); - CallStack.push_back(StackDiagPair(C, N)); - continue; - } - - if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) { - // Flush all locations, and pop the active path. - bool VisitedEntireCall = PD.isWithinCall(); - PD.popActivePath(); - - // Either we just added a bunch of stuff to the top-level path, or - // we have a previous CallExitEnd. If the former, it means that the - // path terminated within a function call. We must then take the - // current contents of the active path and place it within - // a new PathDiagnosticCallPiece. - PathDiagnosticCallPiece *C; - if (VisitedEntireCall) { - C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front()); - } else { - const Decl *Caller = CE->getLocationContext()->getDecl(); - C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller); + + do { + if (const CallExitEnd *CE = dyn_cast<CallExitEnd>(&P)) { + PathDiagnosticCallPiece *C = + PathDiagnosticCallPiece::construct(N, *CE, SMgr); + GRBugReporter& BR = PDB.getBugReporter(); + BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); + PD.getActivePath().push_front(C); + PD.pushActivePath(&C->path); + CallStack.push_back(StackDiagPair(C, N)); + break; } - C->setCallee(*CE, SMgr); - if (!CallStack.empty()) { - assert(CallStack.back().first == C); - CallStack.pop_back(); + if (const CallEnter *CE = dyn_cast<CallEnter>(&P)) { + // Flush all locations, and pop the active path. + bool VisitedEntireCall = PD.isWithinCall(); + PD.popActivePath(); + + // Either we just added a bunch of stuff to the top-level path, or + // we have a previous CallExitEnd. If the former, it means that the + // path terminated within a function call. We must then take the + // current contents of the active path and place it within + // a new PathDiagnosticCallPiece. + PathDiagnosticCallPiece *C; + if (VisitedEntireCall) { + C = cast<PathDiagnosticCallPiece>(PD.getActivePath().front()); + } else { + const Decl *Caller = CE->getLocationContext()->getDecl(); + C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller); + GRBugReporter& BR = PDB.getBugReporter(); + BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); + } + + C->setCallee(*CE, SMgr); + if (!CallStack.empty()) { + assert(CallStack.back().first == C); + CallStack.pop_back(); + } + break; } - continue; - } - if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { - const CFGBlock *Src = BE->getSrc(); - const CFGBlock *Dst = BE->getDst(); - const Stmt *T = Src->getTerminator(); + if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { + const CFGBlock *Src = BE->getSrc(); + const CFGBlock *Dst = BE->getDst(); + const Stmt *T = Src->getTerminator(); - if (!T) - continue; + if (!T) + break; - PathDiagnosticLocation Start = - PathDiagnosticLocation::createBegin(T, SMgr, - N->getLocationContext()); + PathDiagnosticLocation Start = + PathDiagnosticLocation::createBegin(T, SMgr, + N->getLocationContext()); - switch (T->getStmtClass()) { + switch (T->getStmtClass()) { default: break; @@ -487,16 +612,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, const Stmt *S = GetNextStmt(N); if (!S) - continue; + break; std::string sbuf; llvm::raw_string_ostream os(sbuf); const PathDiagnosticLocation &End = PDB.getEnclosingStmtLocation(S); os << "Control jumps to line " - << End.asLocation().getExpansionLineNumber(); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + << End.asLocation().getExpansionLineNumber(); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, os.str())); break; } @@ -509,52 +634,52 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, PathDiagnosticLocation End(S, SMgr, LC); switch (S->getStmtClass()) { - default: - os << "No cases match in the switch statement. " - "Control jumps to line " - << End.asLocation().getExpansionLineNumber(); - break; - case Stmt::DefaultStmtClass: - os << "Control jumps to the 'default' case at line " - << End.asLocation().getExpansionLineNumber(); - break; - - case Stmt::CaseStmtClass: { - os << "Control jumps to 'case "; - const CaseStmt *Case = cast<CaseStmt>(S); - const Expr *LHS = Case->getLHS()->IgnoreParenCasts(); - - // Determine if it is an enum. - bool GetRawInt = true; - - if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) { - // FIXME: Maybe this should be an assertion. Are there cases - // were it is not an EnumConstantDecl? - const EnumConstantDecl *D = + default: + os << "No cases match in the switch statement. " + "Control jumps to line " + << End.asLocation().getExpansionLineNumber(); + break; + case Stmt::DefaultStmtClass: + os << "Control jumps to the 'default' case at line " + << End.asLocation().getExpansionLineNumber(); + break; + + case Stmt::CaseStmtClass: { + os << "Control jumps to 'case "; + const CaseStmt *Case = cast<CaseStmt>(S); + const Expr *LHS = Case->getLHS()->IgnoreParenCasts(); + + // Determine if it is an enum. + bool GetRawInt = true; + + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(LHS)) { + // FIXME: Maybe this should be an assertion. Are there cases + // were it is not an EnumConstantDecl? + const EnumConstantDecl *D = dyn_cast<EnumConstantDecl>(DR->getDecl()); - if (D) { - GetRawInt = false; - os << *D; - } + if (D) { + GetRawInt = false; + os << *D; } + } - if (GetRawInt) - os << LHS->EvaluateKnownConstInt(PDB.getASTContext()); + if (GetRawInt) + os << LHS->EvaluateKnownConstInt(PDB.getASTContext()); - os << ":' at line " - << End.asLocation().getExpansionLineNumber(); - break; - } + os << ":' at line " + << End.asLocation().getExpansionLineNumber(); + break; } - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + } + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, os.str())); } else { os << "'Default' branch taken. "; const PathDiagnosticLocation &End = PDB.ExecutionContinues(os, N); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, os.str())); } break; @@ -565,12 +690,12 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, std::string sbuf; llvm::raw_string_ostream os(sbuf); PathDiagnosticLocation End = PDB.ExecutionContinues(os, N); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, os.str())); break; } - // Determine control-flow for ternary '?'. + // Determine control-flow for ternary '?'. case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: { std::string sbuf; @@ -587,12 +712,12 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (const Stmt *S = End.asStmt()) End = PDB.getEnclosingStmtLocation(S); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, os.str())); break; } - // Determine control-flow for short-circuited '&&' and '||'. + // Determine control-flow for short-circuited '&&' and '||'. case Stmt::BinaryOperatorClass: { if (!PDB.supportsLogicalOpControlFlow()) break; @@ -609,16 +734,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, os << "false"; PathDiagnosticLocation End(B->getLHS(), SMgr, LC); PathDiagnosticLocation Start = - PathDiagnosticLocation::createOperatorLoc(B, SMgr); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + PathDiagnosticLocation::createOperatorLoc(B, SMgr); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, os.str())); } else { os << "true"; PathDiagnosticLocation Start(B->getLHS(), SMgr, LC); PathDiagnosticLocation End = PDB.ExecutionContinues(N); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, os.str())); } } else { @@ -629,16 +754,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, os << "false"; PathDiagnosticLocation Start(B->getLHS(), SMgr, LC); PathDiagnosticLocation End = PDB.ExecutionContinues(N); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, os.str())); } else { os << "true"; PathDiagnosticLocation End(B->getLHS(), SMgr, LC); PathDiagnosticLocation Start = - PathDiagnosticLocation::createOperatorLoc(B, SMgr); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + PathDiagnosticLocation::createOperatorLoc(B, SMgr); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, os.str())); } } @@ -656,8 +781,8 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (const Stmt *S = End.asStmt()) End = PDB.getEnclosingStmtLocation(S); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, os.str())); } else { PathDiagnosticLocation End = PDB.ExecutionContinues(N); @@ -665,8 +790,8 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (const Stmt *S = End.asStmt()) End = PDB.getEnclosingStmtLocation(S); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - "Loop condition is false. Exiting loop")); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, "Loop condition is false. Exiting loop")); } break; @@ -683,16 +808,16 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, if (const Stmt *S = End.asStmt()) End = PDB.getEnclosingStmtLocation(S); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - os.str())); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, os.str())); } else { PathDiagnosticLocation End = PDB.ExecutionContinues(N); if (const Stmt *S = End.asStmt()) End = PDB.getEnclosingStmtLocation(S); - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - "Loop condition is true. Entering loop body")); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, "Loop condition is true. Entering loop body")); } break; @@ -705,16 +830,17 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, End = PDB.getEnclosingStmtLocation(S); if (*(Src->succ_begin()+1) == Dst) - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - "Taking false branch")); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, "Taking false branch")); else - PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece(Start, End, - "Taking true branch")); + PD.getActivePath().push_front(new PathDiagnosticControlFlowPiece( + Start, End, "Taking true branch")); break; } + } } - } + } while(0); if (NextNode) { // Add diagnostic pieces from custom visitors. @@ -730,9 +856,13 @@ static void GenerateMinimalPathDiagnostic(PathDiagnostic& PD, } } + if (!PDB.getBugReport()->isValid()) + return false; + // After constructing the full PathDiagnostic, do a pass over it to compact // PathDiagnosticPieces that occur within a macro. CompactPathDiagnostic(PD.getMutablePieces(), PDB.getSourceManager()); + return true; } //===----------------------------------------------------------------------===// @@ -944,6 +1074,11 @@ void EdgeBuilder::rawAddEdge(PathDiagnosticLocation NewLoc) { const PathDiagnosticLocation &NewLocClean = cleanUpLocation(NewLoc); const PathDiagnosticLocation &PrevLocClean = cleanUpLocation(PrevLoc); + if (PrevLocClean.asLocation().isInvalid()) { + PrevLoc = NewLoc; + return; + } + if (NewLocClean.asLocation() == PrevLocClean.asLocation()) return; @@ -1133,7 +1268,7 @@ static void reversePropagateInterestingSymbols(BugReport &R, } } -static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, +static bool GenerateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticBuilder &PDB, const ExplodedNode *N, ArrayRef<BugReporterVisitor *> visitors) { @@ -1166,6 +1301,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, PathDiagnosticCallPiece *C = PathDiagnosticCallPiece::construct(N, *CE, SM); + GRBugReporter& BR = PDB.getBugReporter(); + BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); EB.addEdge(C->callReturn, true); EB.flushLocations(); @@ -1202,6 +1339,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, } else { const Decl *Caller = CE->getLocationContext()->getDecl(); C = PathDiagnosticCallPiece::construct(PD.getActivePath(), Caller); + GRBugReporter& BR = PDB.getBugReporter(); + BR.addCallPieceLocationContextPair(C, CE->getCalleeContext()); } C->setCallee(*CE, SM); @@ -1234,20 +1373,15 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, } } - const CFGBlock &Blk = *BE->getSrc(); - const Stmt *Term = Blk.getTerminator(); - // Are we jumping to the head of a loop? Add a special diagnostic. - if (const Stmt *Loop = BE->getDst()->getLoopTarget()) { + if (const Stmt *Loop = BE->getSrc()->getLoopTarget()) { PathDiagnosticLocation L(Loop, SM, PDB.LC); const CompoundStmt *CS = NULL; - if (!Term) { - if (const ForStmt *FS = dyn_cast<ForStmt>(Loop)) - CS = dyn_cast<CompoundStmt>(FS->getBody()); - else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop)) - CS = dyn_cast<CompoundStmt>(WS->getBody()); - } + if (const ForStmt *FS = dyn_cast<ForStmt>(Loop)) + CS = dyn_cast<CompoundStmt>(FS->getBody()); + else if (const WhileStmt *WS = dyn_cast<WhileStmt>(Loop)) + CS = dyn_cast<CompoundStmt>(WS->getBody()); PathDiagnosticEventPiece *p = new PathDiagnosticEventPiece(L, @@ -1263,15 +1397,16 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, EB.addEdge(BL); } } - - if (Term) + + if (const Stmt *Term = BE->getSrc()->getTerminator()) EB.addContext(Term); break; } if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) { - if (const CFGStmt *S = BE->getFirstElement().getAs<CFGStmt>()) { + CFGElement First = BE->getFirstElement(); + if (const CFGStmt *S = First.getAs<CFGStmt>()) { const Stmt *stmt = S->getStmt(); if (IsControlFlowExpr(stmt)) { // Add the proper context for '&&', '||', and '?'. @@ -1306,6 +1441,8 @@ static void GenerateExtensivePathDiagnostic(PathDiagnostic& PD, } } } + + return PDB.getBugReport()->isValid(); } //===----------------------------------------------------------------------===// @@ -1414,6 +1551,12 @@ void BugReport::markInteresting(SVal V) { markInteresting(V.getAsSymbol()); } +void BugReport::markInteresting(const LocationContext *LC) { + if (!LC) + return; + InterestingLocationContexts.insert(LC); +} + bool BugReport::isInteresting(SVal V) { return isInteresting(V.getAsRegion()) || isInteresting(V.getAsSymbol()); } @@ -1438,6 +1581,12 @@ bool BugReport::isInteresting(const MemRegion *R) { return false; } +bool BugReport::isInteresting(const LocationContext *LC) { + if (!LC) + return false; + return InterestingLocationContexts.count(LC); +} + void BugReport::lazyInitializeInterestingSets() { if (interestingSymbols.empty()) { interestingSymbols.push_back(new Symbols()); @@ -1823,17 +1972,27 @@ static void CompactPathDiagnostic(PathPieces &path, const SourceManager& SM) { path.push_back(*I); } -void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, +bool GRBugReporter::generatePathDiagnostic(PathDiagnostic& PD, PathDiagnosticConsumer &PC, ArrayRef<BugReport *> &bugReports) { - assert(!bugReports.empty()); + + bool HasValid = false; SmallVector<const ExplodedNode *, 10> errorNodes; for (ArrayRef<BugReport*>::iterator I = bugReports.begin(), E = bugReports.end(); I != E; ++I) { + if ((*I)->isValid()) { + HasValid = true; errorNodes.push_back((*I)->getErrorNode()); + } else { + errorNodes.push_back(0); + } } + // If all the reports have been marked invalid, we're done. + if (!HasValid) + return false; + // Construct a new graph that contains only a single path from the error // node to a root. const std::pair<std::pair<ExplodedGraph*, NodeBackMap*>, @@ -1844,6 +2003,7 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, assert(GPair.second.second < bugReports.size()); BugReport *R = bugReports[GPair.second.second]; assert(R && "No original report found for sliced graph."); + assert(R->isValid() && "Report selected from trimmed graph marked invalid."); OwningPtr<ExplodedGraph> ReportGraph(GPair.first.first); OwningPtr<NodeBackMap> BackMap(GPair.first.second); @@ -1870,36 +2030,53 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, visitors.push_back((*I)->clone()); // Clear out the active path from any previous work. - PD.getActivePath().clear(); + PD.resetPath(); originalReportConfigToken = R->getConfigurationChangeToken(); // Generate the very last diagnostic piece - the piece is visible before // the trace is expanded. - PathDiagnosticPiece *LastPiece = 0; - for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end(); - I != E; ++I) { - if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) { - assert (!LastPiece && - "There can only be one final piece in a diagnostic."); - LastPiece = Piece; + if (PDB.getGenerationScheme() != PathDiagnosticConsumer::None) { + PathDiagnosticPiece *LastPiece = 0; + for (BugReport::visitor_iterator I = visitors.begin(), E = visitors.end(); + I != E; ++I) { + if (PathDiagnosticPiece *Piece = (*I)->getEndPath(PDB, N, *R)) { + assert (!LastPiece && + "There can only be one final piece in a diagnostic."); + LastPiece = Piece; + } } + if (!LastPiece) + LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R); + if (LastPiece) + PD.setEndOfPath(LastPiece); + else + return false; } - if (!LastPiece) - LastPiece = BugReporterVisitor::getDefaultEndPath(PDB, N, *R); - if (LastPiece) - PD.getActivePath().push_back(LastPiece); - else - return; switch (PDB.getGenerationScheme()) { case PathDiagnosticConsumer::Extensive: - GenerateExtensivePathDiagnostic(PD, PDB, N, visitors); + if (!GenerateExtensivePathDiagnostic(PD, PDB, N, visitors)) { + assert(!R->isValid() && "Failed on valid report"); + // Try again. We'll filter out the bad report when we trim the graph. + // FIXME: It would be more efficient to use the same intermediate + // trimmed graph, and just repeat the shortest-path search. + return generatePathDiagnostic(PD, PC, bugReports); + } break; case PathDiagnosticConsumer::Minimal: - GenerateMinimalPathDiagnostic(PD, PDB, N, visitors); + if (!GenerateMinimalPathDiagnostic(PD, PDB, N, visitors)) { + assert(!R->isValid() && "Failed on valid report"); + // Try again. We'll filter out the bad report when we trim the graph. + return generatePathDiagnostic(PD, PC, bugReports); + } break; case PathDiagnosticConsumer::None: - llvm_unreachable("PathDiagnosticConsumer::None should never appear here"); + if (!GenerateVisitorsOnlyPathDiagnostic(PD, PDB, N, visitors)) { + assert(!R->isValid() && "Failed on valid report"); + // Try again. We'll filter out the bad report when we trim the graph. + return generatePathDiagnostic(PD, PC, bugReports); + } + break; } // Clean up the visitors we used. @@ -1910,18 +2087,26 @@ void GRBugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, } while(finalReportConfigToken != originalReportConfigToken); // Finally, prune the diagnostic path of uninteresting stuff. - if (R->shouldPrunePath()) { - bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces()); - assert(hasSomethingInteresting); - (void) hasSomethingInteresting; + if (!PD.path.empty()) { + // Remove messages that are basically the same. + removeRedundantMsgs(PD.getMutablePieces()); + + if (R->shouldPrunePath()) { + bool hasSomethingInteresting = RemoveUneededCalls(PD.getMutablePieces(), + R); + assert(hasSomethingInteresting); + (void) hasSomethingInteresting; + } } + + return true; } void BugReporter::Register(BugType *BT) { BugTypes = F.add(BugTypes, BT); } -void BugReporter::EmitReport(BugReport* R) { +void BugReporter::emitReport(BugReport* R) { // Compute the bug report's hash to determine its equivalence class. llvm::FoldingSetNodeID ID; R->Profile(ID); @@ -2078,17 +2263,17 @@ void BugReporter::FlushReport(BugReport *exampleReport, OwningPtr<PathDiagnostic> D(new PathDiagnostic(exampleReport->getDeclWithIssue(), exampleReport->getBugType().getName(), - PD.useVerboseDescription() - ? exampleReport->getDescription() - : exampleReport->getShortDescription(), + exampleReport->getDescription(), + exampleReport->getShortDescription(/*Fallback=*/false), BT.getCategory())); // Generate the full path diagnostic, using the generation scheme - // specified by the PathDiagnosticConsumer. - if (PD.getGenerationScheme() != PathDiagnosticConsumer::None) { - if (!bugReports.empty()) - GeneratePathDiagnostic(*D.get(), PD, bugReports); - } + // specified by the PathDiagnosticConsumer. Note that we have to generate + // path diagnostics even for consumers which do not support paths, because + // the BugReporterVisitors may mark this bug as a false positive. + if (!bugReports.empty()) + if (!generatePathDiagnostic(*D.get(), PD, bugReports)) + return; // If the path is empty, generate a single step path with the location // of the issue. @@ -2100,7 +2285,7 @@ void BugReporter::FlushReport(BugReport *exampleReport, llvm::tie(Beg, End) = exampleReport->getRanges(); for ( ; Beg != End; ++Beg) piece->addRange(*Beg); - D->getActivePath().push_back(piece); + D->setEndOfPath(piece); } // Get the meta data. @@ -2124,7 +2309,7 @@ void BugReporter::EmitBasicReport(const Decl *DeclWithIssue, BugReport *R = new BugReport(*BT, str, Loc); R->setDeclWithIssue(DeclWithIssue); for ( ; NumRanges > 0 ; --NumRanges, ++RBeg) R->addRange(*RBeg); - EmitReport(R); + emitReport(R); } BugType *BugReporter::getBugTypeForName(StringRef name, diff --git a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index e7295878fa6f..328e8a650df1 100644 --- a/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -17,10 +17,13 @@ #include "clang/AST/ExprObjC.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" using namespace clang; using namespace ento; @@ -29,10 +32,24 @@ using namespace ento; // Utility functions. //===----------------------------------------------------------------------===// +bool bugreporter::isDeclRefExprToReference(const Expr *E) { + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { + return DRE->getDecl()->getType()->isReferenceType(); + } + return false; +} + const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) { // Pattern match for a few useful cases (do something smarter later): // a[0], p->f, *p - const Stmt *S = N->getLocationAs<PostStmt>()->getStmt(); + const PostStmt *Loc = N->getLocationAs<PostStmt>(); + if (!Loc) + return 0; + + const Expr *S = dyn_cast<Expr>(Loc->getStmt()); + if (!S) + return 0; + S = S->IgnoreParenCasts(); while (true) { if (const BinaryOperator *B = dyn_cast<BinaryOperator>(S)) { @@ -45,7 +62,12 @@ const Stmt *bugreporter::GetDerefExpr(const ExplodedNode *N) { return U->getSubExpr()->IgnoreParenCasts(); } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) { - return ME->getBase()->IgnoreParenCasts(); + if (ME->isArrow() || isDeclRefExprToReference(ME->getBase())) { + return ME->getBase()->IgnoreParenCasts(); + } + } + else if (const ObjCIvarRefExpr *IvarRef = dyn_cast<ObjCIvarRefExpr>(S)) { + return IvarRef->getBase()->IgnoreParenCasts(); } else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) { return AE->getBase(); @@ -103,6 +125,228 @@ BugReporterVisitor::getDefaultEndPath(BugReporterContext &BRC, } +namespace { +/// Emits an extra note at the return statement of an interesting stack frame. +/// +/// The returned value is marked as an interesting value, and if it's null, +/// adds a visitor to track where it became null. +/// +/// This visitor is intended to be used when another visitor discovers that an +/// interesting value comes from an inlined function call. +class ReturnVisitor : public BugReporterVisitorImpl<ReturnVisitor> { + const StackFrameContext *StackFrame; + enum { + Initial, + MaybeSuppress, + Satisfied + } Mode; + +public: + ReturnVisitor(const StackFrameContext *Frame) + : StackFrame(Frame), Mode(Initial) {} + + static void *getTag() { + static int Tag = 0; + return static_cast<void *>(&Tag); + } + + virtual void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(ReturnVisitor::getTag()); + ID.AddPointer(StackFrame); + } + + /// Adds a ReturnVisitor if the given statement represents a call that was + /// inlined. + /// + /// This will search back through the ExplodedGraph, starting from the given + /// node, looking for when the given statement was processed. If it turns out + /// the statement is a call that was inlined, we add the visitor to the + /// bug report, so it can print a note later. + static void addVisitorIfNecessary(const ExplodedNode *Node, const Stmt *S, + BugReport &BR) { + if (!CallEvent::isCallStmt(S)) + return; + + // First, find when we processed the statement. + do { + if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>()) + if (CEE->getCalleeContext()->getCallSite() == S) + break; + if (const StmtPoint *SP = Node->getLocationAs<StmtPoint>()) + if (SP->getStmt() == S) + break; + + Node = Node->getFirstPred(); + } while (Node); + + // Next, step over any post-statement checks. + while (Node && isa<PostStmt>(Node->getLocation())) + Node = Node->getFirstPred(); + + // Finally, see if we inlined the call. + if (Node) { + if (const CallExitEnd *CEE = Node->getLocationAs<CallExitEnd>()) { + const StackFrameContext *CalleeContext = CEE->getCalleeContext(); + if (CalleeContext->getCallSite() == S) { + BR.markInteresting(CalleeContext); + BR.addVisitor(new ReturnVisitor(CalleeContext)); + } + } + } + } + + /// Returns true if any counter-suppression heuristics are enabled for + /// ReturnVisitor. + static bool hasCounterSuppression(AnalyzerOptions &Options) { + return Options.shouldAvoidSuppressingNullArgumentPaths(); + } + + PathDiagnosticPiece *visitNodeInitial(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { + // Only print a message at the interesting return statement. + if (N->getLocationContext() != StackFrame) + return 0; + + const StmtPoint *SP = N->getLocationAs<StmtPoint>(); + if (!SP) + return 0; + + const ReturnStmt *Ret = dyn_cast<ReturnStmt>(SP->getStmt()); + if (!Ret) + return 0; + + // Okay, we're at the right return statement, but do we have the return + // value available? + ProgramStateRef State = N->getState(); + SVal V = State->getSVal(Ret, StackFrame); + if (V.isUnknownOrUndef()) + return 0; + + // Don't print any more notes after this one. + Mode = Satisfied; + + const Expr *RetE = Ret->getRetValue(); + assert(RetE && "Tracking a return value for a void function"); + RetE = RetE->IgnoreParenCasts(); + + // If we can't prove the return value is 0, just mark it interesting, and + // make sure to track it into any further inner functions. + if (State->assume(cast<DefinedSVal>(V), true)) { + BR.markInteresting(V); + ReturnVisitor::addVisitorIfNecessary(N, RetE, BR); + return 0; + } + + // If we're returning 0, we should track where that 0 came from. + bugreporter::trackNullOrUndefValue(N, RetE, BR); + + // Build an appropriate message based on the return value. + SmallString<64> Msg; + llvm::raw_svector_ostream Out(Msg); + + if (isa<Loc>(V)) { + // If we are pruning null-return paths as unlikely error paths, mark the + // report invalid. We still want to emit a path note, however, in case + // the report is resurrected as valid later on. + ExprEngine &Eng = BRC.getBugReporter().getEngine(); + AnalyzerOptions &Options = Eng.getAnalysisManager().options; + if (Options.shouldPruneNullReturnPaths()) { + if (hasCounterSuppression(Options)) + Mode = MaybeSuppress; + else + BR.markInvalid(ReturnVisitor::getTag(), StackFrame); + } + + if (RetE->getType()->isObjCObjectPointerType()) + Out << "Returning nil"; + else + Out << "Returning null pointer"; + } else { + Out << "Returning zero"; + } + + // FIXME: We should have a more generalized location printing mechanism. + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(RetE)) + if (const DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(DR->getDecl())) + Out << " (loaded from '" << *DD << "')"; + + PathDiagnosticLocation L(Ret, BRC.getSourceManager(), StackFrame); + return new PathDiagnosticEventPiece(L, Out.str()); + } + + PathDiagnosticPiece *visitNodeMaybeSuppress(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { + // Are we at the entry node for this call? + const CallEnter *CE = N->getLocationAs<CallEnter>(); + if (!CE) + return 0; + + if (CE->getCalleeContext() != StackFrame) + return 0; + + Mode = Satisfied; + + ExprEngine &Eng = BRC.getBugReporter().getEngine(); + AnalyzerOptions &Options = Eng.getAnalysisManager().options; + if (Options.shouldAvoidSuppressingNullArgumentPaths()) { + // Don't automatically suppress a report if one of the arguments is + // known to be a null pointer. Instead, start tracking /that/ null + // value back to its origin. + ProgramStateManager &StateMgr = BRC.getStateManager(); + CallEventManager &CallMgr = StateMgr.getCallEventManager(); + + ProgramStateRef State = N->getState(); + CallEventRef<> Call = CallMgr.getCaller(StackFrame, State); + for (unsigned I = 0, E = Call->getNumArgs(); I != E; ++I) { + SVal ArgV = Call->getArgSVal(I); + if (!isa<Loc>(ArgV)) + continue; + + const Expr *ArgE = Call->getArgExpr(I); + if (!ArgE) + continue; + + // Is it possible for this argument to be non-null? + if (State->assume(cast<Loc>(ArgV), true)) + continue; + + if (bugreporter::trackNullOrUndefValue(N, ArgE, BR, /*IsArg=*/true)) + return 0; + + // If we /can't/ track the null pointer, we should err on the side of + // false negatives, and continue towards marking this report invalid. + // (We will still look at the other arguments, though.) + } + } + + // There is no reason not to suppress this report; go ahead and do it. + BR.markInvalid(ReturnVisitor::getTag(), StackFrame); + return 0; + } + + PathDiagnosticPiece *VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { + switch (Mode) { + case Initial: + return visitNodeInitial(N, PrevN, BRC, BR); + case MaybeSuppress: + return visitNodeMaybeSuppress(N, PrevN, BRC, BR); + case Satisfied: + return 0; + } + + llvm_unreachable("Invalid visit mode!"); + } +}; +} // end anonymous namespace + + void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const { static int tag = 0; ID.AddPointer(&tag); @@ -110,59 +354,90 @@ void FindLastStoreBRVisitor ::Profile(llvm::FoldingSetNodeID &ID) const { ID.Add(V); } -PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N, - const ExplodedNode *PrevN, - BugReporterContext &BRC, - BugReport &BR) { +PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *Succ, + const ExplodedNode *Pred, + BugReporterContext &BRC, + BugReport &BR) { if (satisfied) return NULL; - if (!StoreSite) { - // Make sure the region is actually bound to value V here. - // This is necessary because the region may not actually be live at the - // report's error node. - if (N->getState()->getSVal(R) != V) - return NULL; - - const ExplodedNode *Node = N, *Last = N; - - // Now look for the store of V. - for ( ; Node ; Node = Node->getFirstPred()) { - if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - if (const PostStmt *P = Node->getLocationAs<PostStmt>()) - if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) - if (DS->getSingleDecl() == VR->getDecl()) { - // Record the last seen initialization point. - Last = Node; - break; - } + const ExplodedNode *StoreSite = 0; + const Expr *InitE = 0; + bool IsParam = false; + + // First see if we reached the declaration of the region. + if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { + if (const PostStmt *P = Pred->getLocationAs<PostStmt>()) { + if (const DeclStmt *DS = P->getStmtAs<DeclStmt>()) { + if (DS->getSingleDecl() == VR->getDecl()) { + StoreSite = Pred; + InitE = VR->getDecl()->getInit(); + } } - - // Does the region still bind to value V? If not, we are done - // looking for store sites. - if (Node->getState()->getSVal(R) != V) - break; - - Last = Node; } + } - if (!Node) { - satisfied = true; + // Otherwise, check that Succ has this binding and Pred does not, i.e. this is + // where the binding first occurred. + if (!StoreSite) { + if (Succ->getState()->getSVal(R) != V) + return NULL; + if (Pred->getState()->getSVal(R) == V) return NULL; - } - StoreSite = Last; + StoreSite = Succ; + + // If this is an assignment expression, we can track the value + // being assigned. + if (const PostStmt *P = Succ->getLocationAs<PostStmt>()) + if (const BinaryOperator *BO = P->getStmtAs<BinaryOperator>()) + if (BO->isAssignmentOp()) + InitE = BO->getRHS(); + + // If this is a call entry, the variable should be a parameter. + // FIXME: Handle CXXThisRegion as well. (This is not a priority because + // 'this' should never be NULL, but this visitor isn't just for NULL and + // UndefinedVal.) + if (const CallEnter *CE = Succ->getLocationAs<CallEnter>()) { + const VarRegion *VR = cast<VarRegion>(R); + const ParmVarDecl *Param = cast<ParmVarDecl>(VR->getDecl()); + + ProgramStateManager &StateMgr = BRC.getStateManager(); + CallEventManager &CallMgr = StateMgr.getCallEventManager(); + + CallEventRef<> Call = CallMgr.getCaller(CE->getCalleeContext(), + Succ->getState()); + InitE = Call->getArgExpr(Param->getFunctionScopeIndex()); + IsParam = true; + } } - if (StoreSite != N) + if (!StoreSite) return NULL; - satisfied = true; + + // If we have an expression that provided the value, try to track where it + // came from. + if (InitE) { + if (V.isUndef() || isa<loc::ConcreteInt>(V)) { + if (!IsParam) + InitE = InitE->IgnoreParenCasts(); + bugreporter::trackNullOrUndefValue(StoreSite, InitE, BR, IsParam); + } else { + ReturnVisitor::addVisitorIfNecessary(StoreSite, InitE->IgnoreParenCasts(), + BR); + } + } + + if (!R->canPrintPretty()) + return 0; + + // Okay, we've found the binding. Emit an appropriate message. SmallString<256> sbuf; llvm::raw_svector_ostream os(sbuf); - if (const PostStmt *PS = N->getLocationAs<PostStmt>()) { + if (const PostStmt *PS = StoreSite->getLocationAs<PostStmt>()) { if (const DeclStmt *DS = PS->getStmtAs<DeclStmt>()) { if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { @@ -201,6 +476,30 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N, os << "initialized here"; } } + } else if (isa<CallEnter>(StoreSite->getLocation())) { + const ParmVarDecl *Param = cast<ParmVarDecl>(cast<VarRegion>(R)->getDecl()); + + os << "Passing "; + + if (isa<loc::ConcreteInt>(V)) { + if (Param->getType()->isObjCObjectPointerType()) + os << "nil object reference"; + else + os << "null pointer value"; + } else if (V.isUndef()) { + os << "uninitialized value"; + } else if (isa<nonloc::ConcreteInt>(V)) { + os << "the value " << cast<nonloc::ConcreteInt>(V).getValue(); + } else { + os << "value"; + } + + // Printed parameter indexes are 1-based, not 0-based. + unsigned Idx = Param->getFunctionScopeIndex() + 1; + os << " via " << Idx << llvm::getOrdinalSuffix(Idx) << " parameter '"; + + R->printPretty(os); + os << '\''; } if (os.str().empty()) { @@ -228,17 +527,19 @@ PathDiagnosticPiece *FindLastStoreBRVisitor::VisitNode(const ExplodedNode *N, else os << "Value assigned to "; - if (const VarRegion *VR = dyn_cast<VarRegion>(R)) { - os << '\'' << *VR->getDecl() << '\''; - } - else - return NULL; + os << '\''; + R->printPretty(os); + os << '\''; } // Construct a new PathDiagnosticPiece. - ProgramPoint P = N->getLocation(); - PathDiagnosticLocation L = - PathDiagnosticLocation::create(P, BRC.getSourceManager()); + ProgramPoint P = StoreSite->getLocation(); + PathDiagnosticLocation L; + if (isa<CallEnter>(P)) + L = PathDiagnosticLocation(InitE, BRC.getSourceManager(), + P.getLocationContext()); + else + L = PathDiagnosticLocation::create(P, BRC.getSourceManager()); if (!L.isValid()) return NULL; return new PathDiagnosticEventPiece(L, os.str()); @@ -251,6 +552,12 @@ void TrackConstraintBRVisitor::Profile(llvm::FoldingSetNodeID &ID) const { ID.Add(Constraint); } +/// Return the tag associated with this visitor. This tag will be used +/// to make all PathDiagnosticPieces created by this visitor. +const char *TrackConstraintBRVisitor::getTag() { + return "TrackConstraintBRVisitor"; +} + PathDiagnosticPiece * TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *PrevN, @@ -290,62 +597,97 @@ TrackConstraintBRVisitor::VisitNode(const ExplodedNode *N, PathDiagnosticLocation::create(P, BRC.getSourceManager()); if (!L.isValid()) return NULL; - return new PathDiagnosticEventPiece(L, os.str()); + + PathDiagnosticEventPiece *X = new PathDiagnosticEventPiece(L, os.str()); + X->setTag(getTag()); + return X; } return NULL; } -void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N, - const Stmt *S, - BugReport *report) { +bool bugreporter::trackNullOrUndefValue(const ExplodedNode *N, const Stmt *S, + BugReport &report, bool IsArg) { if (!S || !N) - return; + return false; - ProgramStateManager &StateMgr = N->getState()->getStateManager(); + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(S)) + S = OVE->getSourceExpr(); + + if (IsArg) { + assert(isa<CallEnter>(N->getLocation()) && "Tracking arg but not at call"); + } else { + // Walk through nodes until we get one that matches the statement exactly. + do { + const ProgramPoint &pp = N->getLocation(); + if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) { + if (ps->getStmt() == S) + break; + } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&pp)) { + if (CEE->getCalleeContext()->getCallSite() == S) + break; + } + N = N->getFirstPred(); + } while (N); - // Walk through nodes until we get one that matches the statement - // exactly. - while (N) { - const ProgramPoint &pp = N->getLocation(); - if (const PostStmt *ps = dyn_cast<PostStmt>(&pp)) { - if (ps->getStmt() == S) - break; - } - N = N->getFirstPred(); + if (!N) + return false; } - - if (!N) - return; ProgramStateRef state = N->getState(); - // Walk through lvalue-to-rvalue conversions. - const Expr *Ex = dyn_cast<Expr>(S); - if (Ex) { + // See if the expression we're interested refers to a variable. + // If so, we can track both its contents and constraints on its value. + if (const Expr *Ex = dyn_cast<Expr>(S)) { + // Strip off parens and casts. Note that this will never have issues with + // C++ user-defined implicit conversions, because those have a constructor + // or function call inside. Ex = Ex->IgnoreParenCasts(); if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex)) { + // FIXME: Right now we only track VarDecls because it's non-trivial to + // get a MemRegion for any other DeclRefExprs. <rdar://problem/12114812> if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { - const VarRegion *R = - StateMgr.getRegionManager().getVarRegion(VD, N->getLocationContext()); + ProgramStateManager &StateMgr = state->getStateManager(); + MemRegionManager &MRMgr = StateMgr.getRegionManager(); + const VarRegion *R = MRMgr.getVarRegion(VD, N->getLocationContext()); - // What did we load? + // Mark both the variable region and its contents as interesting. SVal V = state->getRawSVal(loc::MemRegionVal(R)); - report->markInteresting(R); - report->markInteresting(V); + // If the value matches the default for the variable region, that + // might mean that it's been cleared out of the state. Fall back to + // the full argument expression (with casts and such intact). + if (IsArg) { + bool UseArgValue = V.isUnknownOrUndef() || V.isZeroConstant(); + if (!UseArgValue) { + const SymbolRegionValue *SRV = + dyn_cast_or_null<SymbolRegionValue>(V.getAsLocSymbol()); + if (SRV) + UseArgValue = (SRV->getRegion() == R); + } + if (UseArgValue) + V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); + } + + report.markInteresting(R); + report.markInteresting(V); + report.addVisitor(new UndefOrNullArgVisitor(R)); + + // If the contents are symbolic, find out when they became null. if (V.getAsLocSymbol()) { BugReporterVisitor *ConstraintTracker - = new TrackConstraintBRVisitor(cast<loc::MemRegionVal>(V), false); - report->addVisitor(ConstraintTracker); + = new TrackConstraintBRVisitor(cast<DefinedSVal>(V), false); + report.addVisitor(ConstraintTracker); } - report->addVisitor(new FindLastStoreBRVisitor(V, R)); - return; + report.addVisitor(new FindLastStoreBRVisitor(V, R)); + return true; } } } + // If the expression does NOT refer to a variable, we can still track + // constraints on its contents. SVal V = state->getSValAsScalarOrLoc(S, N->getLocationContext()); // Uncomment this to find cases where we aren't properly getting the @@ -354,17 +696,27 @@ void bugreporter::addTrackNullOrUndefValueVisitor(const ExplodedNode *N, // Is it a symbolic value? if (loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&V)) { - const SubRegion *R = cast<SubRegion>(L->getRegion()); - while (R && !isa<SymbolicRegion>(R)) { - R = dyn_cast<SubRegion>(R->getSuperRegion()); - } + // At this point we are dealing with the region's LValue. + // However, if the rvalue is a symbolic region, we should track it as well. + SVal RVal = state->getSVal(L->getRegion()); + const MemRegion *RegionRVal = RVal.getAsRegion(); + report.addVisitor(new UndefOrNullArgVisitor(L->getRegion())); + - if (R) { - report->markInteresting(R); - report->addVisitor(new TrackConstraintBRVisitor(loc::MemRegionVal(R), - false)); + if (RegionRVal && isa<SymbolicRegion>(RegionRVal)) { + report.markInteresting(RegionRVal); + report.addVisitor(new TrackConstraintBRVisitor( + loc::MemRegionVal(RegionRVal), false)); } + } else { + // Otherwise, if the value came from an inlined function call, + // we should at least make sure that function isn't pruned in our output. + if (const Expr *E = dyn_cast<Expr>(S)) + S = E->IgnoreParenCasts(); + ReturnVisitor::addVisitorIfNecessary(N, S, report); } + + return true; } BugReporterVisitor * @@ -406,7 +758,7 @@ PathDiagnosticPiece *NilReceiverBRVisitor::VisitNode(const ExplodedNode *N, // The receiver was nil, and hence the method was skipped. // Register a BugReporterVisitor to issue a message telling us how // the receiver was null. - bugreporter::addTrackNullOrUndefValueVisitor(N, Receiver, &BR); + bugreporter::trackNullOrUndefValue(N, Receiver, BR); // Issue a message saying that the method was skipped. PathDiagnosticLocation L(Receiver, BRC.getSourceManager(), N->getLocationContext()); @@ -452,14 +804,23 @@ void FindLastStoreBRVisitor::registerStatementVarDecls(BugReport &BR, //===----------------------------------------------------------------------===// // Visitor that tries to report interesting diagnostics from conditions. //===----------------------------------------------------------------------===// + +/// Return the tag associated with this visitor. This tag will be used +/// to make all PathDiagnosticPieces created by this visitor. +const char *ConditionBRVisitor::getTag() { + return "ConditionBRVisitor"; +} + PathDiagnosticPiece *ConditionBRVisitor::VisitNode(const ExplodedNode *N, const ExplodedNode *Prev, BugReporterContext &BRC, BugReport &BR) { PathDiagnosticPiece *piece = VisitNodeImpl(N, Prev, BRC, BR); - if (PathDiagnosticEventPiece *ev = - dyn_cast_or_null<PathDiagnosticEventPiece>(piece)) - ev->setPrunable(true, /* override */ false); + if (piece) { + piece->setTag(getTag()); + if (PathDiagnosticEventPiece *ev=dyn_cast<PathDiagnosticEventPiece>(piece)) + ev->setPrunable(true, /* override */ false); + } return piece; } @@ -468,8 +829,7 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, BugReporterContext &BRC, BugReport &BR) { - const ProgramPoint &progPoint = N->getLocation(); - + ProgramPoint progPoint = N->getLocation(); ProgramStateRef CurrentState = N->getState(); ProgramStateRef PrevState = Prev->getState(); @@ -494,7 +854,7 @@ PathDiagnosticPiece *ConditionBRVisitor::VisitNodeImpl(const ExplodedNode *N, // violation. const std::pair<const ProgramPointTag *, const ProgramPointTag *> &tags = cast<GRBugReporter>(BRC.getBugReporter()). - getEngine().getEagerlyAssumeTags(); + getEngine().geteagerlyAssumeBinOpBifurcationTags(); const ProgramPointTag *tag = PS->getTag(); if (tag == tags.first) @@ -533,8 +893,7 @@ ConditionBRVisitor::VisitTerminator(const Stmt *Term, assert(Cond); assert(srcBlk->succ_size() == 2); const bool tookTrue = *(srcBlk->succ_begin()) == dstBlk; - return VisitTrueTest(Cond->IgnoreParenNoopCasts(BRC.getASTContext()), - tookTrue, BRC, R, N); + return VisitTrueTest(Cond, tookTrue, BRC, R, N); } PathDiagnosticPiece * @@ -547,7 +906,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const Expr *Ex = Cond; while (true) { - Ex = Ex->IgnoreParens(); + Ex = Ex->IgnoreParenCasts(); switch (Ex->getStmtClass()) { default: return 0; @@ -561,7 +920,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const UnaryOperator *UO = cast<UnaryOperator>(Ex); if (UO->getOpcode() == UO_LNot) { tookTrue = !tookTrue; - Ex = UO->getSubExpr()->IgnoreParenNoopCasts(BRC.getASTContext()); + Ex = UO->getSubExpr(); continue; } return 0; @@ -802,3 +1161,54 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, return event; } +PathDiagnosticPiece * +UndefOrNullArgVisitor::VisitNode(const ExplodedNode *N, + const ExplodedNode *PrevN, + BugReporterContext &BRC, + BugReport &BR) { + + ProgramStateRef State = N->getState(); + ProgramPoint ProgLoc = N->getLocation(); + + // We are only interested in visiting CallEnter nodes. + CallEnter *CEnter = dyn_cast<CallEnter>(&ProgLoc); + if (!CEnter) + return 0; + + // Check if one of the arguments is the region the visitor is tracking. + CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager(); + CallEventRef<> Call = CEMgr.getCaller(CEnter->getCalleeContext(), State); + unsigned Idx = 0; + for (CallEvent::param_iterator I = Call->param_begin(), + E = Call->param_end(); I != E; ++I, ++Idx) { + const MemRegion *ArgReg = Call->getArgSVal(Idx).getAsRegion(); + + // Are we tracking the argument or its subregion? + if ( !ArgReg || (ArgReg != R && !R->isSubRegionOf(ArgReg->StripCasts()))) + continue; + + // Check the function parameter type. + const ParmVarDecl *ParamDecl = *I; + assert(ParamDecl && "Formal parameter has no decl?"); + QualType T = ParamDecl->getType(); + + if (!(T->isAnyPointerType() || T->isReferenceType())) { + // Function can only change the value passed in by address. + continue; + } + + // If it is a const pointer value, the function does not intend to + // change the value. + if (T->getPointeeType().isConstQualified()) + continue; + + // Mark the call site (LocationContext) as interesting if the value of the + // argument is undefined or '0'/'NULL'. + SVal BoundVal = State->getSVal(R); + if (BoundVal.isUndef() || BoundVal.isZeroConstant()) { + BR.markInteresting(CEnter->getCalleeContext()); + return 0; + } + } + return 0; +} diff --git a/lib/StaticAnalyzer/Core/CMakeLists.txt b/lib/StaticAnalyzer/Core/CMakeLists.txt index b16b233d6346..91f15b31da63 100644 --- a/lib/StaticAnalyzer/Core/CMakeLists.txt +++ b/lib/StaticAnalyzer/Core/CMakeLists.txt @@ -1,9 +1,9 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangStaticAnalyzerCore - AnalysisManager.cpp APSIntType.cpp - BasicConstraintManager.cpp + AnalysisManager.cpp + AnalyzerOptions.cpp BasicValueFactory.cpp BlockCounter.cpp BugReporter.cpp @@ -14,6 +14,7 @@ add_clang_library(clangStaticAnalyzerCore CheckerHelpers.cpp CheckerManager.cpp CheckerRegistry.cpp + ConstraintManager.cpp CoreEngine.cpp Environment.cpp ExplodedGraph.cpp @@ -54,5 +55,5 @@ target_link_libraries(clangStaticAnalyzerCore clangLex clangAST clangFrontend - clangRewrite + clangRewriteCore ) diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index 5345bd517045..c5cb317bd18d 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -14,6 +14,7 @@ //===----------------------------------------------------------------------===// #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/Analysis/ProgramPoint.h" #include "clang/AST/ParentMap.h" #include "llvm/ADT/SmallSet.h" @@ -23,10 +24,26 @@ using namespace clang; using namespace ento; QualType CallEvent::getResultType() const { - QualType ResultTy = getDeclaredResultType(); + const Expr *E = getOriginExpr(); + assert(E && "Calls without origin expressions do not have results"); + QualType ResultTy = E->getType(); - if (ResultTy.isNull()) - ResultTy = getOriginExpr()->getType(); + ASTContext &Ctx = getState()->getStateManager().getContext(); + + // A function that returns a reference to 'int' will have a result type + // of simply 'int'. Check the origin expr's value kind to recover the + // proper type. + switch (E->getValueKind()) { + case VK_LValue: + ResultTy = Ctx.getLValueReferenceType(ResultTy); + break; + case VK_XValue: + ResultTy = Ctx.getRValueReferenceType(ResultTy); + break; + case VK_RValue: + // No adjustment is necessary. + break; + } return ResultTy; } @@ -45,7 +62,7 @@ static bool isCallbackArg(SVal V, QualType T) { // Check if a callback is passed inside a struct (for both, struct passed by // reference and by value). Dig just one level into the struct for now. - if (isa<PointerType>(T) || isa<ReferenceType>(T)) + if (T->isAnyPointerType() || T->isReferenceType()) T = T->getPointeeType(); if (const RecordType *RT = T->getAsStructureType()) { @@ -83,6 +100,14 @@ bool CallEvent::hasNonZeroCallbackArg() const { return false; } +bool CallEvent::isGlobalCFunction(StringRef FunctionName) const { + const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(getDecl()); + if (!FD) + return false; + + return CheckerContext::isCLibraryFunction(FD, FunctionName); +} + /// \brief Returns true if a type is a pointer-to-const or reference-to-const /// with no further indirection. static bool isPointerToConst(QualType Ty) { @@ -207,6 +232,13 @@ SourceRange CallEvent::getArgSourceRange(unsigned Index) const { return ArgE->getSourceRange(); } +SVal CallEvent::getReturnValue() const { + const Expr *E = getOriginExpr(); + if (!E) + return UndefinedVal(); + return getSVal(E); +} + void CallEvent::dump() const { dump(llvm::errs()); } @@ -230,10 +262,20 @@ void CallEvent::dump(raw_ostream &Out) const { } -bool CallEvent::mayBeInlined(const Stmt *S) { - // FIXME: Kill this. +bool CallEvent::isCallStmt(const Stmt *S) { return isa<CallExpr>(S) || isa<ObjCMessageExpr>(S) - || isa<CXXConstructExpr>(S); + || isa<CXXConstructExpr>(S) + || isa<CXXNewExpr>(S); +} + +/// \brief Returns the result type, adjusted for references. +QualType CallEvent::getDeclaredResultType(const Decl *D) { + assert(D); + if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) + return FD->getResultType(); + else if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(D)) + return MD->getResultType(); + return QualType(); } static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx, @@ -285,14 +327,6 @@ void AnyFunctionCall::getInitialStackFrameContents( D->param_begin(), D->param_end()); } -QualType AnyFunctionCall::getDeclaredResultType() const { - const FunctionDecl *D = getDecl(); - if (!D) - return QualType(); - - return D->getResultType(); -} - bool AnyFunctionCall::argumentsMayEscape() const { if (hasNonZeroCallbackArg()) return true; @@ -303,7 +337,7 @@ bool AnyFunctionCall::argumentsMayEscape() const { const IdentifierInfo *II = D->getIdentifier(); if (!II) - return true; + return false; // This set of "escaping" APIs is @@ -376,6 +410,17 @@ void CXXInstanceCall::getExtraInvalidatedRegions(RegionList &Regions) const { Regions.push_back(R); } +SVal CXXInstanceCall::getCXXThisVal() const { + const Expr *Base = getCXXThisExpr(); + // FIXME: This doesn't handle an overloaded ->* operator. + if (!Base) + return UnknownVal(); + + SVal ThisVal = getSVal(Base); + assert(ThisVal.isUnknownOrUndef() || isa<Loc>(ThisVal)); + return ThisVal; +} + RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { // Do we have a decl at all? @@ -400,13 +445,30 @@ RuntimeDefinition CXXInstanceCall::getRuntimeDefinition() const { // Is the type a C++ class? (This is mostly a defensive check.) QualType RegionType = DynType.getType()->getPointeeType(); + assert(!RegionType.isNull() && "DynamicTypeInfo should always be a pointer."); + const CXXRecordDecl *RD = RegionType->getAsCXXRecordDecl(); if (!RD || !RD->hasDefinition()) return RuntimeDefinition(); // Find the decl for this method in that class. const CXXMethodDecl *Result = MD->getCorrespondingMethodInClass(RD, true); - assert(Result && "At the very least the static decl should show up."); + if (!Result) { + // We might not even get the original statically-resolved method due to + // some particularly nasty casting (e.g. casts to sister classes). + // However, we should at least be able to search up and down our own class + // hierarchy, and some real bugs have been caught by checking this. + assert(!RD->isDerivedFrom(MD->getParent()) && "Couldn't find known method"); + + // FIXME: This is checking that our DynamicTypeInfo is at least as good as + // the static type. However, because we currently don't update + // DynamicTypeInfo when an object is cast, we can't actually be sure the + // DynamicTypeInfo is up to date. This assert should be re-enabled once + // this is fixed. <rdar://problem/12287087> + //assert(!MD->getParent()->isDerivedFrom(RD) && "Bad DynamicTypeInfo"); + + return RuntimeDefinition(); + } // Does the decl that we found have an implementation? const FunctionDecl *Definition; @@ -459,6 +521,18 @@ const Expr *CXXMemberCall::getCXXThisExpr() const { return getOriginExpr()->getImplicitObjectArgument(); } +RuntimeDefinition CXXMemberCall::getRuntimeDefinition() const { + // C++11 [expr.call]p1: ...If the selected function is non-virtual, or if the + // id-expression in the class member access expression is a qualified-id, + // that function is called. Otherwise, its final overrider in the dynamic type + // of the object expression is called. + if (const MemberExpr *ME = dyn_cast<MemberExpr>(getOriginExpr()->getCallee())) + if (ME->hasQualifier()) + return AnyFunctionCall::getRuntimeDefinition(); + + return CXXInstanceCall::getRuntimeDefinition(); +} + const Expr *CXXMemberOperatorCall::getCXXThisExpr() const { return getOriginExpr()->getArg(0); @@ -501,15 +575,6 @@ void BlockCall::getInitialStackFrameContents(const StackFrameContext *CalleeCtx, } -QualType BlockCall::getDeclaredResultType() const { - const BlockDataRegion *BR = getBlockRegion(); - if (!BR) - return QualType(); - QualType BlockTy = BR->getCodeRegion()->getLocationType(); - return cast<FunctionType>(BlockTy->getPointeeType())->getResultType(); -} - - SVal CXXConstructorCall::getCXXThisVal() const { if (Data) return loc::MemRegionVal(static_cast<const MemRegion *>(Data)); @@ -539,10 +604,19 @@ void CXXConstructorCall::getInitialStackFrameContents( SVal CXXDestructorCall::getCXXThisVal() const { if (Data) - return loc::MemRegionVal(static_cast<const MemRegion *>(Data)); + return loc::MemRegionVal(DtorDataTy::getFromOpaqueValue(Data).getPointer()); return UnknownVal(); } +RuntimeDefinition CXXDestructorCall::getRuntimeDefinition() const { + // Base destructors are always called non-virtually. + // Skip CXXInstanceCall's devirtualization logic in this case. + if (isBaseDestructor()) + return AnyFunctionCall::getRuntimeDefinition(); + + return CXXInstanceCall::getRuntimeDefinition(); +} + CallEvent::param_iterator ObjCMethodCall::param_begin() const { const ObjCMethodDecl *D = getDecl(); @@ -566,12 +640,12 @@ ObjCMethodCall::getExtraInvalidatedRegions(RegionList &Regions) const { Regions.push_back(R); } -QualType ObjCMethodCall::getDeclaredResultType() const { - const ObjCMethodDecl *D = getDecl(); - if (!D) - return QualType(); - - return D->getResultType(); +SVal ObjCMethodCall::getSelfSVal() const { + const LocationContext *LCtx = getLocationContext(); + const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl(); + if (!SelfDecl) + return SVal(); + return getState()->getSVal(getState()->getRegion(SelfDecl, LCtx)); } SVal ObjCMethodCall::getReceiverSVal() const { @@ -584,10 +658,23 @@ SVal ObjCMethodCall::getReceiverSVal() const { // An instance message with no expression means we are sending to super. // In this case the object reference is the same as 'self'. - const LocationContext *LCtx = getLocationContext(); - const ImplicitParamDecl *SelfDecl = LCtx->getSelfDecl(); - assert(SelfDecl && "No message receiver Expr, but not in an ObjC method"); - return getState()->getSVal(getState()->getRegion(SelfDecl, LCtx)); + assert(getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperInstance); + SVal SelfVal = getSelfSVal(); + assert(SelfVal.isValid() && "Calling super but not in ObjC method"); + return SelfVal; +} + +bool ObjCMethodCall::isReceiverSelfOrSuper() const { + if (getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperInstance || + getOriginExpr()->getReceiverKind() == ObjCMessageExpr::SuperClass) + return true; + + if (!isInstanceMessage()) + return false; + + SVal RecVal = getSVal(getOriginExpr()->getInstanceReceiver()); + + return (RecVal == getSelfSVal()); } SourceRange ObjCMethodCall::getSourceRange() const { @@ -820,7 +907,8 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx, return getSimpleCall(CE, State, CallerCtx); switch (CallSite->getStmtClass()) { - case Stmt::CXXConstructExprClass: { + case Stmt::CXXConstructExprClass: + case Stmt::CXXTemporaryObjectExprClass: { SValBuilder &SVB = State->getStateManager().getSValBuilder(); const CXXMethodDecl *Ctor = cast<CXXMethodDecl>(CalleeCtx->getDecl()); Loc ThisPtr = SVB.getCXXThis(Ctor, CalleeCtx); @@ -858,5 +946,5 @@ CallEventManager::getCaller(const StackFrameContext *CalleeCtx, Trigger = Dtor->getBody(); return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(), - State, CallerCtx); + isa<CFGBaseDtor>(E), State, CallerCtx); } diff --git a/lib/StaticAnalyzer/Core/CheckerContext.cpp b/lib/StaticAnalyzer/Core/CheckerContext.cpp index 0a047d922aa9..74eeef1c67a8 100644 --- a/lib/StaticAnalyzer/Core/CheckerContext.cpp +++ b/lib/StaticAnalyzer/Core/CheckerContext.cpp @@ -38,17 +38,14 @@ StringRef CheckerContext::getCalleeName(const FunctionDecl *FunDecl) const { bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, StringRef Name) { - return isCLibraryFunction(FD, Name, getASTContext()); -} - -bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, - StringRef Name, ASTContext &Context) { // To avoid false positives (Ex: finding user defined functions with // similar names), only perform fuzzy name matching when it's a builtin. // Using a string compare is slow, we might want to switch on BuiltinID here. unsigned BId = FD->getBuiltinID(); if (BId != 0) { - StringRef BName = Context.BuiltinInfo.GetName(BId); + if (Name.empty()) + return true; + StringRef BName = FD->getASTContext().BuiltinInfo.GetName(BId); if (BName.find(Name) != StringRef::npos) return true; } @@ -59,6 +56,24 @@ bool CheckerContext::isCLibraryFunction(const FunctionDecl *FD, if (!II) return false; + // Look through 'extern "C"' and anything similar invented in the future. + const DeclContext *DC = FD->getDeclContext(); + while (DC->isTransparentContext()) + DC = DC->getParent(); + + // If this function is in a namespace, it is not a C library function. + if (!DC->isTranslationUnit()) + return false; + + // If this function is not externally visible, it is not a C library function. + // Note that we make an exception for inline functions, which may be + // declared in header files without external linkage. + if (!FD->isInlined() && FD->getLinkage() != ExternalLinkage) + return false; + + if (Name.empty()) + return true; + StringRef FName = II->getName(); if (FName.equals(Name)) return true; diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp index c7866559c6d7..3672952b8f6e 100644 --- a/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -36,8 +36,7 @@ bool CheckerManager::hasPathSensitiveCheckers() const { !DeadSymbolsCheckers.empty() || !RegionChangesCheckers.empty() || !EvalAssumeCheckers.empty() || - !EvalCallCheckers.empty() || - !InlineCallCheckers.empty(); + !EvalCallCheckers.empty(); } void CheckerManager::finishedCheckerRegistration() { @@ -314,20 +313,19 @@ namespace { SVal Val; const Stmt *S; ExprEngine &Eng; - ProgramPoint::Kind PointKind; + const ProgramPoint &PP; CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); } CheckersTy::const_iterator checkers_end() { return Checkers.end(); } CheckBindContext(const CheckersTy &checkers, SVal loc, SVal val, const Stmt *s, ExprEngine &eng, - ProgramPoint::Kind PK) - : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PointKind(PK) {} + const ProgramPoint &pp) + : Checkers(checkers), Loc(loc), Val(val), S(s), Eng(eng), PP(pp) {} void runChecker(CheckerManager::CheckBindFunc checkFn, NodeBuilder &Bldr, ExplodedNode *Pred) { - const ProgramPoint &L = ProgramPoint::getProgramPoint(S, PointKind, - Pred->getLocationContext(), checkFn.Checker); + const ProgramPoint &L = PP.withTag(checkFn.Checker); CheckerContext C(Bldr, Eng, Pred, L); checkFn(Loc, Val, S, C); @@ -340,8 +338,8 @@ void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src, SVal location, SVal val, const Stmt *S, ExprEngine &Eng, - ProgramPoint::Kind PointKind) { - CheckBindContext C(BindCheckers, location, val, S, Eng, PointKind); + const ProgramPoint &PP) { + CheckBindContext C(BindCheckers, location, val, S, Eng, PP); expandGraphWithCheckers(C, Dst, Src); } @@ -357,8 +355,8 @@ void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, // for this callback since end of path nodes are expected to be final. void CheckerManager::runCheckersForEndPath(NodeBuilderContext &BC, ExplodedNodeSet &Dst, + ExplodedNode *Pred, ExprEngine &Eng) { - ExplodedNode *Pred = BC.Pred; // We define the builder outside of the loop bacause if at least one checkers // creates a sucsessor for Pred, we do not need to generate an @@ -509,41 +507,13 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, const CallExpr *CE = cast<CallExpr>(Call.getOriginExpr()); for (ExplodedNodeSet::iterator NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) { - ExplodedNode *Pred = *NI; bool anyEvaluated = false; - // First, check if any of the InlineCall callbacks can evaluate the call. - assert(InlineCallCheckers.size() <= 1 && - "InlineCall is a special hacky callback to allow intrusive" - "evaluation of the call (which simulates inlining). It is " - "currently only used by OSAtomicChecker and should go away " - "at some point."); - for (std::vector<InlineCallFunc>::iterator - EI = InlineCallCheckers.begin(), EE = InlineCallCheckers.end(); - EI != EE; ++EI) { - ExplodedNodeSet checkDst; - bool evaluated = (*EI)(CE, Eng, Pred, checkDst); - assert(!(evaluated && anyEvaluated) - && "There are more than one checkers evaluating the call"); - if (evaluated) { - anyEvaluated = true; - Dst.insert(checkDst); -#ifdef NDEBUG - break; // on release don't check that no other checker also evals. -#endif - } - } - -#ifdef NDEBUG // on release don't check that no other checker also evals. - if (anyEvaluated) { - break; - } -#endif - ExplodedNodeSet checkDst; NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); - // Next, check if any of the EvalCall callbacks can evaluate the call. + + // Check if any of the EvalCall callbacks can evaluate the call. for (std::vector<EvalCallFunc>::iterator EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end(); EI != EE; ++EI) { @@ -679,10 +649,6 @@ void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) { EvalCallCheckers.push_back(checkfn); } -void CheckerManager::_registerForInlineCall(InlineCallFunc checkfn) { - InlineCallCheckers.push_back(checkfn); -} - void CheckerManager::_registerForEndOfTranslationUnit( CheckEndOfTranslationUnit checkfn) { EndOfTranslationUnitCheckers.push_back(checkfn); diff --git a/lib/StaticAnalyzer/Core/ConstraintManager.cpp b/lib/StaticAnalyzer/Core/ConstraintManager.cpp new file mode 100644 index 000000000000..4dec52600518 --- /dev/null +++ b/lib/StaticAnalyzer/Core/ConstraintManager.cpp @@ -0,0 +1,39 @@ +//== ConstraintManager.cpp - Constraints on symbolic values -----*- C++ -*--==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defined the interface to manage constraints on symbolic values. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" + +using namespace clang; +using namespace ento; + +ConstraintManager::~ConstraintManager() {} + +static DefinedSVal getLocFromSymbol(const ProgramStateRef &State, + SymbolRef Sym) { + const MemRegion *R = State->getStateManager().getRegionManager() + .getSymbolicRegion(Sym); + return loc::MemRegionVal(R); +} + +ConditionTruthVal ConstraintManager::checkNull(ProgramStateRef State, + SymbolRef Sym) { + QualType Ty = Sym->getType(); + DefinedSVal V = Loc::isLocType(Ty) ? getLocFromSymbol(State, Sym) + : nonloc::SymbolVal(Sym); + const ProgramStatePair &P = assumeDual(State, V); + if (P.first && !P.second) + return ConditionTruthVal(false); + if (!P.first && P.second) + return ConditionTruthVal(true); + return ConditionTruthVal(); +} diff --git a/lib/StaticAnalyzer/Core/CoreEngine.cpp b/lib/StaticAnalyzer/Core/CoreEngine.cpp index 1f137424d450..ec2379212dc6 100644 --- a/lib/StaticAnalyzer/Core/CoreEngine.cpp +++ b/lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -243,11 +243,6 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc, case ProgramPoint::CallEnterKind: { CallEnter CEnter = cast<CallEnter>(Loc); - if (AnalyzedCallees) - if (const CallExpr* CE = - dyn_cast_or_null<CallExpr>(CEnter.getCallExpr())) - if (const Decl *CD = CE->getCalleeDecl()) - AnalyzedCallees->insert(CD); SubEng.processCallEnter(CEnter, Pred); break; } @@ -303,7 +298,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { && "EXIT block cannot contain Stmts."); // Process the final state transition. - SubEng.processEndOfFunction(BuilderCtx); + SubEng.processEndOfFunction(BuilderCtx, Pred); // This path is done. Don't enqueue any more nodes. return; @@ -313,7 +308,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) { ExplodedNodeSet dstNodes; BlockEntrance BE(Blk, Pred->getLocationContext()); NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE); - SubEng.processCFGBlockEntrance(L, nodeBuilder); + SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred); // Auto-generate a node. if (!nodeBuilder.hasGeneratedNodes()) { @@ -519,9 +514,9 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N, return; } - const CFGStmt *CS = (*Block)[Idx].getAs<CFGStmt>(); - const Stmt *St = CS ? CS->getStmt() : 0; - PostStmt Loc(St, N->getLocationContext()); + // At this point, we know we're processing a normal statement. + CFGStmt CS = cast<CFGStmt>((*Block)[Idx]); + PostStmt Loc(CS.getStmt(), N->getLocationContext()); if (Loc == N->getLocation()) { // Note: 'N' should be a fresh node because otherwise it shouldn't be diff --git a/lib/StaticAnalyzer/Core/Environment.cpp b/lib/StaticAnalyzer/Core/Environment.cpp index 52644f7702fc..bab89c545c34 100644 --- a/lib/StaticAnalyzer/Core/Environment.cpp +++ b/lib/StaticAnalyzer/Core/Environment.cpp @@ -20,6 +20,44 @@ using namespace clang; using namespace ento; +static const Expr *ignoreTransparentExprs(const Expr *E) { + E = E->IgnoreParens(); + + switch (E->getStmtClass()) { + case Stmt::OpaqueValueExprClass: + E = cast<OpaqueValueExpr>(E)->getSourceExpr(); + break; + case Stmt::ExprWithCleanupsClass: + E = cast<ExprWithCleanups>(E)->getSubExpr(); + break; + case Stmt::CXXBindTemporaryExprClass: + E = cast<CXXBindTemporaryExpr>(E)->getSubExpr(); + break; + case Stmt::SubstNonTypeTemplateParmExprClass: + E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(); + break; + case Stmt::CXXDefaultArgExprClass: + E = cast<CXXDefaultArgExpr>(E)->getExpr(); + break; + default: + // This is the base case: we can't look through more than we already have. + return E; + } + + return ignoreTransparentExprs(E); +} + +static const Stmt *ignoreTransparentExprs(const Stmt *S) { + if (const Expr *E = dyn_cast<Expr>(S)) + return ignoreTransparentExprs(E); + return S; +} + +EnvironmentEntry::EnvironmentEntry(const Stmt *S, const LocationContext *L) + : std::pair<const Stmt *, + const StackFrameContext *>(ignoreTransparentExprs(S), + L ? L->getCurrentStackFrame() : 0) {} + SVal Environment::lookupExpr(const EnvironmentEntry &E) const { const SVal* X = ExprBindings.lookup(E); if (X) { @@ -30,101 +68,72 @@ SVal Environment::lookupExpr(const EnvironmentEntry &E) const { } SVal Environment::getSVal(const EnvironmentEntry &Entry, - SValBuilder& svalBuilder, - bool useOnlyDirectBindings) const { - - if (useOnlyDirectBindings) { - // This branch is rarely taken, but can be exercised by - // checkers that explicitly bind values to arbitrary - // expressions. It is crucial that we do not ignore any - // expression here, and do a direct lookup. - return lookupExpr(Entry); + SValBuilder& svalBuilder) const { + const Stmt *S = Entry.getStmt(); + const LocationContext *LCtx = Entry.getLocationContext(); + + switch (S->getStmtClass()) { + case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXDefaultArgExprClass: + case Stmt::ExprWithCleanupsClass: + case Stmt::GenericSelectionExprClass: + case Stmt::OpaqueValueExprClass: + case Stmt::ParenExprClass: + case Stmt::SubstNonTypeTemplateParmExprClass: + llvm_unreachable("Should have been handled by ignoreTransparentExprs"); + + case Stmt::AddrLabelExprClass: + return svalBuilder.makeLoc(cast<AddrLabelExpr>(S)); + + case Stmt::CharacterLiteralClass: { + const CharacterLiteral *C = cast<CharacterLiteral>(S); + return svalBuilder.makeIntVal(C->getValue(), C->getType()); } - const Stmt *E = Entry.getStmt(); - const LocationContext *LCtx = Entry.getLocationContext(); - - for (;;) { - if (const Expr *Ex = dyn_cast<Expr>(E)) - E = Ex->IgnoreParens(); - - switch (E->getStmtClass()) { - case Stmt::AddrLabelExprClass: - return svalBuilder.makeLoc(cast<AddrLabelExpr>(E)); - case Stmt::OpaqueValueExprClass: { - const OpaqueValueExpr *ope = cast<OpaqueValueExpr>(E); - E = ope->getSourceExpr(); - continue; - } - case Stmt::ParenExprClass: - case Stmt::GenericSelectionExprClass: - llvm_unreachable("ParenExprs and GenericSelectionExprs should " - "have been handled by IgnoreParens()"); - case Stmt::CharacterLiteralClass: { - const CharacterLiteral* C = cast<CharacterLiteral>(E); - return svalBuilder.makeIntVal(C->getValue(), C->getType()); - } - case Stmt::CXXBoolLiteralExprClass: { - const SVal *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx)); - if (X) - return *X; - else - return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(E)); - } - case Stmt::CXXScalarValueInitExprClass: - case Stmt::ImplicitValueInitExprClass: { - QualType Ty = cast<Expr>(E)->getType(); - return svalBuilder.makeZeroVal(Ty); - } - case Stmt::IntegerLiteralClass: { - // In C++, this expression may have been bound to a temporary object. - SVal const *X = ExprBindings.lookup(EnvironmentEntry(E, LCtx)); - if (X) - return *X; - else - return svalBuilder.makeIntVal(cast<IntegerLiteral>(E)); - } - case Stmt::ObjCBoolLiteralExprClass: - return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(E)); - - // For special C0xx nullptr case, make a null pointer SVal. - case Stmt::CXXNullPtrLiteralExprClass: - return svalBuilder.makeNull(); - case Stmt::ExprWithCleanupsClass: - E = cast<ExprWithCleanups>(E)->getSubExpr(); - continue; - case Stmt::CXXBindTemporaryExprClass: - E = cast<CXXBindTemporaryExpr>(E)->getSubExpr(); - continue; - case Stmt::SubstNonTypeTemplateParmExprClass: - E = cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(); - continue; - case Stmt::ObjCStringLiteralClass: { - MemRegionManager &MRMgr = svalBuilder.getRegionManager(); - const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(E); - return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL)); - } - case Stmt::StringLiteralClass: { - MemRegionManager &MRMgr = svalBuilder.getRegionManager(); - const StringLiteral *SL = cast<StringLiteral>(E); - return svalBuilder.makeLoc(MRMgr.getStringRegion(SL)); - } - case Stmt::ReturnStmtClass: { - const ReturnStmt *RS = cast<ReturnStmt>(E); - if (const Expr *RE = RS->getRetValue()) { - E = RE; - continue; - } - return UndefinedVal(); - } - - // Handle all other Stmt* using a lookup. - default: - break; - }; + case Stmt::CXXBoolLiteralExprClass: + return svalBuilder.makeBoolVal(cast<CXXBoolLiteralExpr>(S)); + + case Stmt::CXXScalarValueInitExprClass: + case Stmt::ImplicitValueInitExprClass: { + QualType Ty = cast<Expr>(S)->getType(); + return svalBuilder.makeZeroVal(Ty); + } + + case Stmt::IntegerLiteralClass: + return svalBuilder.makeIntVal(cast<IntegerLiteral>(S)); + + case Stmt::ObjCBoolLiteralExprClass: + return svalBuilder.makeBoolVal(cast<ObjCBoolLiteralExpr>(S)); + + // For special C0xx nullptr case, make a null pointer SVal. + case Stmt::CXXNullPtrLiteralExprClass: + return svalBuilder.makeNull(); + + case Stmt::ObjCStringLiteralClass: { + MemRegionManager &MRMgr = svalBuilder.getRegionManager(); + const ObjCStringLiteral *SL = cast<ObjCStringLiteral>(S); + return svalBuilder.makeLoc(MRMgr.getObjCStringRegion(SL)); + } + + case Stmt::StringLiteralClass: { + MemRegionManager &MRMgr = svalBuilder.getRegionManager(); + const StringLiteral *SL = cast<StringLiteral>(S); + return svalBuilder.makeLoc(MRMgr.getStringRegion(SL)); + } + + case Stmt::ReturnStmtClass: { + const ReturnStmt *RS = cast<ReturnStmt>(S); + if (const Expr *RE = RS->getRetValue()) + return getSVal(EnvironmentEntry(RE, LCtx), svalBuilder); + return UndefinedVal(); + } + + // Handle all other Stmt* using a lookup. + default: break; } - return lookupExpr(EnvironmentEntry(E, LCtx)); + + return lookupExpr(EnvironmentEntry(S, LCtx)); } Environment EnvironmentManager::bindExpr(Environment Env, @@ -140,16 +149,16 @@ Environment EnvironmentManager::bindExpr(Environment Env, return Environment(F.add(Env.ExprBindings, E, V)); } -static inline EnvironmentEntry MakeLocation(const EnvironmentEntry &E) { - const Stmt *S = E.getStmt(); - S = (const Stmt*) (((uintptr_t) S) | 0x1); - return EnvironmentEntry(S, E.getLocationContext()); +EnvironmentEntry EnvironmentEntry::makeLocation() const { + EnvironmentEntry Result = *this; + reinterpret_cast<uintptr_t &>(Result.first) |= 0x1; + return Result; } Environment EnvironmentManager::bindExprAndLocation(Environment Env, const EnvironmentEntry &E, SVal location, SVal V) { - return Environment(F.add(F.add(Env.ExprBindings, MakeLocation(E), location), + return Environment(F.add(F.add(Env.ExprBindings, E.makeLocation(), location), E, V)); } @@ -286,7 +295,8 @@ void Environment::printAux(raw_ostream &Out, bool printLocations, S = (Stmt*) (((uintptr_t) S) & ((uintptr_t) ~0x1)); } - Out << " (" << (void*) En.getLocationContext() << ',' << (void*) S << ") "; + Out << " (" << (const void*) En.getLocationContext() << ',' + << (const void*) S << ") "; LangOptions LO; // FIXME. S->printPretty(Out, 0, PrintingPolicy(LO)); Out << " : " << I.getData(); diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp index b79f3f5d1eaa..c284bd7dfad4 100644 --- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -47,10 +47,8 @@ void ExplodedNode::SetAuditor(ExplodedNode::Auditor* A) { // Cleanup. //===----------------------------------------------------------------------===// -static const unsigned CounterTop = 1000; - ExplodedGraph::ExplodedGraph() - : NumNodes(0), reclaimNodes(false), reclaimCounter(CounterTop) {} + : NumNodes(0), ReclaimNodeInterval(0) {} ExplodedGraph::~ExplodedGraph() {} @@ -63,12 +61,12 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { // // (1) 1 predecessor (that has one successor) // (2) 1 successor (that has one predecessor) - // (3) The ProgramPoint is for a PostStmt. + // (3) The ProgramPoint is for a PostStmt, but not a PostStore. // (4) There is no 'tag' for the ProgramPoint. // (5) The 'store' is the same as the predecessor. // (6) The 'GDM' is the same as the predecessor. // (7) The LocationContext is the same as the predecessor. - // (8) The PostStmt is for a non-consumed Stmt or Expr. + // (8) The PostStmt isn't for a non-consumed Stmt or Expr. // (9) The successor is not a CallExpr StmtPoint (so that we would be able to // find it when retrying a call with no inlining). // FIXME: It may be safe to reclaim PreCall and PostCall nodes as well. @@ -87,16 +85,13 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { // Condition 3. ProgramPoint progPoint = node->getLocation(); - if (!isa<PostStmt>(progPoint)) + if (!isa<PostStmt>(progPoint) || isa<PostStore>(progPoint)) return false; // Condition 4. PostStmt ps = cast<PostStmt>(progPoint); if (ps.getTag()) return false; - - if (isa<BinaryOperator>(ps.getStmt())) - return false; // Conditions 5, 6, and 7. ProgramStateRef state = node->getState(); @@ -106,6 +101,12 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { return false; // Condition 8. + // Do not collect nodes for non-consumed Stmt or Expr to ensure precise + // diagnostic generation; specifically, so that we could anchor arrows + // pointing to the beginning of statements (as written in code). + if (!isa<Expr>(ps.getStmt())) + return false; + if (const Expr *Ex = dyn_cast<Expr>(ps.getStmt())) { ParentMap &PM = progPoint.getLocationContext()->getParentMap(); if (!PM.isConsumedExpr(Ex)) @@ -115,7 +116,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) { // Condition 9. const ProgramPoint SuccLoc = succ->getLocation(); if (const StmtPoint *SP = dyn_cast<StmtPoint>(&SuccLoc)) - if (CallEvent::mayBeInlined(SP->getStmt())) + if (CallEvent::isCallStmt(SP->getStmt())) return false; return true; @@ -141,13 +142,13 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() { if (ChangedNodes.empty()) return; - // Only periodically relcaim nodes so that we can build up a set of + // Only periodically reclaim nodes so that we can build up a set of // nodes that meet the reclamation criteria. Freshly created nodes // by definition have no successor, and thus cannot be reclaimed (see below). - assert(reclaimCounter > 0); - if (--reclaimCounter != 0) + assert(ReclaimCounter > 0); + if (--ReclaimCounter != 0) return; - reclaimCounter = CounterTop; + ReclaimCounter = ReclaimNodeInterval; for (NodeVector::iterator it = ChangedNodes.begin(), et = ChangedNodes.end(); it != et; ++it) { @@ -162,9 +163,18 @@ void ExplodedGraph::reclaimRecentlyAllocatedNodes() { // ExplodedNode. //===----------------------------------------------------------------------===// -static inline BumpVector<ExplodedNode*>& getVector(void *P) { - return *reinterpret_cast<BumpVector<ExplodedNode*>*>(P); -} +// An NodeGroup's storage type is actually very much like a TinyPtrVector: +// it can be either a pointer to a single ExplodedNode, or a pointer to a +// BumpVector allocated with the ExplodedGraph's allocator. This allows the +// common case of single-node NodeGroups to be implemented with no extra memory. +// +// Consequently, each of the NodeGroup methods have up to four cases to handle: +// 1. The flag is set and this group does not actually contain any nodes. +// 2. The group is empty, in which case the storage value is null. +// 3. The group contains a single node. +// 4. The group contains more than one node. +typedef BumpVector<ExplodedNode *> ExplodedNodeVector; +typedef llvm::PointerUnion<ExplodedNode *, ExplodedNodeVector *> GroupStorage; void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) { assert (!V->isSink()); @@ -176,71 +186,77 @@ void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) { } void ExplodedNode::NodeGroup::replaceNode(ExplodedNode *node) { - assert(getKind() == Size1); - P = reinterpret_cast<uintptr_t>(node); - assert(getKind() == Size1); + assert(!getFlag()); + + GroupStorage &Storage = reinterpret_cast<GroupStorage&>(P); + assert(Storage.is<ExplodedNode *>()); + Storage = node; + assert(Storage.is<ExplodedNode *>()); } void ExplodedNode::NodeGroup::addNode(ExplodedNode *N, ExplodedGraph &G) { - assert((reinterpret_cast<uintptr_t>(N) & Mask) == 0x0); assert(!getFlag()); - if (getKind() == Size1) { - if (ExplodedNode *NOld = getNode()) { - BumpVectorContext &Ctx = G.getNodeAllocator(); - BumpVector<ExplodedNode*> *V = - G.getAllocator().Allocate<BumpVector<ExplodedNode*> >(); - new (V) BumpVector<ExplodedNode*>(Ctx, 4); - - assert((reinterpret_cast<uintptr_t>(V) & Mask) == 0x0); - V->push_back(NOld, Ctx); - V->push_back(N, Ctx); - P = reinterpret_cast<uintptr_t>(V) | SizeOther; - assert(getPtr() == (void*) V); - assert(getKind() == SizeOther); - } - else { - P = reinterpret_cast<uintptr_t>(N); - assert(getKind() == Size1); - } + GroupStorage &Storage = reinterpret_cast<GroupStorage&>(P); + if (Storage.isNull()) { + Storage = N; + assert(Storage.is<ExplodedNode *>()); + return; } - else { - assert(getKind() == SizeOther); - getVector(getPtr()).push_back(N, G.getNodeAllocator()); + + ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>(); + + if (!V) { + // Switch from single-node to multi-node representation. + ExplodedNode *Old = Storage.get<ExplodedNode *>(); + + BumpVectorContext &Ctx = G.getNodeAllocator(); + V = G.getAllocator().Allocate<ExplodedNodeVector>(); + new (V) ExplodedNodeVector(Ctx, 4); + V->push_back(Old, Ctx); + + Storage = V; + assert(!getFlag()); + assert(Storage.is<ExplodedNodeVector *>()); } + + V->push_back(N, G.getNodeAllocator()); } unsigned ExplodedNode::NodeGroup::size() const { if (getFlag()) return 0; - if (getKind() == Size1) - return getNode() ? 1 : 0; - else - return getVector(getPtr()).size(); + const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P); + if (Storage.isNull()) + return 0; + if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>()) + return V->size(); + return 1; } -ExplodedNode **ExplodedNode::NodeGroup::begin() const { +ExplodedNode * const *ExplodedNode::NodeGroup::begin() const { if (getFlag()) - return NULL; + return 0; - if (getKind() == Size1) - return (ExplodedNode**) (getPtr() ? &P : NULL); - else - return const_cast<ExplodedNode**>(&*(getVector(getPtr()).begin())); + const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P); + if (Storage.isNull()) + return 0; + if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>()) + return V->begin(); + return Storage.getAddrOfPtr1(); } -ExplodedNode** ExplodedNode::NodeGroup::end() const { +ExplodedNode * const *ExplodedNode::NodeGroup::end() const { if (getFlag()) - return NULL; - - if (getKind() == Size1) - return (ExplodedNode**) (getPtr() ? &P+1 : NULL); - else { - // Dereferencing end() is undefined behaviour. The vector is not empty, so - // we can dereference the last elem and then add 1 to the result. - return const_cast<ExplodedNode**>(getVector(getPtr()).end()); - } + return 0; + + const GroupStorage &Storage = reinterpret_cast<const GroupStorage &>(P); + if (Storage.isNull()) + return 0; + if (ExplodedNodeVector *V = Storage.dyn_cast<ExplodedNodeVector *>()) + return V->end(); + return Storage.getAddrOfPtr1() + 1; } ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L, @@ -266,7 +282,7 @@ ExplodedNode *ExplodedGraph::getNode(const ProgramPoint &L, new (V) NodeTy(L, State, IsSink); - if (reclaimNodes) + if (ReclaimNodeInterval) ChangedNodes.push_back(V); // Insert the node into the node set and return it. @@ -314,8 +330,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, // ===- Pass 1 (reverse DFS) -=== for (const ExplodedNode* const* I = BeginSources; I != EndSources; ++I) { - assert(*I); - WL1.push_back(*I); + if (*I) + WL1.push_back(*I); } // Process the first worklist until it is empty. Because it is a std::list @@ -338,7 +354,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, } // Visit our predecessors and enqueue them. - for (ExplodedNode** I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) + for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end(); + I != E; ++I) WL1.push_back(*I); } @@ -375,7 +392,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, // Walk through the predecessors of 'N' and hook up their corresponding // nodes in the new graph (if any) to the freshly created node. - for (ExplodedNode **I=N->Preds.begin(), **E=N->Preds.end(); I!=E; ++I) { + for (ExplodedNode::pred_iterator I = N->Preds.begin(), E = N->Preds.end(); + I != E; ++I) { Pass2Ty::iterator PI = Pass2.find(*I); if (PI == Pass2.end()) continue; @@ -387,7 +405,8 @@ ExplodedGraph::TrimInternal(const ExplodedNode* const* BeginSources, // been created, we should hook them up as successors. Otherwise, enqueue // the new nodes from the original graph that should have nodes created // in the new graph. - for (ExplodedNode **I=N->Succs.begin(), **E=N->Succs.end(); I!=E; ++I) { + for (ExplodedNode::succ_iterator I = N->Succs.begin(), E = N->Succs.end(); + I != E; ++I) { Pass2Ty::iterator PI = Pass2.find(*I); if (PI != Pass2.end()) { PI->second->addPredecessor(NewN, *G); diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index b0435fb562e3..045591c9074b 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -55,32 +55,32 @@ STATISTIC(NumTimesRetriedWithoutInlining, //===----------------------------------------------------------------------===// ExprEngine::ExprEngine(AnalysisManager &mgr, bool gcEnabled, - SetOfConstDecls *VisitedCallees, + SetOfConstDecls *VisitedCalleesIn, FunctionSummariesTy *FS) : AMgr(mgr), AnalysisDeclContexts(mgr.getAnalysisDeclContextManager()), - Engine(*this, VisitedCallees, FS), + Engine(*this, FS), G(Engine.getGraph()), StateMgr(getContext(), mgr.getStoreManagerCreator(), mgr.getConstraintManagerCreator(), G.getAllocator(), - *this), + this), SymMgr(StateMgr.getSymbolManager()), svalBuilder(StateMgr.getSValBuilder()), EntryNode(NULL), - currentStmt(NULL), currentStmtIdx(0), currentBuilderContext(0), - NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL), - RaiseSel(GetNullarySelector("raise", getContext())), - ObjCGCEnabled(gcEnabled), BR(mgr, *this) { - - if (mgr.shouldEagerlyTrimExplodedGraph()) { - // Enable eager node reclaimation when constructing the ExplodedGraph. - G.enableNodeReclamation(); + currStmt(NULL), currStmtIdx(0), currBldrCtx(0), + ObjCNoRet(mgr.getASTContext()), + ObjCGCEnabled(gcEnabled), BR(mgr, *this), + VisitedCallees(VisitedCalleesIn) +{ + unsigned TrimInterval = mgr.options.getGraphTrimInterval(); + if (TrimInterval != 0) { + // Enable eager node reclaimation when constructing the ExplodedGraph. + G.enableNodeReclamation(TrimInterval); } } ExprEngine::~ExprEngine() { BR.FlushReports(); - delete [] NSExceptionInstanceRaiseSelectors; } //===----------------------------------------------------------------------===// @@ -164,6 +164,23 @@ ProgramStateRef ExprEngine::getInitialState(const LocationContext *InitLoc) { return state; } +/// If the value of the given expression is a NonLoc, copy it into a new +/// temporary region, and replace the value of the expression with that. +static ProgramStateRef createTemporaryRegionIfNeeded(ProgramStateRef State, + const LocationContext *LC, + const Expr *E) { + SVal V = State->getSVal(E, LC); + + if (isa<NonLoc>(V)) { + MemRegionManager &MRMgr = State->getStateManager().getRegionManager(); + const MemRegion *R = MRMgr.getCXXTempObjectRegion(E, LC); + State = State->bindLoc(loc::MemRegionVal(R), V); + State = State->BindExpr(E, LC, loc::MemRegionVal(R)); + } + + return State; +} + //===----------------------------------------------------------------------===// // Top-level transfer function logic (Dispatcher). //===----------------------------------------------------------------------===// @@ -200,8 +217,8 @@ void ExprEngine::processEndWorklist(bool hasWorkRemaining) { void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, unsigned StmtIdx, NodeBuilderContext *Ctx) { - currentStmtIdx = StmtIdx; - currentBuilderContext = Ctx; + currStmtIdx = StmtIdx; + currBldrCtx = Ctx; switch (E.getKind()) { case CFGElement::Invalid: @@ -219,7 +236,7 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, ProcessImplicitDtor(*E.getAs<CFGImplicitDtor>(), Pred); return; } - currentBuilderContext = 0; + currBldrCtx = 0; } static bool shouldRemoveDeadBindings(AnalysisManager &AMgr, @@ -228,7 +245,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr, const LocationContext *LC) { // Are we never purging state values? - if (AMgr.getPurgeMode() == PurgeNone) + if (AMgr.options.AnalysisPurgeOpt == PurgeNone) return false; // Is this the beginning of a basic block? @@ -240,7 +257,7 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr, return true; // Run before processing a call. - if (CallEvent::mayBeInlined(S.getStmt())) + if (CallEvent::isCallStmt(S.getStmt())) return true; // Is this an expression that is consumed by another expression? If so, @@ -251,12 +268,12 @@ static bool shouldRemoveDeadBindings(AnalysisManager &AMgr, void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, const Stmt *ReferenceStmt, - const LocationContext *LC, + const StackFrameContext *LC, const Stmt *DiagnosticStmt, ProgramPoint::Kind K) { assert((K == ProgramPoint::PreStmtPurgeDeadSymbolsKind || - ReferenceStmt == 0) && "PreStmt is not generally supported by " - "the SymbolReaper yet"); + ReferenceStmt == 0) + && "PostStmt is not generally supported by the SymbolReaper yet"); NumRemoveDeadBindings++; CleanedState = Pred->getState(); SymbolReaper SymReaper(LC, ReferenceStmt, SymMgr, getStoreManager()); @@ -276,8 +293,8 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, // Generate a CleanedNode that has the environment and store cleaned // up. Since no symbols are dead, we can optimize and not clean out // the constraint manager. - StmtNodeBuilder Bldr(Pred, Out, *currentBuilderContext); - Bldr.generateNode(DiagnosticStmt, Pred, CleanedState, false, &cleanupTag,K); + StmtNodeBuilder Bldr(Pred, Out, *currBldrCtx); + Bldr.generateNode(DiagnosticStmt, Pred, CleanedState, &cleanupTag, K); } else { // Call checkers with the non-cleaned state so that they could query the @@ -289,7 +306,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, // For each node in CheckedSet, generate CleanedNodes that have the // environment, the store, and the constraints cleaned up but have the // user-supplied states as the predecessors. - StmtNodeBuilder Bldr(CheckedSet, Out, *currentBuilderContext); + StmtNodeBuilder Bldr(CheckedSet, Out, *currBldrCtx); for (ExplodedNodeSet::const_iterator I = CheckedSet.begin(), E = CheckedSet.end(); I != E; ++I) { ProgramStateRef CheckerState = (*I)->getState(); @@ -309,8 +326,7 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, // generate a transition to that state. ProgramStateRef CleanedCheckerSt = StateMgr.getPersistentStateWithGDM(CleanedState, CheckerState); - Bldr.generateNode(DiagnosticStmt, *I, CleanedCheckerSt, false, - &cleanupTag, K); + Bldr.generateNode(DiagnosticStmt, *I, CleanedCheckerSt, &cleanupTag, K); } } } @@ -320,17 +336,17 @@ void ExprEngine::ProcessStmt(const CFGStmt S, // Reclaim any unnecessary nodes in the ExplodedGraph. G.reclaimRecentlyAllocatedNodes(); - currentStmt = S.getStmt(); + currStmt = S.getStmt(); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), - currentStmt->getLocStart(), + currStmt->getLocStart(), "Error evaluating statement"); // Remove dead bindings and symbols. EntryNode = Pred; ExplodedNodeSet CleanedStates; if (shouldRemoveDeadBindings(AMgr, S, Pred, EntryNode->getLocationContext())){ - removeDead(EntryNode, CleanedStates, currentStmt, - Pred->getLocationContext(), currentStmt); + removeDead(EntryNode, CleanedStates, currStmt, + Pred->getStackFrame(), currStmt); } else CleanedStates.Add(EntryNode); @@ -340,44 +356,45 @@ void ExprEngine::ProcessStmt(const CFGStmt S, E = CleanedStates.end(); I != E; ++I) { ExplodedNodeSet DstI; // Visit the statement. - Visit(currentStmt, *I, DstI); + Visit(currStmt, *I, DstI); Dst.insert(DstI); } // Enqueue the new nodes onto the work list. - Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx); + Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); // NULL out these variables to cleanup. CleanedState = NULL; EntryNode = NULL; - currentStmt = 0; + currStmt = 0; } void ExprEngine::ProcessInitializer(const CFGInitializer Init, ExplodedNode *Pred) { - ExplodedNodeSet Dst; - NodeBuilder Bldr(Pred, Dst, *currentBuilderContext); - - ProgramStateRef State = Pred->getState(); - const CXXCtorInitializer *BMI = Init.getInitializer(); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), BMI->getSourceLocation(), "Error evaluating initializer"); - // We don't set EntryNode and currentStmt. And we don't clean up state. + // We don't set EntryNode and currStmt. And we don't clean up state. const StackFrameContext *stackFrame = cast<StackFrameContext>(Pred->getLocationContext()); const CXXConstructorDecl *decl = cast<CXXConstructorDecl>(stackFrame->getDecl()); + + ProgramStateRef State = Pred->getState(); SVal thisVal = State->getSVal(svalBuilder.getCXXThis(decl, stackFrame)); + PostInitializer PP(BMI, stackFrame); + ExplodedNodeSet Tmp(Pred); + // Evaluate the initializer, if necessary if (BMI->isAnyMemberInitializer()) { // Constructors build the object directly in the field, // but non-objects must be copied in from the initializer. - if (!isa<CXXConstructExpr>(BMI->getInit())) { + const Expr *Init = BMI->getInit(); + if (!isa<CXXConstructExpr>(Init)) { SVal FieldLoc; if (BMI->isIndirectMemberInitializer()) FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal); @@ -385,22 +402,26 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, FieldLoc = State->getLValue(BMI->getMember(), thisVal); SVal InitVal = State->getSVal(BMI->getInit(), stackFrame); - State = State->bindLoc(FieldLoc, InitVal); + + Tmp.clear(); + evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP); } } else { assert(BMI->isBaseInitializer() || BMI->isDelegatingInitializer()); // We already did all the work when visiting the CXXConstructExpr. } - // Construct a PostInitializer node whether the state changed or not, + // Construct PostInitializer nodes whether the state changed or not, // so that the diagnostics don't get confused. - PostInitializer PP(BMI, stackFrame); - // Builder automatically add the generated node to the deferred set, - // which are processed in the builder's dtor. - Bldr.generateNode(PP, State, Pred); + ExplodedNodeSet Dst; + NodeBuilder Bldr(Tmp, Dst, *currBldrCtx); + for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I != E; ++I) { + ExplodedNode *N = *I; + Bldr.generateNode(PP, N->getState(), N); + } // Enqueue the new nodes onto the work list. - Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx); + Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); } void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, @@ -424,7 +445,7 @@ void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D, } // Enqueue the new nodes onto the work list. - Engine.enqueue(Dst, currentBuilderContext->getBlock(), currentStmtIdx); + Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx); } void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, @@ -441,7 +462,7 @@ void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor Dtor, Loc dest = state->getLValue(varDecl, Pred->getLocationContext()); VisitCXXDestructor(varType, cast<loc::MemRegionVal>(dest).getRegion(), - Dtor.getTriggerStmt(), Pred, Dst); + Dtor.getTriggerStmt(), /*IsBase=*/false, Pred, Dst); } void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, @@ -459,7 +480,7 @@ void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D, SVal BaseVal = getStoreManager().evalDerivedToBase(ThisVal, BaseTy); VisitCXXDestructor(BaseTy, cast<loc::MemRegionVal>(BaseVal).getRegion(), - CurDtor->getBody(), Pred, Dst); + CurDtor->getBody(), /*IsBase=*/true, Pred, Dst); } void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D, @@ -475,7 +496,7 @@ void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D, VisitCXXDestructor(Member->getType(), cast<loc::MemRegionVal>(FieldVal).getRegion(), - CurDtor->getBody(), Pred, Dst); + CurDtor->getBody(), /*IsBase=*/false, Pred, Dst); } void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D, @@ -488,7 +509,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, S->getLocStart(), "Error evaluating statement"); ExplodedNodeSet Dst; - StmtNodeBuilder Bldr(Pred, DstTop, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, DstTop, *currBldrCtx); // Expressions to ignore. if (const Expr *Ex = dyn_cast<Expr>(S)) @@ -498,7 +519,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, // this check when we KNOW that there is no block-level subexpression. // The motivation is that this check requires a hashtable lookup. - if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) + if (S != currStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) return; switch (S->getStmtClass()) { @@ -521,21 +542,16 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::CXXNoexceptExprClass: case Stmt::PackExpansionExprClass: case Stmt::SubstNonTypeTemplateParmPackExprClass: + case Stmt::FunctionParmPackExprClass: case Stmt::SEHTryStmtClass: case Stmt::SEHExceptStmtClass: case Stmt::LambdaExprClass: case Stmt::SEHFinallyStmtClass: { - const ExplodedNode *node = Bldr.generateNode(S, Pred, Pred->getState(), - /* sink */ true); - Engine.addAbortedBlock(node, currentBuilderContext->getBlock()); + const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState()); + Engine.addAbortedBlock(node, currBldrCtx->getBlock()); break; } - // We don't handle default arguments either yet, but we can fake it - // for now by just skipping them. - case Stmt::CXXDefaultArgExprClass: - break; - case Stmt::ParenExprClass: llvm_unreachable("ParenExprs already handled."); case Stmt::GenericSelectionExprClass: @@ -607,11 +623,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::AtomicExprClass: // Fall through. - // Currently all handling of 'throw' just falls to the CFG. We - // can consider doing more if necessary. - case Stmt::CXXThrowExprClass: - // Fall through. - // Cases we intentionally don't evaluate, since they don't need // to be explicitly evaluated. case Stmt::AddrLabelExprClass: @@ -626,6 +637,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::StringLiteralClass: case Stmt::ObjCStringLiteralClass: case Stmt::CXXBindTemporaryExprClass: + case Stmt::CXXDefaultArgExprClass: case Stmt::SubstNonTypeTemplateParmExprClass: case Stmt::CXXNullPtrLiteralExprClass: { Bldr.takeNodes(Pred); @@ -647,7 +659,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, getCheckerManager().runCheckersForPreStmt(preVisit, Pred, S, *this); ExplodedNodeSet Tmp; - StmtNodeBuilder Bldr2(preVisit, Tmp, *currentBuilderContext); + StmtNodeBuilder Bldr2(preVisit, Tmp, *currBldrCtx); const Expr *Ex = cast<Expr>(S); QualType resultType = Ex->getType(); @@ -656,9 +668,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, it != et; ++it) { ExplodedNode *N = *it; const LocationContext *LCtx = N->getLocationContext(); - SVal result = - svalBuilder.getConjuredSymbolVal(0, Ex, LCtx, resultType, - currentBuilderContext->getCurrentBlockCount()); + SVal result = svalBuilder.conjureSymbolVal(0, Ex, LCtx, resultType, + currBldrCtx->blockCount()); ProgramStateRef state = N->getState()->BindExpr(Ex, LCtx, result); Bldr2.generateNode(S, N, state); } @@ -674,9 +685,9 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, Bldr.addNodes(Dst); break; - case Stmt::AsmStmtClass: + case Stmt::GCCAsmStmtClass: Bldr.takeNodes(Pred); - VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst); + VisitGCCAsmStmt(cast<GCCAsmStmt>(S), Pred, Dst); Bldr.addNodes(Dst); break; @@ -711,11 +722,11 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, Bldr.takeNodes(Pred); - if (AMgr.shouldEagerlyAssume() && + if (AMgr.options.eagerlyAssumeBinOpBifurcation && (B->isRelationalOp() || B->isEqualityOp())) { ExplodedNodeSet Tmp; VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp); - evalEagerlyAssume(Dst, Tmp, cast<Expr>(S)); + evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, cast<Expr>(S)); } else VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst); @@ -724,8 +735,26 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, break; } + case Stmt::CXXOperatorCallExprClass: { + const CXXOperatorCallExpr *OCE = cast<CXXOperatorCallExpr>(S); + + // For instance method operators, make sure the 'this' argument has a + // valid region. + const Decl *Callee = OCE->getCalleeDecl(); + if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Callee)) { + if (MD->isInstance()) { + ProgramStateRef State = Pred->getState(); + const LocationContext *LCtx = Pred->getLocationContext(); + ProgramStateRef NewState = + createTemporaryRegionIfNeeded(State, LCtx, OCE->getArg(0)); + if (NewState != State) + Pred = Bldr.generateNode(OCE, Pred, NewState, /*Tag=*/0, + ProgramPoint::PreStmtKind); + } + } + // FALLTHROUGH + } case Stmt::CallExprClass: - case Stmt::CXXOperatorCallExprClass: case Stmt::CXXMemberCallExprClass: case Stmt::UserDefinedLiteralClass: { Bldr.takeNodes(Pred); @@ -846,12 +875,8 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Expr::MaterializeTemporaryExprClass: { Bldr.takeNodes(Pred); - const MaterializeTemporaryExpr *Materialize - = cast<MaterializeTemporaryExpr>(S); - if (Materialize->getType()->isRecordType()) - Dst.Add(Pred); - else - CreateCXXTemporaryObject(Materialize, Pred, Dst); + const MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(S); + CreateCXXTemporaryObject(MTE, Pred, Dst); Bldr.addNodes(Dst); break; } @@ -886,12 +911,12 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, Bldr.addNodes(Dst); break; - case Stmt::ObjCAtThrowStmtClass: { + case Stmt::ObjCAtThrowStmtClass: + case Stmt::CXXThrowExprClass: // FIXME: This is not complete. We basically treat @throw as // an abort. - Bldr.generateNode(S, Pred, Pred->getState()); + Bldr.generateSink(S, Pred, Pred->getState()); break; - } case Stmt::ReturnStmtClass: Bldr.takeNodes(Pred); @@ -935,10 +960,10 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::UnaryOperatorClass: { Bldr.takeNodes(Pred); const UnaryOperator *U = cast<UnaryOperator>(S); - if (AMgr.shouldEagerlyAssume() && (U->getOpcode() == UO_LNot)) { + if (AMgr.options.eagerlyAssumeBinOpBifurcation && (U->getOpcode() == UO_LNot)) { ExplodedNodeSet Tmp; VisitUnaryOperator(U, Pred, Tmp); - evalEagerlyAssume(Dst, Tmp, U); + evalEagerlyAssumeBinOpBifurcation(Dst, Tmp, U); } else VisitUnaryOperator(U, Pred, Dst); @@ -1030,19 +1055,18 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N, /// Block entrance. (Update counters). void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, - NodeBuilderWithSinks &nodeBuilder) { + NodeBuilderWithSinks &nodeBuilder, + ExplodedNode *Pred) { // FIXME: Refactor this into a checker. - ExplodedNode *pred = nodeBuilder.getContext().getPred(); - - if (nodeBuilder.getContext().getCurrentBlockCount() >= AMgr.getMaxVisit()) { + if (nodeBuilder.getContext().blockCount() >= AMgr.options.maxBlockVisitOnPath) { static SimpleProgramPointTag tag("ExprEngine : Block count exceeded"); const ExplodedNode *Sink = - nodeBuilder.generateNode(pred->getState(), pred, &tag, true); + nodeBuilder.generateSink(Pred->getState(), Pred, &tag); // Check if we stopped at the top level function or not. // Root node should have the location context of the top most function. - const LocationContext *CalleeLC = pred->getLocation().getLocationContext(); + const LocationContext *CalleeLC = Pred->getLocation().getLocationContext(); const LocationContext *CalleeSF = CalleeLC->getCurrentStackFrame(); const LocationContext *RootLC = (*G.roots_begin())->getLocation().getLocationContext(); @@ -1053,7 +1077,8 @@ void ExprEngine::processCFGBlockEntrance(const BlockEdge &L, // no-inlining policy in the state and enqueuing the new work item on // the list. Replay should almost never fail. Use the stats to catch it // if it does. - if ((!AMgr.NoRetryExhausted && replayWithoutInlining(pred, CalleeLC))) + if ((!AMgr.options.NoRetryExhausted && + replayWithoutInlining(Pred, CalleeLC))) return; NumMaxBlockCountReachedInInlined++; } else @@ -1155,7 +1180,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, ExplodedNodeSet &Dst, const CFGBlock *DstT, const CFGBlock *DstF) { - currentBuilderContext = &BldCtx; + currBldrCtx = &BldCtx; // Check for NULL conditions; e.g. "for(;;)" if (!Condition) { @@ -1238,7 +1263,7 @@ void ExprEngine::processBranch(const Stmt *Condition, const Stmt *Term, builder.markInfeasible(false); } } - currentBuilderContext = 0; + currBldrCtx = 0; } /// processIndirectGoto - Called by CoreEngine. Used to generate successor @@ -1287,10 +1312,25 @@ void ExprEngine::processIndirectGoto(IndirectGotoNodeBuilder &builder) { /// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path /// nodes when the control reaches the end of a function. -void ExprEngine::processEndOfFunction(NodeBuilderContext& BC) { - StateMgr.EndPath(BC.Pred->getState()); +void ExprEngine::processEndOfFunction(NodeBuilderContext& BC, + ExplodedNode *Pred) { + StateMgr.EndPath(Pred->getState()); + ExplodedNodeSet Dst; - getCheckerManager().runCheckersForEndPath(BC, Dst, *this); + if (Pred->getLocationContext()->inTopFrame()) { + // Remove dead symbols. + ExplodedNodeSet AfterRemovedDead; + removeDeadOnEndOfFunction(BC, Pred, AfterRemovedDead); + + // Notify checkers. + for (ExplodedNodeSet::iterator I = AfterRemovedDead.begin(), + E = AfterRemovedDead.end(); I != E; ++I) { + getCheckerManager().runCheckersForEndPath(BC, Dst, *I, *this); + } + } else { + getCheckerManager().runCheckersForEndPath(BC, Dst, Pred, *this); + } + Engine.enqueueEndOfFunction(Dst); } @@ -1404,7 +1444,7 @@ void ExprEngine::processSwitch(SwitchNodeBuilder& builder) { void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); @@ -1422,7 +1462,7 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, V = UnknownVal(); } - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), false, 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, ProgramPoint::PostLValueKind); return; } @@ -1434,19 +1474,23 @@ void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D, } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { SVal V = svalBuilder.getFunctionPointer(FD); - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), false, 0, + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, ProgramPoint::PostLValueKind); return; } if (isa<FieldDecl>(D)) { - // FIXME: Compute lvalue of fields. - Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, UnknownVal()), - false, 0, ProgramPoint::PostLValueKind); + // FIXME: Compute lvalue of field pointers-to-member. + // Right now we just use a non-null void pointer, so that it gives proper + // results in boolean contexts. + SVal V = svalBuilder.conjureSymbolVal(Ex, LCtx, getContext().VoidPtrTy, + currBldrCtx->blockCount()); + state = state->assume(cast<DefinedOrUnknownSVal>(V), true); + Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, V), 0, + ProgramPoint::PostLValueKind); return; } - assert (false && - "ValueDecl support for this ValueDecl not implemented."); + llvm_unreachable("Support for this Decl not implemented."); } /// VisitArraySubscriptExpr - Transfer function for array accesses @@ -1461,7 +1505,7 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, ExplodedNodeSet checkerPreStmt; getCheckerManager().runCheckersForPreStmt(checkerPreStmt, Pred, A, *this); - StmtNodeBuilder Bldr(checkerPreStmt, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(checkerPreStmt, Dst, *currBldrCtx); for (ExplodedNodeSet::iterator it = checkerPreStmt.begin(), ei = checkerPreStmt.end(); it != ei; ++it) { @@ -1471,8 +1515,8 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, state->getSVal(Idx, LCtx), state->getSVal(Base, LCtx)); assert(A->isGLValue()); - Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), - false, 0, ProgramPoint::PostLValueKind); + Bldr.generateNode(A, *it, state->BindExpr(A, LCtx, V), 0, + ProgramPoint::PostLValueKind); } } @@ -1480,52 +1524,40 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, ExplodedNodeSet &TopDst) { - StmtNodeBuilder Bldr(Pred, TopDst, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, TopDst, *currBldrCtx); ExplodedNodeSet Dst; - Decl *member = M->getMemberDecl(); + ValueDecl *Member = M->getMemberDecl(); - if (VarDecl *VD = dyn_cast<VarDecl>(member)) { - assert(M->isGLValue()); + // Handle static member variables and enum constants accessed via + // member syntax. + if (isa<VarDecl>(Member) || isa<EnumConstantDecl>(Member)) { Bldr.takeNodes(Pred); - VisitCommonDeclRefExpr(M, VD, Pred, Dst); + VisitCommonDeclRefExpr(M, Member, Pred, Dst); Bldr.addNodes(Dst); return; } - // Handle C++ method calls. - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(member)) { - Bldr.takeNodes(Pred); - SVal MDVal = svalBuilder.getFunctionPointer(MD); - ProgramStateRef state = - Pred->getState()->BindExpr(M, Pred->getLocationContext(), MDVal); - Bldr.generateNode(M, Pred, state); - return; - } + ProgramStateRef state = Pred->getState(); + const LocationContext *LCtx = Pred->getLocationContext(); + Expr *BaseExpr = M->getBase(); + // Handle C++ method calls. + if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Member)) { + if (MD->isInstance()) + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - FieldDecl *field = dyn_cast<FieldDecl>(member); - if (!field) // FIXME: skipping member expressions for non-fields - return; + SVal MDVal = svalBuilder.getFunctionPointer(MD); + state = state->BindExpr(M, LCtx, MDVal); - Expr *baseExpr = M->getBase()->IgnoreParens(); - ProgramStateRef state = Pred->getState(); - const LocationContext *LCtx = Pred->getLocationContext(); - SVal baseExprVal = state->getSVal(baseExpr, Pred->getLocationContext()); - if (isa<nonloc::LazyCompoundVal>(baseExprVal) || - isa<nonloc::CompoundVal>(baseExprVal) || - // FIXME: This can originate by conjuring a symbol for an unknown - // temporary struct object, see test/Analysis/fields.c: - // (p = getit()).x - isa<nonloc::SymbolVal>(baseExprVal)) { - Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, UnknownVal())); + Bldr.generateNode(M, Pred, state); return; } - // FIXME: Should we insert some assumption logic in here to determine - // if "Base" is a valid piece of memory? Before we put this assumption - // later when using FieldOffset lvals (which we no longer have). + // Handle regular struct fields / member variables. + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + SVal baseExprVal = state->getSVal(BaseExpr, LCtx); - // For all other cases, compute an lvalue. + FieldDecl *field = cast<FieldDecl>(Member); SVal L = state->getLValue(field, baseExprVal); if (M->isGLValue()) { if (field->getType()->isReferenceType()) { @@ -1535,7 +1567,7 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, L = UnknownVal(); } - Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), false, 0, + Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), 0, ProgramPoint::PostLValueKind); } else { Bldr.takeNodes(Pred); @@ -1548,40 +1580,48 @@ void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, /// This method is used by evalStore and (soon) VisitDeclStmt, and others. void ExprEngine::evalBind(ExplodedNodeSet &Dst, const Stmt *StoreE, ExplodedNode *Pred, - SVal location, SVal Val, bool atDeclInit) { + SVal location, SVal Val, + bool atDeclInit, const ProgramPoint *PP) { + + const LocationContext *LC = Pred->getLocationContext(); + PostStmt PS(StoreE, LC); + if (!PP) + PP = &PS; // Do a previsit of the bind. ExplodedNodeSet CheckedSet; getCheckerManager().runCheckersForBind(CheckedSet, Pred, location, Val, - StoreE, *this, - ProgramPoint::PostStmtKind); + StoreE, *this, *PP); + // If the location is not a 'Loc', it will already be handled by + // the checkers. There is nothing left to do. + if (!isa<Loc>(location)) { + Dst = CheckedSet; + return; + } + ExplodedNodeSet TmpDst; - StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currentBuilderContext); + StmtNodeBuilder Bldr(CheckedSet, TmpDst, *currBldrCtx); - const LocationContext *LC = Pred->getLocationContext(); for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); I!=E; ++I) { ExplodedNode *PredI = *I; ProgramStateRef state = PredI->getState(); - - if (atDeclInit) { - const VarRegion *VR = - cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion()); - - state = state->bindDecl(VR, Val); - } else { - state = state->bindLoc(location, Val); - } - + + // When binding the value, pass on the hint that this is a initialization. + // For initializations, we do not need to inform clients of region + // changes. + state = state->bindLoc(cast<Loc>(location), + Val, /* notifyChanges = */ !atDeclInit); + const MemRegion *LocReg = 0; - if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location)) + if (loc::MemRegionVal *LocRegVal = dyn_cast<loc::MemRegionVal>(&location)) { LocReg = LocRegVal->getRegion(); - + } + const ProgramPoint L = PostStore(StoreE, LC, LocReg, 0); - Bldr.generateNode(L, PredI, state, false); + Bldr.generateNode(L, state, PredI); } - Dst.insert(TmpDst); } @@ -1671,7 +1711,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst, if (Tmp.empty()) return; - StmtNodeBuilder Bldr(Tmp, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(Tmp, Dst, *currBldrCtx); if (location.isUndef()) return; @@ -1684,8 +1724,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst, // This is important. We must nuke the old binding. Bldr.generateNode(NodeEx, *NI, state->BindExpr(BoundEx, LCtx, UnknownVal()), - false, tag, - ProgramPoint::PostLoadKind); + tag, ProgramPoint::PostLoadKind); } else { if (LoadTy.isNull()) @@ -1693,7 +1732,7 @@ void ExprEngine::evalLoadCommon(ExplodedNodeSet &Dst, SVal V = state->getSVal(cast<Loc>(location), LoadTy); Bldr.generateNode(NodeEx, *NI, state->bindExprAndLocation(BoundEx, LCtx, location, V), - false, tag, ProgramPoint::PostLoadKind); + tag, ProgramPoint::PostLoadKind); } } } @@ -1706,7 +1745,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, SVal location, const ProgramPointTag *tag, bool isLoad) { - StmtNodeBuilder BldrTop(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder BldrTop(Pred, Dst, *currBldrCtx); // Early checks for performance reason. if (location.isUnknown()) { return; @@ -1714,7 +1753,7 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, ExplodedNodeSet Src; BldrTop.takeNodes(Pred); - StmtNodeBuilder Bldr(Pred, Src, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Src, *currBldrCtx); if (Pred->getState() != state) { // Associate this new state with an ExplodedNode. // FIXME: If I pass null tag, the graph is incorrect, e.g for @@ -1725,9 +1764,8 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, // instead "int *p" is noted as // "Variable 'p' initialized to a null pointer value" - // FIXME: why is 'tag' not used instead of etag? - static SimpleProgramPointTag etag("ExprEngine: Location"); - Bldr.generateNode(NodeEx, Pred, state, false, &etag); + static SimpleProgramPointTag tag("ExprEngine: Location"); + Bldr.generateNode(NodeEx, Pred, state, &tag); } ExplodedNodeSet Tmp; getCheckerManager().runCheckersForLocation(Tmp, Src, location, isLoad, @@ -1736,16 +1774,18 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, } std::pair<const ProgramPointTag *, const ProgramPointTag*> -ExprEngine::getEagerlyAssumeTags() { +ExprEngine::geteagerlyAssumeBinOpBifurcationTags() { static SimpleProgramPointTag - EagerlyAssumeTrue("ExprEngine : Eagerly Assume True"), - EagerlyAssumeFalse("ExprEngine : Eagerly Assume False"); - return std::make_pair(&EagerlyAssumeTrue, &EagerlyAssumeFalse); + eagerlyAssumeBinOpBifurcationTrue("ExprEngine : Eagerly Assume True"), + eagerlyAssumeBinOpBifurcationFalse("ExprEngine : Eagerly Assume False"); + return std::make_pair(&eagerlyAssumeBinOpBifurcationTrue, + &eagerlyAssumeBinOpBifurcationFalse); } -void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, - const Expr *Ex) { - StmtNodeBuilder Bldr(Src, Dst, *currentBuilderContext); +void ExprEngine::evalEagerlyAssumeBinOpBifurcation(ExplodedNodeSet &Dst, + ExplodedNodeSet &Src, + const Expr *Ex) { + StmtNodeBuilder Bldr(Src, Dst, *currBldrCtx); for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) { ExplodedNode *Pred = *I; @@ -1762,28 +1802,28 @@ void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src, nonloc::SymbolVal *SEV = dyn_cast<nonloc::SymbolVal>(&V); if (SEV && SEV->isExpression()) { const std::pair<const ProgramPointTag *, const ProgramPointTag*> &tags = - getEagerlyAssumeTags(); + geteagerlyAssumeBinOpBifurcationTags(); // First assume that the condition is true. if (ProgramStateRef StateTrue = state->assume(*SEV, true)) { SVal Val = svalBuilder.makeIntVal(1U, Ex->getType()); StateTrue = StateTrue->BindExpr(Ex, Pred->getLocationContext(), Val); - Bldr.generateNode(Ex, Pred, StateTrue, false, tags.first); + Bldr.generateNode(Ex, Pred, StateTrue, tags.first); } // Next, assume that the condition is false. if (ProgramStateRef StateFalse = state->assume(*SEV, false)) { SVal Val = svalBuilder.makeIntVal(0U, Ex->getType()); StateFalse = StateFalse->BindExpr(Ex, Pred->getLocationContext(), Val); - Bldr.generateNode(Ex, Pred, StateFalse, false, tags.second); + Bldr.generateNode(Ex, Pred, StateFalse, tags.second); } } } } -void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); +void ExprEngine::VisitGCCAsmStmt(const GCCAsmStmt *A, ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); // We have processed both the inputs and the outputs. All of the outputs // should evaluate to Locs. Nuke all of their values. @@ -1793,7 +1833,7 @@ void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, ProgramStateRef state = Pred->getState(); - for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(), + for (GCCAsmStmt::const_outputs_iterator OI = A->begin_outputs(), OE = A->end_outputs(); OI != OE; ++OI) { SVal X = state->getSVal(*OI, Pred->getLocationContext()); assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef. @@ -1807,7 +1847,7 @@ void ExprEngine::VisitAsmStmt(const AsmStmt *A, ExplodedNode *Pred, void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); Bldr.generateNode(A, Pred, Pred->getState()); } @@ -1932,7 +1972,7 @@ struct DOTGraphTraits<ExplodedNode*> : if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) { const Stmt *S = L->getStmt(); - Out << S->getStmtClassName() << ' ' << (void*) S << ' '; + Out << S->getStmtClassName() << ' ' << (const void*) S << ' '; LangOptions LO; // FIXME. S->printPretty(Out, 0, PrintingPolicy(LO)); printLocation(Out, S->getLocStart()); @@ -2038,8 +2078,8 @@ struct DOTGraphTraits<ExplodedNode*> : } ProgramStateRef state = N->getState(); - Out << "\\|StateID: " << (void*) state.getPtr() - << " NodeID: " << (void*) N << "\\|"; + Out << "\\|StateID: " << (const void*) state.getPtr() + << " NodeID: " << (const void*) N << "\\|"; state->printDOT(Out); Out << "\\l"; diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 46cba81b14f7..00b2f4a6bee9 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -45,8 +45,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // EXPERIMENTAL: "Conjured" symbols. // FIXME: Handle structs. if (RightV.isUnknown()) { - unsigned Count = currentBuilderContext->getCurrentBlockCount(); - RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LCtx, Count); + unsigned Count = currBldrCtx->blockCount(); + RightV = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, Count); } // Simulate the effects of a "store": bind the value of the RHS // to the L-Value represented by the LHS. @@ -57,7 +57,7 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, } if (!B->isAssignmentOp()) { - StmtNodeBuilder Bldr(*it, Tmp2, *currentBuilderContext); + StmtNodeBuilder Bldr(*it, Tmp2, *currBldrCtx); if (B->isAdditiveOp()) { // If one of the operands is a location, conjure a symbol for the other @@ -65,16 +65,16 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, // results in an ElementRegion. // TODO: This can be removed after we enable history tracking with // SymSymExpr. - unsigned Count = currentBuilderContext->getCurrentBlockCount(); + unsigned Count = currBldrCtx->blockCount(); if (isa<Loc>(LeftV) && RHS->getType()->isIntegerType() && RightV.isUnknown()) { - RightV = svalBuilder.getConjuredSymbolVal(RHS, LCtx, - RHS->getType(), Count); + RightV = svalBuilder.conjureSymbolVal(RHS, LCtx, RHS->getType(), + Count); } if (isa<Loc>(RightV) && LHS->getType()->isIntegerType() && LeftV.isUnknown()) { - LeftV = svalBuilder.getConjuredSymbolVal(LHS, LCtx, - LHS->getType(), Count); + LeftV = svalBuilder.conjureSymbolVal(LHS, LCtx, LHS->getType(), + Count); } } @@ -145,15 +145,11 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, SVal LHSVal; if (Result.isUnknown()) { - - unsigned Count = currentBuilderContext->getCurrentBlockCount(); - // The symbolic value is actually for the type of the left-hand side // expression, not the computation type, as this is the value the // LValue on the LHS will bind to. - LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LCtx, - LTy, Count); - + LHSVal = svalBuilder.conjureSymbolVal(0, B->getRHS(), LCtx, LTy, + currBldrCtx->blockCount()); // However, we need to convert the symbol to the computation type. Result = svalBuilder.evalCast(LHSVal, CTy, LTy); } @@ -208,11 +204,10 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, } ExplodedNodeSet Tmp; - StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx); Bldr.generateNode(BE, Pred, State->BindExpr(BE, Pred->getLocationContext(), V), - false, 0, - ProgramPoint::PostLValueKind); + 0, ProgramPoint::PostLValueKind); // FIXME: Move all post/pre visits to ::Visit(). getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); @@ -242,12 +237,14 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE)) T = ExCast->getTypeAsWritten(); - StmtNodeBuilder Bldr(dstPreStmt, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(dstPreStmt, Dst, *currBldrCtx); for (ExplodedNodeSet::iterator I = dstPreStmt.begin(), E = dstPreStmt.end(); I != E; ++I) { Pred = *I; - + ProgramStateRef state = Pred->getState(); + const LocationContext *LCtx = Pred->getLocationContext(); + switch (CastE->getCastKind()) { case CK_LValueToRValue: llvm_unreachable("LValueToRValue casts handled earlier."); @@ -267,7 +264,10 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_NonAtomicToAtomic: // True no-ops. case CK_NoOp: - case CK_FunctionToPointerDecay: { + case CK_ConstructorConversion: + case CK_UserDefinedConversion: + case CK_FunctionToPointerDecay: + case CK_BuiltinFnToFnPtr: { // Copy the SVal of Ex to CastE. ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); @@ -276,6 +276,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, Bldr.generateNode(CastE, Pred, state); continue; } + case CK_MemberPointerToBoolean: + // FIXME: For now, member pointers are represented by void *. + // FALLTHROUGH case CK_Dependent: case CK_ArrayToPointerDecay: case CK_BitCast: @@ -304,8 +307,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_AnyPointerToBlockPointerCast: case CK_ObjCObjectLValueCast: { // Delegate to SValBuilder to process. - ProgramStateRef state = Pred->getState(); - const LocationContext *LCtx = Pred->getLocationContext(); SVal V = state->getSVal(Ex, LCtx); V = svalBuilder.evalCast(V, T, ExTy); state = state->BindExpr(CastE, LCtx, V); @@ -315,8 +316,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_DerivedToBase: case CK_UncheckedDerivedToBase: { // For DerivedToBase cast, delegate to the store manager. - ProgramStateRef state = Pred->getState(); - const LocationContext *LCtx = Pred->getLocationContext(); SVal val = state->getSVal(Ex, LCtx); val = getStoreManager().evalDerivedToBase(val, CastE); state = state->BindExpr(CastE, LCtx, val); @@ -325,8 +324,6 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, } // Handle C++ dyn_cast. case CK_Dynamic: { - ProgramStateRef state = Pred->getState(); - const LocationContext *LCtx = Pred->getLocationContext(); SVal val = state->getSVal(Ex, LCtx); // Compute the type of the result. @@ -347,7 +344,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, if (T->isReferenceType()) { // A bad_cast exception is thrown if input value is a reference. // Currently, we model this, by generating a sink. - Bldr.generateNode(CastE, Pred, state, true); + Bldr.generateSink(CastE, Pred, state); continue; } else { // If the cast fails on a pointer, bind to 0. @@ -356,9 +353,9 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, } else { // If we don't know if the cast succeeded, conjure a new symbol. if (val.isUnknown()) { - DefinedOrUnknownSVal NewSym = svalBuilder.getConjuredSymbolVal(NULL, - CastE, LCtx, resultType, - currentBuilderContext->getCurrentBlockCount()); + DefinedOrUnknownSVal NewSym = + svalBuilder.conjureSymbolVal(0, CastE, LCtx, resultType, + currBldrCtx->blockCount()); state = state->BindExpr(CastE, LCtx, NewSym); } else // Else, bind to the derived region value. @@ -367,27 +364,29 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, Bldr.generateNode(CastE, Pred, state); continue; } + case CK_NullToMemberPointer: { + // FIXME: For now, member pointers are represented by void *. + SVal V = svalBuilder.makeIntValWithPtrWidth(0, true); + state = state->BindExpr(CastE, LCtx, V); + Bldr.generateNode(CastE, Pred, state); + continue; + } // Various C++ casts that are not handled yet. case CK_ToUnion: case CK_BaseToDerived: - case CK_NullToMemberPointer: case CK_BaseToDerivedMemberPointer: case CK_DerivedToBaseMemberPointer: case CK_ReinterpretMemberPointer: - case CK_UserDefinedConversion: - case CK_ConstructorConversion: case CK_VectorSplat: - case CK_MemberPointerToBoolean: case CK_LValueBitCast: { // Recover some path-sensitivty by conjuring a new value. QualType resultType = CastE->getType(); if (CastE->isGLValue()) resultType = getContext().getPointerType(resultType); - const LocationContext *LCtx = Pred->getLocationContext(); - SVal result = svalBuilder.getConjuredSymbolVal(NULL, CastE, LCtx, - resultType, currentBuilderContext->getCurrentBlockCount()); - ProgramStateRef state = Pred->getState()->BindExpr(CastE, LCtx, - result); + SVal result = svalBuilder.conjureSymbolVal(0, CastE, LCtx, + resultType, + currBldrCtx->blockCount()); + state = state->BindExpr(CastE, LCtx, result); Bldr.generateNode(CastE, Pred, state); continue; } @@ -398,7 +397,7 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr *CL, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder B(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder B(Pred, Dst, *currBldrCtx); const InitListExpr *ILE = cast<InitListExpr>(CL->getInitializer()->IgnoreParens()); @@ -442,7 +441,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, DS, *this); - StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext); + StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx); const VarDecl *VD = dyn_cast<VarDecl>(D); for (ExplodedNodeSet::iterator I = dstPreVisit.begin(), E = dstPreVisit.end(); I!=E; ++I) { @@ -478,8 +477,8 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, Ty = getContext().getPointerType(Ty); } - InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx, LC, Ty, - currentBuilderContext->getCurrentBlockCount()); + InitVal = svalBuilder.conjureSymbolVal(0, InitEx, LC, Ty, + currBldrCtx->blockCount()); } B.takeNodes(N); ExplodedNodeSet Dst2; @@ -488,7 +487,7 @@ void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred, } } else { - B.generateNode(DS, N,state->bindDeclWithNoInit(state->getRegion(VD, LC))); + B.generateNode(DS, N, state); } } } @@ -498,7 +497,7 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, assert(B->getOpcode() == BO_LAnd || B->getOpcode() == BO_LOr); - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); ExplodedNode *N = Pred; @@ -531,10 +530,28 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, else { // If there is no terminator, by construction the last statement // in SrcBlock is the value of the enclosing expression. + // However, we still need to constrain that value to be 0 or 1. assert(!SrcBlock->empty()); CFGStmt Elem = cast<CFGStmt>(*SrcBlock->rbegin()); - const Stmt *S = Elem.getStmt(); - X = N->getState()->getSVal(S, Pred->getLocationContext()); + const Expr *RHS = cast<Expr>(Elem.getStmt()); + SVal RHSVal = N->getState()->getSVal(RHS, Pred->getLocationContext()); + + DefinedOrUnknownSVal DefinedRHS = cast<DefinedOrUnknownSVal>(RHSVal); + ProgramStateRef StTrue, StFalse; + llvm::tie(StTrue, StFalse) = N->getState()->assume(DefinedRHS); + if (StTrue) { + if (StFalse) { + // We can't constrain the value to 0 or 1; the best we can do is a cast. + X = getSValBuilder().evalCast(RHSVal, B->getType(), RHS->getType()); + } else { + // The value is known to be true. + X = getSValBuilder().makeIntVal(1, B->getType()); + } + } else { + // The value is known to be false. + assert(StFalse && "Infeasible path!"); + X = getSValBuilder().makeIntVal(0, B->getType()); + } } Bldr.generateNode(B, Pred, state->BindExpr(B, Pred->getLocationContext(), X)); @@ -543,14 +560,15 @@ void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode *Pred, void ExprEngine::VisitInitListExpr(const InitListExpr *IE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder B(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder B(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); QualType T = getContext().getCanonicalType(IE->getType()); unsigned NumInitElements = IE->getNumInits(); - if (T->isArrayType() || T->isRecordType() || T->isVectorType()) { + if (T->isArrayType() || T->isRecordType() || T->isVectorType() || + T->isAnyComplexType()) { llvm::ImmutableList<SVal> vals = getBasicVals().getEmptySValList(); // Handle base case where the initializer has no elements. @@ -590,7 +608,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, const Expr *R, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder B(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder B(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); const CFGBlock *SrcBlock = 0; @@ -631,7 +649,7 @@ void ExprEngine::VisitGuardedExpr(const Expr *Ex, void ExprEngine:: VisitOffsetOfExpr(const OffsetOfExpr *OOE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder B(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder B(Pred, Dst, *currBldrCtx); APSInt IV; if (OOE->EvaluateAsInt(IV, getContext())) { assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType())); @@ -650,7 +668,7 @@ void ExprEngine:: VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); QualType T = Ex->getTypeOfArgument(); @@ -683,7 +701,7 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); switch (U->getOpcode()) { default: { Bldr.takeNodes(Pred); @@ -816,7 +834,7 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, evalLoad(Tmp, U, Ex, Pred, state, loc); ExplodedNodeSet Dst2; - StmtNodeBuilder Bldr(Tmp, Dst2, *currentBuilderContext); + StmtNodeBuilder Bldr(Tmp, Dst2, *currBldrCtx); for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end();I!=E;++I) { state = (*I)->getState(); @@ -840,16 +858,17 @@ void ExprEngine::VisitIncrementDecrementOperator(const UnaryOperator* U, if (U->getType()->isAnyPointerType()) RHS = svalBuilder.makeArrayIndex(1); - else + else if (U->getType()->isIntegralOrEnumerationType()) RHS = svalBuilder.makeIntVal(1, U->getType()); + else + RHS = UnknownVal(); SVal Result = evalBinOp(state, Op, V2, RHS, U->getType()); // Conjure a new symbol if necessary to recover precision. if (Result.isUnknown()){ DefinedOrUnknownSVal SymVal = - svalBuilder.getConjuredSymbolVal(NULL, Ex, LCtx, - currentBuilderContext->getCurrentBlockCount()); + svalBuilder.conjureSymbolVal(0, Ex, LCtx, currBldrCtx->blockCount()); Result = SymVal; // If the value is a location, ++/-- should always preserve diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 44a860f689da..b3baa7905782 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -25,20 +25,28 @@ using namespace ento; void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens(); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); // Bind the temporary object to the value of the expression. Then bind // the expression to the location of the object. - SVal V = state->getSVal(tempExpr, Pred->getLocationContext()); - - const MemRegion *R = - svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx); + SVal V = state->getSVal(tempExpr, LCtx); + + // If the value is already a CXXTempObjectRegion, it is fine as it is. + // Otherwise, create a new CXXTempObjectRegion, and copy the value into it. + const MemRegion *MR = V.getAsRegion(); + if (!MR || !isa<CXXTempObjectRegion>(MR)) { + const MemRegion *R = + svalBuilder.getRegionManager().getCXXTempObjectRegion(ME, LCtx); + + SVal L = loc::MemRegionVal(R); + state = state->bindLoc(L, V); + V = L; + } - state = state->bindLoc(loc::MemRegionVal(R), V); - Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, loc::MemRegionVal(R))); + Bldr.generateNode(ME, Pred, state->BindExpr(ME, LCtx, V)); } void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, @@ -53,9 +61,9 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, case CXXConstructExpr::CK_Complete: { // See if we're constructing an existing region by looking at the next // element in the CFG. - const CFGBlock *B = currentBuilderContext->getBlock(); - if (currentStmtIdx + 1 < B->size()) { - CFGElement Next = (*B)[currentStmtIdx+1]; + const CFGBlock *B = currBldrCtx->getBlock(); + if (currStmtIdx + 1 < B->size()) { + CFGElement Next = (*B)[currStmtIdx+1]; // Is this a constructor for a local variable? if (const CFGStmt *StmtElem = dyn_cast<CFGStmt>(&Next)) { @@ -101,8 +109,12 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, // FIXME: This will eventually need to handle new-expressions as well. } - // If we couldn't find an existing region to construct into, we'll just - // generate a symbolic region, which is fine. + // If we couldn't find an existing region to construct into, assume we're + // constructing a temporary. + if (!Target) { + MemRegionManager &MRMgr = getSValBuilder().getRegionManager(); + Target = MRMgr.getCXXTempObjectRegion(CE, LCtx); + } break; } @@ -137,7 +149,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, *Call, *this); ExplodedNodeSet DstInvalidated; - StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext); + StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) defaultEvalCall(Bldr, *I, *Call); @@ -151,6 +163,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, void ExprEngine::VisitCXXDestructor(QualType ObjectType, const MemRegion *Dest, const Stmt *S, + bool IsBaseDtor, ExplodedNode *Pred, ExplodedNodeSet &Dst) { const LocationContext *LCtx = Pred->getLocationContext(); @@ -171,7 +184,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, CallEventManager &CEMgr = getStateManager().getCallEventManager(); CallEventRef<CXXDestructorCall> Call = - CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, State, LCtx); + CEMgr.getCXXDestructorCall(DtorDecl, S, Dest, IsBaseDtor, State, LCtx); PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(), Call->getSourceRange().getBegin(), @@ -182,7 +195,7 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, *Call, *this); ExplodedNodeSet DstInvalidated; - StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currentBuilderContext); + StmtNodeBuilder Bldr(DstPreCall, DstInvalidated, *currBldrCtx); for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end(); I != E; ++I) defaultEvalCall(Bldr, *I, *Call); @@ -198,12 +211,13 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // Also, we need to decide how allocators actually work -- they're not // really part of the CXXNewExpr because they happen BEFORE the // CXXConstructExpr subexpression. See PR12014 for some discussion. - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); - unsigned blockCount = currentBuilderContext->getCurrentBlockCount(); + unsigned blockCount = currBldrCtx->blockCount(); const LocationContext *LCtx = Pred->getLocationContext(); - DefinedOrUnknownSVal symVal = - svalBuilder.getConjuredSymbolVal(0, CNE, LCtx, CNE->getType(), blockCount); + DefinedOrUnknownSVal symVal = svalBuilder.conjureSymbolVal(0, CNE, LCtx, + CNE->getType(), + blockCount); ProgramStateRef State = Pred->getState(); CallEventManager &CEMgr = getStateManager().getCallEventManager(); @@ -215,6 +229,18 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // we should be using the usual pre-/(default-)eval-/post-call checks here. State = Call->invalidateRegions(blockCount); + // If we're compiling with exceptions enabled, and this allocation function + // is not declared as non-throwing, failures /must/ be signalled by + // exceptions, and thus the return value will never be NULL. + // C++11 [basic.stc.dynamic.allocation]p3. + FunctionDecl *FD = CNE->getOperatorNew(); + if (FD && getContext().getLangOpts().CXXExceptions) { + QualType Ty = FD->getType(); + if (const FunctionProtoType *ProtoType = Ty->getAs<FunctionProtoType>()) + if (!ProtoType->isNothrow(getContext())) + State = State->assume(symVal, true); + } + if (CNE->isArray()) { // FIXME: allocating an array requires simulating the constructors. // For now, just return a symbolicated region. @@ -232,11 +258,12 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, // CXXNewExpr, we need to make sure that the constructed object is not // immediately invalidated here. (The placement call should happen before // the constructor call anyway.) - FunctionDecl *FD = CNE->getOperatorNew(); if (FD && FD->isReservedGlobalPlacementOperator()) { // Non-array placement new should always return the placement location. SVal PlacementLoc = State->getSVal(CNE->getPlacementArg(0), LCtx); - State = State->BindExpr(CNE, LCtx, PlacementLoc); + SVal Result = svalBuilder.evalCast(PlacementLoc, CNE->getType(), + CNE->getPlacementArg(0)->getType()); + State = State->BindExpr(CNE, LCtx, Result); } else { State = State->BindExpr(CNE, LCtx, symVal); } @@ -259,7 +286,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); ProgramStateRef state = Pred->getState(); Bldr.generateNode(CDE, Pred, state); } @@ -274,18 +301,18 @@ void ExprEngine::VisitCXXCatchStmt(const CXXCatchStmt *CS, } const LocationContext *LCtx = Pred->getLocationContext(); - SVal V = svalBuilder.getConjuredSymbolVal(CS, LCtx, VD->getType(), - currentBuilderContext->getCurrentBlockCount()); + SVal V = svalBuilder.conjureSymbolVal(CS, LCtx, VD->getType(), + currBldrCtx->blockCount()); ProgramStateRef state = Pred->getState(); state = state->bindLoc(state->getLValue(VD, LCtx), V); - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); Bldr.generateNode(CS, Pred, state); } void ExprEngine::VisitCXXThisExpr(const CXXThisExpr *TE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); // Get the this object region from StoreManager. const LocationContext *LCtx = Pred->getLocationContext(); diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 3b2e4ec8243b..3ead0817f71b 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -17,19 +17,22 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/ParentMap.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Support/SaveAndRestore.h" -#define CXX_INLINING_ENABLED 1 - using namespace clang; using namespace ento; STATISTIC(NumOfDynamicDispatchPathSplits, "The # of times we split the path due to imprecise dynamic dispatch info"); +STATISTIC(NumInlinedCalls, + "The # of times we inlined a call"); + void ExprEngine::processCallEnter(CallEnter CE, ExplodedNode *Pred) { // Get the entry block in the CFG of the callee. const StackFrameContext *calleeCtx = CE.getCalleeContext(); @@ -64,35 +67,47 @@ static std::pair<const Stmt*, const StackFrameContext *SF = Node->getLocation().getLocationContext()->getCurrentStackFrame(); - // Back up through the ExplodedGraph until we reach a statement node. + // Back up through the ExplodedGraph until we reach a statement node in this + // stack frame. while (Node) { const ProgramPoint &PP = Node->getLocation(); - if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) { - S = SP->getStmt(); - break; - } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&PP)) { - S = CEE->getCalleeContext()->getCallSite(); - if (S) + if (PP.getLocationContext()->getCurrentStackFrame() == SF) { + if (const StmtPoint *SP = dyn_cast<StmtPoint>(&PP)) { + S = SP->getStmt(); break; - // If we have an implicit call, we'll probably end up with a - // StmtPoint inside the callee, which is acceptable. - // (It's possible a function ONLY contains implicit calls -- such as an - // implicitly-generated destructor -- so we shouldn't just skip back to - // the CallEnter node and keep going.) + } else if (const CallExitEnd *CEE = dyn_cast<CallExitEnd>(&PP)) { + S = CEE->getCalleeContext()->getCallSite(); + if (S) + break; + + // If there is no statement, this is an implicitly-generated call. + // We'll walk backwards over it and then continue the loop to find + // an actual statement. + const CallEnter *CE; + do { + Node = Node->getFirstPred(); + CE = Node->getLocationAs<CallEnter>(); + } while (!CE || CE->getCalleeContext() != CEE->getCalleeContext()); + + // Continue searching the graph. + } } else if (const CallEnter *CE = dyn_cast<CallEnter>(&PP)) { // If we reached the CallEnter for this function, it has no statements. if (CE->getCalleeContext() == SF) break; } + if (Node->pred_empty()) + return std::pair<const Stmt*, const CFGBlock*>((Stmt*)0, (CFGBlock*)0); + Node = *Node->pred_begin(); } const CFGBlock *Blk = 0; if (S) { // Now, get the enclosing basic block. - while (Node && Node->pred_size() >=1 ) { + while (Node) { const ProgramPoint &PP = Node->getLocation(); if (isa<BlockEdge>(PP) && (PP.getLocationContext()->getCurrentStackFrame() == SF)) { @@ -100,6 +115,9 @@ static std::pair<const Stmt*, Blk = EPP.getDst(); break; } + if (Node->pred_empty()) + return std::pair<const Stmt*, const CFGBlock*>(S, (CFGBlock*)0); + Node = *Node->pred_begin(); } } @@ -107,6 +125,82 @@ static std::pair<const Stmt*, return std::pair<const Stmt*, const CFGBlock*>(S, Blk); } +/// Adjusts a return value when the called function's return type does not +/// match the caller's expression type. This can happen when a dynamic call +/// is devirtualized, and the overridding method has a covariant (more specific) +/// return type than the parent's method. For C++ objects, this means we need +/// to add base casts. +static SVal adjustReturnValue(SVal V, QualType ExpectedTy, QualType ActualTy, + StoreManager &StoreMgr) { + // For now, the only adjustments we handle apply only to locations. + if (!isa<Loc>(V)) + return V; + + // If the types already match, don't do any unnecessary work. + ExpectedTy = ExpectedTy.getCanonicalType(); + ActualTy = ActualTy.getCanonicalType(); + if (ExpectedTy == ActualTy) + return V; + + // No adjustment is needed between Objective-C pointer types. + if (ExpectedTy->isObjCObjectPointerType() && + ActualTy->isObjCObjectPointerType()) + return V; + + // C++ object pointers may need "derived-to-base" casts. + const CXXRecordDecl *ExpectedClass = ExpectedTy->getPointeeCXXRecordDecl(); + const CXXRecordDecl *ActualClass = ActualTy->getPointeeCXXRecordDecl(); + if (ExpectedClass && ActualClass) { + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (ActualClass->isDerivedFrom(ExpectedClass, Paths) && + !Paths.isAmbiguous(ActualTy->getCanonicalTypeUnqualified())) { + return StoreMgr.evalDerivedToBase(V, Paths.front()); + } + } + + // Unfortunately, Objective-C does not enforce that overridden methods have + // covariant return types, so we can't assert that that never happens. + // Be safe and return UnknownVal(). + return UnknownVal(); +} + +void ExprEngine::removeDeadOnEndOfFunction(NodeBuilderContext& BC, + ExplodedNode *Pred, + ExplodedNodeSet &Dst) { + NodeBuilder Bldr(Pred, Dst, BC); + + // Find the last statement in the function and the corresponding basic block. + const Stmt *LastSt = 0; + const CFGBlock *Blk = 0; + llvm::tie(LastSt, Blk) = getLastStmt(Pred); + if (!Blk || !LastSt) { + return; + } + + // If the last statement is return, everything it references should stay live. + if (isa<ReturnStmt>(LastSt)) + return; + + // Here, we call the Symbol Reaper with 0 stack context telling it to clean up + // everything on the stack. We use LastStmt as a diagnostic statement, with + // which the PreStmtPurgeDead point will be associated. + currBldrCtx = &BC; + removeDead(Pred, Dst, 0, 0, LastSt, + ProgramPoint::PostStmtPurgeDeadSymbolsKind); + currBldrCtx = 0; +} + +static bool wasDifferentDeclUsedForInlining(CallEventRef<> Call, + const StackFrameContext *calleeCtx) { + const Decl *RuntimeCallee = calleeCtx->getDecl(); + const Decl *StaticDecl = Call->getDecl(); + assert(RuntimeCallee); + if (!StaticDecl) + return true; + return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl(); +} + /// The call exit is simulated with a sequence of nodes, which occur between /// CallExitBegin and CallExitEnd. The following operations occur between the /// two program points: @@ -133,6 +227,11 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { const CFGBlock *Blk = 0; llvm::tie(LastSt, Blk) = getLastStmt(CEBNode); + // Generate a CallEvent /before/ cleaning the state, so that we can get the + // correct value for 'this' (if necessary). + CallEventManager &CEMgr = getStateManager().getCallEventManager(); + CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state); + // Step 2: generate node with bound return value: CEBNode -> BindedRetNode. // If the callee returns an expression, bind its value to CallExpr. @@ -140,6 +239,19 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) { const LocationContext *LCtx = CEBNode->getLocationContext(); SVal V = state->getSVal(RS, LCtx); + + // Ensure that the return type matches the type of the returned Expr. + if (wasDifferentDeclUsedForInlining(Call, calleeCtx)) { + QualType ReturnedTy = + CallEvent::getDeclaredResultType(calleeCtx->getDecl()); + if (!ReturnedTy.isNull()) { + if (const Expr *Ex = dyn_cast<Expr>(CE)) { + V = adjustReturnValue(V, Ex->getType(), ReturnedTy, + getStoreManager()); + } + } + } + state = state->BindExpr(CE, callerCtx, V); } @@ -149,23 +261,25 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx); SVal ThisV = state->getSVal(This); - // Always bind the region to the CXXConstructExpr. + // If the constructed object is a prvalue, get its bindings. + // Note that we have to be careful here because constructors embedded + // in DeclStmts are not marked as lvalues. + if (!CCE->isGLValue()) + if (const MemRegion *MR = ThisV.getAsRegion()) + if (isa<CXXTempObjectRegion>(MR)) + ThisV = state->getSVal(cast<Loc>(ThisV)); + state = state->BindExpr(CCE, callerCtx, ThisV); } } - // Generate a CallEvent /before/ cleaning the state, so that we can get the - // correct value for 'this' (if necessary). - CallEventManager &CEMgr = getStateManager().getCallEventManager(); - CallEventRef<> Call = CEMgr.getCaller(calleeCtx, state); - // Step 3: BindedRetNode -> CleanedNodes // If we can find a statement and a block in the inlined function, run remove // dead bindings before returning from the call. This is important to ensure // that we report the issues such as leaks in the stack contexts in which // they occurred. ExplodedNodeSet CleanedNodes; - if (LastSt && Blk) { + if (LastSt && Blk && AMgr.options.AnalysisPurgeOpt != PurgeNone) { static SimpleProgramPointTag retValBind("ExprEngine : Bind Return Value"); PostStmt Loc(LastSt, calleeCtx, &retValBind); bool isNew; @@ -175,14 +289,14 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { return; NodeBuilderContext Ctx(getCoreEngine(), Blk, BindedRetNode); - currentBuilderContext = &Ctx; + currBldrCtx = &Ctx; // Here, we call the Symbol Reaper with 0 statement and caller location // context, telling it to clean up everything in the callee's context // (and it's children). We use LastStmt as a diagnostic statement, which // which the PreStmtPurge Dead point will be associated. removeDead(BindedRetNode, CleanedNodes, 0, callerCtx, LastSt, ProgramPoint::PostStmtPurgeDeadSymbolsKind); - currentBuilderContext = 0; + currBldrCtx = 0; } else { CleanedNodes.Add(CEBNode); } @@ -204,9 +318,9 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { // result onto the work list. // CEENode -> Dst -> WorkList NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode); - SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext, + SaveAndRestore<const NodeBuilderContext*> NBCSave(currBldrCtx, &Ctx); - SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex()); + SaveAndRestore<unsigned> CBISave(currStmtIdx, calleeCtx->getIndex()); CallEventRef<> UpdatedCall = Call.cloneWithState(CEEState); @@ -236,14 +350,48 @@ void ExprEngine::processCallExit(ExplodedNode *CEBNode) { } } -static unsigned getNumberStackFrames(const LocationContext *LCtx) { - unsigned count = 0; +void ExprEngine::examineStackFrames(const Decl *D, const LocationContext *LCtx, + bool &IsRecursive, unsigned &StackDepth) { + IsRecursive = false; + StackDepth = 0; + while (LCtx) { - if (isa<StackFrameContext>(LCtx)) - ++count; + if (const StackFrameContext *SFC = dyn_cast<StackFrameContext>(LCtx)) { + const Decl *DI = SFC->getDecl(); + + // Mark recursive (and mutually recursive) functions and always count + // them when measuring the stack depth. + if (DI == D) { + IsRecursive = true; + ++StackDepth; + LCtx = LCtx->getParent(); + continue; + } + + // Do not count the small functions when determining the stack depth. + AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(DI); + const CFG *CalleeCFG = CalleeADC->getCFG(); + if (CalleeCFG->getNumBlockIDs() > AMgr.options.getAlwaysInlineSize()) + ++StackDepth; + } LCtx = LCtx->getParent(); } - return count; + +} + +static bool IsInStdNamespace(const FunctionDecl *FD) { + const DeclContext *DC = FD->getEnclosingNamespaceContext(); + const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC); + if (!ND) + return false; + + while (const DeclContext *Parent = ND->getParent()) { + if (!isa<NamespaceDecl>(Parent)) + break; + ND = cast<NamespaceDecl>(Parent); + } + + return ND->getName() == "std"; } // Determine if we should inline the call. @@ -256,14 +404,18 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) { if (!CalleeCFG) return false; - if (getNumberStackFrames(Pred->getLocationContext()) - == AMgr.InlineMaxStackDepth) + bool IsRecursive = false; + unsigned StackDepth = 0; + examineStackFrames(D, Pred->getLocationContext(), IsRecursive, StackDepth); + if ((StackDepth >= AMgr.options.InlineMaxStackDepth) && + ((CalleeCFG->getNumBlockIDs() > AMgr.options.getAlwaysInlineSize()) + || IsRecursive)) return false; if (Engine.FunctionSummaries->hasReachedMaxBlockCount(D)) return false; - if (CalleeCFG->getNumBlockIDs() > AMgr.InlineMaxFunctionSize) + if (CalleeCFG->getNumBlockIDs() > AMgr.options.InlineMaxFunctionSize) return false; // Do not inline variadic calls (for now). @@ -276,6 +428,21 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) { return false; } + if (getContext().getLangOpts().CPlusPlus) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // Conditionally allow the inlining of template functions. + if (!getAnalysisManager().options.mayInlineTemplateFunctions()) + if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate) + return false; + + // Conditionally allow the inlining of C++ standard library functions. + if (!getAnalysisManager().options.mayInlineCXXStandardLibrary()) + if (getContext().getSourceManager().isInSystemHeader(FD->getLocation())) + if (IsInStdNamespace(FD)) + return false; + } + } + // It is possible that the live variables analysis cannot be // run. If so, bail out. if (!CalleeADC->getAnalysis<RelaxedLiveVariables>()) @@ -284,26 +451,21 @@ bool ExprEngine::shouldInlineDecl(const Decl *D, ExplodedNode *Pred) { return true; } -/// The GDM component containing the dynamic dispatch bifurcation info. When -/// the exact type of the receiver is not known, we want to explore both paths - -/// one on which we do inline it and the other one on which we don't. This is -/// done to ensure we do not drop coverage. -/// This is the map from the receiver region to a bool, specifying either we -/// consider this region's information precise or not along the given path. -namespace clang { -namespace ento { -enum DynamicDispatchMode { DynamicDispatchModeInlined = 1, - DynamicDispatchModeConservative }; - -struct DynamicDispatchBifurcationMap {}; -typedef llvm::ImmutableMap<const MemRegion*, - unsigned int> DynamicDispatchBifur; -template<> struct ProgramStateTrait<DynamicDispatchBifurcationMap> - : public ProgramStatePartialTrait<DynamicDispatchBifur> { - static void *GDMIndex() { static int index; return &index; } -}; - -}} +// The GDM component containing the dynamic dispatch bifurcation info. When +// the exact type of the receiver is not known, we want to explore both paths - +// one on which we do inline it and the other one on which we don't. This is +// done to ensure we do not drop coverage. +// This is the map from the receiver region to a bool, specifying either we +// consider this region's information precise or not along the given path. +namespace { + enum DynamicDispatchMode { + DynamicDispatchModeInlined = 1, + DynamicDispatchModeConservative + }; +} +REGISTER_TRAIT_WITH_PROGRAMSTATE(DynamicDispatchBifurcationMap, + CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, + unsigned)) bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, NodeBuilder &Bldr, ExplodedNode *Pred, @@ -314,24 +476,19 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame(); const LocationContext *ParentOfCallee = 0; + AnalyzerOptions &Opts = getAnalysisManager().options; + // FIXME: Refactor this check into a hypothetical CallEvent::canInline. switch (Call.getKind()) { case CE_Function: break; case CE_CXXMember: case CE_CXXMemberOperator: - if (!CXX_INLINING_ENABLED) + if (!Opts.mayInlineCXXMemberFunction(CIMK_MemberFunctions)) return false; break; case CE_CXXConstructor: { - if (!CXX_INLINING_ENABLED) - return false; - - // Only inline constructors and destructors if we built the CFGs for them - // properly. - const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); - if (!ADC->getCFGBuildOptions().AddImplicitDtors || - !ADC->getCFGBuildOptions().AddInitializers) + if (!Opts.mayInlineCXXMemberFunction(CIMK_Constructors)) return false; const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call); @@ -341,9 +498,31 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, if (Target && isa<ElementRegion>(Target)) return false; + // FIXME: This is a hack. We don't use the correct region for a new + // expression, so if we inline the constructor its result will just be + // thrown away. This short-term hack is tracked in <rdar://problem/12180598> + // and the longer-term possible fix is discussed in PR12014. + const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr(); + if (const Stmt *Parent = CurLC->getParentMap().getParent(CtorExpr)) + if (isa<CXXNewExpr>(Parent)) + return false; + + // Inlining constructors requires including initializers in the CFG. + const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); + assert(ADC->getCFGBuildOptions().AddInitializers && "No CFG initializers"); + (void)ADC; + + // If the destructor is trivial, it's always safe to inline the constructor. + if (Ctor.getDecl()->getParent()->hasTrivialDestructor()) + break; + + // For other types, only inline constructors if destructor inlining is + // also enabled. + if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) + return false; + // FIXME: This is a hack. We don't handle temporary destructors // right now, so we shouldn't inline their constructors. - const CXXConstructExpr *CtorExpr = Ctor.getOriginExpr(); if (CtorExpr->getConstructionKind() == CXXConstructExpr::CK_Complete) if (!Target || !isa<DeclRegion>(Target)) return false; @@ -351,15 +530,13 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, break; } case CE_CXXDestructor: { - if (!CXX_INLINING_ENABLED) + if (!Opts.mayInlineCXXMemberFunction(CIMK_Destructors)) return false; - // Only inline constructors and destructors if we built the CFGs for them - // properly. + // Inlining destructors requires building the CFG correctly. const AnalysisDeclContext *ADC = CallerSFC->getAnalysisDeclContext(); - if (!ADC->getCFGBuildOptions().AddImplicitDtors || - !ADC->getCFGBuildOptions().AddInitializers) - return false; + assert(ADC->getCFGBuildOptions().AddImplicitDtors && "No CFG destructors"); + (void)ADC; const CXXDestructorCall &Dtor = cast<CXXDestructorCall>(Call); @@ -371,9 +548,6 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, break; } case CE_CXXAllocator: - if (!CXX_INLINING_ENABLED) - return false; - // Do not inline allocators until we model deallocators. // This is unfortunate, but basically necessary for smart pointers and such. return false; @@ -387,8 +561,10 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, break; } case CE_ObjCMessage: - if (!(getAnalysisManager().IPAMode == DynamicDispatch || - getAnalysisManager().IPAMode == DynamicDispatchBifurcate)) + if (!Opts.mayInlineObjCMethod()) + return false; + if (!(getAnalysisManager().options.IPAMode == DynamicDispatch || + getAnalysisManager().options.IPAMode == DynamicDispatchBifurcate)) return false; break; } @@ -406,8 +582,8 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, AnalysisDeclContext *CalleeADC = AMgr.getAnalysisDeclContext(D); const StackFrameContext *CalleeSFC = CalleeADC->getStackFrame(ParentOfCallee, CallE, - currentBuilderContext->getBlock(), - currentStmtIdx); + currBldrCtx->getBlock(), + currStmtIdx); CallEnter Loc(CallE, CalleeSFC, CurLC); @@ -426,6 +602,12 @@ bool ExprEngine::inlineCall(const CallEvent &Call, const Decl *D, // added onto the work list so remove it from the node builder. Bldr.takeNodes(Pred); + NumInlinedCalls++; + + // Mark the decl as visited. + if (VisitedCallees) + VisitedCallees->insert(D); + return true; } @@ -520,8 +702,8 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, // Conjure a symbol if the return value is unknown. QualType ResultTy = Call.getResultType(); SValBuilder &SVB = getSValBuilder(); - unsigned Count = currentBuilderContext->getCurrentBlockCount(); - SVal R = SVB.getConjuredSymbolVal(0, E, LCtx, ResultTy, Count); + unsigned Count = currBldrCtx->blockCount(); + SVal R = SVB.conjureSymbolVal(0, E, LCtx, ResultTy, Count); return State->BindExpr(E, LCtx, R); } @@ -529,8 +711,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, // a conjured return value. void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr, ExplodedNode *Pred, ProgramStateRef State) { - unsigned Count = currentBuilderContext->getCurrentBlockCount(); - State = Call.invalidateRegions(Count, State); + State = Call.invalidateRegions(currBldrCtx->blockCount(), State); State = bindReturnValue(Call, Pred->getLocationContext(), State); // And make the result node. @@ -562,13 +743,13 @@ void ExprEngine::defaultEvalCall(NodeBuilder &Bldr, ExplodedNode *Pred, if (D) { if (RD.mayHaveOtherDefinitions()) { // Explore with and without inlining the call. - if (getAnalysisManager().IPAMode == DynamicDispatchBifurcate) { + if (getAnalysisManager().options.IPAMode == DynamicDispatchBifurcate) { BifurcateCall(RD.getDispatchRegion(), *Call, D, Bldr, Pred); return; } // Don't inline if we're not in any dynamic dispatch mode. - if (getAnalysisManager().IPAMode != DynamicDispatch) { + if (getAnalysisManager().options.IPAMode != DynamicDispatch) { conservativeEvalCall(*Call, Bldr, Pred, State); return; } @@ -593,7 +774,7 @@ void ExprEngine::BifurcateCall(const MemRegion *BifurReg, // Check if we've performed the split already - note, we only want // to split the path once per memory region. ProgramStateRef State = Pred->getState(); - const unsigned int *BState = + const unsigned *BState = State->get<DynamicDispatchBifurcationMap>(BifurReg); if (BState) { // If we are on "inline path", keep inlining if possible. @@ -630,7 +811,7 @@ void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred, ExplodedNodeSet dstPreVisit; getCheckerManager().runCheckersForPreStmt(dstPreVisit, Pred, RS, *this); - StmtNodeBuilder B(dstPreVisit, Dst, *currentBuilderContext); + StmtNodeBuilder B(dstPreVisit, Dst, *currBldrCtx); if (RS->getRetValue()) { for (ExplodedNodeSet::iterator it = dstPreVisit.begin(), diff --git a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp index e3bc498b51e8..51dda19b5315 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineObjC.cpp @@ -28,7 +28,7 @@ void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr *Ex, SVal location = state->getLValue(Ex->getDecl(), baseVal); ExplodedNodeSet dstIvar; - StmtNodeBuilder Bldr(Pred, dstIvar, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, dstIvar, *currBldrCtx); Bldr.generateNode(Ex, Pred, state->BindExpr(Ex, LCtx, location)); // Perform the post-condition check of the ObjCIvarRefExpr and store @@ -88,7 +88,7 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, evalLocation(dstLocation, S, elem, Pred, state, elementV, NULL, false); ExplodedNodeSet Tmp; - StmtNodeBuilder Bldr(Pred, Tmp, *currentBuilderContext); + StmtNodeBuilder Bldr(Pred, Tmp, *currBldrCtx); for (ExplodedNodeSet::iterator NI = dstLocation.begin(), NE = dstLocation.end(); NI!=NE; ++NI) { @@ -112,8 +112,8 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, // For now, just 'conjure' up a symbolic value. QualType T = R->getValueType(); assert(Loc::isLocType(T)); - unsigned Count = currentBuilderContext->getCurrentBlockCount(); - SymbolRef Sym = SymMgr.getConjuredSymbol(elem, LCtx, T, Count); + SymbolRef Sym = SymMgr.conjureSymbol(elem, LCtx, T, + currBldrCtx->blockCount()); SVal V = svalBuilder.makeLoc(Sym); hasElems = hasElems->bindLoc(elementV, V); @@ -132,14 +132,6 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S, getCheckerManager().runCheckersForPostStmt(Dst, Tmp, S, *this); } -static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) { - if (!Class) - return false; - if (Class->getIdentifier() == II) - return true; - return isSubclass(Class->getSuperClass(), II); -} - void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { @@ -157,7 +149,7 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, // Proceed with evaluate the message expression. ExplodedNodeSet dstEval; - StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext); + StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currBldrCtx); for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(), DE = dstGenericPrevisit.end(); DI != DE; ++DI) { @@ -184,68 +176,30 @@ void ExprEngine::VisitObjCMessage(const ObjCMessageExpr *ME, // Check if the "raise" message was sent. assert(notNilState); - if (Msg->getSelector() == RaiseSel) { + if (ObjCNoRet.isImplicitNoReturn(ME)) { // If we raise an exception, for now treat it as a sink. // Eventually we will want to handle exceptions properly. - Bldr.generateNode(currentStmt, Pred, State, true); + Bldr.generateSink(currStmt, Pred, State); continue; } // Generate a transition to non-Nil state. - if (notNilState != State) - Pred = Bldr.generateNode(currentStmt, Pred, notNilState); + if (notNilState != State) { + Pred = Bldr.generateNode(currStmt, Pred, notNilState); + assert(Pred && "Should have cached out already!"); + } } } else { - // Check for special class methods. - if (const ObjCInterfaceDecl *Iface = Msg->getReceiverInterface()) { - if (!NSExceptionII) { - ASTContext &Ctx = getContext(); - NSExceptionII = &Ctx.Idents.get("NSException"); - } - - if (isSubclass(Iface, NSExceptionII)) { - enum { NUM_RAISE_SELECTORS = 2 }; - - // Lazily create a cache of the selectors. - if (!NSExceptionInstanceRaiseSelectors) { - ASTContext &Ctx = getContext(); - NSExceptionInstanceRaiseSelectors = - new Selector[NUM_RAISE_SELECTORS]; - SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II; - unsigned idx = 0; - - // raise:format: - II.push_back(&Ctx.Idents.get("raise")); - II.push_back(&Ctx.Idents.get("format")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); - - // raise:format:arguments: - II.push_back(&Ctx.Idents.get("arguments")); - NSExceptionInstanceRaiseSelectors[idx++] = - Ctx.Selectors.getSelector(II.size(), &II[0]); - } - - Selector S = Msg->getSelector(); - bool RaisesException = false; - for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) { - if (S == NSExceptionInstanceRaiseSelectors[i]) { - RaisesException = true; - break; - } - } - if (RaisesException) { - // If we raise an exception, for now treat it as a sink. - // Eventually we will want to handle exceptions properly. - Bldr.generateNode(currentStmt, Pred, Pred->getState(), true); - continue; - } - - } + // Check for special class methods that are known to not return + // and that we should treat as a sink. + if (ObjCNoRet.isImplicitNoReturn(ME)) { + // If we raise an exception, for now treat it as a sink. + // Eventually we will want to handle exceptions properly. + Bldr.generateSink(currStmt, Pred, Pred->getState()); + continue; } } - // Evaluate the call. defaultEvalCall(Bldr, Pred, *UpdatedMsg); } diff --git a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp index 982bcbfcdf9a..fd875f66d2db 100644 --- a/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/HTMLDiagnostics.cpp @@ -17,8 +17,8 @@ #include "clang/AST/Decl.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" -#include "clang/Rewrite/Rewriter.h" -#include "clang/Rewrite/HTMLRewrite.h" +#include "clang/Rewrite/Core/Rewriter.h" +#include "clang/Rewrite/Core/HTMLRewrite.h" #include "clang/Lex/Lexer.h" #include "clang/Lex/Preprocessor.h" #include "llvm/Support/FileSystem.h" @@ -189,7 +189,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, << (*path.rbegin())->getLocation().asLocation().getExpansionColumnNumber() << "</a></td></tr>\n" "<tr><td class=\"rowname\">Description:</td><td>" - << D.getDescription() << "</td></tr>\n"; + << D.getVerboseDescription() << "</td></tr>\n"; // Output any other meta data. @@ -209,15 +209,15 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, std::string s; llvm::raw_string_ostream os(s); - const std::string& BugDesc = D.getDescription(); + StringRef BugDesc = D.getVerboseDescription(); if (!BugDesc.empty()) os << "\n<!-- BUGDESC " << BugDesc << " -->\n"; - const std::string& BugType = D.getBugType(); + StringRef BugType = D.getBugType(); if (!BugType.empty()) os << "\n<!-- BUGTYPE " << BugType << " -->\n"; - const std::string& BugCategory = D.getCategory(); + StringRef BugCategory = D.getCategory(); if (!BugCategory.empty()) os << "\n<!-- BUGCATEGORY " << BugCategory << " -->\n"; @@ -267,8 +267,7 @@ void HTMLDiagnostics::ReportDiag(const PathDiagnostic& D, } if (filesMade) { - filesMade->push_back(std::make_pair(StringRef(getName()), - llvm::sys::path::filename(H.str()))); + filesMade->addDiagnostic(D, getName(), llvm::sys::path::filename(H.str())); } // Emit the HTML to disk. diff --git a/lib/StaticAnalyzer/Core/MemRegion.cpp b/lib/StaticAnalyzer/Core/MemRegion.cpp index 62e602a7e1e1..fab10cfd3d04 100644 --- a/lib/StaticAnalyzer/Core/MemRegion.cpp +++ b/lib/StaticAnalyzer/Core/MemRegion.cpp @@ -352,7 +352,7 @@ void ElementRegion::Profile(llvm::FoldingSetNodeID& ID) const { } void FunctionTextRegion::ProfileRegion(llvm::FoldingSetNodeID& ID, - const FunctionDecl *FD, + const NamedDecl *FD, const MemRegion*) { ID.AddInteger(MemRegion::FunctionTextRegionKind); ID.AddPointer(FD); @@ -444,7 +444,7 @@ void MemRegion::dumpToStream(raw_ostream &os) const { } void AllocaRegion::dumpToStream(raw_ostream &os) const { - os << "alloca{" << (void*) Ex << ',' << Cnt << '}'; + os << "alloca{" << (const void*) Ex << ',' << Cnt << '}'; } void FunctionTextRegion::dumpToStream(raw_ostream &os) const { @@ -452,7 +452,7 @@ void FunctionTextRegion::dumpToStream(raw_ostream &os) const { } void BlockTextRegion::dumpToStream(raw_ostream &os) const { - os << "block_code{" << (void*) this << '}'; + os << "block_code{" << (const void*) this << '}'; } void BlockDataRegion::dumpToStream(raw_ostream &os) const { @@ -461,12 +461,12 @@ void BlockDataRegion::dumpToStream(raw_ostream &os) const { void CompoundLiteralRegion::dumpToStream(raw_ostream &os) const { // FIXME: More elaborate pretty-printing. - os << "{ " << (void*) CL << " }"; + os << "{ " << (const void*) CL << " }"; } void CXXTempObjectRegion::dumpToStream(raw_ostream &os) const { os << "temp_object{" << getValueType().getAsString() << ',' - << (void*) Ex << '}'; + << (const void*) Ex << '}'; } void CXXBaseObjectRegion::dumpToStream(raw_ostream &os) const { @@ -748,11 +748,11 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, } else { assert(D->isStaticLocal()); - const Decl *D = STC->getDecl(); - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + const Decl *STCD = STC->getDecl(); + if (isa<FunctionDecl>(STCD) || isa<ObjCMethodDecl>(STCD)) sReg = getGlobalsRegion(MemRegion::StaticGlobalSpaceRegionKind, - getFunctionTextRegion(FD)); - else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) { + getFunctionTextRegion(cast<NamedDecl>(STCD))); + else if (const BlockDecl *BD = dyn_cast<BlockDecl>(STCD)) { const BlockTextRegion *BTR = getBlockTextRegion(BD, C.getCanonicalType(BD->getSignatureAsWritten()->getType()), @@ -761,8 +761,6 @@ const VarRegion* MemRegionManager::getVarRegion(const VarDecl *D, BTR); } else { - // FIXME: For ObjC-methods, we need a new CodeTextRegion. For now - // just use the main global memspace. sReg = getGlobalsRegion(); } } @@ -845,7 +843,7 @@ MemRegionManager::getElementRegion(QualType elementType, NonLoc Idx, } const FunctionTextRegion * -MemRegionManager::getFunctionTextRegion(const FunctionDecl *FD) { +MemRegionManager::getFunctionTextRegion(const NamedDecl *FD) { return getSubRegion<FunctionTextRegion>(FD, getCodeRegion()); } @@ -990,6 +988,10 @@ const MemRegion *MemRegion::getBaseRegion() const { return R; } +bool MemRegion::isSubRegionOf(const MemRegion *R) const { + return false; +} + //===----------------------------------------------------------------------===// // View handling. //===----------------------------------------------------------------------===// @@ -1107,7 +1109,7 @@ RegionOffset MemRegion::getAsOffset() const { // If our base region is symbolic, we don't know what type it really is. // Pretend the type of the symbol is the true dynamic type. // (This will at least be self-consistent for the life of the symbol.) - Ty = SR->getSymbol()->getType(getContext())->getPointeeType(); + Ty = SR->getSymbol()->getType()->getPointeeType(); } const CXXRecordDecl *Child = Ty->getAsCXXRecordDecl(); @@ -1166,8 +1168,12 @@ RegionOffset MemRegion::getAsOffset() const { R = FR->getSuperRegion(); const RecordDecl *RD = FR->getDecl()->getParent(); - if (!RD->isCompleteDefinition()) { + if (RD->isUnion() || !RD->isCompleteDefinition()) { // We cannot compute offset for incomplete type. + // For unions, we could treat everything as offset 0, but we'd rather + // treat each field as a symbolic offset so they aren't stored on top + // of each other, since we depend on things in typed regions actually + // matching their types. SymbolicOffsetBase = R; } diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index c849778e7f23..0f48d1e1c798 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -21,6 +21,7 @@ #include "clang/AST/ParentMap.h" #include "clang/AST/StmtCXX.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" using namespace clang; using namespace ento; @@ -104,11 +105,12 @@ void PathPieces::flattenTo(PathPieces &Primary, PathPieces &Current, PathDiagnostic::~PathDiagnostic() {} PathDiagnostic::PathDiagnostic(const Decl *declWithIssue, - StringRef bugtype, StringRef desc, - StringRef category) + StringRef bugtype, StringRef verboseDesc, + StringRef shortDesc, StringRef category) : DeclWithIssue(declWithIssue), BugType(StripTrailingDots(bugtype)), - Desc(StripTrailingDots(desc)), + VerboseDesc(StripTrailingDots(verboseDesc)), + ShortDesc(StripTrailingDots(shortDesc)), Category(StripTrailingDots(category)), path(pathImpl) {} @@ -198,6 +200,7 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { if (orig_size <= new_size) return; + assert(orig != D); Diags.RemoveNode(orig); delete orig; } @@ -205,39 +208,151 @@ void PathDiagnosticConsumer::HandlePathDiagnostic(PathDiagnostic *D) { Diags.InsertNode(OwningD.take()); } +static llvm::Optional<bool> comparePath(const PathPieces &X, + const PathPieces &Y); +static llvm::Optional<bool> +compareControlFlow(const PathDiagnosticControlFlowPiece &X, + const PathDiagnosticControlFlowPiece &Y) { + FullSourceLoc XSL = X.getStartLocation().asLocation(); + FullSourceLoc YSL = Y.getStartLocation().asLocation(); + if (XSL != YSL) + return XSL.isBeforeInTranslationUnitThan(YSL); + FullSourceLoc XEL = X.getEndLocation().asLocation(); + FullSourceLoc YEL = Y.getEndLocation().asLocation(); + if (XEL != YEL) + return XEL.isBeforeInTranslationUnitThan(YEL); + return llvm::Optional<bool>(); +} + +static llvm::Optional<bool> +compareMacro(const PathDiagnosticMacroPiece &X, + const PathDiagnosticMacroPiece &Y) { + return comparePath(X.subPieces, Y.subPieces); +} + +static llvm::Optional<bool> +compareCall(const PathDiagnosticCallPiece &X, + const PathDiagnosticCallPiece &Y) { + FullSourceLoc X_CEL = X.callEnter.asLocation(); + FullSourceLoc Y_CEL = Y.callEnter.asLocation(); + if (X_CEL != Y_CEL) + return X_CEL.isBeforeInTranslationUnitThan(Y_CEL); + FullSourceLoc X_CEWL = X.callEnterWithin.asLocation(); + FullSourceLoc Y_CEWL = Y.callEnterWithin.asLocation(); + if (X_CEWL != Y_CEWL) + return X_CEWL.isBeforeInTranslationUnitThan(Y_CEWL); + FullSourceLoc X_CRL = X.callReturn.asLocation(); + FullSourceLoc Y_CRL = Y.callReturn.asLocation(); + if (X_CRL != Y_CRL) + return X_CRL.isBeforeInTranslationUnitThan(Y_CRL); + return comparePath(X.path, Y.path); +} + +static llvm::Optional<bool> comparePiece(const PathDiagnosticPiece &X, + const PathDiagnosticPiece &Y) { + if (X.getKind() != Y.getKind()) + return X.getKind() < Y.getKind(); + + FullSourceLoc XL = X.getLocation().asLocation(); + FullSourceLoc YL = Y.getLocation().asLocation(); + if (XL != YL) + return XL.isBeforeInTranslationUnitThan(YL); + + if (X.getString() != Y.getString()) + return X.getString() < Y.getString(); + + if (X.getRanges().size() != Y.getRanges().size()) + return X.getRanges().size() < Y.getRanges().size(); + + const SourceManager &SM = XL.getManager(); + + for (unsigned i = 0, n = X.getRanges().size(); i < n; ++i) { + SourceRange XR = X.getRanges()[i]; + SourceRange YR = Y.getRanges()[i]; + if (XR != YR) { + if (XR.getBegin() != YR.getBegin()) + return SM.isBeforeInTranslationUnit(XR.getBegin(), YR.getBegin()); + return SM.isBeforeInTranslationUnit(XR.getEnd(), YR.getEnd()); + } + } + + switch (X.getKind()) { + case clang::ento::PathDiagnosticPiece::ControlFlow: + return compareControlFlow(cast<PathDiagnosticControlFlowPiece>(X), + cast<PathDiagnosticControlFlowPiece>(Y)); + case clang::ento::PathDiagnosticPiece::Event: + return llvm::Optional<bool>(); + case clang::ento::PathDiagnosticPiece::Macro: + return compareMacro(cast<PathDiagnosticMacroPiece>(X), + cast<PathDiagnosticMacroPiece>(Y)); + case clang::ento::PathDiagnosticPiece::Call: + return compareCall(cast<PathDiagnosticCallPiece>(X), + cast<PathDiagnosticCallPiece>(Y)); + } + llvm_unreachable("all cases handled"); +} + +static llvm::Optional<bool> comparePath(const PathPieces &X, + const PathPieces &Y) { + if (X.size() != Y.size()) + return X.size() < Y.size(); + for (unsigned i = 0, n = X.size(); i != n; ++i) { + llvm::Optional<bool> b = comparePiece(*X[i], *Y[i]); + if (b.hasValue()) + return b.getValue(); + } + return llvm::Optional<bool>(); +} + +static bool compare(const PathDiagnostic &X, const PathDiagnostic &Y) { + FullSourceLoc XL = X.getLocation().asLocation(); + FullSourceLoc YL = Y.getLocation().asLocation(); + if (XL != YL) + return XL.isBeforeInTranslationUnitThan(YL); + if (X.getBugType() != Y.getBugType()) + return X.getBugType() < Y.getBugType(); + if (X.getCategory() != Y.getCategory()) + return X.getCategory() < Y.getCategory(); + if (X.getVerboseDescription() != Y.getVerboseDescription()) + return X.getVerboseDescription() < Y.getVerboseDescription(); + if (X.getShortDescription() != Y.getShortDescription()) + return X.getShortDescription() < Y.getShortDescription(); + if (X.getDeclWithIssue() != Y.getDeclWithIssue()) { + const Decl *XD = X.getDeclWithIssue(); + if (!XD) + return true; + const Decl *YD = Y.getDeclWithIssue(); + if (!YD) + return false; + SourceLocation XDL = XD->getLocation(); + SourceLocation YDL = YD->getLocation(); + if (XDL != YDL) { + const SourceManager &SM = XL.getManager(); + return SM.isBeforeInTranslationUnit(XDL, YDL); + } + } + PathDiagnostic::meta_iterator XI = X.meta_begin(), XE = X.meta_end(); + PathDiagnostic::meta_iterator YI = Y.meta_begin(), YE = Y.meta_end(); + if (XE - XI != YE - YI) + return (XE - XI) < (YE - YI); + for ( ; XI != XE ; ++XI, ++YI) { + if (*XI != *YI) + return (*XI) < (*YI); + } + llvm::Optional<bool> b = comparePath(X.path, Y.path); + assert(b.hasValue()); + return b.getValue(); +} namespace { struct CompareDiagnostics { // Compare if 'X' is "<" than 'Y'. bool operator()(const PathDiagnostic *X, const PathDiagnostic *Y) const { - // First compare by location - const FullSourceLoc &XLoc = X->getLocation().asLocation(); - const FullSourceLoc &YLoc = Y->getLocation().asLocation(); - if (XLoc < YLoc) - return true; - if (XLoc != YLoc) + if (X == Y) return false; - - // Next, compare by bug type. - StringRef XBugType = X->getBugType(); - StringRef YBugType = Y->getBugType(); - if (XBugType < YBugType) - return true; - if (XBugType != YBugType) - return false; - - // Next, compare by bug description. - StringRef XDesc = X->getDescription(); - StringRef YDesc = Y->getDescription(); - if (XDesc < YDesc) - return true; - if (XDesc != YDesc) - return false; - - // FIXME: Further refine by comparing PathDiagnosticPieces? - return false; - } -}; + return compare(*X, *Y); + } +}; } void PathDiagnosticConsumer::FlushDiagnostics( @@ -250,11 +365,9 @@ void PathDiagnosticConsumer::FlushDiagnostics( std::vector<const PathDiagnostic *> BatchDiags; for (llvm::FoldingSet<PathDiagnostic>::iterator it = Diags.begin(), et = Diags.end(); it != et; ++it) { - BatchDiags.push_back(&*it); + const PathDiagnostic *D = &*it; + BatchDiags.push_back(D); } - - // Clear out the FoldingSet. - Diags.clear(); // Sort the diagnostics so that they are always emitted in a deterministic // order. @@ -269,6 +382,42 @@ void PathDiagnosticConsumer::FlushDiagnostics( const PathDiagnostic *D = *it; delete D; } + + // Clear out the FoldingSet. + Diags.clear(); +} + +void PathDiagnosticConsumer::FilesMade::addDiagnostic(const PathDiagnostic &PD, + StringRef ConsumerName, + StringRef FileName) { + llvm::FoldingSetNodeID NodeID; + NodeID.Add(PD); + void *InsertPos; + PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); + if (!Entry) { + Entry = Alloc.Allocate<PDFileEntry>(); + Entry = new (Entry) PDFileEntry(NodeID); + InsertNode(Entry, InsertPos); + } + + // Allocate persistent storage for the file name. + char *FileName_cstr = (char*) Alloc.Allocate(FileName.size(), 1); + memcpy(FileName_cstr, FileName.data(), FileName.size()); + + Entry->files.push_back(std::make_pair(ConsumerName, + StringRef(FileName_cstr, + FileName.size()))); +} + +PathDiagnosticConsumer::PDFileEntry::ConsumerFiles * +PathDiagnosticConsumer::FilesMade::getFiles(const PathDiagnostic &PD) { + llvm::FoldingSetNodeID NodeID; + NodeID.Add(PD); + void *InsertPos; + PDFileEntry *Entry = FindNodeOrInsertPos(NodeID, InsertPos); + if (!Entry) + return 0; + return &Entry->files; } //===----------------------------------------------------------------------===// @@ -437,8 +586,8 @@ PathDiagnosticLocation const CFGBlock *BSrc = BE->getSrc(); S = BSrc->getTerminatorCondition(); } - else if (const PostStmt *PS = dyn_cast<PostStmt>(&P)) { - S = PS->getStmt(); + else if (const StmtPoint *SP = dyn_cast<StmtPoint>(&P)) { + S = SP->getStmt(); } else if (const PostImplicitCall *PIE = dyn_cast<PostImplicitCall>(&P)) { return PathDiagnosticLocation(PIE->getLocation(), SMng); @@ -453,6 +602,9 @@ PathDiagnosticLocation CEE->getLocationContext(), SMng); } + else { + llvm_unreachable("Unexpected ProgramPoint"); + } return PathDiagnosticLocation(S, SMng, P.getLocationContext()); } @@ -463,21 +615,26 @@ PathDiagnosticLocation assert(N && "Cannot create a location with a null node."); const ExplodedNode *NI = N; + const Stmt *S = 0; while (NI) { ProgramPoint P = NI->getLocation(); - const LocationContext *LC = P.getLocationContext(); if (const StmtPoint *PS = dyn_cast<StmtPoint>(&P)) - return PathDiagnosticLocation(PS->getStmt(), SM, LC); - else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) { - const Stmt *Term = BE->getSrc()->getTerminator(); - if (Term) { - return PathDiagnosticLocation(Term, SM, LC); - } - } + S = PS->getStmt(); + else if (const BlockEdge *BE = dyn_cast<BlockEdge>(&P)) + S = BE->getSrc()->getTerminator(); + if (S) + break; NI = NI->succ_empty() ? 0 : *(NI->succ_begin()); } + if (S) { + const LocationContext *LC = NI->getLocationContext(); + if (S->getLocStart().isValid()) + return PathDiagnosticLocation(S, SM, LC); + return PathDiagnosticLocation(getValidSourceLocation(S, LC), SM); + } + return createDeclEnd(N->getLocationContext(), SM); } @@ -587,24 +744,6 @@ void PathDiagnosticLocation::flatten() { } } -PathDiagnosticLocation PathDiagnostic::getLocation() const { - assert(path.size() > 0 && - "getLocation() requires a non-empty PathDiagnostic."); - - PathDiagnosticPiece *p = path.rbegin()->getPtr(); - - while (true) { - if (PathDiagnosticCallPiece *cp = dyn_cast<PathDiagnosticCallPiece>(p)) { - assert(!cp->path.empty()); - p = cp->path.rbegin()->getPtr(); - continue; - } - break; - } - - return p->getLocation(); -} - //===----------------------------------------------------------------------===// // Manipulation of PathDiagnosticCallPieces. //===----------------------------------------------------------------------===// @@ -753,10 +892,9 @@ void PathDiagnosticMacroPiece::Profile(llvm::FoldingSetNodeID &ID) const { } void PathDiagnostic::Profile(llvm::FoldingSetNodeID &ID) const { - if (!path.empty()) - getLocation().Profile(ID); + ID.Add(getLocation()); ID.AddString(BugType); - ID.AddString(Desc); + ID.AddString(VerboseDesc); ID.AddString(Category); } @@ -818,42 +956,16 @@ std::string StackHintGeneratorForSymbol::getMessage(const ExplodedNode *N){ return getMessageForSymbolNotFound(); } -/// TODO: This is copied from clang diagnostics. Maybe we could just move it to -/// some common place. (Same as HandleOrdinalModifier.) -void StackHintGeneratorForSymbol::printOrdinal(unsigned ValNo, - llvm::raw_svector_ostream &Out) { - assert(ValNo != 0 && "ValNo must be strictly positive!"); - - // We could use text forms for the first N ordinals, but the numeric - // forms are actually nicer in diagnostics because they stand out. - Out << ValNo; - - // It is critically important that we do this perfectly for - // user-written sequences with over 100 elements. - switch (ValNo % 100) { - case 11: - case 12: - case 13: - Out << "th"; return; - default: - switch (ValNo % 10) { - case 1: Out << "st"; return; - case 2: Out << "nd"; return; - case 3: Out << "rd"; return; - default: Out << "th"; return; - } - } -} - std::string StackHintGeneratorForSymbol::getMessageForArg(const Expr *ArgE, - unsigned ArgIndex) { + unsigned ArgIndex) { + // Printed parameters start at 1, not 0. + ++ArgIndex; + SmallString<200> buf; llvm::raw_svector_ostream os(buf); - os << Msg << " via "; - // Printed parameters start at 1, not 0. - printOrdinal(++ArgIndex, os); - os << " parameter"; + os << Msg << " via " << ArgIndex << llvm::getOrdinalSuffix(ArgIndex) + << " parameter"; return os.str(); } diff --git a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp index d5fdd9d2bb99..17ef4cf571e8 100644 --- a/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/PlistDiagnostics.cpp @@ -13,8 +13,9 @@ #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" -#include "clang/Basic/SourceManager.h" #include "clang/Basic/FileManager.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/Version.h" #include "clang/Lex/Preprocessor.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Casting.h" @@ -47,7 +48,6 @@ namespace { PathGenerationScheme getGenerationScheme() const { return Extensive; } bool supportsLogicalOpControlFlow() const { return true; } bool supportsAllBlockEdges() const { return true; } - virtual bool useVerboseDescription() const { return false; } virtual bool supportsCrossFileDiagnostics() const { return SupportsCrossFileDiagnostics; } @@ -247,6 +247,7 @@ static void ReportEvent(raw_ostream &o, const PathDiagnosticPiece& P, // Output the short text. // FIXME: Really use a short string. Indent(o, indent) << "<key>message</key>\n"; + Indent(o, indent); EmitString(o, P.getString()) << '\n'; // Finish up. @@ -409,10 +410,13 @@ void PlistDiagnostics::FlushDiagnosticsImpl( "<plist version=\"1.0\">\n"; // Write the root object: a <dict> containing... + // - "clang_version", the string representation of clang version // - "files", an <array> mapping from FIDs to file names // - "diagnostics", an <array> containing the path diagnostics - o << "<dict>\n" - " <key>files</key>\n" + o << "<dict>\n" << + " <key>clang_version</key>\n"; + EmitString(o, getClangFullVersion()) << '\n'; + o << " <key>files</key>\n" " <array>\n"; for (SmallVectorImpl<FileID>::iterator I=Fids.begin(), E=Fids.end(); @@ -443,7 +447,7 @@ void PlistDiagnostics::FlushDiagnosticsImpl( // Output the bug type and bug category. o << " <key>description</key>"; - EmitString(o, D->getDescription()) << '\n'; + EmitString(o, D->getShortDescription()) << '\n'; o << " <key>category</key>"; EmitString(o, D->getCategory()) << '\n'; o << " <key>type</key>"; @@ -499,19 +503,23 @@ void PlistDiagnostics::FlushDiagnosticsImpl( // Output the diagnostic to the sub-diagnostic client, if any. if (!filesMade->empty()) { StringRef lastName; - for (FilesMade::iterator I = filesMade->begin(), E = filesMade->end(); - I != E; ++I) { - StringRef newName = I->first; - if (newName != lastName) { - if (!lastName.empty()) - o << " </array>\n"; - lastName = newName; - o << " <key>" << lastName << "_files</key>\n"; - o << " <array>\n"; + PDFileEntry::ConsumerFiles *files = filesMade->getFiles(*D); + if (files) { + for (PDFileEntry::ConsumerFiles::const_iterator CI = files->begin(), + CE = files->end(); CI != CE; ++CI) { + StringRef newName = CI->first; + if (newName != lastName) { + if (!lastName.empty()) { + o << " </array>\n"; + } + lastName = newName; + o << " <key>" << lastName << "_files</key>\n"; + o << " <array>\n"; + } + o << " <string>" << CI->second << "</string>\n"; } - o << " <string>" << I->second << "</string>\n"; + o << " </array>\n"; } - o << " </array>\n"; } // Close up the entry. @@ -521,10 +529,5 @@ void PlistDiagnostics::FlushDiagnosticsImpl( o << " </array>\n"; // Finish. - o << "</dict>\n</plist>"; - - if (filesMade) { - StringRef Name(getName()); - filesMade->push_back(std::make_pair(Name, OutputFile)); - } + o << "</dict>\n</plist>"; } diff --git a/lib/StaticAnalyzer/Core/ProgramState.cpp b/lib/StaticAnalyzer/Core/ProgramState.cpp index 2000338ee0a6..b49a11e64214 100644 --- a/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -22,10 +22,6 @@ using namespace clang; using namespace ento; -// Give the vtable for ConstraintManager somewhere to live. -// FIXME: Move this elsewhere. -ConstraintManager::~ConstraintManager() {} - namespace clang { namespace ento { /// Increments the number of times this state is referenced. @@ -75,8 +71,8 @@ ProgramStateManager::ProgramStateManager(ASTContext &Ctx, StoreManagerCreator CreateSMgr, ConstraintManagerCreator CreateCMgr, llvm::BumpPtrAllocator &alloc, - SubEngine &SubEng) - : Eng(&SubEng), EnvMgr(alloc), GDMFactory(alloc), + SubEngine *SubEng) + : Eng(SubEng), EnvMgr(alloc), GDMFactory(alloc), svalBuilder(createSimpleSValBuilder(alloc, Ctx, *this)), CallEventMgr(new CallEventManager(alloc)), Alloc(alloc) { StoreMgr.reset((*CreateSMgr)(*this)); @@ -110,47 +106,25 @@ ProgramStateManager::removeDeadBindings(ProgramStateRef state, SymReaper); NewState.setStore(newStore); SymReaper.setReapedStore(newStore); - - return getPersistentState(NewState); -} - -ProgramStateRef ProgramStateManager::MarshalState(ProgramStateRef state, - const StackFrameContext *InitLoc) { - // make up an empty state for now. - ProgramState State(this, - EnvMgr.getInitialEnvironment(), - StoreMgr->getInitialStore(InitLoc), - GDMFactory.getEmptyMap()); - return getPersistentState(State); + ProgramStateRef Result = getPersistentState(NewState); + return ConstraintMgr->removeDeadBindings(Result, SymReaper); } ProgramStateRef ProgramState::bindCompoundLiteral(const CompoundLiteralExpr *CL, const LocationContext *LC, SVal V) const { const StoreRef &newStore = - getStateManager().StoreMgr->BindCompoundLiteral(getStore(), CL, LC, V); + getStateManager().StoreMgr->bindCompoundLiteral(getStore(), CL, LC, V); return makeWithStore(newStore); } -ProgramStateRef ProgramState::bindDecl(const VarRegion* VR, SVal IVal) const { - const StoreRef &newStore = - getStateManager().StoreMgr->BindDecl(getStore(), VR, IVal); - return makeWithStore(newStore); -} - -ProgramStateRef ProgramState::bindDeclWithNoInit(const VarRegion* VR) const { - const StoreRef &newStore = - getStateManager().StoreMgr->BindDeclWithNoInit(getStore(), VR); - return makeWithStore(newStore); -} - -ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V) const { +ProgramStateRef ProgramState::bindLoc(Loc LV, SVal V, bool notifyChanges) const { ProgramStateManager &Mgr = getStateManager(); ProgramStateRef newState = makeWithStore(Mgr.StoreMgr->Bind(getStore(), LV, V)); const MemRegion *MR = LV.getAsRegion(); - if (MR && Mgr.getOwningEngine()) + if (MR && Mgr.getOwningEngine() && notifyChanges) return Mgr.getOwningEngine()->processRegionChange(newState, MR); return newState; @@ -204,11 +178,12 @@ ProgramState::invalidateRegionsImpl(ArrayRef<const MemRegion *> Regions, return makeWithStore(newStore); } -ProgramStateRef ProgramState::unbindLoc(Loc LV) const { +ProgramStateRef ProgramState::killBinding(Loc LV) const { assert(!isa<loc::MemRegionVal>(LV) && "Use invalidateRegion instead."); Store OldStore = getStore(); - const StoreRef &newStore = getStateManager().StoreMgr->Remove(OldStore, LV); + const StoreRef &newStore = + getStateManager().StoreMgr->killBinding(OldStore, LV); if (newStore.getStore() == OldStore) return this; @@ -249,7 +224,9 @@ SVal ProgramState::getSVal(Loc location, QualType T) const { // about). if (!T.isNull()) { if (SymbolRef sym = V.getAsSymbol()) { - if (const llvm::APSInt *Int = getSymVal(sym)) { + if (const llvm::APSInt *Int = getStateManager() + .getConstraintManager() + .getSymVal(this, sym)) { // FIXME: Because we don't correctly model (yet) sign-extension // and truncation of symbolic values, we need to convert // the integer value to the correct signedness and bitwidth. @@ -710,7 +687,9 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const { bool Tainted = false; for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), SE =Sym->symbol_end(); SI != SE; ++SI) { - assert(isa<SymbolData>(*SI)); + if (!isa<SymbolData>(*SI)) + continue; + const TaintTagType *Tag = get<TaintMap>(*SI); Tainted = (Tag && *Tag == Kind); @@ -734,15 +713,10 @@ bool ProgramState::isTainted(SymbolRef Sym, TaintTagType Kind) const { } /// The GDM component containing the dynamic type info. This is a map from a -/// symbol to it's most likely type. -namespace clang { -namespace ento { -typedef llvm::ImmutableMap<const MemRegion *, DynamicTypeInfo> DynamicTypeMap; -template<> struct ProgramStateTrait<DynamicTypeMap> - : public ProgramStatePartialTrait<DynamicTypeMap> { - static void *GDMIndex() { static int index; return &index; } -}; -}} +/// symbol to its most likely type. +REGISTER_TRAIT_WITH_PROGRAMSTATE(DynamicTypeMap, + CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, + DynamicTypeInfo)) DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const { Reg = Reg->StripCasts(); @@ -758,7 +732,7 @@ DynamicTypeInfo ProgramState::getDynamicTypeInfo(const MemRegion *Reg) const { if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(Reg)) { SymbolRef Sym = SR->getSymbol(); - return DynamicTypeInfo(Sym->getType(getStateManager().getContext())); + return DynamicTypeInfo(Sym->getType()); } return DynamicTypeInfo(); diff --git a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 550404a51075..411094bc1d14 100644 --- a/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -24,9 +24,6 @@ using namespace clang; using namespace ento; -namespace { class ConstraintRange {}; } -static int ConstraintRangeIndex = 0; - /// A Range represents the closed range [from, to]. The caller must /// guarantee that from <= to. Note that Range is immutable, so as not /// to subvert RangeSet's immutability. @@ -280,23 +277,15 @@ public: }; } // end anonymous namespace -typedef llvm::ImmutableMap<SymbolRef,RangeSet> ConstraintRangeTy; - -namespace clang { -namespace ento { -template<> -struct ProgramStateTrait<ConstraintRange> - : public ProgramStatePartialTrait<ConstraintRangeTy> { - static inline void *GDMIndex() { return &ConstraintRangeIndex; } -}; -} -} +REGISTER_TRAIT_WITH_PROGRAMSTATE(ConstraintRange, + CLANG_ENTO_PROGRAMSTATE_MAP(SymbolRef, + RangeSet)) namespace { class RangeConstraintManager : public SimpleConstraintManager{ RangeSet GetRange(ProgramStateRef state, SymbolRef sym); public: - RangeConstraintManager(SubEngine &subengine, BasicValueFactory &BVF) + RangeConstraintManager(SubEngine *subengine, BasicValueFactory &BVF) : SimpleConstraintManager(subengine, BVF) {} ProgramStateRef assumeSymNE(ProgramStateRef state, SymbolRef sym, @@ -324,12 +313,7 @@ public: const llvm::APSInt& Adjustment); const llvm::APSInt* getSymVal(ProgramStateRef St, SymbolRef sym) const; - - // FIXME: Refactor into SimpleConstraintManager? - bool isEqual(ProgramStateRef St, SymbolRef sym, const llvm::APSInt& V) const { - const llvm::APSInt *i = getSymVal(St, sym); - return i ? *i == V : false; - } + ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym); ProgramStateRef removeDeadBindings(ProgramStateRef St, SymbolReaper& SymReaper); @@ -343,7 +327,7 @@ private: } // end anonymous namespace ConstraintManager * -ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine &Eng) { +ento::CreateRangeConstraintManager(ProgramStateManager &StMgr, SubEngine *Eng) { return new RangeConstraintManager(Eng, StMgr.getBasicVals()); } @@ -353,6 +337,30 @@ const llvm::APSInt* RangeConstraintManager::getSymVal(ProgramStateRef St, return T ? T->getConcreteValue() : NULL; } +ConditionTruthVal RangeConstraintManager::checkNull(ProgramStateRef State, + SymbolRef Sym) { + const RangeSet *Ranges = State->get<ConstraintRange>(Sym); + + // If we don't have any information about this symbol, it's underconstrained. + if (!Ranges) + return ConditionTruthVal(); + + // If we have a concrete value, see if it's zero. + if (const llvm::APSInt *Value = Ranges->getConcreteValue()) + return *Value == 0; + + BasicValueFactory &BV = getBasicVals(); + APSIntType IntType = BV.getAPSIntType(Sym->getType()); + llvm::APSInt Zero = IntType.getZeroValue(); + + // Check if zero is in the set of possible values. + if (Ranges->Intersect(BV, F, Zero, Zero).isEmpty()) + return false; + + // Zero is a possible value, but it is not the /only/ possible value. + return ConditionTruthVal(); +} + /// Scan all symbols referenced by the constraints. If the symbol is not alive /// as marked in LSymbols, mark it as dead in DSymbols. ProgramStateRef @@ -379,8 +387,18 @@ RangeConstraintManager::GetRange(ProgramStateRef state, SymbolRef sym) { // Lazily generate a new RangeSet representing all possible values for the // given symbol type. BasicValueFactory &BV = getBasicVals(); - QualType T = sym->getType(BV.getContext()); - return RangeSet(F, BV.getMinValue(T), BV.getMaxValue(T)); + QualType T = sym->getType(); + + RangeSet Result(F, BV.getMinValue(T), BV.getMaxValue(T)); + + // Special case: references are known to be non-zero. + if (T->isReferenceType()) { + APSIntType IntType = BV.getAPSIntType(T); + Result = Result.Intersect(BV, F, ++IntType.getZeroValue(), + --IntType.getZeroValue()); + } + + return Result; } //===------------------------------------------------------------------------=== diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index bc4e4bbf602b..aed994df4110 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -15,9 +15,6 @@ // //===----------------------------------------------------------------------===// #include "clang/AST/CharUnits.h" -#include "clang/AST/DeclCXX.h" -#include "clang/AST/ExprCXX.h" -#include "clang/AST/CXXInheritance.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Basic/TargetInfo.h" @@ -193,19 +190,6 @@ public: /// casts from arrays to pointers. SVal ArrayToPointer(Loc Array); - /// For DerivedToBase casts, create a CXXBaseObjectRegion and return it. - virtual SVal evalDerivedToBase(SVal derived, QualType basePtrType); - - /// \brief Evaluates C++ dynamic_cast cast. - /// The callback may result in the following 3 scenarios: - /// - Successful cast (ex: derived is subclass of base). - /// - Failed cast (ex: derived is definitely not a subclass of base). - /// - We don't know (base is a symbolic region and we don't have - /// enough info to determine if the cast will succeed at run time). - /// The function returns an SVal representing the derived class; it's - /// valid only if Failed flag is set to false. - virtual SVal evalDynamicCast(SVal base, QualType derivedPtrType,bool &Failed); - StoreRef getInitialStore(const LocationContext *InitLoc) { return StoreRef(RBFactory.getEmptyMap().getRootWithoutRetain(), *this); } @@ -244,7 +228,7 @@ public: // Made public for helper classes. RegionBindings removeBinding(RegionBindings B, BindingKey K); RegionBindings removeBinding(RegionBindings B, const MemRegion *R, - BindingKey::Kind k); + BindingKey::Kind k); RegionBindings removeBinding(RegionBindings B, const MemRegion *R) { return removeBinding(removeBinding(B, R, BindingKey::Direct), R, @@ -266,15 +250,20 @@ public: // Part of public interface to class. .getRootWithoutRetain(), *this); } - StoreRef BindCompoundLiteral(Store store, const CompoundLiteralExpr *CL, + /// \brief Create a new store that binds a value to a compound literal. + /// + /// \param ST The original store whose bindings are the basis for the new + /// store. + /// + /// \param CL The compound literal to bind (the binding key). + /// + /// \param LC The LocationContext for the binding. + /// + /// \param V The value to bind to the compound literal. + StoreRef bindCompoundLiteral(Store ST, + const CompoundLiteralExpr *CL, const LocationContext *LC, SVal V); - StoreRef BindDecl(Store store, const VarRegion *VR, SVal InitVal); - - StoreRef BindDeclWithNoInit(Store store, const VarRegion *) { - return StoreRef(store, *this); - } - /// BindStruct - Bind a compound value to a structure. StoreRef BindStruct(Store store, const TypedValueRegion* R, SVal V); @@ -287,7 +276,10 @@ public: // Part of public interface to class. /// as a Default binding. StoreRef BindAggregate(Store store, const TypedRegion *R, SVal DefaultVal); - StoreRef Remove(Store store, Loc LV); + /// \brief Create a new store with the specified binding removed. + /// \param ST the original store, that is the basis for the new store. + /// \param L the location whose binding should be removed. + StoreRef killBinding(Store ST, Loc L); void incrementReferenceCount(Store store) { GetRegionBindings(store).manualRetain(); @@ -477,12 +469,8 @@ public: } bool AddToWorkList(const MemRegion *R, const ClusterBindings *C) { - if (C) { - if (Visited.count(C)) - return false; - Visited.insert(C); - } - + if (C && !Visited.insert(C)) + return false; WL.push_back(R); return true; } @@ -534,6 +522,46 @@ bool RegionStoreManager::scanReachableSymbols(Store S, const MemRegion *R, return true; } +static inline bool isUnionField(const FieldRegion *FR) { + return FR->getDecl()->getParent()->isUnion(); +} + +typedef SmallVector<const FieldDecl *, 8> FieldVector; + +void getSymbolicOffsetFields(BindingKey K, FieldVector &Fields) { + assert(K.hasSymbolicOffset() && "Not implemented for concrete offset keys"); + + const MemRegion *Base = K.getConcreteOffsetRegion(); + const MemRegion *R = K.getRegion(); + + while (R != Base) { + if (const FieldRegion *FR = dyn_cast<FieldRegion>(R)) + if (!isUnionField(FR)) + Fields.push_back(FR->getDecl()); + + R = cast<SubRegion>(R)->getSuperRegion(); + } +} + +static bool isCompatibleWithFields(BindingKey K, const FieldVector &Fields) { + assert(K.hasSymbolicOffset() && "Not implemented for concrete offset keys"); + + if (Fields.empty()) + return true; + + FieldVector FieldsInBindingKey; + getSymbolicOffsetFields(K, FieldsInBindingKey); + + ptrdiff_t Delta = FieldsInBindingKey.size() - Fields.size(); + if (Delta >= 0) + return std::equal(FieldsInBindingKey.begin() + Delta, + FieldsInBindingKey.end(), + Fields.begin()); + else + return std::equal(FieldsInBindingKey.begin(), FieldsInBindingKey.end(), + Fields.begin() - Delta); +} + RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B, const SubRegion *R) { BindingKey SRKey = BindingKey::Make(R, BindingKey::Default); @@ -543,10 +571,12 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B, return RBFactory.remove(B, R); } - if (SRKey.hasSymbolicOffset()) { - const SubRegion *Base = cast<SubRegion>(SRKey.getConcreteOffsetRegion()); - B = removeSubRegionBindings(B, Base); - return addBinding(B, Base, BindingKey::Default, UnknownVal()); + FieldVector FieldsInSymbolicSubregions; + bool HasSymbolicOffset = SRKey.hasSymbolicOffset(); + if (HasSymbolicOffset) { + getSymbolicOffsetFields(SRKey, FieldsInSymbolicSubregions); + R = cast<SubRegion>(SRKey.getConcreteOffsetRegion()); + SRKey = BindingKey::Make(R, BindingKey::Default); } // This assumes the region being invalidated is char-aligned. This isn't @@ -574,11 +604,17 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B, I != E; ++I) { BindingKey NextKey = I.getKey(); if (NextKey.getRegion() == SRKey.getRegion()) { + // FIXME: This doesn't catch the case where we're really invalidating a + // region with a symbolic offset. Example: + // R: points[i].y + // Next: points[0].x + if (NextKey.getOffset() > SRKey.getOffset() && NextKey.getOffset() - SRKey.getOffset() < Length) { // Case 1: The next binding is inside the region we're invalidating. // Remove it. Result = CBFactory.remove(Result, NextKey); + } else if (NextKey.getOffset() == SRKey.getOffset()) { // Case 2: The next binding is at the same offset as the region we're // invalidating. In this case, we need to leave default bindings alone, @@ -589,6 +625,7 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B, if (NextKey.isDirect()) Result = CBFactory.remove(Result, NextKey); } + } else if (NextKey.hasSymbolicOffset()) { const MemRegion *Base = NextKey.getConcreteOffsetRegion(); if (R->isSubRegionOf(Base)) { @@ -596,16 +633,24 @@ RegionBindings RegionStoreManager::removeSubRegionBindings(RegionBindings B, // its concrete region. We don't know if the binding is still valid, so // we'll be conservative and remove it. if (NextKey.isDirect()) - Result = CBFactory.remove(Result, NextKey); + if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions)) + Result = CBFactory.remove(Result, NextKey); } else if (const SubRegion *BaseSR = dyn_cast<SubRegion>(Base)) { // Case 4: The next key is symbolic, but we changed a known // super-region. In this case the binding is certainly no longer valid. if (R == Base || BaseSR->isSubRegionOf(R)) - Result = CBFactory.remove(Result, NextKey); + if (isCompatibleWithFields(NextKey, FieldsInSymbolicSubregions)) + Result = CBFactory.remove(Result, NextKey); } } } + // If we're invalidating a region with a symbolic offset, we need to make sure + // we don't treat the base region as uninitialized anymore. + // FIXME: This isn't very precise; see the example in the loop. + if (HasSymbolicOffset) + Result = CBFactory.add(Result, SRKey, UnknownVal()); + if (Result.isEmpty()) return RBFactory.remove(B, ClusterHead); return RBFactory.add(B, ClusterHead, Result); @@ -724,7 +769,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. DefinedOrUnknownSVal V = - svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count); + svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count); B = RM.addBinding(B, baseR, BindingKey::Default, V); return; } @@ -739,8 +784,8 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { if (T->isStructureOrClassType()) { // Invalidate the region by setting its default value to // conjured symbol. The type of the symbol is irrelavant. - DefinedOrUnknownSVal V = - svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx, Ctx.IntTy, Count); + DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, + Ctx.IntTy, Count); B = RM.addBinding(B, baseR, BindingKey::Default, V); return; } @@ -748,7 +793,7 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { if (const ArrayType *AT = Ctx.getAsArrayType(T)) { // Set the default value of the array to conjured symbol. DefinedOrUnknownSVal V = - svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx, + svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, AT->getElementType(), Count); B = RM.addBinding(B, baseR, BindingKey::Default, V); return; @@ -764,8 +809,8 @@ void invalidateRegionsWorker::VisitBaseRegion(const MemRegion *baseR) { } - DefinedOrUnknownSVal V = svalBuilder.getConjuredSymbolVal(baseR, Ex, LCtx, - T,Count); + DefinedOrUnknownSVal V = svalBuilder.conjureSymbolVal(baseR, Ex, LCtx, + T,Count); assert(SymbolManager::canSymbolicate(T) || V.isUnknown()); B = RM.addBinding(B, baseR, BindingKey::Direct, V); } @@ -779,10 +824,9 @@ RegionBindings RegionStoreManager::invalidateGlobalRegion(MemRegion::Kind K, // Bind the globals memory space to a new symbol that we will use to derive // the bindings for all globals. const GlobalsSpaceRegion *GS = MRMgr.getGlobalsRegion(K); - SVal V = - svalBuilder.getConjuredSymbolVal(/* SymbolTag = */ (void*) GS, Ex, LCtx, - /* symbol type, doesn't matter */ Ctx.IntTy, - Count); + SVal V = svalBuilder.conjureSymbolVal(/* SymbolTag = */ (const void*) GS, Ex, LCtx, + /* type does not matter */ Ctx.IntTy, + Count); B = removeBinding(B, GS); B = addBinding(B, BindingKey::Make(GS, BindingKey::Default), V); @@ -897,103 +941,6 @@ SVal RegionStoreManager::ArrayToPointer(Loc Array) { return loc::MemRegionVal(MRMgr.getElementRegion(T, ZeroIdx, ArrayR, Ctx)); } -// This mirrors Type::getCXXRecordDeclForPointerType(), but there doesn't -// appear to be another need for this in the rest of the codebase. -static const CXXRecordDecl *GetCXXRecordDeclForReferenceType(QualType Ty) { - if (const ReferenceType *RT = Ty->getAs<ReferenceType>()) - if (const RecordType *RCT = RT->getPointeeType()->getAs<RecordType>()) - return dyn_cast<CXXRecordDecl>(RCT->getDecl()); - return 0; -} - -SVal RegionStoreManager::evalDerivedToBase(SVal derived, QualType baseType) { - const CXXRecordDecl *baseDecl; - - if (baseType->isPointerType()) - baseDecl = baseType->getCXXRecordDeclForPointerType(); - else if (baseType->isReferenceType()) - baseDecl = GetCXXRecordDeclForReferenceType(baseType); - else - baseDecl = baseType->getAsCXXRecordDecl(); - - assert(baseDecl && "not a CXXRecordDecl?"); - - loc::MemRegionVal *derivedRegVal = dyn_cast<loc::MemRegionVal>(&derived); - if (!derivedRegVal) - return derived; - - const MemRegion *baseReg = - MRMgr.getCXXBaseObjectRegion(baseDecl, derivedRegVal->getRegion()); - - return loc::MemRegionVal(baseReg); -} - -SVal RegionStoreManager::evalDynamicCast(SVal base, QualType derivedType, - bool &Failed) { - Failed = false; - - loc::MemRegionVal *baseRegVal = dyn_cast<loc::MemRegionVal>(&base); - if (!baseRegVal) - return UnknownVal(); - const MemRegion *BaseRegion = baseRegVal->stripCasts(/*StripBases=*/false); - - // Assume the derived class is a pointer or a reference to a CXX record. - derivedType = derivedType->getPointeeType(); - assert(!derivedType.isNull()); - const CXXRecordDecl *DerivedDecl = derivedType->getAsCXXRecordDecl(); - if (!DerivedDecl && !derivedType->isVoidType()) - return UnknownVal(); - - // Drill down the CXXBaseObject chains, which represent upcasts (casts from - // derived to base). - const MemRegion *SR = BaseRegion; - while (const TypedRegion *TSR = dyn_cast_or_null<TypedRegion>(SR)) { - QualType BaseType = TSR->getLocationType()->getPointeeType(); - assert(!BaseType.isNull()); - const CXXRecordDecl *SRDecl = BaseType->getAsCXXRecordDecl(); - if (!SRDecl) - return UnknownVal(); - - // If found the derived class, the cast succeeds. - if (SRDecl == DerivedDecl) - return loc::MemRegionVal(TSR); - - if (!derivedType->isVoidType()) { - // Static upcasts are marked as DerivedToBase casts by Sema, so this will - // only happen when multiple or virtual inheritance is involved. - CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, - /*DetectVirtual=*/false); - if (SRDecl->isDerivedFrom(DerivedDecl, Paths)) { - SVal Result = loc::MemRegionVal(TSR); - const CXXBasePath &Path = *Paths.begin(); - for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end(); - I != E; ++I) { - Result = evalDerivedToBase(Result, I->Base->getType()); - } - return Result; - } - } - - if (const CXXBaseObjectRegion *R = dyn_cast<CXXBaseObjectRegion>(TSR)) - // Drill down the chain to get the derived classes. - SR = R->getSuperRegion(); - else { - // We reached the bottom of the hierarchy. - - // If this is a cast to void*, return the region. - if (derivedType->isVoidType()) - return loc::MemRegionVal(TSR); - - // We did not find the derived class. We we must be casting the base to - // derived, so the cast should fail. - Failed = true; - return UnknownVal(); - } - } - - return UnknownVal(); -} - //===----------------------------------------------------------------------===// // Loading values from regions. //===----------------------------------------------------------------------===// @@ -1047,7 +994,7 @@ SVal RegionStoreManager::getBinding(Store store, Loc L, QualType T) { T = TR->getLocationType(); else { const SymbolicRegion *SR = cast<SymbolicRegion>(MR); - T = SR->getSymbol()->getType(Ctx); + T = SR->getSymbol()->getType(); } } MR = GetElementZeroRegion(MR, T); @@ -1540,14 +1487,14 @@ bool RegionStoreManager::includedInBindings(Store store, // Binding values to regions. //===----------------------------------------------------------------------===// -StoreRef RegionStoreManager::Remove(Store store, Loc L) { +StoreRef RegionStoreManager::killBinding(Store ST, Loc L) { if (isa<loc::MemRegionVal>(L)) if (const MemRegion* R = cast<loc::MemRegionVal>(L).getRegion()) - return StoreRef(removeBinding(GetRegionBindings(store), + return StoreRef(removeBinding(GetRegionBindings(ST), R).getRootWithoutRetain(), *this); - return StoreRef(store, *this); + return StoreRef(ST, *this); } StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) { @@ -1560,6 +1507,8 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) { // Check if the region is a struct region. if (const TypedValueRegion* TR = dyn_cast<TypedValueRegion>(R)) { QualType Ty = TR->getValueType(); + if (Ty->isArrayType()) + return BindArray(store, TR, V); if (Ty->isStructureOrClassType()) return BindStruct(store, TR, V); if (Ty->isVectorType()) @@ -1569,13 +1518,9 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) { if (const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R)) { // Binding directly to a symbolic region should be treated as binding // to element 0. - QualType T = SR->getSymbol()->getType(Ctx); - - // FIXME: Is this the right way to handle symbols that are references? - if (const PointerType *PT = T->getAs<PointerType>()) - T = PT->getPointeeType(); - else - T = T->getAs<ReferenceType>()->getPointeeType(); + QualType T = SR->getSymbol()->getType(); + if (T->isAnyPointerType() || T->isReferenceType()) + T = T->getPointeeType(); R = GetElementZeroRegion(SR, T); } @@ -1589,26 +1534,12 @@ StoreRef RegionStoreManager::Bind(Store store, Loc L, SVal V) { return StoreRef(addBinding(B, Key, V).getRootWithoutRetain(), *this); } -StoreRef RegionStoreManager::BindDecl(Store store, const VarRegion *VR, - SVal InitVal) { - - QualType T = VR->getDecl()->getType(); - - if (T->isArrayType()) - return BindArray(store, VR, InitVal); - if (T->isStructureOrClassType()) - return BindStruct(store, VR, InitVal); - - return Bind(store, svalBuilder.makeLoc(VR), InitVal); -} - // FIXME: this method should be merged into Bind(). -StoreRef RegionStoreManager::BindCompoundLiteral(Store store, +StoreRef RegionStoreManager::bindCompoundLiteral(Store ST, const CompoundLiteralExpr *CL, const LocationContext *LC, SVal V) { - return Bind(store, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), - V); + return Bind(ST, loc::MemRegionVal(MRMgr.getCompoundLiteralRegion(CL, LC)), V); } StoreRef RegionStoreManager::setImplicitDefaultValue(Store store, @@ -1864,7 +1795,7 @@ RegionBindings RegionStoreManager::removeBinding(RegionBindings B, RegionBindings RegionStoreManager::removeBinding(RegionBindings B, const MemRegion *R, - BindingKey::Kind k){ + BindingKey::Kind k){ return removeBinding(B, BindingKey::Make(R, k)); } @@ -1897,7 +1828,6 @@ public: void VisitAddedToCluster(const MemRegion *baseR, const ClusterBindings &C); void VisitCluster(const MemRegion *baseR, const ClusterBindings &C); - void VisitBindingKey(BindingKey K); bool UpdatePostponed(); void VisitBinding(SVal V); }; @@ -1932,17 +1862,21 @@ void removeDeadBindingsWorker::VisitAddedToCluster(const MemRegion *baseR, const StackArgumentsSpaceRegion *StackReg = cast<StackArgumentsSpaceRegion>(TR->getSuperRegion()); const StackFrameContext *RegCtx = StackReg->getStackFrame(); - if (RegCtx == CurrentLCtx || RegCtx->isParentOf(CurrentLCtx)) + if (CurrentLCtx && + (RegCtx == CurrentLCtx || RegCtx->isParentOf(CurrentLCtx))) AddToWorkList(TR, &C); } } void removeDeadBindingsWorker::VisitCluster(const MemRegion *baseR, const ClusterBindings &C) { - for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I) { - VisitBindingKey(I.getKey()); + // Mark the symbol for any SymbolicRegion with live bindings as live itself. + // This means we should continue to track that symbol. + if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(baseR)) + SymReaper.markLive(SymR->getSymbol()); + + for (ClusterBindings::iterator I = C.begin(), E = C.end(); I != E; ++I) VisitBinding(I.getData()); - } } void removeDeadBindingsWorker::VisitBinding(SVal V) { @@ -1979,8 +1913,8 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) { if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) { BlockDataRegion::referenced_vars_iterator I = BR->referenced_vars_begin(), E = BR->referenced_vars_end(); - for ( ; I != E; ++I) - AddToWorkList(I.getCapturedRegion()); + for ( ; I != E; ++I) + AddToWorkList(I.getCapturedRegion()); } } @@ -1991,20 +1925,6 @@ void removeDeadBindingsWorker::VisitBinding(SVal V) { SymReaper.markLive(*SI); } -void removeDeadBindingsWorker::VisitBindingKey(BindingKey K) { - const MemRegion *R = K.getRegion(); - - // Mark this region "live" by adding it to the worklist. This will cause - // use to visit all regions in the cluster (if we haven't visited them - // already). - if (AddToWorkList(R)) { - // Mark the symbol for any live SymbolicRegion as "live". This means we - // should continue to track that symbol. - if (const SymbolicRegion *SymR = dyn_cast<SymbolicRegion>(R)) - SymReaper.markLive(SymR->getSymbol()); - } -} - bool removeDeadBindingsWorker::UpdatePostponed() { // See if any postponed SymbolicRegions are actually live now, after // having done a scan. @@ -2012,7 +1932,7 @@ bool removeDeadBindingsWorker::UpdatePostponed() { for (SmallVectorImpl<const SymbolicRegion*>::iterator I = Postponed.begin(), E = Postponed.end() ; I != E ; ++I) { - if (const SymbolicRegion *SR = cast_or_null<SymbolicRegion>(*I)) { + if (const SymbolicRegion *SR = *I) { if (SymReaper.isLive(SR->getSymbol())) { changed |= AddToWorkList(SR); *I = NULL; diff --git a/lib/StaticAnalyzer/Core/SValBuilder.cpp b/lib/StaticAnalyzer/Core/SValBuilder.cpp index d1936cd3603e..b87169a4b335 100644 --- a/lib/StaticAnalyzer/Core/SValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SValBuilder.cpp @@ -106,25 +106,23 @@ SValBuilder::getRegionValueSymbolVal(const TypedValueRegion* region) { return nonloc::SymbolVal(sym); } -DefinedOrUnknownSVal -SValBuilder::getConjuredSymbolVal(const void *symbolTag, - const Expr *expr, - const LocationContext *LCtx, - unsigned count) { +DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, + const Expr *expr, + const LocationContext *LCtx, + unsigned count) { QualType T = expr->getType(); - return getConjuredSymbolVal(symbolTag, expr, LCtx, T, count); + return conjureSymbolVal(symbolTag, expr, LCtx, T, count); } -DefinedOrUnknownSVal -SValBuilder::getConjuredSymbolVal(const void *symbolTag, - const Expr *expr, - const LocationContext *LCtx, - QualType type, - unsigned count) { +DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const void *symbolTag, + const Expr *expr, + const LocationContext *LCtx, + QualType type, + unsigned count) { if (!SymbolManager::canSymbolicate(type)) return UnknownVal(); - SymbolRef sym = SymMgr.getConjuredSymbol(expr, LCtx, type, count, symbolTag); + SymbolRef sym = SymMgr.conjureSymbol(expr, LCtx, type, count, symbolTag); if (Loc::isLocType(type)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); @@ -133,15 +131,14 @@ SValBuilder::getConjuredSymbolVal(const void *symbolTag, } -DefinedOrUnknownSVal -SValBuilder::getConjuredSymbolVal(const Stmt *stmt, - const LocationContext *LCtx, - QualType type, - unsigned visitCount) { +DefinedOrUnknownSVal SValBuilder::conjureSymbolVal(const Stmt *stmt, + const LocationContext *LCtx, + QualType type, + unsigned visitCount) { if (!SymbolManager::canSymbolicate(type)) return UnknownVal(); - SymbolRef sym = SymMgr.getConjuredSymbol(stmt, LCtx, type, visitCount); + SymbolRef sym = SymMgr.conjureSymbol(stmt, LCtx, type, visitCount); if (Loc::isLocType(type)) return loc::MemRegionVal(MemMgr.getSymbolicRegion(sym)); @@ -157,7 +154,7 @@ SValBuilder::getConjuredHeapSymbolVal(const Expr *E, assert(Loc::isLocType(T)); assert(SymbolManager::canSymbolicate(T)); - SymbolRef sym = SymMgr.getConjuredSymbol(E, LCtx, T, VisitCount); + SymbolRef sym = SymMgr.conjureSymbol(E, LCtx, T, VisitCount); return loc::MemRegionVal(MemMgr.getSymbolicHeapRegion(sym)); } diff --git a/lib/StaticAnalyzer/Core/SVals.cpp b/lib/StaticAnalyzer/Core/SVals.cpp index 8437f50f911f..e34ab6a2be91 100644 --- a/lib/StaticAnalyzer/Core/SVals.cpp +++ b/lib/StaticAnalyzer/Core/SVals.cpp @@ -51,7 +51,8 @@ const FunctionDecl *SVal::getAsFunctionDecl() const { if (const loc::MemRegionVal* X = dyn_cast<loc::MemRegionVal>(this)) { const MemRegion* R = X->getRegion(); if (const FunctionTextRegion *CTR = R->getAs<FunctionTextRegion>()) - return CTR->getDecl(); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CTR->getDecl())) + return FD; } return 0; diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp index 5568f1ca555d..4236ee470af4 100644 --- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp +++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.cpp @@ -67,7 +67,9 @@ ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state, ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state, Loc cond, bool assumption) { state = assumeAux(state, cond, assumption); - return SU.processAssume(state, cond, assumption); + if (NotifyAssumeClients && SU) + return SU->processAssume(state, cond, assumption); + return state; } ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state, @@ -113,7 +115,9 @@ ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef state, NonLoc cond, bool assumption) { state = assumeAux(state, cond, assumption); - return SU.processAssume(state, cond, assumption); + if (NotifyAssumeClients && SU) + return SU->processAssume(state, cond, assumption); + return state; } static BinaryOperator::Opcode NegateComparison(BinaryOperator::Opcode op) { @@ -136,7 +140,7 @@ ProgramStateRef SimpleConstraintManager::assumeAuxForSymbol(ProgramStateRef State, SymbolRef Sym, bool Assumption) { BasicValueFactory &BVF = getBasicVals(); - QualType T = Sym->getType(BVF.getContext()); + QualType T = Sym->getType(); // None of the constraint solvers currently support non-integer types. if (!T->isIntegerType()) @@ -186,7 +190,7 @@ ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef state, BinaryOperator::Opcode op = SE->getOpcode(); // Implicitly compare non-comparison expressions to 0. if (!BinaryOperator::isComparisonOp(op)) { - QualType T = SE->getType(BasicVals.getContext()); + QualType T = SE->getType(); const llvm::APSInt &zero = BasicVals.getValue(0, T); op = (Assumption ? BO_NE : BO_EQ); return assumeSymRel(state, SE, op, zero); @@ -235,11 +239,9 @@ ProgramStateRef SimpleConstraintManager::assumeSymRel(ProgramStateRef state, assert(BinaryOperator::isComparisonOp(op) && "Non-comparison ops should be rewritten as comparisons to zero."); - BasicValueFactory &BVF = getBasicVals(); - ASTContext &Ctx = BVF.getContext(); - // Get the type used for calculating wraparound. - APSIntType WraparoundType = BVF.getAPSIntType(LHS->getType(Ctx)); + BasicValueFactory &BVF = getBasicVals(); + APSIntType WraparoundType = BVF.getAPSIntType(LHS->getType()); // We only handle simple comparisons of the form "$sym == constant" // or "($sym+constant1) == constant2". diff --git a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h index 088d70c2717f..01f0b4e4461f 100644 --- a/lib/StaticAnalyzer/Core/SimpleConstraintManager.h +++ b/lib/StaticAnalyzer/Core/SimpleConstraintManager.h @@ -22,10 +22,10 @@ namespace clang { namespace ento { class SimpleConstraintManager : public ConstraintManager { - SubEngine &SU; + SubEngine *SU; BasicValueFactory &BVF; public: - SimpleConstraintManager(SubEngine &subengine, BasicValueFactory &BV) + SimpleConstraintManager(SubEngine *subengine, BasicValueFactory &BV) : SU(subengine), BVF(BV) {} virtual ~SimpleConstraintManager(); diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index ad58a07c784e..fbc6ba055105 100644 --- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -81,7 +81,7 @@ SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { } if (const SymExpr *se = val.getAsSymbolicExpression()) { - QualType T = Context.getCanonicalType(se->getType(Context)); + QualType T = Context.getCanonicalType(se->getType()); // If types are the same or both are integers, ignore the cast. // FIXME: Remove this hack when we support symbolic truncation/extension. // HACK: If both castTy and T are integers, ignore the cast. This is @@ -276,7 +276,7 @@ SVal SimpleSValBuilder::MakeSymIntVal(const SymExpr *LHS, // with the given constant. // FIXME: This is an approximation of Sema::UsualArithmeticConversions. ASTContext &Ctx = getContext(); - QualType SymbolType = LHS->getType(Ctx); + QualType SymbolType = LHS->getType(); uint64_t ValWidth = RHS.getBitWidth(); uint64_t TypeWidth = Ctx.getTypeSize(SymbolType); @@ -318,7 +318,9 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, return makeTruthVal(false, resultTy); case BO_Xor: case BO_Sub: - return makeIntVal(0, resultTy); + if (resultTy->isIntegralOrEnumerationType()) + return makeIntVal(0, resultTy); + return evalCastFromNonLoc(makeIntVal(0, /*Unsigned=*/false), resultTy); case BO_Or: case BO_And: return evalCastFromNonLoc(lhs, resultTy); @@ -459,7 +461,7 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, case BO_NE: // Negate the comparison and make a value. opc = NegateComparison(opc); - assert(symIntExpr->getType(Context) == resultTy); + assert(symIntExpr->getType() == resultTy); return makeNonLoc(symIntExpr->getLHS(), opc, symIntExpr->getRHS(), resultTy); } @@ -505,7 +507,8 @@ SVal SimpleSValBuilder::evalBinOpNN(ProgramStateRef state, } else if (isa<SymbolData>(Sym)) { // Does the symbol simplify to a constant? If so, "fold" the constant // by setting 'lhs' to a ConcreteInt and try again. - if (const llvm::APSInt *Constant = state->getSymVal(Sym)) { + if (const llvm::APSInt *Constant = state->getConstraintManager() + .getSymVal(state, Sym)) { lhs = nonloc::ConcreteInt(*Constant); continue; } @@ -916,14 +919,8 @@ SVal SimpleSValBuilder::evalBinOpLN(ProgramStateRef state, else if (isa<SubRegion>(region)) { superR = region; index = rhs; - if (const PointerType *PT = resultTy->getAs<PointerType>()) { - elementType = PT->getPointeeType(); - } - else { - const ObjCObjectPointerType *OT = - resultTy->getAs<ObjCObjectPointerType>(); - elementType = OT->getPointeeType(); - } + if (resultTy->isAnyPointerType()) + elementType = resultTy->getPointeeType(); } if (NonLoc *indexV = dyn_cast<NonLoc>(&index)) { @@ -946,7 +943,7 @@ const llvm::APSInt *SimpleSValBuilder::getKnownValue(ProgramStateRef state, return &X->getValue(); if (SymbolRef Sym = V.getAsSymbol()) - return state->getSymVal(Sym); + return state->getConstraintManager().getSymVal(state, Sym); // FIXME: Add support for SymExprs. return NULL; diff --git a/lib/StaticAnalyzer/Core/Store.cpp b/lib/StaticAnalyzer/Core/Store.cpp index 3af60a170727..939ae54dad74 100644 --- a/lib/StaticAnalyzer/Core/Store.cpp +++ b/lib/StaticAnalyzer/Core/Store.cpp @@ -15,6 +15,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" using namespace clang; @@ -233,6 +234,91 @@ SVal StoreManager::evalDerivedToBase(SVal Derived, const CastExpr *Cast) { return Result; } +SVal StoreManager::evalDerivedToBase(SVal Derived, const CXXBasePath &Path) { + // Walk through the path to create nested CXXBaseRegions. + SVal Result = Derived; + for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end(); + I != E; ++I) { + Result = evalDerivedToBase(Result, I->Base->getType()); + } + return Result; +} + +SVal StoreManager::evalDerivedToBase(SVal Derived, QualType BaseType) { + loc::MemRegionVal *DerivedRegVal = dyn_cast<loc::MemRegionVal>(&Derived); + if (!DerivedRegVal) + return Derived; + + const CXXRecordDecl *BaseDecl = BaseType->getPointeeCXXRecordDecl(); + if (!BaseDecl) + BaseDecl = BaseType->getAsCXXRecordDecl(); + assert(BaseDecl && "not a C++ object?"); + + const MemRegion *BaseReg = + MRMgr.getCXXBaseObjectRegion(BaseDecl, DerivedRegVal->getRegion()); + + return loc::MemRegionVal(BaseReg); +} + +SVal StoreManager::evalDynamicCast(SVal Base, QualType DerivedType, + bool &Failed) { + Failed = false; + + loc::MemRegionVal *BaseRegVal = dyn_cast<loc::MemRegionVal>(&Base); + if (!BaseRegVal) + return UnknownVal(); + const MemRegion *BaseRegion = BaseRegVal->stripCasts(/*StripBases=*/false); + + // Assume the derived class is a pointer or a reference to a CXX record. + DerivedType = DerivedType->getPointeeType(); + assert(!DerivedType.isNull()); + const CXXRecordDecl *DerivedDecl = DerivedType->getAsCXXRecordDecl(); + if (!DerivedDecl && !DerivedType->isVoidType()) + return UnknownVal(); + + // Drill down the CXXBaseObject chains, which represent upcasts (casts from + // derived to base). + const MemRegion *SR = BaseRegion; + while (const TypedRegion *TSR = dyn_cast_or_null<TypedRegion>(SR)) { + QualType BaseType = TSR->getLocationType()->getPointeeType(); + assert(!BaseType.isNull()); + const CXXRecordDecl *SRDecl = BaseType->getAsCXXRecordDecl(); + if (!SRDecl) + return UnknownVal(); + + // If found the derived class, the cast succeeds. + if (SRDecl == DerivedDecl) + return loc::MemRegionVal(TSR); + + if (!DerivedType->isVoidType()) { + // Static upcasts are marked as DerivedToBase casts by Sema, so this will + // only happen when multiple or virtual inheritance is involved. + CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (SRDecl->isDerivedFrom(DerivedDecl, Paths)) + return evalDerivedToBase(loc::MemRegionVal(TSR), Paths.front()); + } + + if (const CXXBaseObjectRegion *R = dyn_cast<CXXBaseObjectRegion>(TSR)) + // Drill down the chain to get the derived classes. + SR = R->getSuperRegion(); + else { + // We reached the bottom of the hierarchy. + + // If this is a cast to void*, return the region. + if (DerivedType->isVoidType()) + return loc::MemRegionVal(TSR); + + // We did not find the derived class. We we must be casting the base to + // derived, so the cast should fail. + Failed = true; + return UnknownVal(); + } + } + + return UnknownVal(); +} + /// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted diff --git a/lib/StaticAnalyzer/Core/SymbolManager.cpp b/lib/StaticAnalyzer/Core/SymbolManager.cpp index 0bc192d64571..0c5098b1e7d0 100644 --- a/lib/StaticAnalyzer/Core/SymbolManager.cpp +++ b/lib/StaticAnalyzer/Core/SymbolManager.cpp @@ -117,21 +117,17 @@ bool SymExpr::symbol_iterator::operator!=(const symbol_iterator &X) const { SymExpr::symbol_iterator::symbol_iterator(const SymExpr *SE) { itr.push_back(SE); - while (!isa<SymbolData>(itr.back())) expand(); } SymExpr::symbol_iterator &SymExpr::symbol_iterator::operator++() { assert(!itr.empty() && "attempting to iterate on an 'end' iterator"); - assert(isa<SymbolData>(itr.back())); - itr.pop_back(); - if (!itr.empty()) - while (!isa<SymbolData>(itr.back())) expand(); + expand(); return *this; } SymbolRef SymExpr::symbol_iterator::operator*() { assert(!itr.empty() && "attempting to dereference an 'end' iterator"); - return cast<SymbolData>(itr.back()); + return itr.back(); } void SymExpr::symbol_iterator::expand() { @@ -187,11 +183,11 @@ SymbolManager::getRegionValueSymbol(const TypedValueRegion* R) { return cast<SymbolRegionValue>(SD); } -const SymbolConjured* -SymbolManager::getConjuredSymbol(const Stmt *E, const LocationContext *LCtx, - QualType T, unsigned Count, - const void *SymbolTag) { - +const SymbolConjured* SymbolManager::conjureSymbol(const Stmt *E, + const LocationContext *LCtx, + QualType T, + unsigned Count, + const void *SymbolTag) { llvm::FoldingSetNodeID profile; SymbolConjured::Profile(profile, E, T, Count, LCtx, SymbolTag); void *InsertPos; @@ -328,23 +324,24 @@ const SymSymExpr *SymbolManager::getSymSymExpr(const SymExpr *lhs, return cast<SymSymExpr>(data); } -QualType SymbolConjured::getType(ASTContext&) const { +QualType SymbolConjured::getType() const { return T; } -QualType SymbolDerived::getType(ASTContext &Ctx) const { +QualType SymbolDerived::getType() const { return R->getValueType(); } -QualType SymbolExtent::getType(ASTContext &Ctx) const { +QualType SymbolExtent::getType() const { + ASTContext &Ctx = R->getMemRegionManager()->getContext(); return Ctx.getSizeType(); } -QualType SymbolMetadata::getType(ASTContext&) const { +QualType SymbolMetadata::getType() const { return T; } -QualType SymbolRegionValue::getType(ASTContext &C) const { +QualType SymbolRegionValue::getType() const { return R->getValueType(); } @@ -466,41 +463,56 @@ bool SymbolReaper::isLive(SymbolRef sym) { markDependentsLive(sym); return true; } - - if (const SymbolDerived *derived = dyn_cast<SymbolDerived>(sym)) { - if (isLive(derived->getParentSymbol())) { - markLive(sym); - return true; - } - return false; - } - - if (const SymbolExtent *extent = dyn_cast<SymbolExtent>(sym)) { - if (isLiveRegion(extent->getRegion())) { - markLive(sym); - return true; - } - return false; + + bool KnownLive; + + switch (sym->getKind()) { + case SymExpr::RegionValueKind: + // FIXME: We should be able to use isLiveRegion here (this behavior + // predates isLiveRegion), but doing so causes test failures. Investigate. + KnownLive = true; + break; + case SymExpr::ConjuredKind: + KnownLive = false; + break; + case SymExpr::DerivedKind: + KnownLive = isLive(cast<SymbolDerived>(sym)->getParentSymbol()); + break; + case SymExpr::ExtentKind: + KnownLive = isLiveRegion(cast<SymbolExtent>(sym)->getRegion()); + break; + case SymExpr::MetadataKind: + KnownLive = MetadataInUse.count(sym) && + isLiveRegion(cast<SymbolMetadata>(sym)->getRegion()); + if (KnownLive) + MetadataInUse.erase(sym); + break; + case SymExpr::SymIntKind: + KnownLive = isLive(cast<SymIntExpr>(sym)->getLHS()); + break; + case SymExpr::IntSymKind: + KnownLive = isLive(cast<IntSymExpr>(sym)->getRHS()); + break; + case SymExpr::SymSymKind: + KnownLive = isLive(cast<SymSymExpr>(sym)->getLHS()) && + isLive(cast<SymSymExpr>(sym)->getRHS()); + break; + case SymExpr::CastSymbolKind: + KnownLive = isLive(cast<SymbolCast>(sym)->getOperand()); + break; } - if (const SymbolMetadata *metadata = dyn_cast<SymbolMetadata>(sym)) { - if (MetadataInUse.count(sym)) { - if (isLiveRegion(metadata->getRegion())) { - markLive(sym); - MetadataInUse.erase(sym); - return true; - } - } - return false; - } + if (KnownLive) + markLive(sym); - // Interogate the symbol. It may derive from an input value to - // the analyzed function/method. - return isa<SymbolRegionValue>(sym); + return KnownLive; } bool SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const { + if (LCtx == 0) + return false; + if (LCtx != ELCtx) { // If the reaper's location context is a parent of the expression's // location context, then the expression value is now "out of scope". @@ -508,6 +520,7 @@ SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const { return false; return true; } + // If no statement is provided, everything is this and parent contexts is live. if (!Loc) return true; @@ -517,10 +530,16 @@ SymbolReaper::isLive(const Stmt *ExprVal, const LocationContext *ELCtx) const { bool SymbolReaper::isLive(const VarRegion *VR, bool includeStoreBindings) const{ const StackFrameContext *VarContext = VR->getStackFrame(); + + if (!VarContext) + return true; + + if (!LCtx) + return false; const StackFrameContext *CurrentContext = LCtx->getCurrentStackFrame(); if (VarContext == CurrentContext) { - // If no statemetnt is provided, everything is live. + // If no statement is provided, everything is live. if (!Loc) return true; diff --git a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp index 66bf4bb222d1..e09f4e365344 100644 --- a/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp +++ b/lib/StaticAnalyzer/Core/TextPathDiagnostics.cpp @@ -41,7 +41,6 @@ public: PathGenerationScheme getGenerationScheme() const { return Minimal; } bool supportsLogicalOpControlFlow() const { return true; } bool supportsAllBlockEdges() const { return true; } - virtual bool useVerboseDescription() const { return true; } virtual bool supportsCrossFileDiagnostics() const { return true; } }; diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 34b5266e4b76..7dbac3cf93a0 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -34,7 +34,7 @@ #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" -#include "clang/Frontend/AnalyzerOptions.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/Lex/Preprocessor.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" @@ -78,7 +78,6 @@ public: ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) : Diag(Diag) {} virtual ~ClangDiagPathDiagConsumer() {} virtual StringRef getName() const { return "ClangDiags"; } - virtual bool useVerboseDescription() const { return false; } virtual PathGenerationScheme getGenerationScheme() const { return None; } void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, @@ -86,7 +85,7 @@ public: for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(), E = Diags.end(); I != E; ++I) { const PathDiagnostic *PD = *I; - StringRef desc = PD->getDescription(); + StringRef desc = PD->getShortDescription(); SmallString<512> TmpStr; llvm::raw_svector_ostream Out(TmpStr); for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) { @@ -121,11 +120,12 @@ namespace { class AnalysisConsumer : public ASTConsumer, public RecursiveASTVisitor<AnalysisConsumer> { - enum AnalysisMode { - ANALYSIS_SYNTAX, - ANALYSIS_PATH, - ANALYSIS_ALL + enum { + AM_None = 0, + AM_Syntax = 0x1, + AM_Path = 0x2 }; + typedef unsigned AnalysisMode; /// Mode of the analyzes while recursively visiting Decls. AnalysisMode RecVisitorMode; @@ -136,7 +136,7 @@ public: ASTContext *Ctx; const Preprocessor &PP; const std::string OutDir; - AnalyzerOptions Opts; + AnalyzerOptionsRef Opts; ArrayRef<std::string> Plugins; /// \brief Stores the declarations from the local translation unit. @@ -164,19 +164,19 @@ public: AnalysisConsumer(const Preprocessor& pp, const std::string& outdir, - const AnalyzerOptions& opts, + AnalyzerOptionsRef opts, ArrayRef<std::string> plugins) - : RecVisitorMode(ANALYSIS_ALL), RecVisitorBR(0), + : RecVisitorMode(0), RecVisitorBR(0), Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) { DigestAnalyzerOptions(); - if (Opts.PrintStats) { + if (Opts->PrintStats) { llvm::EnableStatistics(); TUTotalTimer = new llvm::Timer("Analyzer Total Time"); } } ~AnalysisConsumer() { - if (Opts.PrintStats) + if (Opts->PrintStats) delete TUTotalTimer; } @@ -185,49 +185,52 @@ public: PathConsumers.push_back(new ClangDiagPathDiagConsumer(PP.getDiagnostics())); if (!OutDir.empty()) { - switch (Opts.AnalysisDiagOpt) { + switch (Opts->AnalysisDiagOpt) { default: #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \ case PD_##NAME: CREATEFN(PathConsumers, OutDir, PP); break; -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" } - } else if (Opts.AnalysisDiagOpt == PD_TEXT) { + } else if (Opts->AnalysisDiagOpt == PD_TEXT) { // Create the text client even without a specified output file since // it just uses diagnostic notes. createTextPathDiagnosticConsumer(PathConsumers, "", PP); } // Create the analyzer component creators. - switch (Opts.AnalysisStoreOpt) { + switch (Opts->AnalysisStoreOpt) { default: llvm_unreachable("Unknown store manager."); #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ case NAME##Model: CreateStoreMgr = CREATEFN; break; -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" } - switch (Opts.AnalysisConstraintsOpt) { + switch (Opts->AnalysisConstraintsOpt) { default: llvm_unreachable("Unknown store manager."); #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ case NAME##Model: CreateConstraintMgr = CREATEFN; break; -#include "clang/Frontend/Analyses.def" +#include "clang/StaticAnalyzer/Core/Analyses.def" } } void DisplayFunction(const Decl *D, AnalysisMode Mode) { - if (!Opts.AnalyzerDisplayProgress) + if (!Opts->AnalyzerDisplayProgress) return; SourceManager &SM = Mgr->getASTContext().getSourceManager(); PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); if (Loc.isValid()) { llvm::errs() << "ANALYZE"; - switch (Mode) { - case ANALYSIS_SYNTAX: llvm::errs() << "(Syntax)"; break; - case ANALYSIS_PATH: llvm::errs() << "(Path Sensitive)"; break; - case ANALYSIS_ALL: break; - }; + + if (Mode == AM_Syntax) + llvm::errs() << " (Syntax)"; + else if (Mode == AM_Path) + llvm::errs() << " (Path)"; + else + assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!"); + llvm::errs() << ": " << Loc.getFilename(); if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { const NamedDecl *ND = cast<NamedDecl>(D); @@ -246,7 +249,7 @@ public: virtual void Initialize(ASTContext &Context) { Ctx = &Context; - checkerMgr.reset(createCheckerManager(Opts, PP.getLangOpts(), Plugins, + checkerMgr.reset(createCheckerManager(*Opts, PP.getLangOpts(), Plugins, PP.getDiagnostics())); Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), @@ -255,17 +258,7 @@ public: CreateStoreMgr, CreateConstraintMgr, checkerMgr.get(), - Opts.MaxNodes, Opts.MaxLoop, - Opts.VisualizeEGDot, Opts.VisualizeEGUbi, - Opts.AnalysisPurgeOpt, Opts.EagerlyAssume, - Opts.TrimGraph, - Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors, - Opts.EagerlyTrimEGraph, - Opts.IPAMode, - Opts.InlineMaxStackDepth, - Opts.InlineMaxFunctionSize, - Opts.InliningMode, - Opts.NoRetryExhausted)); + *Opts)); } /// \brief Store the top level decls in the set to be processed later on. @@ -277,7 +270,7 @@ public: /// \brief Build the call graph for all the top level decls of this TU and /// use it to define the order in which the functions should be visited. - void HandleDeclsGallGraph(const unsigned LocalTUDeclsSize); + void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize); /// \brief Run analyzes(syntax or path sensitive) on the given function. /// \param Mode - determines if we are requesting syntax only or path @@ -297,7 +290,9 @@ public: /// Handle callbacks for arbitrary Decls. bool VisitDecl(Decl *D) { - checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR); + AnalysisMode Mode = getModeForDecl(D, RecVisitorMode); + if (Mode & AM_Syntax) + checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR); return true; } @@ -316,7 +311,6 @@ public: } bool VisitObjCMethodDecl(ObjCMethodDecl *MD) { - checkerMgr->runCheckersOnASTDecl(MD, *Mgr, *RecVisitorBR); if (MD->isThisDeclarationADefinition()) HandleCode(MD, RecVisitorMode); return true; @@ -326,7 +320,7 @@ private: void storeTopLevelDecls(DeclGroupRef DG); /// \brief Check if we should skip (not analyze) the given function. - bool skipFunction(Decl *D); + AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode); }; } // end anonymous namespace @@ -358,7 +352,23 @@ void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) { } } -void AnalysisConsumer::HandleDeclsGallGraph(const unsigned LocalTUDeclsSize) { +static bool shouldSkipFunction(CallGraphNode *N, + SmallPtrSet<CallGraphNode*,24> Visited) { + // We want to re-analyse the functions as top level in several cases: + // - The 'init' methods should be reanalyzed because + // ObjCNonNilReturnValueChecker assumes that '[super init]' never returns + // 'nil' and unless we analyze the 'init' functions as top level, we will not + // catch errors within defensive code. + // - We want to reanalyze all ObjC methods as top level to report Retain + // Count naming convention errors more aggressively. + if (isa<ObjCMethodDecl>(N->getDecl())) + return false; + + // Otherwise, if we visited the function before, do not reanalyze it. + return Visited.count(N); +} + +void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) { // Otherwise, use the Callgraph to derive the order. // Build the Call Graph. CallGraph CG; @@ -407,21 +417,21 @@ void AnalysisConsumer::HandleDeclsGallGraph(const unsigned LocalTUDeclsSize) { // Push the children into the queue. for (CallGraphNode::const_iterator CI = N->begin(), CE = N->end(); CI != CE; ++CI) { - if (!Visited.count(*CI)) + if (!shouldSkipFunction(*CI, Visited)) BFSQueue.push_back(*CI); } // Skip the functions which have been processed already or previously // inlined. - if (Visited.count(N)) + if (shouldSkipFunction(N, Visited)) continue; // Analyze the function. SetOfConstDecls VisitedCallees; Decl *D = N->getDecl(); assert(D); - HandleCode(D, ANALYSIS_PATH, - (Mgr->InliningMode == All ? 0 : &VisitedCallees)); + HandleCode(D, AM_Path, + (Mgr->options.InliningMode == All ? 0 : &VisitedCallees)); // Add the visited callees to the global visited set. for (SetOfConstDecls::iterator I = VisitedCallees.begin(), @@ -451,7 +461,9 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { // Run the AST-only checks using the order in which functions are defined. // If inlining is not turned on, use the simplest function order for path // sensitive analyzes as well. - RecVisitorMode = (Mgr->shouldInlineCall() ? ANALYSIS_SYNTAX : ANALYSIS_ALL); + RecVisitorMode = AM_Syntax; + if (!Mgr->shouldInlineCall()) + RecVisitorMode |= AM_Path; RecVisitorBR = &BR; // Process all the top level declarations. @@ -466,7 +478,7 @@ void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { } if (Mgr->shouldInlineCall()) - HandleDeclsGallGraph(LocalTUDeclsSize); + HandleDeclsCallGraph(LocalTUDeclsSize); // After all decls handled, run checkers on the entire TranslationUnit. checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR); @@ -513,24 +525,32 @@ static std::string getFunctionName(const Decl *D) { return ""; } -bool AnalysisConsumer::skipFunction(Decl *D) { - if (!Opts.AnalyzeSpecificFunction.empty() && - getFunctionName(D) != Opts.AnalyzeSpecificFunction) - return true; - - // Don't run the actions on declarations in header files unless - // otherwise specified. +AnalysisConsumer::AnalysisMode +AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) { + if (!Opts->AnalyzeSpecificFunction.empty() && + getFunctionName(D) != Opts->AnalyzeSpecificFunction) + return AM_None; + + // Unless -analyze-all is specified, treat decls differently depending on + // where they came from: + // - Main source file: run both path-sensitive and non-path-sensitive checks. + // - Header files: run non-path-sensitive checks only. + // - System headers: don't run any checks. SourceManager &SM = Ctx->getSourceManager(); SourceLocation SL = SM.getExpansionLoc(D->getLocation()); - if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL)) - return true; + if (!Opts->AnalyzeAll && !SM.isFromMainFile(SL)) { + if (SL.isInvalid() || SM.isInSystemHeader(SL)) + return AM_None; + return Mode & ~AM_Path; + } - return false; + return Mode; } void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, SetOfConstDecls *VisitedCallees) { - if (skipFunction(D)) + Mode = getModeForDecl(D, Mode); + if (Mode == AM_None) return; DisplayFunction(D, Mode); @@ -548,16 +568,16 @@ void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, SmallVector<Decl*, 10> WL; WL.push_back(D); - if (D->hasBody() && Opts.AnalyzeNestedBlocks) + if (D->hasBody() && Opts->AnalyzeNestedBlocks) FindBlocks(cast<DeclContext>(D), WL); BugReporter BR(*Mgr); for (SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); WI != WE; ++WI) if ((*WI)->hasBody()) { - if (Mode != ANALYSIS_PATH) + if (Mode & AM_Syntax) checkerMgr->runCheckersOnASTBody(*WI, *Mgr, BR); - if (Mode != ANALYSIS_SYNTAX && checkerMgr->hasPathSensitiveCheckers()) { + if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) { RunPathSensitiveChecks(*WI, VisitedCallees); NumFunctionsAnalyzed++; } @@ -583,22 +603,22 @@ void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled, // Set the graph auditor. OwningPtr<ExplodedNode::Auditor> Auditor; - if (Mgr->shouldVisualizeUbigraph()) { + if (Mgr->options.visualizeExplodedGraphWithUbiGraph) { Auditor.reset(CreateUbiViz()); ExplodedNode::SetAuditor(Auditor.get()); } // Execute the worklist algorithm. Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D), - Mgr->getMaxNodes()); + Mgr->options.MaxNodes); // Release the auditor (if any) so that it doesn't monitor the graph // created BugReporter. ExplodedNode::SetAuditor(0); // Visualize the exploded graph. - if (Mgr->shouldVisualizeGraphviz()) - Eng.ViewGraph(Mgr->shouldTrimGraph()); + if (Mgr->options.visualizeExplodedGraphWithGraphViz) + Eng.ViewGraph(Mgr->options.TrimGraph); // Display warnings. Eng.getBugReporter().FlushReports(); @@ -629,7 +649,7 @@ void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp, const std::string& outDir, - const AnalyzerOptions& opts, + AnalyzerOptionsRef opts, ArrayRef<std::string> plugins) { // Disable the effects of '-Werror' when using the AnalysisConsumer. pp.getDiagnostics().setWarningsAsErrors(false); diff --git a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h index 5a16bffeacf3..b75220b62de3 100644 --- a/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h +++ b/lib/StaticAnalyzer/Frontend/AnalysisConsumer.h @@ -16,11 +16,11 @@ #define LLVM_CLANG_GR_ANALYSISCONSUMER_H #include "clang/Basic/LLVM.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include <string> namespace clang { -class AnalyzerOptions; class ASTConsumer; class Preprocessor; class DiagnosticsEngine; @@ -33,7 +33,7 @@ class CheckerManager; /// options.) ASTConsumer* CreateAnalysisConsumer(const Preprocessor &pp, const std::string &output, - const AnalyzerOptions& opts, + AnalyzerOptionsRef opts, ArrayRef<std::string> plugins); } // end GR namespace diff --git a/lib/StaticAnalyzer/Frontend/CMakeLists.txt b/lib/StaticAnalyzer/Frontend/CMakeLists.txt index 06d148507874..aafb249c587f 100644 --- a/lib/StaticAnalyzer/Frontend/CMakeLists.txt +++ b/lib/StaticAnalyzer/Frontend/CMakeLists.txt @@ -25,6 +25,7 @@ target_link_libraries(clangStaticAnalyzerFrontend clangLex clangAST clangFrontend - clangRewrite + clangRewriteCore + clangRewriteFrontend clangStaticAnalyzerCheckers ) diff --git a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp index 0229aed6bdaa..e8daa65e410a 100644 --- a/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp +++ b/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp @@ -17,7 +17,7 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/CheckerOptInfo.h" #include "clang/StaticAnalyzer/Core/CheckerRegistry.h" -#include "clang/Frontend/AnalyzerOptions.h" +#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Basic/Diagnostic.h" #include "llvm/Support/DynamicLibrary.h" diff --git a/lib/Tooling/CMakeLists.txt b/lib/Tooling/CMakeLists.txt index 49d3101f0e99..d29e564e34fe 100644 --- a/lib/Tooling/CMakeLists.txt +++ b/lib/Tooling/CMakeLists.txt @@ -2,8 +2,10 @@ set(LLVM_LINK_COMPONENTS support) add_clang_library(clangTooling ArgumentsAdjusters.cpp - CommandLineClangTool.cpp + CommonOptionsParser.cpp CompilationDatabase.cpp + FileMatchTrie.cpp + JSONCompilationDatabase.cpp Refactoring.cpp RefactoringCallbacks.cpp Tooling.cpp @@ -23,5 +25,6 @@ target_link_libraries(clangTooling clangFrontend clangAST clangASTMatchers - clangRewrite + clangRewriteCore + clangRewriteFrontend ) diff --git a/lib/Tooling/CommandLineClangTool.cpp b/lib/Tooling/CommonOptionsParser.cpp index 8da2a335a557..15091c7e901e 100644 --- a/lib/Tooling/CommandLineClangTool.cpp +++ b/lib/Tooling/CommonOptionsParser.cpp @@ -1,4 +1,4 @@ -//===--- CommandLineClangTool.cpp - command-line clang tools driver -------===// +//===--- CommonOptionsParser.cpp - common options for clang tools ---------===// // // The LLVM Compiler Infrastructure // @@ -7,28 +7,31 @@ // //===----------------------------------------------------------------------===// // -// This file implements the CommandLineClangTool class used to run clang -// tools as separate command-line applications with a consistent common -// interface for handling compilation database and input files. +// This file implements the CommonOptionsParser class used to parse common +// command-line options for clang tools, so that they can be run as separate +// command-line applications with a consistent common interface for handling +// compilation database and input files. // // It provides a common subset of command-line options, common algorithm // for locating a compilation database and source files, and help messages // for the basic command-line interface. // -// It creates a CompilationDatabase, initializes a ClangTool and runs a -// user-specified FrontendAction over all TUs in which the given files are -// compiled. +// It creates a CompilationDatabase and reads common command-line options. +// +// This class uses the Clang Tooling infrastructure, see +// http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html +// for details on setting it up with LLVM source tree. // //===----------------------------------------------------------------------===// -#include "clang/Frontend/FrontendActions.h" -#include "clang/Tooling/CommandLineClangTool.h" +#include "llvm/Support/CommandLine.h" +#include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" using namespace clang::tooling; using namespace llvm; -static const char *MoreHelpText = +const char *const CommonOptionsParser::HelpMessage = "\n" "-p <build-path> is used to read a compile command database.\n" "\n" @@ -40,26 +43,27 @@ static const char *MoreHelpText = "\thttp://clang.llvm.org/docs/HowToSetupToolingForLLVM.html for an\n" "\texample of setting up Clang Tooling on a source tree.\n" "\n" - "<source0> ... specify the paths of source files. These paths are looked\n" - "\tup in the compile command database. If the path of a file is absolute,\n" - "\tit needs to point into CMake's source tree. If the path is relative,\n" - "\tthe current working directory needs to be in the CMake source tree and\n" - "\tthe file must be in a subdirectory of the current working directory.\n" - "\t\"./\" prefixes in the relative files will be automatically removed,\n" - "\tbut the rest of a relative path must be a suffix of a path in the\n" - "\tcompile command database.\n" + "<source0> ... specify the paths of source files. These paths are\n" + "\tlooked up in the compile command database. If the path of a file is\n" + "\tabsolute, it needs to point into CMake's source tree. If the path is\n" + "\trelative, the current working directory needs to be in the CMake\n" + "\tsource tree and the file must be in a subdirectory of the current\n" + "\tworking directory. \"./\" prefixes in the relative files will be\n" + "\tautomatically removed, but the rest of a relative path must be a\n" + "\tsuffix of a path in the compile command database.\n" "\n"; -CommandLineClangTool::CommandLineClangTool() : - BuildPath("p", cl::desc("Build path"), cl::Optional), - SourcePaths(cl::Positional, cl::desc("<source0> [... <sourceN>]"), - cl::OneOrMore), - MoreHelp(MoreHelpText) { -} +CommonOptionsParser::CommonOptionsParser(int &argc, const char **argv) { + static cl::opt<std::string> BuildPath( + "p", cl::desc("Build path"), cl::Optional); + + static cl::list<std::string> SourcePaths( + cl::Positional, cl::desc("<source0> [... <sourceN>]"), cl::OneOrMore); -void CommandLineClangTool::initialize(int argc, const char **argv) { - Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, argv)); + Compilations.reset(FixedCompilationDatabase::loadFromCommandLine(argc, + argv)); cl::ParseCommandLineOptions(argc, argv); + SourcePathList = SourcePaths; if (!Compilations) { std::string ErrorMessage; if (!BuildPath.empty()) { @@ -73,8 +77,3 @@ void CommandLineClangTool::initialize(int argc, const char **argv) { llvm::report_fatal_error(ErrorMessage); } } - -int CommandLineClangTool::run(FrontendActionFactory *ActionFactory) { - ClangTool Tool(*Compilations, SourcePaths); - return Tool.run(ActionFactory); -} diff --git a/lib/Tooling/CompilationDatabase.cpp b/lib/Tooling/CompilationDatabase.cpp index 3139cc21bb8d..4149cda3787c 100644 --- a/lib/Tooling/CompilationDatabase.cpp +++ b/lib/Tooling/CompilationDatabase.cpp @@ -7,132 +7,49 @@ // //===----------------------------------------------------------------------===// // -// This file contains multiple implementations for CompilationDatabases. +// This file contains implementations of the CompilationDatabase base class +// and the FixedCompilationDatabase. // //===----------------------------------------------------------------------===// +#include <sstream> #include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/CompilationDatabasePluginRegistry.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Support/YAMLParser.h" #include "llvm/Support/Path.h" #include "llvm/Support/system_error.h" -#ifdef USE_CUSTOM_COMPILATION_DATABASE -#include "CustomCompilationDatabase.h" -#endif - namespace clang { namespace tooling { -namespace { - -/// \brief A parser for escaped strings of command line arguments. -/// -/// Assumes \-escaping for quoted arguments (see the documentation of -/// unescapeCommandLine(...)). -class CommandLineArgumentParser { - public: - CommandLineArgumentParser(StringRef CommandLine) - : Input(CommandLine), Position(Input.begin()-1) {} - - std::vector<std::string> parse() { - bool HasMoreInput = true; - while (HasMoreInput && nextNonWhitespace()) { - std::string Argument; - HasMoreInput = parseStringInto(Argument); - CommandLine.push_back(Argument); - } - return CommandLine; - } - - private: - // All private methods return true if there is more input available. - - bool parseStringInto(std::string &String) { - do { - if (*Position == '"') { - if (!parseQuotedStringInto(String)) return false; - } else { - if (!parseFreeStringInto(String)) return false; - } - } while (*Position != ' '); - return true; - } - - bool parseQuotedStringInto(std::string &String) { - if (!next()) return false; - while (*Position != '"') { - if (!skipEscapeCharacter()) return false; - String.push_back(*Position); - if (!next()) return false; - } - return next(); - } - - bool parseFreeStringInto(std::string &String) { - do { - if (!skipEscapeCharacter()) return false; - String.push_back(*Position); - if (!next()) return false; - } while (*Position != ' ' && *Position != '"'); - return true; - } - - bool skipEscapeCharacter() { - if (*Position == '\\') { - return next(); - } - return true; - } - - bool nextNonWhitespace() { - do { - if (!next()) return false; - } while (*Position == ' '); - return true; - } - - bool next() { - ++Position; - return Position != Input.end(); - } - - const StringRef Input; - StringRef::iterator Position; - std::vector<std::string> CommandLine; -}; - -std::vector<std::string> unescapeCommandLine( - StringRef EscapedCommandLine) { - CommandLineArgumentParser parser(EscapedCommandLine); - return parser.parse(); -} - -} // end namespace - CompilationDatabase::~CompilationDatabase() {} CompilationDatabase * CompilationDatabase::loadFromDirectory(StringRef BuildDirectory, std::string &ErrorMessage) { - llvm::SmallString<1024> JSONDatabasePath(BuildDirectory); - llvm::sys::path::append(JSONDatabasePath, "compile_commands.json"); - llvm::OwningPtr<CompilationDatabase> Database( - JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage)); - if (!Database) { - return NULL; + std::stringstream ErrorStream; + for (CompilationDatabasePluginRegistry::iterator + It = CompilationDatabasePluginRegistry::begin(), + Ie = CompilationDatabasePluginRegistry::end(); + It != Ie; ++It) { + std::string DatabaseErrorMessage; + OwningPtr<CompilationDatabasePlugin> Plugin(It->instantiate()); + if (CompilationDatabase *DB = + Plugin->loadFromDirectory(BuildDirectory, DatabaseErrorMessage)) + return DB; + else + ErrorStream << It->getName() << ": " << DatabaseErrorMessage << "\n"; } - return Database.take(); + ErrorMessage = ErrorStream.str(); + return NULL; } static CompilationDatabase * -findCompilationDatabaseFromDirectory(StringRef Directory) { -#ifdef USE_CUSTOM_COMPILATION_DATABASE - if (CompilationDatabase *DB = - ::clang::tooling::findCompilationDatabaseForDirectory(Directory)) - return DB; -#endif +findCompilationDatabaseFromDirectory(StringRef Directory, + std::string &ErrorMessage) { + std::stringstream ErrorStream; + bool HasErrorMessage = false; while (!Directory.empty()) { std::string LoadErrorMessage; @@ -140,8 +57,15 @@ findCompilationDatabaseFromDirectory(StringRef Directory) { CompilationDatabase::loadFromDirectory(Directory, LoadErrorMessage)) return DB; + if (!HasErrorMessage) { + ErrorStream << "No compilation database found in " << Directory.str() + << " or any parent directory\n" << LoadErrorMessage; + HasErrorMessage = true; + } + Directory = llvm::sys::path::parent_path(Directory); } + ErrorMessage = ErrorStream.str(); return NULL; } @@ -151,11 +75,12 @@ CompilationDatabase::autoDetectFromSource(StringRef SourceFile, llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceFile)); StringRef Directory = llvm::sys::path::parent_path(AbsolutePath); - CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory); + CompilationDatabase *DB = findCompilationDatabaseFromDirectory(Directory, + ErrorMessage); if (!DB) ErrorMessage = ("Could not auto-detect compilation database for file \"" + - SourceFile + "\"").str(); + SourceFile + "\"\n" + ErrorMessage).str(); return DB; } @@ -164,14 +89,17 @@ CompilationDatabase::autoDetectFromDirectory(StringRef SourceDir, std::string &ErrorMessage) { llvm::SmallString<1024> AbsolutePath(getAbsolutePath(SourceDir)); - CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath); + CompilationDatabase *DB = findCompilationDatabaseFromDirectory(AbsolutePath, + ErrorMessage); if (!DB) ErrorMessage = ("Could not auto-detect compilation database from directory \"" + - SourceDir + "\"").str(); + SourceDir + "\"\n" + ErrorMessage).str(); return DB; } +CompilationDatabasePlugin::~CompilationDatabasePlugin() {} + FixedCompilationDatabase * FixedCompilationDatabase::loadFromCommandLine(int &Argc, const char **Argv, @@ -204,153 +132,10 @@ FixedCompilationDatabase::getAllFiles() const { return std::vector<std::string>(); } -JSONCompilationDatabase * -JSONCompilationDatabase::loadFromFile(StringRef FilePath, - std::string &ErrorMessage) { - llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer; - llvm::error_code Result = - llvm::MemoryBuffer::getFile(FilePath, DatabaseBuffer); - if (Result != 0) { - ErrorMessage = "Error while opening JSON database: " + Result.message(); - return NULL; - } - llvm::OwningPtr<JSONCompilationDatabase> Database( - new JSONCompilationDatabase(DatabaseBuffer.take())); - if (!Database->parse(ErrorMessage)) - return NULL; - return Database.take(); -} - -JSONCompilationDatabase * -JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString, - std::string &ErrorMessage) { - llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer( - llvm::MemoryBuffer::getMemBuffer(DatabaseString)); - llvm::OwningPtr<JSONCompilationDatabase> Database( - new JSONCompilationDatabase(DatabaseBuffer.take())); - if (!Database->parse(ErrorMessage)) - return NULL; - return Database.take(); -} - -std::vector<CompileCommand> -JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const { - llvm::SmallString<128> NativeFilePath; - llvm::sys::path::native(FilePath, NativeFilePath); - llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator - CommandsRefI = IndexByFile.find(NativeFilePath); - if (CommandsRefI == IndexByFile.end()) - return std::vector<CompileCommand>(); - const std::vector<CompileCommandRef> &CommandsRef = CommandsRefI->getValue(); - std::vector<CompileCommand> Commands; - for (int I = 0, E = CommandsRef.size(); I != E; ++I) { - llvm::SmallString<8> DirectoryStorage; - llvm::SmallString<1024> CommandStorage; - Commands.push_back(CompileCommand( - // FIXME: Escape correctly: - CommandsRef[I].first->getValue(DirectoryStorage), - unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage)))); - } - return Commands; -} - -std::vector<std::string> -JSONCompilationDatabase::getAllFiles() const { - std::vector<std::string> Result; - - llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator - CommandsRefI = IndexByFile.begin(); - const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator - CommandsRefEnd = IndexByFile.end(); - for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) { - Result.push_back(CommandsRefI->first().str()); - } - - return Result; -} - -bool JSONCompilationDatabase::parse(std::string &ErrorMessage) { - llvm::yaml::document_iterator I = YAMLStream.begin(); - if (I == YAMLStream.end()) { - ErrorMessage = "Error while parsing YAML."; - return false; - } - llvm::yaml::Node *Root = I->getRoot(); - if (Root == NULL) { - ErrorMessage = "Error while parsing YAML."; - return false; - } - llvm::yaml::SequenceNode *Array = - llvm::dyn_cast<llvm::yaml::SequenceNode>(Root); - if (Array == NULL) { - ErrorMessage = "Expected array."; - return false; - } - for (llvm::yaml::SequenceNode::iterator AI = Array->begin(), - AE = Array->end(); - AI != AE; ++AI) { - llvm::yaml::MappingNode *Object = - llvm::dyn_cast<llvm::yaml::MappingNode>(&*AI); - if (Object == NULL) { - ErrorMessage = "Expected object."; - return false; - } - llvm::yaml::ScalarNode *Directory = NULL; - llvm::yaml::ScalarNode *Command = NULL; - llvm::yaml::ScalarNode *File = NULL; - for (llvm::yaml::MappingNode::iterator KVI = Object->begin(), - KVE = Object->end(); - KVI != KVE; ++KVI) { - llvm::yaml::Node *Value = (*KVI).getValue(); - if (Value == NULL) { - ErrorMessage = "Expected value."; - return false; - } - llvm::yaml::ScalarNode *ValueString = - llvm::dyn_cast<llvm::yaml::ScalarNode>(Value); - if (ValueString == NULL) { - ErrorMessage = "Expected string as value."; - return false; - } - llvm::yaml::ScalarNode *KeyString = - llvm::dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey()); - if (KeyString == NULL) { - ErrorMessage = "Expected strings as key."; - return false; - } - llvm::SmallString<8> KeyStorage; - if (KeyString->getValue(KeyStorage) == "directory") { - Directory = ValueString; - } else if (KeyString->getValue(KeyStorage) == "command") { - Command = ValueString; - } else if (KeyString->getValue(KeyStorage) == "file") { - File = ValueString; - } else { - ErrorMessage = ("Unknown key: \"" + - KeyString->getRawValue() + "\"").str(); - return false; - } - } - if (!File) { - ErrorMessage = "Missing key: \"file\"."; - return false; - } - if (!Command) { - ErrorMessage = "Missing key: \"command\"."; - return false; - } - if (!Directory) { - ErrorMessage = "Missing key: \"directory\"."; - return false; - } - llvm::SmallString<8> FileStorage; - llvm::SmallString<128> NativeFilePath; - llvm::sys::path::native(File->getValue(FileStorage), NativeFilePath); - IndexByFile[NativeFilePath].push_back( - CompileCommandRef(Directory, Command)); - } - return true; -} +// This anchor is used to force the linker to link in the generated object file +// and thus register the JSONCompilationDatabasePlugin. +extern volatile int JSONAnchorSource; +static int JSONAnchorDest = JSONAnchorSource; } // end namespace tooling } // end namespace clang diff --git a/lib/Tooling/CustomCompilationDatabase.h b/lib/Tooling/CustomCompilationDatabase.h deleted file mode 100644 index b375f8d25634..000000000000 --- a/lib/Tooling/CustomCompilationDatabase.h +++ /dev/null @@ -1,42 +0,0 @@ -//===--- CustomCompilationDatabase.h --------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file contains a hook to supply a custom \c CompilationDatabase -// implementation. -// -// The mechanism can be used by IDEs or non-public code bases to integrate with -// their build system. Currently we support statically linking in an -// implementation of \c findCompilationDatabaseForDirectory and enabling it -// with -DUSE_CUSTOM_COMPILATION_DATABASE when compiling the Tooling library. -// -// FIXME: The strategy forward is to provide a plugin system that can load -// custom compilation databases and make enabling that a build option. -// -//===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_TOOLING_CUSTOM_COMPILATION_DATABASE_H -#define LLVM_CLANG_TOOLING_CUSTOM_COMPILATION_DATABASE_H - -#include "llvm/ADT/StringRef.h" - -namespace clang { -namespace tooling { -class CompilationDatabase; - -/// \brief Returns a CompilationDatabase for the given \c Directory. -/// -/// \c Directory can be any directory within a project. This methods will -/// then try to find compilation database files in \c Directory or any of its -/// parents. If a compilation database cannot be found or loaded, returns NULL. -clang::tooling::CompilationDatabase *findCompilationDatabaseForDirectory( - llvm::StringRef Directory); - -} // namespace tooling -} // namespace clang - -#endif // LLVM_CLANG_TOOLING_CUSTOM_COMPILATION_DATABASE_H diff --git a/lib/Tooling/FileMatchTrie.cpp b/lib/Tooling/FileMatchTrie.cpp new file mode 100644 index 000000000000..8f25a8c2bcfb --- /dev/null +++ b/lib/Tooling/FileMatchTrie.cpp @@ -0,0 +1,188 @@ +//===--- FileMatchTrie.cpp - ----------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation of a FileMatchTrie. +// +//===----------------------------------------------------------------------===// + +#include <sstream> +#include "clang/Tooling/FileMatchTrie.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/PathV2.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +namespace tooling { + +/// \brief Default \c PathComparator using \c llvm::sys::fs::equivalent(). +struct DefaultPathComparator : public PathComparator { + virtual ~DefaultPathComparator() {} + virtual bool equivalent(StringRef FileA, StringRef FileB) const { + return FileA == FileB || llvm::sys::fs::equivalent(FileA, FileB); + } +}; + +/// \brief A node of the \c FileMatchTrie. +/// +/// Each node has storage for up to one path and a map mapping a path segment to +/// child nodes. The trie starts with an empty root node. +class FileMatchTrieNode { +public: + /// \brief Inserts 'NewPath' into this trie. \c ConsumedLength denotes + /// the number of \c NewPath's trailing characters already consumed during + /// recursion. + /// + /// An insert of a path + /// 'p'starts at the root node and does the following: + /// - If the node is empty, insert 'p' into its storage and abort. + /// - If the node has a path 'p2' but no children, take the last path segment + /// 's' of 'p2', put a new child into the map at 's' an insert the rest of + /// 'p2' there. + /// - Insert a new child for the last segment of 'p' and insert the rest of + /// 'p' there. + /// + /// An insert operation is linear in the number of a path's segments. + void insert(StringRef NewPath, unsigned ConsumedLength = 0) { + // We cannot put relative paths into the FileMatchTrie as then a path can be + // a postfix of another path, violating a core assumption of the trie. + if (llvm::sys::path::is_relative(NewPath)) + return; + if (Path.empty()) { + // This is an empty leaf. Store NewPath and return. + Path = NewPath; + return; + } + if (Children.empty()) { + // This is a leaf, ignore duplicate entry if 'Path' equals 'NewPath'. + if (NewPath == Path) + return; + // Make this a node and create a child-leaf with 'Path'. + StringRef Element(llvm::sys::path::filename( + StringRef(Path).drop_back(ConsumedLength))); + Children[Element].Path = Path; + } + StringRef Element(llvm::sys::path::filename( + StringRef(NewPath).drop_back(ConsumedLength))); + Children[Element].insert(NewPath, ConsumedLength + Element.size() + 1); + } + + /// \brief Tries to find the node under this \c FileMatchTrieNode that best + /// matches 'FileName'. + /// + /// If multiple paths fit 'FileName' equally well, \c IsAmbiguous is set to + /// \c true and an empty string is returned. If no path fits 'FileName', an + /// empty string is returned. \c ConsumedLength denotes the number of + /// \c Filename's trailing characters already consumed during recursion. + /// + /// To find the best matching node for a given path 'p', the + /// \c findEquivalent() function is called recursively for each path segment + /// (back to fron) of 'p' until a node 'n' is reached that does not .. + /// - .. have children. In this case it is checked + /// whether the stored path is equivalent to 'p'. If yes, the best match is + /// found. Otherwise continue with the parent node as if this node did not + /// exist. + /// - .. a child matching the next path segment. In this case, all children of + /// 'n' are an equally good match for 'p'. All children are of 'n' are found + /// recursively and their equivalence to 'p' is determined. If none are + /// equivalent, continue with the parent node as if 'n' didn't exist. If one + /// is equivalent, the best match is found. Otherwise, report and ambigiuity + /// error. + StringRef findEquivalent(const PathComparator& Comparator, + StringRef FileName, + bool &IsAmbiguous, + unsigned ConsumedLength = 0) const { + if (Children.empty()) { + if (Comparator.equivalent(StringRef(Path), FileName)) + return StringRef(Path); + return StringRef(); + } + StringRef Element(llvm::sys::path::filename(FileName.drop_back( + ConsumedLength))); + llvm::StringMap<FileMatchTrieNode>::const_iterator MatchingChild = + Children.find(Element); + if (MatchingChild != Children.end()) { + StringRef Result = MatchingChild->getValue().findEquivalent( + Comparator, FileName, IsAmbiguous, + ConsumedLength + Element.size() + 1); + if (!Result.empty() || IsAmbiguous) + return Result; + } + std::vector<StringRef> AllChildren; + getAll(AllChildren, MatchingChild); + StringRef Result; + for (unsigned i = 0; i < AllChildren.size(); i++) { + if (Comparator.equivalent(AllChildren[i], FileName)) { + if (Result.empty()) { + Result = AllChildren[i]; + } else { + IsAmbiguous = true; + return StringRef(); + } + } + } + return Result; + } + +private: + /// \brief Gets all paths under this FileMatchTrieNode. + void getAll(std::vector<StringRef> &Results, + llvm::StringMap<FileMatchTrieNode>::const_iterator Except) const { + if (Path.empty()) + return; + if (Children.empty()) { + Results.push_back(StringRef(Path)); + return; + } + for (llvm::StringMap<FileMatchTrieNode>::const_iterator + It = Children.begin(), E = Children.end(); + It != E; ++It) { + if (It == Except) + continue; + It->getValue().getAll(Results, Children.end()); + } + } + + // The stored absolute path in this node. Only valid for leaf nodes, i.e. + // nodes where Children.empty(). + std::string Path; + + // The children of this node stored in a map based on the next path segment. + llvm::StringMap<FileMatchTrieNode> Children; +}; + +FileMatchTrie::FileMatchTrie() + : Root(new FileMatchTrieNode), Comparator(new DefaultPathComparator()) {} + +FileMatchTrie::FileMatchTrie(PathComparator *Comparator) + : Root(new FileMatchTrieNode), Comparator(Comparator) {} + +FileMatchTrie::~FileMatchTrie() { + delete Root; +} + +void FileMatchTrie::insert(StringRef NewPath) { + Root->insert(NewPath); +} + +StringRef FileMatchTrie::findEquivalent(StringRef FileName, + llvm::raw_ostream &Error) const { + if (llvm::sys::path::is_relative(FileName)) { + Error << "Cannot resolve relative paths"; + return StringRef(); + } + bool IsAmbiguous = false; + StringRef Result = Root->findEquivalent(*Comparator, FileName, IsAmbiguous); + if (IsAmbiguous) + Error << "Path is ambiguous"; + return Result; +} + +} // end namespace tooling +} // end namespace clang diff --git a/lib/Tooling/JSONCompilationDatabase.cpp b/lib/Tooling/JSONCompilationDatabase.cpp new file mode 100644 index 000000000000..cf35a2566637 --- /dev/null +++ b/lib/Tooling/JSONCompilationDatabase.cpp @@ -0,0 +1,303 @@ +//===--- JSONCompilationDatabase.cpp - ------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains the implementation of the JSONCompilationDatabase. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/JSONCompilationDatabase.h" + +#include "clang/Tooling/CompilationDatabase.h" +#include "clang/Tooling/CompilationDatabasePluginRegistry.h" +#include "clang/Tooling/Tooling.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/system_error.h" + +namespace clang { +namespace tooling { + +namespace { + +/// \brief A parser for escaped strings of command line arguments. +/// +/// Assumes \-escaping for quoted arguments (see the documentation of +/// unescapeCommandLine(...)). +class CommandLineArgumentParser { + public: + CommandLineArgumentParser(StringRef CommandLine) + : Input(CommandLine), Position(Input.begin()-1) {} + + std::vector<std::string> parse() { + bool HasMoreInput = true; + while (HasMoreInput && nextNonWhitespace()) { + std::string Argument; + HasMoreInput = parseStringInto(Argument); + CommandLine.push_back(Argument); + } + return CommandLine; + } + + private: + // All private methods return true if there is more input available. + + bool parseStringInto(std::string &String) { + do { + if (*Position == '"') { + if (!parseQuotedStringInto(String)) return false; + } else { + if (!parseFreeStringInto(String)) return false; + } + } while (*Position != ' '); + return true; + } + + bool parseQuotedStringInto(std::string &String) { + if (!next()) return false; + while (*Position != '"') { + if (!skipEscapeCharacter()) return false; + String.push_back(*Position); + if (!next()) return false; + } + return next(); + } + + bool parseFreeStringInto(std::string &String) { + do { + if (!skipEscapeCharacter()) return false; + String.push_back(*Position); + if (!next()) return false; + } while (*Position != ' ' && *Position != '"'); + return true; + } + + bool skipEscapeCharacter() { + if (*Position == '\\') { + return next(); + } + return true; + } + + bool nextNonWhitespace() { + do { + if (!next()) return false; + } while (*Position == ' '); + return true; + } + + bool next() { + ++Position; + return Position != Input.end(); + } + + const StringRef Input; + StringRef::iterator Position; + std::vector<std::string> CommandLine; +}; + +std::vector<std::string> unescapeCommandLine( + StringRef EscapedCommandLine) { + CommandLineArgumentParser parser(EscapedCommandLine); + return parser.parse(); +} + +} // end namespace + +class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin { + virtual CompilationDatabase *loadFromDirectory( + StringRef Directory, std::string &ErrorMessage) { + llvm::SmallString<1024> JSONDatabasePath(Directory); + llvm::sys::path::append(JSONDatabasePath, "compile_commands.json"); + llvm::OwningPtr<CompilationDatabase> Database( + JSONCompilationDatabase::loadFromFile(JSONDatabasePath, ErrorMessage)); + if (!Database) + return NULL; + return Database.take(); + } +}; + +// Register the JSONCompilationDatabasePlugin with the +// CompilationDatabasePluginRegistry using this statically initialized variable. +static CompilationDatabasePluginRegistry::Add<JSONCompilationDatabasePlugin> +X("json-compilation-database", "Reads JSON formatted compilation databases"); + +// This anchor is used to force the linker to link in the generated object file +// and thus register the JSONCompilationDatabasePlugin. +volatile int JSONAnchorSource = 0; + +JSONCompilationDatabase * +JSONCompilationDatabase::loadFromFile(StringRef FilePath, + std::string &ErrorMessage) { + llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer; + llvm::error_code Result = + llvm::MemoryBuffer::getFile(FilePath, DatabaseBuffer); + if (Result != 0) { + ErrorMessage = "Error while opening JSON database: " + Result.message(); + return NULL; + } + llvm::OwningPtr<JSONCompilationDatabase> Database( + new JSONCompilationDatabase(DatabaseBuffer.take())); + if (!Database->parse(ErrorMessage)) + return NULL; + return Database.take(); +} + +JSONCompilationDatabase * +JSONCompilationDatabase::loadFromBuffer(StringRef DatabaseString, + std::string &ErrorMessage) { + llvm::OwningPtr<llvm::MemoryBuffer> DatabaseBuffer( + llvm::MemoryBuffer::getMemBuffer(DatabaseString)); + llvm::OwningPtr<JSONCompilationDatabase> Database( + new JSONCompilationDatabase(DatabaseBuffer.take())); + if (!Database->parse(ErrorMessage)) + return NULL; + return Database.take(); +} + +std::vector<CompileCommand> +JSONCompilationDatabase::getCompileCommands(StringRef FilePath) const { + llvm::SmallString<128> NativeFilePath; + llvm::sys::path::native(FilePath, NativeFilePath); + std::vector<StringRef> PossibleMatches; + std::string Error; + llvm::raw_string_ostream ES(Error); + StringRef Match = MatchTrie.findEquivalent(NativeFilePath.str(), ES); + if (Match.empty()) { + if (Error.empty()) + Error = "No match found."; + llvm::outs() << Error << "\n"; + return std::vector<CompileCommand>(); + } + llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator + CommandsRefI = IndexByFile.find(Match); + if (CommandsRefI == IndexByFile.end()) + return std::vector<CompileCommand>(); + const std::vector<CompileCommandRef> &CommandsRef = CommandsRefI->getValue(); + std::vector<CompileCommand> Commands; + for (int I = 0, E = CommandsRef.size(); I != E; ++I) { + llvm::SmallString<8> DirectoryStorage; + llvm::SmallString<1024> CommandStorage; + Commands.push_back(CompileCommand( + // FIXME: Escape correctly: + CommandsRef[I].first->getValue(DirectoryStorage), + unescapeCommandLine(CommandsRef[I].second->getValue(CommandStorage)))); + } + return Commands; +} + +std::vector<std::string> +JSONCompilationDatabase::getAllFiles() const { + std::vector<std::string> Result; + + llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator + CommandsRefI = IndexByFile.begin(); + const llvm::StringMap< std::vector<CompileCommandRef> >::const_iterator + CommandsRefEnd = IndexByFile.end(); + for (; CommandsRefI != CommandsRefEnd; ++CommandsRefI) { + Result.push_back(CommandsRefI->first().str()); + } + + return Result; +} + +bool JSONCompilationDatabase::parse(std::string &ErrorMessage) { + llvm::yaml::document_iterator I = YAMLStream.begin(); + if (I == YAMLStream.end()) { + ErrorMessage = "Error while parsing YAML."; + return false; + } + llvm::yaml::Node *Root = I->getRoot(); + if (Root == NULL) { + ErrorMessage = "Error while parsing YAML."; + return false; + } + llvm::yaml::SequenceNode *Array = + llvm::dyn_cast<llvm::yaml::SequenceNode>(Root); + if (Array == NULL) { + ErrorMessage = "Expected array."; + return false; + } + for (llvm::yaml::SequenceNode::iterator AI = Array->begin(), + AE = Array->end(); + AI != AE; ++AI) { + llvm::yaml::MappingNode *Object = + llvm::dyn_cast<llvm::yaml::MappingNode>(&*AI); + if (Object == NULL) { + ErrorMessage = "Expected object."; + return false; + } + llvm::yaml::ScalarNode *Directory = NULL; + llvm::yaml::ScalarNode *Command = NULL; + llvm::yaml::ScalarNode *File = NULL; + for (llvm::yaml::MappingNode::iterator KVI = Object->begin(), + KVE = Object->end(); + KVI != KVE; ++KVI) { + llvm::yaml::Node *Value = (*KVI).getValue(); + if (Value == NULL) { + ErrorMessage = "Expected value."; + return false; + } + llvm::yaml::ScalarNode *ValueString = + llvm::dyn_cast<llvm::yaml::ScalarNode>(Value); + if (ValueString == NULL) { + ErrorMessage = "Expected string as value."; + return false; + } + llvm::yaml::ScalarNode *KeyString = + llvm::dyn_cast<llvm::yaml::ScalarNode>((*KVI).getKey()); + if (KeyString == NULL) { + ErrorMessage = "Expected strings as key."; + return false; + } + llvm::SmallString<8> KeyStorage; + if (KeyString->getValue(KeyStorage) == "directory") { + Directory = ValueString; + } else if (KeyString->getValue(KeyStorage) == "command") { + Command = ValueString; + } else if (KeyString->getValue(KeyStorage) == "file") { + File = ValueString; + } else { + ErrorMessage = ("Unknown key: \"" + + KeyString->getRawValue() + "\"").str(); + return false; + } + } + if (!File) { + ErrorMessage = "Missing key: \"file\"."; + return false; + } + if (!Command) { + ErrorMessage = "Missing key: \"command\"."; + return false; + } + if (!Directory) { + ErrorMessage = "Missing key: \"directory\"."; + return false; + } + llvm::SmallString<8> FileStorage; + StringRef FileName = File->getValue(FileStorage); + llvm::SmallString<128> NativeFilePath; + if (llvm::sys::path::is_relative(FileName)) { + llvm::SmallString<8> DirectoryStorage; + llvm::SmallString<128> AbsolutePath( + Directory->getValue(DirectoryStorage)); + llvm::sys::path::append(AbsolutePath, FileName); + llvm::sys::path::native(AbsolutePath.str(), NativeFilePath); + } else { + llvm::sys::path::native(FileName, NativeFilePath); + } + IndexByFile[NativeFilePath].push_back( + CompileCommandRef(Directory, Command)); + MatchTrie.insert(NativeFilePath.str()); + } + return true; +} + +} // end namespace tooling +} // end namespace clang diff --git a/lib/Tooling/Refactoring.cpp b/lib/Tooling/Refactoring.cpp index 628435307c0b..c5002ef9fcfc 100644 --- a/lib/Tooling/Refactoring.cpp +++ b/lib/Tooling/Refactoring.cpp @@ -11,12 +11,12 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" -#include "clang/Frontend/DiagnosticOptions.h" #include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Lex/Lexer.h" -#include "clang/Rewrite/Rewriter.h" +#include "clang/Rewrite/Core/Rewriter.h" #include "clang/Tooling/Refactoring.h" #include "llvm/Support/raw_os_ostream.h" @@ -164,12 +164,11 @@ Replacements &RefactoringTool::getReplacements() { return Replace; } int RefactoringTool::run(FrontendActionFactory *ActionFactory) { int Result = Tool.run(ActionFactory); LangOptions DefaultLangOptions; - DiagnosticOptions DefaultDiagnosticOptions; - TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), - DefaultDiagnosticOptions); + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); + TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts); DiagnosticsEngine Diagnostics( llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), - &DiagnosticPrinter, false); + &*DiagOpts, &DiagnosticPrinter, false); SourceManager Sources(Diagnostics, Tool.getFiles()); Rewriter Rewrite(Sources, DefaultLangOptions); if (!applyAllReplacements(Replace, Rewrite)) { diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp index e93e0c97f710..af20254811aa 100644 --- a/lib/Tooling/Tooling.cpp +++ b/lib/Tooling/Tooling.cpp @@ -97,17 +97,22 @@ static clang::CompilerInvocation *newInvocation( bool runToolOnCode(clang::FrontendAction *ToolAction, const Twine &Code, const Twine &FileName) { + return runToolOnCodeWithArgs( + ToolAction, Code, std::vector<std::string>(), FileName); +} + +bool runToolOnCodeWithArgs(clang::FrontendAction *ToolAction, const Twine &Code, + const std::vector<std::string> &Args, + const Twine &FileName) { SmallString<16> FileNameStorage; StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage); - const char *const CommandLine[] = { - "clang-tool", "-fsyntax-only", FileNameRef.data() - }; + std::vector<std::string> Commands; + Commands.push_back("clang-tool"); + Commands.push_back("-fsyntax-only"); + Commands.insert(Commands.end(), Args.begin(), Args.end()); + Commands.push_back(FileNameRef.data()); FileManager Files((FileSystemOptions())); - ToolInvocation Invocation( - std::vector<std::string>( - CommandLine, - CommandLine + llvm::array_lengthof(CommandLine)), - ToolAction, &Files); + ToolInvocation Invocation(Commands, ToolAction, &Files); SmallString<1024> CodeStorage; Invocation.mapVirtualFile(FileNameRef, @@ -154,11 +159,12 @@ bool ToolInvocation::run() { for (int I = 0, E = CommandLine.size(); I != E; ++I) Argv.push_back(CommandLine[I].c_str()); const char *const BinaryName = Argv[0]; - DiagnosticOptions DefaultDiagnosticOptions; + IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions(); TextDiagnosticPrinter DiagnosticPrinter( - llvm::errs(), DefaultDiagnosticOptions); - DiagnosticsEngine Diagnostics(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>( - new DiagnosticIDs()), &DiagnosticPrinter, false); + llvm::errs(), &*DiagOpts); + DiagnosticsEngine Diagnostics( + llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(new DiagnosticIDs()), + &*DiagOpts, &DiagnosticPrinter, false); const llvm::OwningPtr<clang::driver::Driver> Driver( newDriver(&Diagnostics, BinaryName)); |