diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-01-18 16:23:48 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-01-18 16:23:48 +0000 |
commit | 06d4ba388873e6d1cfa9cd715a8935ecc8cd2097 (patch) | |
tree | 3eb853da77d46cc77c4b017525a422f9ddb1385b /lib | |
parent | 30d791273d07fac9c0c1641a0731191bca6e8606 (diff) | |
download | src-06d4ba388873e6d1cfa9cd715a8935ecc8cd2097.tar.gz src-06d4ba388873e6d1cfa9cd715a8935ecc8cd2097.zip |
Vendor import of clang RELEASE_360/rc1 tag r226102 (effectively, 3.6.0 RC1):vendor/clang/clang-release_360-r226102
Notes
Notes:
svn path=/vendor/clang/dist/; revision=277325
svn path=/vendor/clang/clang-release_360-r226102/; revision=277326; tag=vendor/clang/clang-release_360-r226102
Diffstat (limited to 'lib')
401 files changed, 42800 insertions, 20633 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp index 8a13b2ee4f1d..dddc886a269c 100644 --- a/lib/ARCMigrate/ARCMT.cpp +++ b/lib/ARCMigrate/ARCMT.cpp @@ -446,11 +446,11 @@ public: ARCMTMacroTrackerAction(std::vector<SourceLocation> &ARCMTMacroLocs) : ARCMTMacroLocs(ARCMTMacroLocs) { } - ASTConsumer *CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) override { + std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI, + StringRef InFile) override { CI.getPreprocessor().addPPCallbacks( - new ARCMTMacroTrackerPPCallbacks(ARCMTMacroLocs)); - return new ASTConsumer(); + llvm::make_unique<ARCMTMacroTrackerPPCallbacks>(ARCMTMacroLocs)); + return llvm::make_unique<ASTConsumer>(); } }; @@ -597,11 +597,12 @@ bool MigrationProcess::applyTransform(TransformFn trans, llvm::raw_svector_ostream vecOS(newText); buf.write(vecOS); vecOS.flush(); - llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( - StringRef(newText.data(), newText.size()), newFname); + std::unique_ptr<llvm::MemoryBuffer> memBuf( + llvm::MemoryBuffer::getMemBufferCopy( + StringRef(newText.data(), newText.size()), newFname)); SmallString<64> filePath(file->getName()); Unit->getFileManager().FixupRelativePath(filePath); - Remapper.remap(filePath.str(), memBuf); + Remapper.remap(filePath.str(), std::move(memBuf)); } return false; diff --git a/lib/ARCMigrate/FileRemapper.cpp b/lib/ARCMigrate/FileRemapper.cpp index 40e606090064..72a55da5d50b 100644 --- a/lib/ARCMigrate/FileRemapper.cpp +++ b/lib/ARCMigrate/FileRemapper.cpp @@ -58,9 +58,7 @@ bool FileRemapper::initFromFile(StringRef filePath, DiagnosticsEngine &Diag, assert(FromToMappings.empty() && "initFromDisk should be called before any remap calls"); std::string infoFile = filePath; - bool fileExists = false; - llvm::sys::fs::exists(infoFile, fileExists); - if (!fileExists) + if (!llvm::sys::fs::exists(infoFile)) return false; std::vector<std::pair<const FileEntry *, const FileEntry *> > pairs; @@ -122,11 +120,11 @@ bool FileRemapper::flushToDisk(StringRef outputDir, DiagnosticsEngine &Diag) { bool FileRemapper::flushToFile(StringRef outputPath, DiagnosticsEngine &Diag) { using namespace llvm::sys; - std::string errMsg; + std::error_code EC; std::string infoFile = outputPath; - llvm::raw_fd_ostream infoOut(infoFile.c_str(), errMsg, llvm::sys::fs::F_None); - if (!errMsg.empty()) - return report(errMsg, Diag); + llvm::raw_fd_ostream infoOut(infoFile, EC, llvm::sys::fs::F_None); + if (EC) + return report(EC.message(), Diag); for (MappingsTy::iterator I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) { @@ -173,16 +171,14 @@ bool FileRemapper::overwriteOriginal(DiagnosticsEngine &Diag, I = FromToMappings.begin(), E = FromToMappings.end(); I != E; ++I) { const FileEntry *origFE = I->first; assert(I->second.is<llvm::MemoryBuffer *>()); - bool fileExists = false; - fs::exists(origFE->getName(), fileExists); - if (!fileExists) + if (!fs::exists(origFE->getName())) return report(StringRef("File does not exist: ") + origFE->getName(), Diag); - std::string errMsg; - llvm::raw_fd_ostream Out(origFE->getName(), errMsg, llvm::sys::fs::F_None); - if (!errMsg.empty()) - return report(errMsg, Diag); + std::error_code EC; + llvm::raw_fd_ostream Out(origFE->getName(), EC, llvm::sys::fs::F_None); + if (EC) + return report(EC.message(), Diag); llvm::MemoryBuffer *mem = I->second.get<llvm::MemoryBuffer *>(); Out.write(mem->getBufferStart(), mem->getBufferSize()); @@ -207,15 +203,17 @@ void FileRemapper::applyMappings(PreprocessorOptions &PPOpts) const { PPOpts.RetainRemappedFileBuffers = true; } -void FileRemapper::remap(StringRef filePath, llvm::MemoryBuffer *memBuf) { - remap(getOriginalFile(filePath), memBuf); +void FileRemapper::remap(StringRef filePath, + std::unique_ptr<llvm::MemoryBuffer> memBuf) { + remap(getOriginalFile(filePath), std::move(memBuf)); } -void FileRemapper::remap(const FileEntry *file, llvm::MemoryBuffer *memBuf) { +void FileRemapper::remap(const FileEntry *file, + std::unique_ptr<llvm::MemoryBuffer> memBuf) { assert(file); Target &targ = FromToMappings[file]; resetTarget(targ); - targ = memBuf; + targ = memBuf.release(); } void FileRemapper::remap(const FileEntry *file, const FileEntry *newfile) { diff --git a/lib/ARCMigrate/Internals.h b/lib/ARCMigrate/Internals.h index a65b329c5b03..4f153b1ad2f4 100644 --- a/lib/ARCMigrate/Internals.h +++ b/lib/ARCMigrate/Internals.h @@ -73,7 +73,7 @@ public: bool clearDiagnostic(ArrayRef<unsigned> IDs, SourceRange range); bool clearAllDiagnostics(SourceRange range) { - return clearDiagnostic(ArrayRef<unsigned>(), range); + return clearDiagnostic(None, range); } bool clearDiagnostic(unsigned ID1, unsigned ID2, SourceRange range) { unsigned IDs[] = { ID1, ID2 }; diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp index 1a2055e9c452..52c424c000f8 100644 --- a/lib/ARCMigrate/ObjCMT.cpp +++ b/lib/ARCMigrate/ObjCMT.cpp @@ -29,6 +29,7 @@ #include "clang/Rewrite/Core/Rewriter.h" #include "clang/StaticAnalyzer/Checkers/ObjCRetainCount.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSet.h" #include "llvm/Support/Path.h" #include "llvm/Support/SourceMgr.h" #include "llvm/Support/YAMLParser.h" @@ -81,6 +82,8 @@ class ObjCMigrateASTConsumer : public ASTConsumer { void inferDesignatedInitializers(ASTContext &Ctx, const ObjCImplementationDecl *ImplD); + + bool InsertFoundation(ASTContext &Ctx, SourceLocation Loc); public: std::string MigrateDir; @@ -95,10 +98,11 @@ public: const PPConditionalDirectiveRecord *PPRec; Preprocessor &PP; bool IsOutputFile; + bool FoundationIncluded; llvm::SmallPtrSet<ObjCProtocolDecl *, 32> ObjCProtocolDecls; llvm::SmallVector<const Decl *, 8> CFFunctionIBCandidates; - llvm::StringMap<char> WhiteListFilenames; - + llvm::StringSet<> WhiteListFilenames; + ObjCMigrateASTConsumer(StringRef migrateDir, unsigned astMigrateActions, FileRemapper &remapper, @@ -111,12 +115,12 @@ public: ASTMigrateActions(astMigrateActions), NSIntegerTypedefed(nullptr), NSUIntegerTypedefed(nullptr), Remapper(remapper), FileMgr(fileMgr), PPRec(PPRec), PP(PP), - IsOutputFile(isOutputFile) { + IsOutputFile(isOutputFile), + FoundationIncluded(false){ - for (ArrayRef<std::string>::iterator - I = WhiteList.begin(), E = WhiteList.end(); I != E; ++I) { - WhiteListFilenames.GetOrCreateValue(*I); - } + // FIXME: StringSet should have insert(iter, iter) to use here. + for (const std::string &Val : WhiteList) + WhiteListFilenames.insert(Val); } protected: @@ -185,23 +189,17 @@ ObjCMigrateAction::ObjCMigrateAction(FrontendAction *WrappedAction, MigrateDir = "."; // user current directory if none is given. } -ASTConsumer *ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { +std::unique_ptr<ASTConsumer> +ObjCMigrateAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { PPConditionalDirectiveRecord * PPRec = new PPConditionalDirectiveRecord(CompInst->getSourceManager()); - CompInst->getPreprocessor().addPPCallbacks(PPRec); - ASTConsumer * - WrappedConsumer = WrapperFrontendAction::CreateASTConsumer(CI, InFile); - ASTConsumer *MTConsumer = new ObjCMigrateASTConsumer(MigrateDir, - ObjCMigAction, - Remapper, - CompInst->getFileManager(), - PPRec, - CompInst->getPreprocessor(), - false, - ArrayRef<std::string>()); - ASTConsumer *Consumers[] = { MTConsumer, WrappedConsumer }; - return new MultiplexConsumer(Consumers); + CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec)); + std::vector<std::unique_ptr<ASTConsumer>> Consumers; + Consumers.push_back(WrapperFrontendAction::CreateASTConsumer(CI, InFile)); + Consumers.push_back(llvm::make_unique<ObjCMigrateASTConsumer>( + MigrateDir, ObjCMigAction, Remapper, CompInst->getFileManager(), PPRec, + CompInst->getPreprocessor(), false, None)); + return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); } bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) { @@ -213,6 +211,110 @@ bool ObjCMigrateAction::BeginInvocation(CompilerInstance &CI) { } namespace { + // FIXME. This duplicates one in RewriteObjCFoundationAPI.cpp + bool subscriptOperatorNeedsParens(const Expr *FullExpr) { + const Expr* Expr = FullExpr->IgnoreImpCasts(); + if (isa<ArraySubscriptExpr>(Expr) || + isa<CallExpr>(Expr) || + isa<DeclRefExpr>(Expr) || + isa<CXXNamedCastExpr>(Expr) || + isa<CXXConstructExpr>(Expr) || + isa<CXXThisExpr>(Expr) || + isa<CXXTypeidExpr>(Expr) || + isa<CXXUnresolvedConstructExpr>(Expr) || + isa<ObjCMessageExpr>(Expr) || + isa<ObjCPropertyRefExpr>(Expr) || + isa<ObjCProtocolExpr>(Expr) || + isa<MemberExpr>(Expr) || + isa<ObjCIvarRefExpr>(Expr) || + isa<ParenExpr>(FullExpr) || + isa<ParenListExpr>(Expr) || + isa<SizeOfPackExpr>(Expr)) + return false; + + return true; + } + + /// \brief - Rewrite message expression for Objective-C setter and getters into + /// property-dot syntax. + bool rewriteToPropertyDotSyntax(const ObjCMessageExpr *Msg, + Preprocessor &PP, + const NSAPI &NS, edit::Commit &commit, + const ParentMap *PMap) { + if (!Msg || Msg->isImplicit() || + (Msg->getReceiverKind() != ObjCMessageExpr::Instance && + Msg->getReceiverKind() != ObjCMessageExpr::SuperInstance)) + return false; + const ObjCMethodDecl *Method = Msg->getMethodDecl(); + if (!Method) + return false; + if (!Method->isPropertyAccessor()) + return false; + + const ObjCInterfaceDecl *IFace = + NS.getASTContext().getObjContainingInterface(Method); + if (!IFace) + return false; + + const ObjCPropertyDecl *Prop = Method->findPropertyDecl(); + if (!Prop) + return false; + + SourceRange MsgRange = Msg->getSourceRange(); + bool ReceiverIsSuper = + (Msg->getReceiverKind() == ObjCMessageExpr::SuperInstance); + // for 'super' receiver is nullptr. + const Expr *receiver = Msg->getInstanceReceiver(); + bool NeedsParen = + ReceiverIsSuper ? false : subscriptOperatorNeedsParens(receiver); + bool IsGetter = (Msg->getNumArgs() == 0); + if (IsGetter) { + // Find space location range between receiver expression and getter method. + SourceLocation BegLoc = + ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getLocEnd(); + BegLoc = PP.getLocForEndOfToken(BegLoc); + SourceLocation EndLoc = Msg->getSelectorLoc(0); + SourceRange SpaceRange(BegLoc, EndLoc); + std::string PropertyDotString; + // rewrite getter method expression into: receiver.property or + // (receiver).property + if (NeedsParen) { + commit.insertBefore(receiver->getLocStart(), "("); + PropertyDotString = ")."; + } + else + PropertyDotString = "."; + PropertyDotString += Prop->getName(); + commit.replace(SpaceRange, PropertyDotString); + + // remove '[' ']' + commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), ""); + commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), ""); + } else { + if (NeedsParen) + commit.insertWrap("(", receiver->getSourceRange(), ")"); + std::string PropertyDotString = "."; + PropertyDotString += Prop->getName(); + PropertyDotString += " ="; + const Expr*const* Args = Msg->getArgs(); + const Expr *RHS = Args[0]; + if (!RHS) + return false; + SourceLocation BegLoc = + ReceiverIsSuper ? Msg->getSuperLoc() : receiver->getLocEnd(); + BegLoc = PP.getLocForEndOfToken(BegLoc); + SourceLocation EndLoc = RHS->getLocStart(); + EndLoc = EndLoc.getLocWithOffset(-1); + SourceRange Range(BegLoc, EndLoc); + commit.replace(Range, PropertyDotString); + // remove '[' ']' + commit.replace(SourceRange(MsgRange.getBegin(), MsgRange.getBegin()), ""); + commit.replace(SourceRange(MsgRange.getEnd(), MsgRange.getEnd()), ""); + } + return true; + } + + class ObjCMigrator : public RecursiveASTVisitor<ObjCMigrator> { ObjCMigrateASTConsumer &Consumer; ParentMap &PMap; @@ -237,6 +339,13 @@ public: Consumer.Editor->commit(commit); } + if (Consumer.ASTMigrateActions & FrontendOptions::ObjCMT_PropertyDotSyntax) { + edit::Commit commit(*Consumer.Editor); + rewriteToPropertyDotSyntax(E, Consumer.PP, *Consumer.NSAPIObj, + commit, &PMap); + Consumer.Editor->commit(commit); + } + return true; } @@ -590,18 +699,32 @@ static bool rewriteToObjCInterfaceDecl(const ObjCInterfaceDecl *IDecl, return true; } +static StringRef GetUnsignedName(StringRef NSIntegerName) { + StringRef UnsignedName = llvm::StringSwitch<StringRef>(NSIntegerName) + .Case("int8_t", "uint8_t") + .Case("int16_t", "uint16_t") + .Case("int32_t", "uint32_t") + .Case("NSInteger", "NSUInteger") + .Case("int64_t", "uint64_t") + .Default(NSIntegerName); + return UnsignedName; +} + static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl, const NSAPI &NS, edit::Commit &commit, - bool IsNSIntegerType, + StringRef NSIntegerName, bool NSOptions) { std::string ClassString; - if (NSOptions) - ClassString = "typedef NS_OPTIONS(NSUInteger, "; - else - ClassString = - IsNSIntegerType ? "typedef NS_ENUM(NSInteger, " - : "typedef NS_ENUM(NSUInteger, "; + if (NSOptions) { + ClassString = "typedef NS_OPTIONS("; + ClassString += GetUnsignedName(NSIntegerName); + } + else { + ClassString = "typedef NS_ENUM("; + ClassString += NSIntegerName; + } + ClassString += ", "; ClassString += TypedefDcl->getIdentifier()->getName(); ClassString += ')'; @@ -640,18 +763,31 @@ static bool rewriteToNSEnumDecl(const EnumDecl *EnumDcl, return false; } -static void rewriteToNSMacroDecl(const EnumDecl *EnumDcl, +static void rewriteToNSMacroDecl(ASTContext &Ctx, + const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl, const NSAPI &NS, edit::Commit &commit, bool IsNSIntegerType) { - std::string ClassString = - IsNSIntegerType ? "NS_ENUM(NSInteger, " : "NS_OPTIONS(NSUInteger, "; + QualType EnumUnderlyingT = EnumDcl->getPromotionType(); + assert(!EnumUnderlyingT.isNull() + && "rewriteToNSMacroDecl - underlying enum type is null"); + + PrintingPolicy Policy(Ctx.getPrintingPolicy()); + std::string TypeString = EnumUnderlyingT.getAsString(Policy); + std::string ClassString = IsNSIntegerType ? "NS_ENUM(" : "NS_OPTIONS("; + ClassString += TypeString; + ClassString += ", "; + ClassString += TypedefDcl->getIdentifier()->getName(); ClassString += ')'; SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart()); commit.replace(R, ClassString); - SourceLocation TypedefLoc = TypedefDcl->getLocEnd(); - commit.remove(SourceRange(TypedefLoc, TypedefLoc)); + // This is to remove spaces between '}' and typedef name. + SourceLocation StartTypedefLoc = EnumDcl->getLocEnd(); + StartTypedefLoc = StartTypedefLoc.getLocWithOffset(+1); + SourceLocation EndTypedefLoc = TypedefDcl->getLocEnd(); + + commit.remove(SourceRange(StartTypedefLoc, EndTypedefLoc)); } static bool UseNSOptionsMacro(Preprocessor &PP, ASTContext &Ctx, @@ -706,11 +842,9 @@ void ObjCMigrateASTConsumer::migrateProtocolConformance(ASTContext &Ctx, Ctx.CollectInheritedProtocols(IDecl, ExplicitProtocols); llvm::SmallVector<ObjCProtocolDecl *, 8> PotentialImplicitProtocols; - for (llvm::SmallPtrSet<ObjCProtocolDecl*, 32>::iterator I = - ObjCProtocolDecls.begin(), - E = ObjCProtocolDecls.end(); I != E; ++I) - if (!ExplicitProtocols.count(*I)) - PotentialImplicitProtocols.push_back(*I); + for (ObjCProtocolDecl *ProtDecl : ObjCProtocolDecls) + if (!ExplicitProtocols.count(ProtDecl)) + PotentialImplicitProtocols.push_back(ProtDecl); if (PotentialImplicitProtocols.empty()) return; @@ -768,7 +902,7 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl) { if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() || - EnumDcl->isDeprecated()) + EnumDcl->isDeprecated() || EnumDcl->getIntegerTypeSourceInfo()) return false; if (!TypedefDcl) { if (NSIntegerTypedefed) { @@ -792,22 +926,17 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx, return false; QualType qt = TypedefDcl->getTypeSourceInfo()->getType(); - bool IsNSIntegerType = NSAPIObj->isObjCNSIntegerType(qt); - bool IsNSUIntegerType = !IsNSIntegerType && NSAPIObj->isObjCNSUIntegerType(qt); + StringRef NSIntegerName = NSAPIObj->GetNSIntegralKind(qt); - if (!IsNSIntegerType && !IsNSUIntegerType) { + if (NSIntegerName.empty()) { // Also check for typedef enum {...} TD; if (const EnumType *EnumTy = qt->getAs<EnumType>()) { if (EnumTy->getDecl() == EnumDcl) { bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl); - if (NSOptions) { - if (!Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition()) - return false; - } - else if (!Ctx.Idents.get("NS_ENUM").hasMacroDefinition()) + if (!InsertFoundation(Ctx, TypedefDcl->getLocStart())) return false; edit::Commit commit(*Editor); - rewriteToNSMacroDecl(EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions); + rewriteToNSMacroDecl(Ctx, EnumDcl, TypedefDcl, *NSAPIObj, commit, !NSOptions); Editor->commit(commit); return true; } @@ -817,15 +946,11 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx, // We may still use NS_OPTIONS based on what we find in the enumertor list. bool NSOptions = UseNSOptionsMacro(PP, Ctx, EnumDcl); - // NS_ENUM must be available. - if (IsNSIntegerType && !Ctx.Idents.get("NS_ENUM").hasMacroDefinition()) - return false; - // NS_OPTIONS must be available. - if (IsNSUIntegerType && !Ctx.Idents.get("NS_OPTIONS").hasMacroDefinition()) + if (!InsertFoundation(Ctx, TypedefDcl->getLocStart())) return false; edit::Commit commit(*Editor); bool Res = rewriteToNSEnumDecl(EnumDcl, TypedefDcl, *NSAPIObj, - commit, IsNSIntegerType, NSOptions); + commit, NSIntegerName, NSOptions); Editor->commit(commit); return Res; } @@ -1606,6 +1731,22 @@ void ObjCMigrateASTConsumer::inferDesignatedInitializers( } } +bool ObjCMigrateASTConsumer::InsertFoundation(ASTContext &Ctx, + SourceLocation Loc) { + if (FoundationIncluded) + return true; + if (Loc.isInvalid()) + return false; + edit::Commit commit(*Editor); + if (Ctx.getLangOpts().Modules) + commit.insert(Loc, "#ifndef NS_ENUM\n@import Foundation;\n#endif\n"); + else + commit.insert(Loc, "#ifndef NS_ENUM\n#import <Foundation/Foundation.h>\n#endif\n"); + Editor->commit(commit); + FoundationIncluded = true; + return true; +} + namespace { class RewritesReceiver : public edit::EditsReceiver { @@ -1799,12 +1940,12 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { } if (IsOutputFile) { - std::string Error; - llvm::raw_fd_ostream OS(MigrateDir.c_str(), Error, llvm::sys::fs::F_None); - if (!Error.empty()) { + std::error_code EC; + llvm::raw_fd_ostream OS(MigrateDir, EC, llvm::sys::fs::F_None); + if (EC) { DiagnosticsEngine &Diags = Ctx.getDiagnostics(); Diags.Report(Diags.getCustomDiagID(DiagnosticsEngine::Error, "%0")) - << Error; + << EC.message(); return; } @@ -1827,11 +1968,12 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { llvm::raw_svector_ostream vecOS(newText); buf.write(vecOS); vecOS.flush(); - llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( - StringRef(newText.data(), newText.size()), file->getName()); + std::unique_ptr<llvm::MemoryBuffer> memBuf( + llvm::MemoryBuffer::getMemBufferCopy( + StringRef(newText.data(), newText.size()), file->getName())); SmallString<64> filePath(file->getName()); FileMgr.FixupRelativePath(filePath); - Remapper.remap(filePath.str(), memBuf); + Remapper.remap(filePath.str(), std::move(memBuf)); } if (IsOutputFile) { @@ -1865,8 +2007,8 @@ static std::vector<std::string> getWhiteListFilenames(StringRef DirPath) { return Filenames; } -ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, - StringRef InFile) { +std::unique_ptr<ASTConsumer> +MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { PPConditionalDirectiveRecord * PPRec = new PPConditionalDirectiveRecord(CI.getSourceManager()); unsigned ObjCMTAction = CI.getFrontendOpts().ObjCMTAction; @@ -1880,17 +2022,13 @@ ASTConsumer *MigrateSourceAction::CreateASTConsumer(CompilerInstance &CI, ObjCMTAction |= FrontendOptions::ObjCMT_Literals | FrontendOptions::ObjCMT_Subscripting; } - CI.getPreprocessor().addPPCallbacks(PPRec); + CI.getPreprocessor().addPPCallbacks(std::unique_ptr<PPCallbacks>(PPRec)); std::vector<std::string> WhiteList = getWhiteListFilenames(CI.getFrontendOpts().ObjCMTWhiteListPath); - return new ObjCMigrateASTConsumer(CI.getFrontendOpts().OutputFile, - ObjCMTAction, - Remapper, - CI.getFileManager(), - PPRec, - CI.getPreprocessor(), - /*isOutputFile=*/true, - WhiteList); + return llvm::make_unique<ObjCMigrateASTConsumer>( + CI.getFrontendOpts().OutputFile, ObjCMTAction, Remapper, + CI.getFileManager(), PPRec, CI.getPreprocessor(), + /*isOutputFile=*/true, WhiteList); } namespace { @@ -1949,7 +2087,7 @@ public: return true; llvm::SourceMgr SM; - Stream YAMLStream(FileBufOrErr.get().release(), SM); + Stream YAMLStream(FileBufOrErr.get()->getMemBufferRef(), SM); document_iterator I = YAMLStream.begin(); if (I == YAMLStream.end()) return true; diff --git a/lib/ARCMigrate/PlistReporter.cpp b/lib/ARCMigrate/PlistReporter.cpp index 6b34ef0c2b9e..53398b27af49 100644 --- a/lib/ARCMigrate/PlistReporter.cpp +++ b/lib/ARCMigrate/PlistReporter.cpp @@ -56,9 +56,9 @@ void arcmt::writeARCDiagsToPlist(const std::string &outPath, } } - std::string errMsg; - llvm::raw_fd_ostream o(outPath.c_str(), errMsg, llvm::sys::fs::F_Text); - if (!errMsg.empty()) { + std::error_code EC; + llvm::raw_fd_ostream o(outPath, EC, llvm::sys::fs::F_Text); + if (EC) { llvm::errs() << "error: could not create file: " << outPath << '\n'; return; } diff --git a/lib/ARCMigrate/TransformActions.cpp b/lib/ARCMigrate/TransformActions.cpp index 6d178bea0907..9fb2f1d3eea8 100644 --- a/lib/ARCMigrate/TransformActions.cpp +++ b/lib/ARCMigrate/TransformActions.cpp @@ -581,8 +581,7 @@ void TransformActionsImpl::applyRewrites( /// "alive". Since the vast majority of text will be the same, we also unique /// the strings using a StringMap. StringRef TransformActionsImpl::getUniqueText(StringRef text) { - llvm::StringMapEntry<bool> &entry = UniqueText.GetOrCreateValue(text); - return entry.getKey(); + return UniqueText.insert(std::make_pair(text, false)).first->first(); } /// \brief Computes the source location just past the end of the token at diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index 0fa0216d9dac..91f1e20d73b6 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -573,7 +573,7 @@ bool APValue::hasLValuePath() const { ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const { assert(isLValue() && hasLValuePath() && "Invalid accessor"); const LV &LVal = *((const LV*)(const char*)Data.buffer); - return ArrayRef<LValuePathEntry>(LVal.getPath(), LVal.PathLength); + return llvm::makeArrayRef(LVal.getPath(), LVal.PathLength); } unsigned APValue::getLValueCallIndex() const { @@ -623,7 +623,7 @@ ArrayRef<const CXXRecordDecl*> APValue::getMemberPointerPath() const { assert(isMemberPointer() && "Invalid accessor"); const MemberPointerData &MPD = *((const MemberPointerData *)(const char *)Data.buffer); - return ArrayRef<const CXXRecordDecl*>(MPD.getPath(), MPD.PathLength); + return llvm::makeArrayRef(MPD.getPath(), MPD.PathLength); } void APValue::MakeLValue() { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index bccdae91d2eb..6b864d0f0ac2 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -699,9 +699,10 @@ static const LangAS::Map *getAddressSpaceMap(const TargetInfo &T, 1, // opencl_global 2, // opencl_local 3, // opencl_constant - 4, // cuda_device - 5, // cuda_constant - 6 // cuda_shared + 4, // opencl_generic + 5, // cuda_device + 6, // cuda_constant + 7 // cuda_shared }; return &FakeAddrSpaceMap; } else { @@ -722,35 +723,28 @@ static bool isAddrSpaceMapManglingEnabled(const TargetInfo &TI, llvm_unreachable("getAddressSpaceMapMangling() doesn't cover anything."); } -ASTContext::ASTContext(LangOptions& LOpts, SourceManager &SM, +ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, IdentifierTable &idents, SelectorTable &sels, Builtin::Context &builtins) - : FunctionProtoTypes(this_()), - TemplateSpecializationTypes(this_()), - DependentTemplateSpecializationTypes(this_()), - SubstTemplateTemplateParmPacks(this_()), - GlobalNestedNameSpecifier(nullptr), - Int128Decl(nullptr), UInt128Decl(nullptr), Float128StubDecl(nullptr), - BuiltinVaListDecl(nullptr), - ObjCIdDecl(nullptr), ObjCSelDecl(nullptr), ObjCClassDecl(nullptr), - ObjCProtocolClassDecl(nullptr), BOOLDecl(nullptr), - CFConstantStringTypeDecl(nullptr), ObjCInstanceTypeDecl(nullptr), - FILEDecl(nullptr), - jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr), ucontext_tDecl(nullptr), - BlockDescriptorType(nullptr), BlockDescriptorExtendedType(nullptr), - cudaConfigureCallDecl(nullptr), - NullTypeSourceInfo(QualType()), - FirstLocalImport(), LastLocalImport(), - SourceMgr(SM), LangOpts(LOpts), - AddrSpaceMap(nullptr), Target(nullptr), PrintingPolicy(LOpts), - Idents(idents), Selectors(sels), - BuiltinInfo(builtins), - DeclarationNames(*this), - ExternalSource(nullptr), Listener(nullptr), - Comments(SM), CommentsLoaded(false), - CommentCommandTraits(BumpAlloc, LOpts.CommentOpts), - LastSDM(nullptr, 0) -{ + : FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()), + DependentTemplateSpecializationTypes(this_()), + SubstTemplateTemplateParmPacks(this_()), + GlobalNestedNameSpecifier(nullptr), Int128Decl(nullptr), + UInt128Decl(nullptr), Float128StubDecl(nullptr), + BuiltinVaListDecl(nullptr), ObjCIdDecl(nullptr), ObjCSelDecl(nullptr), + ObjCClassDecl(nullptr), ObjCProtocolClassDecl(nullptr), BOOLDecl(nullptr), + CFConstantStringTypeDecl(nullptr), ObjCInstanceTypeDecl(nullptr), + FILEDecl(nullptr), jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr), + ucontext_tDecl(nullptr), BlockDescriptorType(nullptr), + BlockDescriptorExtendedType(nullptr), cudaConfigureCallDecl(nullptr), + FirstLocalImport(), LastLocalImport(), + SourceMgr(SM), LangOpts(LOpts), + SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFile, SM)), + AddrSpaceMap(nullptr), Target(nullptr), PrintingPolicy(LOpts), + Idents(idents), Selectors(sels), BuiltinInfo(builtins), + DeclarationNames(*this), ExternalSource(nullptr), Listener(nullptr), + Comments(SM), CommentsLoaded(false), + CommentCommandTraits(BumpAlloc, LOpts.CommentOpts), LastSDM(nullptr, 0) { TUDecl = TranslationUnitDecl::Create(*this); } @@ -1413,9 +1407,9 @@ std::pair<CharUnits, CharUnits> ASTContext::getTypeInfoInChars(const Type *T) const { if (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(T)) return getConstantArrayInfoInChars(*this, CAT); - std::pair<uint64_t, unsigned> Info = getTypeInfo(T); - return std::make_pair(toCharUnitsFromBits(Info.first), - toCharUnitsFromBits(Info.second)); + TypeInfo Info = getTypeInfo(T); + return std::make_pair(toCharUnitsFromBits(Info.Width), + toCharUnitsFromBits(Info.Align)); } std::pair<CharUnits, CharUnits> @@ -1423,14 +1417,23 @@ ASTContext::getTypeInfoInChars(QualType T) const { return getTypeInfoInChars(T.getTypePtr()); } -std::pair<uint64_t, unsigned> ASTContext::getTypeInfo(const Type *T) const { - TypeInfoMap::iterator it = MemoizedTypeInfo.find(T); - if (it != MemoizedTypeInfo.end()) - return it->second; +bool ASTContext::isAlignmentRequired(const Type *T) const { + return getTypeInfo(T).AlignIsRequired; +} + +bool ASTContext::isAlignmentRequired(QualType T) const { + return isAlignmentRequired(T.getTypePtr()); +} + +TypeInfo ASTContext::getTypeInfo(const Type *T) const { + TypeInfoMap::iterator I = MemoizedTypeInfo.find(T); + if (I != MemoizedTypeInfo.end()) + return I->second; - std::pair<uint64_t, unsigned> Info = getTypeInfoImpl(T); - MemoizedTypeInfo.insert(std::make_pair(T, Info)); - return Info; + // This call can invalidate MemoizedTypeInfo[T], so we need a second lookup. + TypeInfo TI = getTypeInfoImpl(T); + MemoizedTypeInfo[T] = TI; + return TI; } /// getTypeInfoImpl - Return the size of the specified type, in bits. This @@ -1439,10 +1442,10 @@ std::pair<uint64_t, unsigned> ASTContext::getTypeInfo(const Type *T) const { /// FIXME: Pointers into different addr spaces could have different sizes and /// alignment requirements: getPointerInfo should take an AddrSpace, this /// should take a QualType, &c. -std::pair<uint64_t, unsigned> -ASTContext::getTypeInfoImpl(const Type *T) const { - uint64_t Width=0; - unsigned Align=8; +TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { + uint64_t Width = 0; + unsigned Align = 8; + bool AlignIsRequired = false; switch (T->getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) @@ -1471,12 +1474,12 @@ ASTContext::getTypeInfoImpl(const Type *T) const { case Type::ConstantArray: { const ConstantArrayType *CAT = cast<ConstantArrayType>(T); - std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(CAT->getElementType()); + TypeInfo EltInfo = getTypeInfo(CAT->getElementType()); uint64_t Size = CAT->getSize().getZExtValue(); - assert((Size == 0 || EltInfo.first <= (uint64_t)(-1)/Size) && + assert((Size == 0 || EltInfo.Width <= (uint64_t)(-1) / Size) && "Overflow in array type bit size evaluation"); - Width = EltInfo.first*Size; - Align = EltInfo.second; + Width = EltInfo.Width * Size; + Align = EltInfo.Align; if (!getTargetInfo().getCXXABI().isMicrosoft() || getTargetInfo().getPointerWidth(0) == 64) Width = llvm::RoundUpToAlignment(Width, Align); @@ -1485,8 +1488,8 @@ ASTContext::getTypeInfoImpl(const Type *T) const { case Type::ExtVector: case Type::Vector: { const VectorType *VT = cast<VectorType>(T); - std::pair<uint64_t, unsigned> EltInfo = getTypeInfo(VT->getElementType()); - Width = EltInfo.first*VT->getNumElements(); + TypeInfo EltInfo = getTypeInfo(VT->getElementType()); + Width = EltInfo.Width * VT->getNumElements(); Align = Width; // If the alignment is not a power of 2, round up to the next power of 2. // This happens for non-power-of-2 length vectors. @@ -1638,10 +1641,9 @@ ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Complex: { // Complex types have the same alignment as their elements, but twice the // size. - std::pair<uint64_t, unsigned> EltInfo = - getTypeInfo(cast<ComplexType>(T)->getElementType()); - Width = EltInfo.first*2; - Align = EltInfo.second; + TypeInfo EltInfo = getTypeInfo(cast<ComplexType>(T)->getElementType()); + Width = EltInfo.Width * 2; + Align = EltInfo.Align; break; } case Type::ObjCObject: @@ -1692,16 +1694,18 @@ ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Typedef: { const TypedefNameDecl *Typedef = cast<TypedefType>(T)->getDecl(); - std::pair<uint64_t, unsigned> Info - = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); + TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); // If the typedef has an aligned attribute on it, it overrides any computed // alignment we have. This violates the GCC documentation (which says that // attribute(aligned) can only round up) but matches its implementation. - if (unsigned AttrAlign = Typedef->getMaxAlignment()) + if (unsigned AttrAlign = Typedef->getMaxAlignment()) { Align = AttrAlign; - else - Align = Info.second; - Width = Info.first; + AlignIsRequired = true; + } else { + Align = Info.Align; + AlignIsRequired = Info.AlignIsRequired; + } + Width = Info.Width; break; } @@ -1714,10 +1718,9 @@ ASTContext::getTypeInfoImpl(const Type *T) const { case Type::Atomic: { // Start with the base type information. - std::pair<uint64_t, unsigned> Info - = getTypeInfo(cast<AtomicType>(T)->getValueType()); - Width = Info.first; - Align = Info.second; + TypeInfo Info = getTypeInfo(cast<AtomicType>(T)->getValueType()); + Width = Info.Width; + Align = Info.Align; // If the size of the type doesn't exceed the platform's max // atomic promotion width, make the size and alignment more @@ -1735,7 +1738,7 @@ ASTContext::getTypeInfoImpl(const Type *T) const { } assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2"); - return std::make_pair(Width, Align); + return TypeInfo(Width, Align, AlignIsRequired); } /// toCharUnitsFromBits - Convert a size in bits to a size in characters. @@ -1771,13 +1774,12 @@ CharUnits ASTContext::getTypeAlignInChars(const Type *T) const { /// alignment in cases where it is beneficial for performance to overalign /// a data type. unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { - unsigned ABIAlign = getTypeAlign(T); + TypeInfo TI = getTypeInfo(T); + unsigned ABIAlign = TI.Align; if (Target->getTriple().getArch() == llvm::Triple::xcore) return ABIAlign; // Never overalign on XCore. - const TypedefType *TT = T->getAs<TypedefType>(); - // Double and long long should be naturally aligned if possible. T = T->getBaseElementTypeUnsafe(); if (const ComplexType *CT = T->getAs<ComplexType>()) @@ -1787,7 +1789,7 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { T->isSpecificBuiltinType(BuiltinType::ULongLong)) // Don't increase the alignment if an alignment attribute was specified on a // typedef declaration. - if (!TT || !TT->getDecl()->getMaxAlignment()) + if (!TI.AlignIsRequired) return std::max(ABIAlign, (unsigned)getTypeSize(T)); return ABIAlign; @@ -2110,6 +2112,62 @@ void ASTContext::adjustDeducedFunctionResultType(FunctionDecl *FD, L->DeducedReturnType(FD, ResultType); } +/// Get a function type and produce the equivalent function type with the +/// specified exception specification. Type sugar that can be present on a +/// declaration of a function with an exception specification is permitted +/// and preserved. Other type sugar (for instance, typedefs) is not. +static QualType getFunctionTypeWithExceptionSpec( + ASTContext &Context, QualType Orig, + const FunctionProtoType::ExceptionSpecInfo &ESI) { + // Might have some parens. + if (auto *PT = dyn_cast<ParenType>(Orig)) + return Context.getParenType( + getFunctionTypeWithExceptionSpec(Context, PT->getInnerType(), ESI)); + + // Might have a calling-convention attribute. + if (auto *AT = dyn_cast<AttributedType>(Orig)) + return Context.getAttributedType( + AT->getAttrKind(), + getFunctionTypeWithExceptionSpec(Context, AT->getModifiedType(), ESI), + getFunctionTypeWithExceptionSpec(Context, AT->getEquivalentType(), + ESI)); + + // Anything else must be a function type. Rebuild it with the new exception + // specification. + const FunctionProtoType *Proto = cast<FunctionProtoType>(Orig); + return Context.getFunctionType( + Proto->getReturnType(), Proto->getParamTypes(), + Proto->getExtProtoInfo().withExceptionSpec(ESI)); +} + +void ASTContext::adjustExceptionSpec( + FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI, + bool AsWritten) { + // Update the type. + QualType Updated = + getFunctionTypeWithExceptionSpec(*this, FD->getType(), ESI); + FD->setType(Updated); + + if (!AsWritten) + return; + + // Update the type in the type source information too. + if (TypeSourceInfo *TSInfo = FD->getTypeSourceInfo()) { + // If the type and the type-as-written differ, we may need to update + // the type-as-written too. + if (TSInfo->getType() != FD->getType()) + Updated = getFunctionTypeWithExceptionSpec(*this, TSInfo->getType(), ESI); + + // FIXME: When we get proper type location information for exceptions, + // we'll also have to rebuild the TypeSourceInfo. For now, we just patch + // up the TypeSourceInfo; + assert(TypeLoc::getFullDataSizeForType(Updated) == + TypeLoc::getFullDataSizeForType(TSInfo->getType()) && + "TypeLoc size mismatch from updating exception specification"); + TSInfo->overrideType(Updated); + } +} + /// getComplexType - Return the uniqued reference to the type for a complex /// number with the specified element type. QualType ASTContext::getComplexType(QualType T) const { @@ -2840,7 +2898,7 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray, // Determine whether the type being created is already canonical or not. bool isCanonical = - EPI.ExceptionSpecType == EST_None && isCanonicalResultType(ResultTy) && + EPI.ExceptionSpec.Type == EST_None && isCanonicalResultType(ResultTy) && !EPI.HasTrailingReturn; for (unsigned i = 0; i != NumArgs && isCanonical; ++i) if (!ArgArray[i].isCanonicalAsParam()) @@ -2857,8 +2915,7 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray, FunctionProtoType::ExtProtoInfo CanonicalEPI = EPI; CanonicalEPI.HasTrailingReturn = false; - CanonicalEPI.ExceptionSpecType = EST_None; - CanonicalEPI.NumExceptions = 0; + CanonicalEPI.ExceptionSpec = FunctionProtoType::ExceptionSpecInfo(); // Result types do not have ARC lifetime qualifiers. QualType CanResultTy = getCanonicalType(ResultTy); @@ -2886,13 +2943,13 @@ ASTContext::getFunctionType(QualType ResultTy, ArrayRef<QualType> ArgArray, // specification. size_t Size = sizeof(FunctionProtoType) + NumArgs * sizeof(QualType); - if (EPI.ExceptionSpecType == EST_Dynamic) { - Size += EPI.NumExceptions * sizeof(QualType); - } else if (EPI.ExceptionSpecType == EST_ComputedNoexcept) { + if (EPI.ExceptionSpec.Type == EST_Dynamic) { + Size += EPI.ExceptionSpec.Exceptions.size() * sizeof(QualType); + } else if (EPI.ExceptionSpec.Type == EST_ComputedNoexcept) { Size += sizeof(Expr*); - } else if (EPI.ExceptionSpecType == EST_Uninstantiated) { + } else if (EPI.ExceptionSpec.Type == EST_Uninstantiated) { Size += 2 * sizeof(FunctionDecl*); - } else if (EPI.ExceptionSpecType == EST_Unevaluated) { + } else if (EPI.ExceptionSpec.Type == EST_Unevaluated) { Size += sizeof(FunctionDecl*); } if (EPI.ConsumedParameters) @@ -4099,7 +4156,7 @@ ASTContext::getCanonicalTemplateArgument(const TemplateArgument &Arg) const { case TemplateArgument::Declaration: { ValueDecl *D = cast<ValueDecl>(Arg.getAsDecl()->getCanonicalDecl()); - return TemplateArgument(D, Arg.isDeclForReferenceParam()); + return TemplateArgument(D, Arg.getParamTypeForDecl()); } case TemplateArgument::NullPtr: @@ -4188,7 +4245,8 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { } case NestedNameSpecifier::Global: - // The global specifier is canonical and unique. + case NestedNameSpecifier::Super: + // The global specifier and __super specifer are canonical and unique. return NNS; } @@ -4414,7 +4472,11 @@ unsigned ASTContext::getIntegerRank(const Type *T) const { QualType ASTContext::isPromotableBitField(Expr *E) const { if (E->isTypeDependent() || E->isValueDependent()) return QualType(); - + + // FIXME: We should not do this unless E->refersToBitField() is true. This + // matters in C where getSourceBitField() will find bit-fields for various + // cases where the source expression is not a bit-field designator. + FieldDecl *Field = E->getSourceBitField(); // FIXME: conditional bit-fields? if (!Field) return QualType(); @@ -4423,9 +4485,20 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { uint64_t BitWidth = Field->getBitWidthValue(*this); uint64_t IntSize = getTypeSize(IntTy); - // GCC extension compatibility: if the bit-field size is less than or equal - // to the size of int, it gets promoted no matter what its type is. - // For instance, unsigned long bf : 4 gets promoted to signed int. + // C++ [conv.prom]p5: + // A prvalue for an integral bit-field can be converted to a prvalue of type + // int if int can represent all the values of the bit-field; otherwise, it + // can be converted to unsigned int if unsigned int can represent all the + // values of the bit-field. If the bit-field is larger yet, no integral + // promotion applies to it. + // C11 6.3.1.1/2: + // [For a bit-field of type _Bool, int, signed int, or unsigned int:] + // If an int can represent all values of the original type (as restricted by + // the width, for a bit-field), the value is converted to an int; otherwise, + // it is converted to an unsigned int. + // + // FIXME: C does not permit promotion of a 'long : 3' bitfield to int. + // We perform that promotion here to match GCC and C++. if (BitWidth < IntSize) return IntTy; @@ -4433,9 +4506,10 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { return FT->isSignedIntegerType() ? IntTy : UnsignedIntTy; // Types bigger than int are not subject to promotions, and therefore act - // like the base type. - // FIXME: This doesn't quite match what gcc does, but what gcc does here - // is ridiculous. + // like the base type. GCC has some weird bugs in this area that we + // deliberately do not follow (GCC follows a pre-standard resolution to + // C's DR315 which treats bit-width as being part of the type, and this leaks + // into their semantics in some cases). return QualType(); } @@ -5090,13 +5164,15 @@ void ASTContext::getLegacyIntegralTypeEncoding (QualType &PointeeTy) const { } void ASTContext::getObjCEncodingForType(QualType T, std::string& S, - const FieldDecl *Field) const { + const FieldDecl *Field, + QualType *NotEncodedT) const { // We follow the behavior of gcc, expanding structures which are // directly pointed to, and expanding embedded structures. Note that // these rules are sufficient to prevent recursive encoding of the // same type. getObjCEncodingForTypeImpl(T, S, true, true, Field, - true /* outermost type */); + true /* outermost type */, false, false, + false, false, false, NotEncodedT); } void ASTContext::getObjCEncodingForPropertyType(QualType T, @@ -5222,7 +5298,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, bool StructField, bool EncodeBlockParameters, bool EncodeClassNames, - bool EncodePointerToObjCTypedef) const { + bool EncodePointerToObjCTypedef, + QualType *NotEncodedT) const { CanQualType CT = getCanonicalType(T); switch (CT->getTypeClass()) { case Type::Builtin: @@ -5238,16 +5315,14 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, case Type::Complex: { const ComplexType *CT = T->castAs<ComplexType>(); S += 'j'; - getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, nullptr, - false, false); + getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, nullptr); return; } case Type::Atomic: { const AtomicType *AT = T->castAs<AtomicType>(); S += 'A'; - getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, nullptr, - false, false); + getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, nullptr); return; } @@ -5318,7 +5393,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, getLegacyIntegralTypeEncoding(PointeeTy); getObjCEncodingForTypeImpl(PointeeTy, S, false, ExpandPointedToStructures, - nullptr); + nullptr, false, false, false, false, false, false, + NotEncodedT); return; } @@ -5346,7 +5422,9 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, } getObjCEncodingForTypeImpl(AT->getElementType(), S, - false, ExpandStructures, FD); + false, ExpandStructures, FD, + false, false, false, false, false, false, + NotEncodedT); S += ']'; } return; @@ -5378,7 +5456,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, if (ExpandStructures) { S += '='; if (!RDecl->isUnion()) { - getObjCEncodingForStructureImpl(RDecl, S, FD); + getObjCEncodingForStructureImpl(RDecl, S, FD, true, NotEncodedT); } else { for (const auto *Field : RDecl->fields()) { if (FD) { @@ -5397,7 +5475,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, getObjCEncodingForTypeImpl(qt, S, false, true, FD, /*OutermostType*/false, /*EncodingProperty*/false, - /*StructField*/true); + /*StructField*/true, + false, false, false, NotEncodedT); } } } @@ -5417,7 +5496,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, getObjCEncodingForTypeImpl( FT->getReturnType(), S, ExpandPointedToStructures, ExpandStructures, FD, false /* OutermostType */, EncodingProperty, - false /* StructField */, EncodeBlockParameters, EncodeClassNames); + false /* StructField */, EncodeBlockParameters, EncodeClassNames, false, + NotEncodedT); // Block self S += "@?"; // Block parameters @@ -5426,7 +5506,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, getObjCEncodingForTypeImpl( I, S, ExpandPointedToStructures, ExpandStructures, FD, false /* OutermostType */, EncodingProperty, - false /* StructField */, EncodeBlockParameters, EncodeClassNames); + false /* StructField */, EncodeBlockParameters, EncodeClassNames, + false, NotEncodedT); } S += '>'; } @@ -5468,7 +5549,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, else getObjCEncodingForTypeImpl(Field->getType(), S, false, true, FD, false, false, false, false, false, - EncodePointerToObjCTypedef); + EncodePointerToObjCTypedef, + NotEncodedT); } S += '}'; return; @@ -5555,19 +5637,21 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, // gcc just blithely ignores member pointers. // FIXME: we shoul do better than that. 'M' is available. case Type::MemberPointer: - return; - + // This matches gcc's encoding, even though technically it is insufficient. + //FIXME. We should do a better job than gcc. case Type::Vector: case Type::ExtVector: - // This matches gcc's encoding, even though technically it is - // insufficient. - // FIXME. We should do a better job than gcc. - return; - + // Until we have a coherent encoding of these three types, issue warning. + { if (NotEncodedT) + *NotEncodedT = T; + return; + } + + // We could see an undeduced auto type here during error recovery. + // Just ignore it. case Type::Auto: - // We could see an undeduced auto type here during error recovery. - // Just ignore it. return; + #define ABSTRACT_TYPE(KIND, BASE) #define TYPE(KIND, BASE) @@ -5586,7 +5670,8 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string& S, void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, std::string &S, const FieldDecl *FD, - bool includeVBases) const { + bool includeVBases, + QualType *NotEncodedT) const { assert(RDecl && "Expected non-null RecordDecl"); assert(!RDecl->isUnion() && "Should not be called for unions"); if (!RDecl->getDefinition()) @@ -5610,12 +5695,11 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, } unsigned i = 0; - for (RecordDecl::field_iterator Field = RDecl->field_begin(), - FieldEnd = RDecl->field_end(); - Field != FieldEnd; ++Field, ++i) { + for (auto *Field : RDecl->fields()) { uint64_t offs = layout.getFieldOffset(i); FieldOrBaseOffsets.insert(FieldOrBaseOffsets.upper_bound(offs), - std::make_pair(offs, *Field)); + std::make_pair(offs, Field)); + ++i; } if (CXXRec && includeVBases) { @@ -5691,7 +5775,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, // in the initial structure. Note that this differs from gcc which // expands virtual bases each time one is encountered in the hierarchy, // making the encoding type bigger than it really is. - getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false); + getObjCEncodingForStructureImpl(base, S, FD, /*includeVBases*/false, + NotEncodedT); assert(!base->isEmpty()); #ifndef NDEBUG CurOffs += toBits(getASTRecordLayout(base).getNonVirtualSize()); @@ -5715,7 +5800,8 @@ void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl, getObjCEncodingForTypeImpl(qt, S, false, true, FD, /*OutermostType*/false, /*EncodingProperty*/false, - /*StructField*/true); + /*StructField*/true, + false, false, false, NotEncodedT); #ifndef NDEBUG CurOffs += getTypeSize(field->getType()); #endif @@ -6654,11 +6740,9 @@ void getIntersectionOfProtocols(ASTContext &Context, llvm::SmallPtrSet<ObjCProtocolDecl *, 8> RHSInheritedProtocols; Context.CollectInheritedProtocols(RHS->getInterface(), RHSInheritedProtocols); - for (llvm::SmallPtrSet<ObjCProtocolDecl*,8>::iterator I = - RHSInheritedProtocols.begin(), - E = RHSInheritedProtocols.end(); I != E; ++I) - if (InheritedProtocolSet.count((*I))) - IntersectionOfProtocols.push_back((*I)); + for (ObjCProtocolDecl *ProtDecl : RHSInheritedProtocols) + if (InheritedProtocolSet.count(ProtDecl)) + IntersectionOfProtocols.push_back(ProtDecl); } } @@ -6708,58 +6792,40 @@ bool ASTContext::canAssignObjCInterfaces(const ObjCObjectType *LHS, if (LHS->getNumProtocols() == 0) return true; - // Okay, we know the LHS has protocol qualifiers. If the RHS doesn't, - // more detailed analysis is required. - if (RHS->getNumProtocols() == 0) { - // OK, if LHS is a superclass of RHS *and* - // this superclass is assignment compatible with LHS. - // false otherwise. - bool IsSuperClass = - LHS->getInterface()->isSuperClassOf(RHS->getInterface()); - if (IsSuperClass) { - // OK if conversion of LHS to SuperClass results in narrowing of types - // ; i.e., SuperClass may implement at least one of the protocols - // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok. - // But not SuperObj<P1,P2,P3> = lhs<P1,P2>. - llvm::SmallPtrSet<ObjCProtocolDecl *, 8> SuperClassInheritedProtocols; - CollectInheritedProtocols(RHS->getInterface(), SuperClassInheritedProtocols); - // If super class has no protocols, it is not a match. - if (SuperClassInheritedProtocols.empty()) - return false; + // Okay, we know the LHS has protocol qualifiers. But RHS may or may not. + // More detailed analysis is required. + // OK, if LHS is same or a superclass of RHS *and* + // this LHS, or as RHS's super class is assignment compatible with LHS. + bool IsSuperClass = + LHS->getInterface()->isSuperClassOf(RHS->getInterface()); + if (IsSuperClass) { + // OK if conversion of LHS to SuperClass results in narrowing of types + // ; i.e., SuperClass may implement at least one of the protocols + // in LHS's protocol list. Example, SuperObj<P1> = lhs<P1,P2> is ok. + // But not SuperObj<P1,P2,P3> = lhs<P1,P2>. + llvm::SmallPtrSet<ObjCProtocolDecl *, 8> SuperClassInheritedProtocols; + CollectInheritedProtocols(RHS->getInterface(), SuperClassInheritedProtocols); + // Also, if RHS has explicit quelifiers, include them for comparing with LHS's + // qualifiers. + for (auto *RHSPI : RHS->quals()) + SuperClassInheritedProtocols.insert(RHSPI->getCanonicalDecl()); + // If there is no protocols associated with RHS, it is not a match. + if (SuperClassInheritedProtocols.empty()) + return false; - for (const auto *LHSProto : LHS->quals()) { - bool SuperImplementsProtocol = false; - for (auto *SuperClassProto : SuperClassInheritedProtocols) { - if (SuperClassProto->lookupProtocolNamed(LHSProto->getIdentifier())) { - SuperImplementsProtocol = true; - break; - } + for (const auto *LHSProto : LHS->quals()) { + bool SuperImplementsProtocol = false; + for (auto *SuperClassProto : SuperClassInheritedProtocols) + if (SuperClassProto->lookupProtocolNamed(LHSProto->getIdentifier())) { + SuperImplementsProtocol = true; + break; } - if (!SuperImplementsProtocol) - return false; - } - return true; - } - return false; - } - - for (const auto *LHSPI : LHS->quals()) { - bool RHSImplementsProtocol = false; - - // If the RHS doesn't implement the protocol on the left, the types - // are incompatible. - for (auto *RHSPI : RHS->quals()) { - if (RHSPI->lookupProtocolNamed(LHSPI->getIdentifier())) { - RHSImplementsProtocol = true; - break; - } + if (!SuperImplementsProtocol) + return false; } - // FIXME: For better diagnostics, consider passing back the protocol name. - if (!RHSImplementsProtocol) - return false; + return true; } - // The RHS implements all protocols listed on the LHS. - return true; + return false; } bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) { @@ -7895,7 +7961,9 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { // We never need to emit an uninstantiated function template. if (FD->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) return false; - } else + } else if (isa<OMPThreadPrivateDecl>(D)) + return true; + else return false; // If this is a member of a class template, we do not need to emit it. @@ -8236,7 +8304,7 @@ namespace { } // end namespace -ASTContext::ParentVector +ArrayRef<ast_type_traits::DynTypedNode> ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) { assert(Node.getMemoizationData() && "Invariant broken: only nodes that support memoization may be " @@ -8249,13 +8317,12 @@ ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) { } ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData()); if (I == AllParents->end()) { - return ParentVector(); + return None; } - if (I->second.is<ast_type_traits::DynTypedNode *>()) { - return ParentVector(1, *I->second.get<ast_type_traits::DynTypedNode *>()); + if (auto *N = I->second.dyn_cast<ast_type_traits::DynTypedNode *>()) { + return llvm::makeArrayRef(N, 1); } - const auto &Parents = *I->second.get<ParentVector *>(); - return ParentVector(Parents.begin(), Parents.end()); + return *I->second.get<ParentVector *>(); } bool diff --git a/lib/AST/ASTDiagnostic.cpp b/lib/AST/ASTDiagnostic.cpp index 8c8b1dff0cbf..3212359db183 100644 --- a/lib/AST/ASTDiagnostic.cpp +++ b/lib/AST/ASTDiagnostic.cpp @@ -342,26 +342,22 @@ void clang::FormatASTNodeDiagnosticArgument( assert(DC && "Should never have a null declaration context"); NeedQuotes = false; + // FIXME: Get the strings for DeclContext from some localized place if (DC->isTranslationUnit()) { - // FIXME: Get these strings from some localized place if (Context.getLangOpts().CPlusPlus) OS << "the global namespace"; else OS << "the global scope"; + } else if (DC->isClosure()) { + OS << "block literal"; + } else if (isLambdaCallOperator(DC)) { + OS << "lambda expression"; } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) { OS << ConvertTypeToDiagnosticString(Context, Context.getTypeDeclType(Type), PrevArgs, QualTypeVals); } else { - // FIXME: Get these strings from some localized place - if (isa<BlockDecl>(DC)) { - OS << "block literal"; - break; - } - if (isLambdaCallOperator(DC)) { - OS << "lambda expression"; - break; - } + assert(isa<NamedDecl>(DC) && "Expected a NamedDecl"); NamedDecl *ND = cast<NamedDecl>(DC); if (isa<NamespaceDecl>(ND)) OS << "namespace "; @@ -877,6 +873,194 @@ class TemplateDiff { return Ty->getAs<TemplateSpecializationType>(); } + /// DiffTypes - Fills a DiffNode with information about a type difference. + void DiffTypes(const TSTiterator &FromIter, const TSTiterator &ToIter, + TemplateTypeParmDecl *FromDefaultTypeDecl, + TemplateTypeParmDecl *ToDefaultTypeDecl) { + QualType FromType = GetType(FromIter, FromDefaultTypeDecl); + QualType ToType = GetType(ToIter, ToDefaultTypeDecl); + + Tree.SetNode(FromType, ToType); + Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(), + ToIter.isEnd() && !ToType.isNull()); + Tree.SetKind(DiffTree::Type); + if (FromType.isNull() || ToType.isNull()) + return; + + if (Context.hasSameType(FromType, ToType)) { + Tree.SetSame(true); + return; + } + + const TemplateSpecializationType *FromArgTST = + GetTemplateSpecializationType(Context, FromType); + if (!FromArgTST) + return; + + const TemplateSpecializationType *ToArgTST = + GetTemplateSpecializationType(Context, ToType); + if (!ToArgTST) + return; + + if (!hasSameTemplate(FromArgTST, ToArgTST)) + return; + + Qualifiers FromQual = FromType.getQualifiers(), + ToQual = ToType.getQualifiers(); + FromQual -= QualType(FromArgTST, 0).getQualifiers(); + ToQual -= QualType(ToArgTST, 0).getQualifiers(); + Tree.SetNode(FromArgTST->getTemplateName().getAsTemplateDecl(), + ToArgTST->getTemplateName().getAsTemplateDecl()); + Tree.SetNode(FromQual, ToQual); + Tree.SetKind(DiffTree::Template); + DiffTemplate(FromArgTST, ToArgTST); + } + + /// DiffTemplateTemplates - Fills a DiffNode with information about a + /// template template difference. + void DiffTemplateTemplates(const TSTiterator &FromIter, + const TSTiterator &ToIter, + TemplateTemplateParmDecl *FromDefaultTemplateDecl, + TemplateTemplateParmDecl *ToDefaultTemplateDecl) { + TemplateDecl *FromDecl = GetTemplateDecl(FromIter, FromDefaultTemplateDecl); + TemplateDecl *ToDecl = GetTemplateDecl(ToIter, ToDefaultTemplateDecl); + Tree.SetNode(FromDecl, ToDecl); + Tree.SetSame(FromDecl && ToDecl && + FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl()); + Tree.SetDefault(FromIter.isEnd() && FromDecl, ToIter.isEnd() && ToDecl); + Tree.SetKind(DiffTree::TemplateTemplate); + } + + /// InitializeNonTypeDiffVariables - Helper function for DiffNonTypes + static void InitializeNonTypeDiffVariables( + ASTContext &Context, const TSTiterator &Iter, + NonTypeTemplateParmDecl *Default, bool &HasInt, bool &HasValueDecl, + bool &IsNullPtr, Expr *&E, llvm::APSInt &Value, ValueDecl *&VD) { + HasInt = !Iter.isEnd() && Iter->getKind() == TemplateArgument::Integral; + + HasValueDecl = + !Iter.isEnd() && Iter->getKind() == TemplateArgument::Declaration; + + IsNullPtr = !Iter.isEnd() && Iter->getKind() == TemplateArgument::NullPtr; + + if (HasInt) + Value = Iter->getAsIntegral(); + else if (HasValueDecl) + VD = Iter->getAsDecl(); + else if (!IsNullPtr) + E = GetExpr(Iter, Default); + + if (E && Default->getType()->isPointerType()) + IsNullPtr = CheckForNullPtr(Context, E); + } + + /// NeedsAddressOf - Helper function for DiffNonTypes. Returns true if the + /// ValueDecl needs a '&' when printed. + static bool NeedsAddressOf(ValueDecl *VD, Expr *E, + NonTypeTemplateParmDecl *Default) { + if (!VD) + return false; + + if (E) { + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParens())) { + if (UO->getOpcode() == UO_AddrOf) { + return true; + } + } + return false; + } + + if (!Default->getType()->isReferenceType()) { + return true; + } + + return false; + } + + /// DiffNonTypes - Handles any template parameters not handled by DiffTypes + /// of DiffTemplatesTemplates, such as integer and declaration parameters. + void DiffNonTypes(const TSTiterator &FromIter, const TSTiterator &ToIter, + NonTypeTemplateParmDecl *FromDefaultNonTypeDecl, + NonTypeTemplateParmDecl *ToDefaultNonTypeDecl) { + Expr *FromExpr = nullptr, *ToExpr = nullptr; + llvm::APSInt FromInt, ToInt; + ValueDecl *FromValueDecl = nullptr, *ToValueDecl = nullptr; + bool HasFromInt = false, HasToInt = false, HasFromValueDecl = false, + HasToValueDecl = false, FromNullPtr = false, ToNullPtr = false; + InitializeNonTypeDiffVariables(Context, FromIter, FromDefaultNonTypeDecl, + HasFromInt, HasFromValueDecl, FromNullPtr, + FromExpr, FromInt, FromValueDecl); + InitializeNonTypeDiffVariables(Context, ToIter, ToDefaultNonTypeDecl, + HasToInt, HasToValueDecl, ToNullPtr, + ToExpr, ToInt, ToValueDecl); + + assert(((!HasFromInt && !HasToInt) || + (!HasFromValueDecl && !HasToValueDecl)) && + "Template argument cannot be both integer and declaration"); + + unsigned ParamWidth = 128; // Safe default + if (FromDefaultNonTypeDecl->getType()->isIntegralOrEnumerationType()) + ParamWidth = Context.getIntWidth(FromDefaultNonTypeDecl->getType()); + + if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) { + Tree.SetNode(FromExpr, ToExpr); + Tree.SetDefault(FromIter.isEnd() && FromExpr, ToIter.isEnd() && ToExpr); + if (FromDefaultNonTypeDecl->getType()->isIntegralOrEnumerationType()) { + if (FromExpr) + HasFromInt = GetInt(Context, FromIter, FromExpr, FromInt); + if (ToExpr) + HasToInt = GetInt(Context, ToIter, ToExpr, ToInt); + } + if (HasFromInt && HasToInt) { + Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt); + Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt)); + Tree.SetKind(DiffTree::Integer); + } else if (HasFromInt || HasToInt) { + Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt); + Tree.SetSame(false); + Tree.SetKind(DiffTree::Integer); + } else { + Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr) || + (FromNullPtr && ToNullPtr)); + Tree.SetNullPtr(FromNullPtr, ToNullPtr); + Tree.SetKind(DiffTree::Expression); + } + return; + } + + if (HasFromInt || HasToInt) { + if (!HasFromInt && FromExpr) + HasFromInt = GetInt(Context, FromIter, FromExpr, FromInt); + if (!HasToInt && ToExpr) + HasToInt = GetInt(Context, ToIter, ToExpr, ToInt); + Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt); + Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt)); + Tree.SetDefault(FromIter.isEnd() && HasFromInt, + ToIter.isEnd() && HasToInt); + Tree.SetKind(DiffTree::Integer); + return; + } + + if (!HasFromValueDecl && FromExpr) + FromValueDecl = GetValueDecl(FromIter, FromExpr); + if (!HasToValueDecl && ToExpr) + ToValueDecl = GetValueDecl(ToIter, ToExpr); + + bool FromAddressOf = + NeedsAddressOf(FromValueDecl, FromExpr, FromDefaultNonTypeDecl); + bool ToAddressOf = + NeedsAddressOf(ToValueDecl, ToExpr, ToDefaultNonTypeDecl); + + Tree.SetNullPtr(FromNullPtr, ToNullPtr); + Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf); + Tree.SetSame(FromValueDecl && ToValueDecl && + FromValueDecl->getCanonicalDecl() == + ToValueDecl->getCanonicalDecl()); + Tree.SetDefault(FromIter.isEnd() && FromValueDecl, + ToIter.isEnd() && ToValueDecl); + Tree.SetKind(DiffTree::Declaration); + } + /// DiffTemplate - recursively visits template arguments and stores the /// argument info into a tree. void DiffTemplate(const TemplateSpecializationType *FromTST, @@ -894,191 +1078,33 @@ class TemplateDiff { // Get the parameter at index TotalArgs. If index is larger // than the total number of parameters, then there is an // argument pack, so re-use the last parameter. - unsigned ParamIndex = std::min(TotalArgs, ParamsFrom->size() - 1); - NamedDecl *ParamND = ParamsFrom->getParam(ParamIndex); - - // Handle Types - if (TemplateTypeParmDecl *DefaultTTPD = - dyn_cast<TemplateTypeParmDecl>(ParamND)) { - QualType FromType, ToType; - FromType = GetType(FromIter, DefaultTTPD); - // A forward declaration can have no default arg but the actual class - // can, don't mix up iterators and get the original parameter. - ToType = GetType( - ToIter, cast<TemplateTypeParmDecl>(ParamsTo->getParam(ParamIndex))); - Tree.SetNode(FromType, ToType); - Tree.SetDefault(FromIter.isEnd() && !FromType.isNull(), - ToIter.isEnd() && !ToType.isNull()); - Tree.SetKind(DiffTree::Type); - if (!FromType.isNull() && !ToType.isNull()) { - 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 && - 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); - Tree.SetKind(DiffTree::Template); - DiffTemplate(FromArgTST, ToArgTST); - } - } - } - } - - // Handle Expressions - if (NonTypeTemplateParmDecl *DefaultNTTPD = - dyn_cast<NonTypeTemplateParmDecl>(ParamND)) { - Expr *FromExpr = nullptr, *ToExpr = nullptr; - llvm::APSInt FromInt, ToInt; - ValueDecl *FromValueDecl = nullptr, *ToValueDecl = nullptr; - unsigned ParamWidth = 128; // Safe default - if (DefaultNTTPD->getType()->isIntegralOrEnumerationType()) - ParamWidth = Context.getIntWidth(DefaultNTTPD->getType()); - bool HasFromInt = !FromIter.isEnd() && - FromIter->getKind() == TemplateArgument::Integral; - bool HasToInt = !ToIter.isEnd() && - ToIter->getKind() == TemplateArgument::Integral; - bool HasFromValueDecl = - !FromIter.isEnd() && - FromIter->getKind() == TemplateArgument::Declaration; - bool HasToValueDecl = - !ToIter.isEnd() && - ToIter->getKind() == TemplateArgument::Declaration; - bool FromNullPtr = !FromIter.isEnd() && - FromIter->getKind() == TemplateArgument::NullPtr; - bool ToNullPtr = - !ToIter.isEnd() && ToIter->getKind() == TemplateArgument::NullPtr; - - assert(((!HasFromInt && !HasToInt) || - (!HasFromValueDecl && !HasToValueDecl)) && - "Template argument cannot be both integer and declaration"); - - if (HasFromInt) - FromInt = FromIter->getAsIntegral(); - else if (HasFromValueDecl) - FromValueDecl = FromIter->getAsDecl(); - else if (!FromNullPtr) - FromExpr = GetExpr(FromIter, DefaultNTTPD); - - if (HasToInt) - ToInt = ToIter->getAsIntegral(); - else if (HasToValueDecl) - ToValueDecl = ToIter->getAsDecl(); - else if (!ToNullPtr) - ToExpr = GetExpr(ToIter, DefaultNTTPD); - - bool TemplateArgumentIsPointerType = - DefaultNTTPD->getType()->isPointerType(); - if (FromExpr && TemplateArgumentIsPointerType) { - FromNullPtr = CheckForNullPtr(FromExpr); - } - if (ToExpr && TemplateArgumentIsPointerType) { - ToNullPtr = CheckForNullPtr(ToExpr); - } - - if (!HasFromInt && !HasToInt && !HasFromValueDecl && !HasToValueDecl) { - Tree.SetNode(FromExpr, ToExpr); - Tree.SetDefault(FromIter.isEnd() && FromExpr, - ToIter.isEnd() && ToExpr); - if (DefaultNTTPD->getType()->isIntegralOrEnumerationType()) { - if (FromExpr) - HasFromInt = GetInt(FromIter, FromExpr, FromInt); - if (ToExpr) - HasToInt = GetInt(ToIter, ToExpr, ToInt); - } - if (HasFromInt && HasToInt) { - Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt); - Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt)); - Tree.SetKind(DiffTree::Integer); - } else if (HasFromInt || HasToInt) { - Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt); - Tree.SetSame(false); - Tree.SetKind(DiffTree::Integer); - } else { - Tree.SetSame(IsEqualExpr(Context, ParamWidth, FromExpr, ToExpr) || - (FromNullPtr && ToNullPtr)); - Tree.SetNullPtr(FromNullPtr, ToNullPtr); - Tree.SetKind(DiffTree::Expression); - } - } else if (HasFromInt || HasToInt) { - if (!HasFromInt && FromExpr) - HasFromInt = GetInt(FromIter, FromExpr, FromInt); - if (!HasToInt && ToExpr) - HasToInt = GetInt(ToIter, ToExpr, ToInt); - Tree.SetNode(FromInt, ToInt, HasFromInt, HasToInt); - Tree.SetSame(IsSameConvertedInt(ParamWidth, FromInt, ToInt)); - Tree.SetDefault(FromIter.isEnd() && HasFromInt, - ToIter.isEnd() && HasToInt); - Tree.SetKind(DiffTree::Integer); - } else { - if (!HasFromValueDecl && FromExpr) - FromValueDecl = GetValueDecl(FromIter, FromExpr); - if (!HasToValueDecl && ToExpr) - ToValueDecl = GetValueDecl(ToIter, ToExpr); - QualType ArgumentType = DefaultNTTPD->getType(); - bool FromAddressOf = false; - if (FromValueDecl) { - if (FromExpr) { - if (UnaryOperator *UO = - dyn_cast<UnaryOperator>(FromExpr->IgnoreParens())) { - if (UO->getOpcode() == UO_AddrOf) - FromAddressOf = true; - } - } else { - if (!ArgumentType->isReferenceType()) { - FromAddressOf = true; - } - } - } - bool ToAddressOf = false; - if (ToValueDecl) { - if (ToExpr) { - if (UnaryOperator *UO = - dyn_cast<UnaryOperator>(ToExpr->IgnoreParens())) { - if (UO->getOpcode() == UO_AddrOf) { - ToAddressOf = true; - } - } - } else { - if (!ArgumentType->isReferenceType()) { - ToAddressOf = true; - } - } - } - Tree.SetNullPtr(FromNullPtr, ToNullPtr); - Tree.SetNode(FromValueDecl, ToValueDecl, FromAddressOf, ToAddressOf); - Tree.SetSame(FromValueDecl && ToValueDecl && - FromValueDecl->getCanonicalDecl() == - ToValueDecl->getCanonicalDecl()); - Tree.SetDefault(FromIter.isEnd() && FromValueDecl, - ToIter.isEnd() && ToValueDecl); - Tree.SetKind(DiffTree::Declaration); - } - } - - // Handle Templates - if (TemplateTemplateParmDecl *DefaultTTPD = - dyn_cast<TemplateTemplateParmDecl>(ParamND)) { - TemplateDecl *FromDecl, *ToDecl; - FromDecl = GetTemplateDecl(FromIter, DefaultTTPD); - ToDecl = GetTemplateDecl(ToIter, DefaultTTPD); - Tree.SetNode(FromDecl, ToDecl); - Tree.SetSame( - FromDecl && ToDecl && - FromDecl->getCanonicalDecl() == ToDecl->getCanonicalDecl()); - Tree.SetDefault(FromIter.isEnd() && FromDecl, ToIter.isEnd() && ToDecl); - Tree.SetKind(DiffTree::TemplateTemplate); - } + unsigned FromParamIndex = std::min(TotalArgs, ParamsFrom->size() - 1); + unsigned ToParamIndex = std::min(TotalArgs, ParamsTo->size() - 1); + NamedDecl *FromParamND = ParamsFrom->getParam(FromParamIndex); + NamedDecl *ToParamND = ParamsTo->getParam(ToParamIndex); + + TemplateTypeParmDecl *FromDefaultTypeDecl = + dyn_cast<TemplateTypeParmDecl>(FromParamND); + TemplateTypeParmDecl *ToDefaultTypeDecl = + dyn_cast<TemplateTypeParmDecl>(ToParamND); + if (FromDefaultTypeDecl && ToDefaultTypeDecl) + DiffTypes(FromIter, ToIter, FromDefaultTypeDecl, ToDefaultTypeDecl); + + TemplateTemplateParmDecl *FromDefaultTemplateDecl = + dyn_cast<TemplateTemplateParmDecl>(FromParamND); + TemplateTemplateParmDecl *ToDefaultTemplateDecl = + dyn_cast<TemplateTemplateParmDecl>(ToParamND); + if (FromDefaultTemplateDecl && ToDefaultTemplateDecl) + DiffTemplateTemplates(FromIter, ToIter, FromDefaultTemplateDecl, + ToDefaultTemplateDecl); + + NonTypeTemplateParmDecl *FromDefaultNonTypeDecl = + dyn_cast<NonTypeTemplateParmDecl>(FromParamND); + NonTypeTemplateParmDecl *ToDefaultNonTypeDecl = + dyn_cast<NonTypeTemplateParmDecl>(ToParamND); + if (FromDefaultNonTypeDecl && ToDefaultNonTypeDecl) + DiffNonTypes(FromIter, ToIter, FromDefaultNonTypeDecl, + ToDefaultNonTypeDecl); ++FromIter; ++ToIter; @@ -1147,7 +1173,8 @@ class TemplateDiff { /// GetType - Retrieves the template type arguments, including default /// arguments. - QualType GetType(const TSTiterator &Iter, TemplateTypeParmDecl *DefaultTTPD) { + static QualType GetType(const TSTiterator &Iter, + TemplateTypeParmDecl *DefaultTTPD) { bool isVariadic = DefaultTTPD->isParameterPack(); if (!Iter.isEnd()) @@ -1164,7 +1191,8 @@ class TemplateDiff { /// GetExpr - Retrieves the template expression argument, including default /// arguments. - Expr *GetExpr(const TSTiterator &Iter, NonTypeTemplateParmDecl *DefaultNTTPD) { + static Expr *GetExpr(const TSTiterator &Iter, + NonTypeTemplateParmDecl *DefaultNTTPD) { Expr *ArgExpr = nullptr; bool isVariadic = DefaultNTTPD->isParameterPack(); @@ -1183,7 +1211,8 @@ class TemplateDiff { /// GetInt - Retrieves the template integer argument, including evaluating /// default arguments. - bool GetInt(const TSTiterator &Iter, Expr *ArgExpr, llvm::APInt &Int) { + static bool GetInt(ASTContext &Context, const TSTiterator &Iter, + Expr *ArgExpr, llvm::APInt &Int) { // Default, value-depenedent expressions require fetching // from the desugared TemplateArgument, otherwise expression needs to // be evaluatable. @@ -1209,7 +1238,7 @@ class TemplateDiff { /// GetValueDecl - Retrieves the template Decl argument, including /// default expression argument. - ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) { + static ValueDecl *GetValueDecl(const TSTiterator &Iter, Expr *ArgExpr) { // Default, value-depenedent expressions require fetching // from the desugared TemplateArgument if (Iter.isEnd() && ArgExpr->isValueDependent()) @@ -1235,7 +1264,7 @@ class TemplateDiff { /// CheckForNullPtr - returns true if the expression can be evaluated as /// a null pointer - bool CheckForNullPtr(Expr *E) { + static bool CheckForNullPtr(ASTContext &Context, Expr *E) { assert(E && "Expected expression"); E = E->IgnoreParenCasts(); @@ -1256,7 +1285,7 @@ class TemplateDiff { /// GetTemplateDecl - Retrieves the template template arguments, including /// default arguments. - TemplateDecl *GetTemplateDecl(const TSTiterator &Iter, + static TemplateDecl *GetTemplateDecl(const TSTiterator &Iter, TemplateTemplateParmDecl *DefaultTTPD) { bool isVariadic = DefaultTTPD->isParameterPack(); diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index df7a2cb4712b..ebf5e651ef9a 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -20,6 +20,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclVisitor.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeVisitor.h" #include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" @@ -90,24 +91,22 @@ namespace { class ASTDumper : public ConstDeclVisitor<ASTDumper>, public ConstStmtVisitor<ASTDumper>, - public ConstCommentVisitor<ASTDumper> { + public ConstCommentVisitor<ASTDumper>, public TypeVisitor<ASTDumper> { raw_ostream &OS; const CommandTraits *Traits; const SourceManager *SM; - bool IsFirstLine; - // Indicates whether more child are expected at the current tree depth - enum IndentType { IT_Child, IT_LastChild }; + /// Pending[i] is an action to dump an entity at level i. + llvm::SmallVector<std::function<void(bool isLastChild)>, 32> Pending; - /// Indents[i] indicates if another child exists at level i. - /// Used by Indent() to print the tree structure. - llvm::SmallVector<IndentType, 32> Indents; + /// Indicates whether we're at the top level. + bool TopLevel; - /// Indicates that more children will be needed at this indent level. - /// If true, prevents lastChild() from marking the node as the last child. - /// This is used when there are multiple collections of children to be - /// dumped as well as during conditional node dumping. - bool MoreChildren; + /// Indicates if we're handling the first child after entering a new depth. + bool FirstChild; + + /// Prefix for currently-being-dumped entity. + std::string Prefix; /// Keep track of the last location we print out so that we can /// print out deltas from then on out. @@ -119,21 +118,70 @@ namespace { bool ShowColors; - class IndentScope { - ASTDumper &Dumper; - // Preserve the Dumper's MoreChildren value from the previous IndentScope - bool MoreChildren; - public: - IndentScope(ASTDumper &Dumper) : Dumper(Dumper) { - MoreChildren = Dumper.hasMoreChildren(); - Dumper.setMoreChildren(false); - Dumper.indent(); + /// Dump a child of the current node. + template<typename Fn> void dumpChild(Fn doDumpChild) { + // If we're at the top level, there's nothing interesting to do; just + // run the dumper. + if (TopLevel) { + TopLevel = false; + doDumpChild(); + while (!Pending.empty()) { + Pending.back()(true); + Pending.pop_back(); + } + Prefix.clear(); + OS << "\n"; + TopLevel = true; + return; } - ~IndentScope() { - Dumper.setMoreChildren(MoreChildren); - Dumper.unindent(); + + const FullComment *OrigFC = FC; + auto dumpWithIndent = [this, doDumpChild, OrigFC](bool isLastChild) { + // Print out the appropriate tree structure and work out the prefix for + // children of this node. For instance: + // + // A Prefix = "" + // |-B Prefix = "| " + // | `-C Prefix = "| " + // `-D Prefix = " " + // |-E Prefix = " | " + // `-F Prefix = " " + // G Prefix = "" + // + // Note that the first level gets no prefix. + { + OS << '\n'; + ColorScope Color(*this, IndentColor); + OS << Prefix << (isLastChild ? '`' : '|') << '-'; + this->Prefix.push_back(isLastChild ? ' ' : '|'); + this->Prefix.push_back(' '); + } + + FirstChild = true; + unsigned Depth = Pending.size(); + + FC = OrigFC; + doDumpChild(); + + // If any children are left, they're the last at their nesting level. + // Dump those ones out now. + while (Depth < Pending.size()) { + Pending.back()(true); + this->Pending.pop_back(); + } + + // Restore the old prefix. + this->Prefix.resize(Prefix.size() - 2); + }; + + if (FirstChild) { + Pending.push_back(std::move(dumpWithIndent)); + } else { + Pending.back()(false); + Pending.back() = std::move(dumpWithIndent); } - }; + FirstChild = false; + } class ColorScope { ASTDumper &Dumper; @@ -149,78 +197,37 @@ namespace { } }; - class ChildDumper { - ASTDumper &Dumper; - - const Decl *Prev; - bool PrevRef; - public: - ChildDumper(ASTDumper &Dumper) : Dumper(Dumper), Prev(nullptr) {} - ~ChildDumper() { - if (Prev) { - Dumper.lastChild(); - dump(nullptr); - } - } - - // FIXME: This should take an arbitrary callable as the dumping action. - void dump(const Decl *D, bool Ref = false) { - if (Prev) { - if (PrevRef) - Dumper.dumpDeclRef(Prev); - else - Dumper.dumpDecl(Prev); - } - Prev = D; - PrevRef = Ref; - } - void dumpRef(const Decl *D) { dump(D, true); } - - // Give up ownership of the children of the node. By calling this, - // the caller takes back responsibility for calling lastChild(). - void release() { dump(nullptr); } - }; - public: ASTDumper(raw_ostream &OS, const CommandTraits *Traits, const SourceManager *SM) - : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false), + : OS(OS), Traits(Traits), SM(SM), TopLevel(true), FirstChild(true), LastLocFilename(""), LastLocLine(~0U), FC(nullptr), ShowColors(SM && SM->getDiagnostics().getShowColors()) { } ASTDumper(raw_ostream &OS, const CommandTraits *Traits, const SourceManager *SM, bool ShowColors) - : OS(OS), Traits(Traits), SM(SM), IsFirstLine(true), MoreChildren(false), + : OS(OS), Traits(Traits), SM(SM), TopLevel(true), FirstChild(true), LastLocFilename(""), LastLocLine(~0U), ShowColors(ShowColors) { } - ~ASTDumper() { - OS << "\n"; - } - void dumpDecl(const Decl *D); void dumpStmt(const Stmt *S); void dumpFullComment(const FullComment *C); - // Formatting - void indent(); - void unindent(); - void lastChild(); - bool hasMoreChildren(); - void setMoreChildren(bool Value); - // Utilities void dumpPointer(const void *Ptr); void dumpSourceRange(SourceRange R); void dumpLocation(SourceLocation Loc); - void dumpBareType(QualType T); + void dumpBareType(QualType T, bool Desugar = true); void dumpType(QualType T); + void dumpTypeAsChild(QualType T); + void dumpTypeAsChild(const Type *T); void dumpBareDeclRef(const Decl *Node); void dumpDeclRef(const Decl *Node, const char *Label = nullptr); void dumpName(const NamedDecl *D); bool hasNodes(const DeclContext *DC); void dumpDeclContext(const DeclContext *DC); - void dumpLookups(const DeclContext *DC); + void dumpLookups(const DeclContext *DC, bool DumpDecls); void dumpAttr(const Attr *A); // C++ Utilities @@ -233,6 +240,175 @@ namespace { void dumpTemplateArgument(const TemplateArgument &A, SourceRange R = SourceRange()); + // Types + void VisitComplexType(const ComplexType *T) { + dumpTypeAsChild(T->getElementType()); + } + void VisitPointerType(const PointerType *T) { + dumpTypeAsChild(T->getPointeeType()); + } + void VisitBlockPointerType(const BlockPointerType *T) { + dumpTypeAsChild(T->getPointeeType()); + } + void VisitReferenceType(const ReferenceType *T) { + dumpTypeAsChild(T->getPointeeType()); + } + void VisitRValueReferenceType(const ReferenceType *T) { + if (T->isSpelledAsLValue()) + OS << " written as lvalue reference"; + VisitReferenceType(T); + } + void VisitMemberPointerType(const MemberPointerType *T) { + dumpTypeAsChild(T->getClass()); + dumpTypeAsChild(T->getPointeeType()); + } + void VisitArrayType(const ArrayType *T) { + switch (T->getSizeModifier()) { + case ArrayType::Normal: break; + case ArrayType::Static: OS << " static"; break; + case ArrayType::Star: OS << " *"; break; + } + OS << " " << T->getIndexTypeQualifiers().getAsString(); + dumpTypeAsChild(T->getElementType()); + } + void VisitConstantArrayType(const ConstantArrayType *T) { + OS << " " << T->getSize(); + VisitArrayType(T); + } + void VisitVariableArrayType(const VariableArrayType *T) { + OS << " "; + dumpSourceRange(T->getBracketsRange()); + VisitArrayType(T); + dumpStmt(T->getSizeExpr()); + } + void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { + VisitArrayType(T); + OS << " "; + dumpSourceRange(T->getBracketsRange()); + dumpStmt(T->getSizeExpr()); + } + void VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + OS << " "; + dumpLocation(T->getAttributeLoc()); + dumpTypeAsChild(T->getElementType()); + dumpStmt(T->getSizeExpr()); + } + void VisitVectorType(const VectorType *T) { + switch (T->getVectorKind()) { + case VectorType::GenericVector: break; + case VectorType::AltiVecVector: OS << " altivec"; break; + case VectorType::AltiVecPixel: OS << " altivec pixel"; break; + case VectorType::AltiVecBool: OS << " altivec bool"; break; + case VectorType::NeonVector: OS << " neon"; break; + case VectorType::NeonPolyVector: OS << " neon poly"; break; + } + OS << " " << T->getNumElements(); + dumpTypeAsChild(T->getElementType()); + } + void VisitFunctionType(const FunctionType *T) { + auto EI = T->getExtInfo(); + if (EI.getNoReturn()) OS << " noreturn"; + if (EI.getProducesResult()) OS << " produces_result"; + if (EI.getHasRegParm()) OS << " regparm " << EI.getRegParm(); + OS << " " << FunctionType::getNameForCallConv(EI.getCC()); + dumpTypeAsChild(T->getReturnType()); + } + void VisitFunctionProtoType(const FunctionProtoType *T) { + auto EPI = T->getExtProtoInfo(); + if (EPI.HasTrailingReturn) OS << " trailing_return"; + if (T->isConst()) OS << " const"; + if (T->isVolatile()) OS << " volatile"; + if (T->isRestrict()) OS << " restrict"; + switch (EPI.RefQualifier) { + case RQ_None: break; + case RQ_LValue: OS << " &"; break; + case RQ_RValue: OS << " &&"; break; + } + // FIXME: Exception specification. + // FIXME: Consumed parameters. + VisitFunctionType(T); + for (QualType PT : T->getParamTypes()) + dumpTypeAsChild(PT); + if (EPI.Variadic) + dumpChild([=] { OS << "..."; }); + } + void VisitUnresolvedUsingType(const UnresolvedUsingType *T) { + dumpDeclRef(T->getDecl()); + } + void VisitTypedefType(const TypedefType *T) { + dumpDeclRef(T->getDecl()); + } + void VisitTypeOfExprType(const TypeOfExprType *T) { + dumpStmt(T->getUnderlyingExpr()); + } + void VisitDecltypeType(const DecltypeType *T) { + dumpStmt(T->getUnderlyingExpr()); + } + void VisitUnaryTransformType(const UnaryTransformType *T) { + switch (T->getUTTKind()) { + case UnaryTransformType::EnumUnderlyingType: + OS << " underlying_type"; + break; + } + dumpTypeAsChild(T->getBaseType()); + } + void VisitTagType(const TagType *T) { + dumpDeclRef(T->getDecl()); + } + void VisitAttributedType(const AttributedType *T) { + // FIXME: AttrKind + dumpTypeAsChild(T->getModifiedType()); + } + void VisitTemplateTypeParmType(const TemplateTypeParmType *T) { + OS << " depth " << T->getDepth() << " index " << T->getIndex(); + if (T->isParameterPack()) OS << " pack"; + dumpDeclRef(T->getDecl()); + } + void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *T) { + dumpTypeAsChild(T->getReplacedParameter()); + } + void VisitSubstTemplateTypeParmPackType( + const SubstTemplateTypeParmPackType *T) { + dumpTypeAsChild(T->getReplacedParameter()); + dumpTemplateArgument(T->getArgumentPack()); + } + void VisitAutoType(const AutoType *T) { + if (T->isDecltypeAuto()) OS << " decltype(auto)"; + if (!T->isDeduced()) + OS << " undeduced"; + } + void VisitTemplateSpecializationType(const TemplateSpecializationType *T) { + if (T->isTypeAlias()) OS << " alias"; + OS << " "; T->getTemplateName().dump(OS); + for (auto &Arg : *T) + dumpTemplateArgument(Arg); + if (T->isTypeAlias()) + dumpTypeAsChild(T->getAliasedType()); + } + void VisitInjectedClassNameType(const InjectedClassNameType *T) { + dumpDeclRef(T->getDecl()); + } + void VisitObjCInterfaceType(const ObjCInterfaceType *T) { + dumpDeclRef(T->getDecl()); + } + void VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { + dumpTypeAsChild(T->getPointeeType()); + } + void VisitAtomicType(const AtomicType *T) { + dumpTypeAsChild(T->getValueType()); + } + void VisitAdjustedType(const AdjustedType *T) { + dumpTypeAsChild(T->getOriginalType()); + } + void VisitPackExpansionType(const PackExpansionType *T) { + if (auto N = T->getNumExpansions()) OS << " expansions " << *N; + if (!T->isSugared()) + dumpTypeAsChild(T->getPattern()); + } + // FIXME: ElaboratedType, DependentNameType, + // DependentTemplateSpecializationType, ObjCObjectType + // Decls void VisitLabelDecl(const LabelDecl *D); void VisitTypedefDecl(const TypedefDecl *D); @@ -255,8 +431,7 @@ namespace { void VisitCXXRecordDecl(const CXXRecordDecl *D); void VisitStaticAssertDecl(const StaticAssertDecl *D); template<typename SpecializationDecl> - void VisitTemplateDeclSpecialization(ChildDumper &Children, - const SpecializationDecl *D, + void VisitTemplateDeclSpecialization(const SpecializationDecl *D, bool DumpExplicitInst, bool DumpRefOnly); template<typename TemplateDecl> @@ -378,67 +553,6 @@ namespace { // Utilities //===----------------------------------------------------------------------===// -// Print out the appropriate tree structure using the Indents vector. -// Example of tree and the Indents vector at each level. -// A { } -// |-B { IT_Child } -// | `-C { IT_Child, IT_LastChild } -// `-D { IT_LastChild } -// |-E { IT_LastChild, IT_Child } -// `-F { IT_LastChild, IT_LastChild } -// Type non-last element, last element -// IT_Child "| " "|-" -// IT_LastChild " " "`-" -void ASTDumper::indent() { - if (IsFirstLine) - IsFirstLine = false; - else - OS << "\n"; - - ColorScope Color(*this, IndentColor); - for (SmallVectorImpl<IndentType>::const_iterator I = Indents.begin(), - E = Indents.end(); - I != E; ++I) { - switch (*I) { - case IT_Child: - if (I == E - 1) - OS << "|-"; - else - OS << "| "; - continue; - case IT_LastChild: - if (I == E - 1) - OS << "`-"; - else - OS << " "; - continue; - } - llvm_unreachable("Invalid IndentType"); - } - Indents.push_back(IT_Child); -} - -void ASTDumper::unindent() { - Indents.pop_back(); -} - -// Call before each potential last child node is to be dumped. If MoreChildren -// is false, then this is the last child, otherwise treat as a regular node. -void ASTDumper::lastChild() { - if (!hasMoreChildren()) - Indents.back() = IT_LastChild; -} - -// MoreChildren should be set before calling another function that may print -// additional nodes to prevent conflicting final child nodes. -bool ASTDumper::hasMoreChildren() { - return MoreChildren; -} - -void ASTDumper::setMoreChildren(bool Value) { - MoreChildren = Value; -} - void ASTDumper::dumpPointer(const void *Ptr) { ColorScope Color(*this, AddressColor); OS << ' ' << Ptr; @@ -491,13 +605,13 @@ void ASTDumper::dumpSourceRange(SourceRange R) { } -void ASTDumper::dumpBareType(QualType T) { +void ASTDumper::dumpBareType(QualType T, bool Desugar) { ColorScope Color(*this, TypeColor); - + SplitQualType T_split = T.split(); OS << "'" << QualType::getAsString(T_split) << "'"; - if (!T.isNull()) { + if (Desugar && !T.isNull()) { // If the type is sugared, also dump a (shallow) desugared type. SplitQualType D_split = T.getSplitDesugaredType(); if (T_split != D_split) @@ -510,6 +624,59 @@ void ASTDumper::dumpType(QualType T) { dumpBareType(T); } +void ASTDumper::dumpTypeAsChild(QualType T) { + SplitQualType SQT = T.split(); + if (!SQT.Quals.hasQualifiers()) + return dumpTypeAsChild(SQT.Ty); + + dumpChild([=] { + OS << "QualType"; + dumpPointer(T.getAsOpaquePtr()); + OS << " "; + dumpBareType(T, false); + OS << " " << T.split().Quals.getAsString(); + dumpTypeAsChild(T.split().Ty); + }); +} + +void ASTDumper::dumpTypeAsChild(const Type *T) { + dumpChild([=] { + if (!T) { + ColorScope Color(*this, NullColor); + OS << "<<<NULL>>>"; + return; + } + + { + ColorScope Color(*this, TypeColor); + OS << T->getTypeClassName() << "Type"; + } + dumpPointer(T); + OS << " "; + dumpBareType(QualType(T, 0), false); + + QualType SingleStepDesugar = + T->getLocallyUnqualifiedSingleStepDesugaredType(); + if (SingleStepDesugar != QualType(T, 0)) + OS << " sugar"; + if (T->isDependentType()) + OS << " dependent"; + else if (T->isInstantiationDependentType()) + OS << " instantiation_dependent"; + if (T->isVariablyModifiedType()) + OS << " variably_modified"; + if (T->containsUnexpandedParameterPack()) + OS << " contains_unexpanded_pack"; + if (T->isFromAST()) + OS << " imported"; + + TypeVisitor<ASTDumper>::Visit(T); + + if (SingleStepDesugar != QualType(T, 0)) + dumpTypeAsChild(SingleStepDesugar); + }); +} + void ASTDumper::dumpBareDeclRef(const Decl *D) { { ColorScope Color(*this, DeclKindNameColor); @@ -530,10 +697,11 @@ void ASTDumper::dumpDeclRef(const Decl *D, const char *Label) { if (!D) return; - IndentScope Indent(*this); - if (Label) - OS << Label << ' '; - dumpBareDeclRef(D); + dumpChild([=]{ + if (Label) + OS << Label << ' '; + dumpBareDeclRef(D); + }); } void ASTDumper::dumpName(const NamedDecl *ND) { @@ -555,86 +723,96 @@ void ASTDumper::dumpDeclContext(const DeclContext *DC) { if (!DC) return; - ChildDumper Children(*this); for (auto *D : DC->noload_decls()) - Children.dump(D); + dumpDecl(D); if (DC->hasExternalLexicalStorage()) { - Children.release(); - - lastChild(); - IndentScope Indent(*this); - ColorScope Color(*this, UndeserializedColor); - OS << "<undeserialized declarations>"; + dumpChild([=]{ + ColorScope Color(*this, UndeserializedColor); + OS << "<undeserialized declarations>"; + }); } } -void ASTDumper::dumpLookups(const DeclContext *DC) { - IndentScope Indent(*this); +void ASTDumper::dumpLookups(const DeclContext *DC, bool DumpDecls) { + dumpChild([=] { + OS << "StoredDeclsMap "; + dumpBareDeclRef(cast<Decl>(DC)); - OS << "StoredDeclsMap "; - dumpBareDeclRef(cast<Decl>(DC)); + const DeclContext *Primary = DC->getPrimaryContext(); + if (Primary != DC) { + OS << " primary"; + dumpPointer(cast<Decl>(Primary)); + } - const DeclContext *Primary = DC->getPrimaryContext(); - if (Primary != DC) { - OS << " primary"; - dumpPointer(cast<Decl>(Primary)); - } + bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); - bool HasUndeserializedLookups = Primary->hasExternalVisibleStorage(); + DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(), + E = Primary->noload_lookups_end(); + while (I != E) { + DeclarationName Name = I.getLookupName(); + DeclContextLookupResult R = *I++; - DeclContext::all_lookups_iterator I = Primary->noload_lookups_begin(), - E = Primary->noload_lookups_end(); - while (I != E) { - DeclarationName Name = I.getLookupName(); - DeclContextLookupResult R = *I++; - if (I == E && !HasUndeserializedLookups) - lastChild(); + dumpChild([=] { + OS << "DeclarationName "; + { + ColorScope Color(*this, DeclNameColor); + OS << '\'' << Name << '\''; + } - IndentScope Indent(*this); - OS << "DeclarationName "; - { - ColorScope Color(*this, DeclNameColor); - OS << '\'' << Name << '\''; + for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end(); + RI != RE; ++RI) { + dumpChild([=] { + dumpBareDeclRef(*RI); + + if ((*RI)->isHidden()) + OS << " hidden"; + + // If requested, dump the redecl chain for this lookup. + if (DumpDecls) { + // Dump earliest decl first. + std::function<void(Decl *)> DumpWithPrev = [&](Decl *D) { + if (Decl *Prev = D->getPreviousDecl()) + DumpWithPrev(Prev); + dumpDecl(D); + }; + DumpWithPrev(*RI); + } + }); + } + }); } - for (DeclContextLookupResult::iterator RI = R.begin(), RE = R.end(); - RI != RE; ++RI) { - if (RI + 1 == RE) - lastChild(); - dumpDeclRef(*RI); - if ((*RI)->isHidden()) - OS << " hidden"; + if (HasUndeserializedLookups) { + dumpChild([=] { + ColorScope Color(*this, UndeserializedColor); + OS << "<undeserialized lookups>"; + }); } - } - - if (HasUndeserializedLookups) { - lastChild(); - IndentScope Indent(*this); - ColorScope Color(*this, UndeserializedColor); - OS << "<undeserialized lookups>"; - } + }); } void ASTDumper::dumpAttr(const Attr *A) { - IndentScope Indent(*this); - { - ColorScope Color(*this, AttrColor); + dumpChild([=] { + { + ColorScope Color(*this, AttrColor); - switch (A->getKind()) { + switch (A->getKind()) { #define ATTR(X) case attr::X: OS << #X; break; #include "clang/Basic/AttrList.inc" - default: llvm_unreachable("unexpected attribute kind"); + default: + llvm_unreachable("unexpected attribute kind"); + } + OS << "Attr"; } - OS << "Attr"; - } - dumpPointer(A); - dumpSourceRange(A->getRange()); - if (A->isInherited()) - OS << " Inherited"; - if (A->isImplicit()) - OS << " Implicit"; + dumpPointer(A); + dumpSourceRange(A->getRange()); + if (A->isInherited()) + OS << " Inherited"; + if (A->isImplicit()) + OS << " Implicit"; #include "clang/AST/AttrDump.inc" + }); } static void dumpPreviousDeclImpl(raw_ostream &OS, ...) {} @@ -687,15 +865,20 @@ void ASTDumper::dumpAccessSpecifier(AccessSpecifier AS) { } void ASTDumper::dumpCXXCtorInitializer(const CXXCtorInitializer *Init) { - IndentScope Indent(*this); - OS << "CXXCtorInitializer"; - if (Init->isAnyMemberInitializer()) { - OS << ' '; - dumpBareDeclRef(Init->getAnyMember()); - } else { - dumpType(QualType(Init->getBaseClass(), 0)); - } - dumpStmt(Init->getInit()); + dumpChild([=] { + OS << "CXXCtorInitializer"; + if (Init->isAnyMemberInitializer()) { + OS << ' '; + dumpBareDeclRef(Init->getAnyMember()); + } else if (Init->isBaseInitializer()) { + dumpType(QualType(Init->getBaseClass(), 0)); + } else if (Init->isDelegatingInitializer()) { + dumpType(Init->getTypeSourceInfo()->getType()); + } else { + llvm_unreachable("Unknown initializer type"); + } + dumpStmt(Init->getInit()); + }); } void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) { @@ -709,11 +892,8 @@ void ASTDumper::dumpTemplateParameters(const TemplateParameterList *TPL) { void ASTDumper::dumpTemplateArgumentListInfo( const TemplateArgumentListInfo &TALI) { - for (unsigned i = 0, e = TALI.size(); i < e; ++i) { - if (i + 1 == e) - lastChild(); + for (unsigned i = 0, e = TALI.size(); i < e; ++i) dumpTemplateArgumentLoc(TALI[i]); - } } void ASTDumper::dumpTemplateArgumentLoc(const TemplateArgumentLoc &A) { @@ -726,54 +906,49 @@ void ASTDumper::dumpTemplateArgumentList(const TemplateArgumentList &TAL) { } void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) { - IndentScope Indent(*this); - OS << "TemplateArgument"; - if (R.isValid()) - dumpSourceRange(R); - - switch (A.getKind()) { - case TemplateArgument::Null: - OS << " null"; - break; - case TemplateArgument::Type: - OS << " type"; - lastChild(); - dumpType(A.getAsType()); - break; - case TemplateArgument::Declaration: - OS << " decl"; - lastChild(); - dumpDeclRef(A.getAsDecl()); - break; - case TemplateArgument::NullPtr: - OS << " nullptr"; - break; - case TemplateArgument::Integral: - OS << " integral " << A.getAsIntegral(); - break; - case TemplateArgument::Template: - OS << " template "; - A.getAsTemplate().dump(OS); - break; - case TemplateArgument::TemplateExpansion: - OS << " template expansion"; - A.getAsTemplateOrTemplatePattern().dump(OS); - break; - case TemplateArgument::Expression: - OS << " expr"; - lastChild(); - dumpStmt(A.getAsExpr()); - break; - case TemplateArgument::Pack: - OS << " pack"; - for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end(); - I != E; ++I) { - if (I + 1 == E) - lastChild(); - dumpTemplateArgument(*I); + dumpChild([=] { + OS << "TemplateArgument"; + if (R.isValid()) + dumpSourceRange(R); + + switch (A.getKind()) { + case TemplateArgument::Null: + OS << " null"; + break; + case TemplateArgument::Type: + OS << " type"; + dumpType(A.getAsType()); + break; + case TemplateArgument::Declaration: + OS << " decl"; + dumpDeclRef(A.getAsDecl()); + break; + case TemplateArgument::NullPtr: + OS << " nullptr"; + break; + case TemplateArgument::Integral: + OS << " integral " << A.getAsIntegral(); + break; + case TemplateArgument::Template: + OS << " template "; + A.getAsTemplate().dump(OS); + break; + case TemplateArgument::TemplateExpansion: + OS << " template expansion"; + A.getAsTemplateOrTemplatePattern().dump(OS); + break; + case TemplateArgument::Expression: + OS << " expr"; + dumpStmt(A.getAsExpr()); + break; + case TemplateArgument::Pack: + OS << " pack"; + for (TemplateArgument::pack_iterator I = A.pack_begin(), E = A.pack_end(); + I != E; ++I) + dumpTemplateArgument(*I); + break; } - break; - } + }); } //===----------------------------------------------------------------------===// @@ -781,64 +956,57 @@ void ASTDumper::dumpTemplateArgument(const TemplateArgument &A, SourceRange R) { //===----------------------------------------------------------------------===// void ASTDumper::dumpDecl(const Decl *D) { - IndentScope Indent(*this); + dumpChild([=] { + if (!D) { + ColorScope Color(*this, NullColor); + OS << "<<<NULL>>>"; + return; + } - if (!D) { - ColorScope Color(*this, NullColor); - OS << "<<<NULL>>>"; - return; - } + { + ColorScope Color(*this, DeclKindNameColor); + OS << D->getDeclKindName() << "Decl"; + } + dumpPointer(D); + if (D->getLexicalDeclContext() != D->getDeclContext()) + OS << " parent " << cast<Decl>(D->getDeclContext()); + dumpPreviousDecl(OS, D); + dumpSourceRange(D->getSourceRange()); + OS << ' '; + dumpLocation(D->getLocation()); + if (Module *M = D->getOwningModule()) + OS << " in " << M->getFullModuleName(); + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) + if (ND->isHidden()) + OS << " hidden"; + if (D->isImplicit()) + OS << " implicit"; + if (D->isUsed()) + OS << " used"; + else if (D->isThisDeclarationReferenced()) + OS << " referenced"; + if (D->isInvalidDecl()) + OS << " invalid"; + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + if (FD->isConstexpr()) + OS << " constexpr"; - { - ColorScope Color(*this, DeclKindNameColor); - OS << D->getDeclKindName() << "Decl"; - } - dumpPointer(D); - if (D->getLexicalDeclContext() != D->getDeclContext()) - OS << " parent " << cast<Decl>(D->getDeclContext()); - dumpPreviousDecl(OS, D); - dumpSourceRange(D->getSourceRange()); - OS << ' '; - dumpLocation(D->getLocation()); - if (Module *M = D->getOwningModule()) - OS << " in " << M->getFullModuleName(); - if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) - if (ND->isHidden()) - OS << " hidden"; - if (D->isImplicit()) - OS << " implicit"; - if (D->isUsed()) - OS << " used"; - else if (D->isReferenced()) - OS << " referenced"; - if (D->isInvalidDecl()) - OS << " invalid"; - - bool HasAttrs = D->hasAttrs(); - const FullComment *Comment = - D->getASTContext().getLocalCommentForDeclUncached(D); - // Decls within functions are visited by the body - bool HasDeclContext = !isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) && - hasNodes(dyn_cast<DeclContext>(D)); - - setMoreChildren(HasAttrs || Comment || HasDeclContext); - ConstDeclVisitor<ASTDumper>::Visit(D); - - setMoreChildren(Comment || HasDeclContext); - for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end(); - I != E; ++I) { - if (I + 1 == E) - lastChild(); - dumpAttr(*I); - } - setMoreChildren(HasDeclContext); - lastChild(); - dumpFullComment(Comment); + ConstDeclVisitor<ASTDumper>::Visit(D); - setMoreChildren(false); - if (HasDeclContext) - dumpDeclContext(cast<DeclContext>(D)); + for (Decl::attr_iterator I = D->attr_begin(), E = D->attr_end(); I != E; + ++I) + dumpAttr(*I); + + if (const FullComment *Comment = + D->getASTContext().getLocalCommentForDeclUncached(D)) + dumpFullComment(Comment); + + // Decls within functions are visited by the body. + if (!isa<FunctionDecl>(*D) && !isa<ObjCMethodDecl>(*D) && + hasNodes(dyn_cast<DeclContext>(D))) + dumpDeclContext(cast<DeclContext>(D)); + }); } void ASTDumper::VisitLabelDecl(const LabelDecl *D) { @@ -878,19 +1046,16 @@ void ASTDumper::VisitRecordDecl(const RecordDecl *D) { void ASTDumper::VisitEnumConstantDecl(const EnumConstantDecl *D) { dumpName(D); dumpType(D->getType()); - if (const Expr *Init = D->getInitExpr()) { - lastChild(); + if (const Expr *Init = D->getInitExpr()) dumpStmt(Init); - } } void ASTDumper::VisitIndirectFieldDecl(const IndirectFieldDecl *D) { dumpName(D); dumpType(D->getType()); - ChildDumper Children(*this); for (auto *Child : D->chain()) - Children.dumpRef(Child); + dumpDeclRef(Child); } void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { @@ -914,73 +1079,39 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { if (const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>()) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); - switch (EPI.ExceptionSpecType) { + switch (EPI.ExceptionSpec.Type) { default: break; case EST_Unevaluated: - OS << " noexcept-unevaluated " << EPI.ExceptionSpecDecl; + OS << " noexcept-unevaluated " << EPI.ExceptionSpec.SourceDecl; break; case EST_Uninstantiated: - OS << " noexcept-uninstantiated " << EPI.ExceptionSpecTemplate; + OS << " noexcept-uninstantiated " << EPI.ExceptionSpec.SourceTemplate; break; } } - bool OldMoreChildren = hasMoreChildren(); - const FunctionTemplateSpecializationInfo *FTSI = - D->getTemplateSpecializationInfo(); - bool HasTemplateSpecialization = FTSI; - - bool HasNamedDecls = D->getDeclsInPrototypeScope().begin() != - D->getDeclsInPrototypeScope().end(); - - bool HasFunctionDecls = D->param_begin() != D->param_end(); - - const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D); - bool HasCtorInitializers = C && C->init_begin() != C->init_end(); - - bool HasDeclarationBody = D->doesThisDeclarationHaveABody(); - - setMoreChildren(OldMoreChildren || HasNamedDecls || HasFunctionDecls || - HasCtorInitializers || HasDeclarationBody); - if (HasTemplateSpecialization) { - lastChild(); + if (const FunctionTemplateSpecializationInfo *FTSI = + D->getTemplateSpecializationInfo()) dumpTemplateArgumentList(*FTSI->TemplateArguments); - } - setMoreChildren(OldMoreChildren || HasFunctionDecls || - HasCtorInitializers || HasDeclarationBody); for (ArrayRef<NamedDecl *>::iterator I = D->getDeclsInPrototypeScope().begin(), - E = D->getDeclsInPrototypeScope().end(); I != E; ++I) { - if (I + 1 == E) - lastChild(); + E = D->getDeclsInPrototypeScope().end(); I != E; ++I) dumpDecl(*I); - } - setMoreChildren(OldMoreChildren || HasCtorInitializers || HasDeclarationBody); for (FunctionDecl::param_const_iterator I = D->param_begin(), E = D->param_end(); - I != E; ++I) { - if (I + 1 == E) - lastChild(); + I != E; ++I) dumpDecl(*I); - } - - setMoreChildren(OldMoreChildren || HasDeclarationBody); - if (HasCtorInitializers) + + if (const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D)) for (CXXConstructorDecl::init_const_iterator I = C->init_begin(), E = C->init_end(); - I != E; ++I) { - if (I + 1 == E) - lastChild(); + I != E; ++I) dumpCXXCtorInitializer(*I); - } - setMoreChildren(OldMoreChildren); - if (HasDeclarationBody) { - lastChild(); + if (D->doesThisDeclarationHaveABody()) dumpStmt(D->getBody()); - } } void ASTDumper::VisitFieldDecl(const FieldDecl *D) { @@ -991,21 +1122,10 @@ void ASTDumper::VisitFieldDecl(const FieldDecl *D) { if (D->isModulePrivate()) OS << " __module_private__"; - bool OldMoreChildren = hasMoreChildren(); - bool IsBitField = D->isBitField(); - Expr *Init = D->getInClassInitializer(); - bool HasInit = Init; - - setMoreChildren(OldMoreChildren || HasInit); - if (IsBitField) { - lastChild(); + if (D->isBitField()) dumpStmt(D->getBitWidth()); - } - setMoreChildren(OldMoreChildren); - if (HasInit) { - lastChild(); + if (Expr *Init = D->getInClassInitializer()) dumpStmt(Init); - } } void ASTDumper::VisitVarDecl(const VarDecl *D) { @@ -1029,13 +1149,11 @@ void ASTDumper::VisitVarDecl(const VarDecl *D) { case VarDecl::CallInit: OS << " callinit"; break; case VarDecl::ListInit: OS << " listinit"; break; } - lastChild(); dumpStmt(D->getInit()); } } void ASTDumper::VisitFileScopeAsmDecl(const FileScopeAsmDecl *D) { - lastChild(); dumpStmt(D->getAsmString()); } @@ -1082,25 +1200,24 @@ void ASTDumper::VisitCXXRecordDecl(const CXXRecordDecl *D) { return; for (const auto &I : D->bases()) { - IndentScope Indent(*this); - if (I.isVirtual()) - OS << "virtual "; - dumpAccessSpecifier(I.getAccessSpecifier()); - dumpType(I.getType()); - if (I.isPackExpansion()) - OS << "..."; + dumpChild([=] { + if (I.isVirtual()) + OS << "virtual "; + dumpAccessSpecifier(I.getAccessSpecifier()); + dumpType(I.getType()); + if (I.isPackExpansion()) + OS << "..."; + }); } } void ASTDumper::VisitStaticAssertDecl(const StaticAssertDecl *D) { dumpStmt(D->getAssertExpr()); - lastChild(); dumpStmt(D->getMessage()); } template<typename SpecializationDecl> -void ASTDumper::VisitTemplateDeclSpecialization(ChildDumper &Children, - const SpecializationDecl *D, +void ASTDumper::VisitTemplateDeclSpecialization(const SpecializationDecl *D, bool DumpExplicitInst, bool DumpRefOnly) { bool DumpedAny = false; @@ -1125,7 +1242,10 @@ void ASTDumper::VisitTemplateDeclSpecialization(ChildDumper &Children, // Fall through. case TSK_Undeclared: case TSK_ImplicitInstantiation: - Children.dump(Redecl, DumpRefOnly); + if (DumpRefOnly) + dumpDeclRef(Redecl); + else + dumpDecl(Redecl); DumpedAny = true; break; case TSK_ExplicitSpecialization: @@ -1135,7 +1255,7 @@ void ASTDumper::VisitTemplateDeclSpecialization(ChildDumper &Children, // Ensure we dump at least one decl for each specialization. if (!DumpedAny) - Children.dumpRef(D); + dumpDeclRef(D); } template<typename TemplateDecl> @@ -1144,11 +1264,10 @@ void ASTDumper::VisitTemplateDecl(const TemplateDecl *D, dumpName(D); dumpTemplateParameters(D->getTemplateParameters()); - ChildDumper Children(*this); - Children.dump(D->getTemplatedDecl()); + dumpDecl(D->getTemplatedDecl()); for (auto *Child : D->specializations()) - VisitTemplateDeclSpecialization(Children, Child, DumpExplicitInst, + VisitTemplateDeclSpecialization(Child, DumpExplicitInst, !D->isCanonicalDecl()); } @@ -1206,10 +1325,8 @@ void ASTDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { if (D->isParameterPack()) OS << " ..."; dumpName(D); - if (D->hasDefaultArgument()) { - lastChild(); + if (D->hasDefaultArgument()) dumpTemplateArgument(D->getDefaultArgument()); - } } void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { @@ -1217,10 +1334,8 @@ void ASTDumper::VisitNonTypeTemplateParmDecl(const NonTypeTemplateParmDecl *D) { if (D->isParameterPack()) OS << " ..."; dumpName(D); - if (D->hasDefaultArgument()) { - lastChild(); + if (D->hasDefaultArgument()) dumpTemplateArgument(D->getDefaultArgument()); - } } void ASTDumper::VisitTemplateTemplateParmDecl( @@ -1229,10 +1344,8 @@ void ASTDumper::VisitTemplateTemplateParmDecl( OS << " ..."; dumpName(D); dumpTemplateParameters(D->getTemplateParameters()); - if (D->hasDefaultArgument()) { - lastChild(); + if (D->hasDefaultArgument()) dumpTemplateArgumentLoc(D->getDefaultArgument()); - } } void ASTDumper::VisitUsingDecl(const UsingDecl *D) { @@ -1273,7 +1386,6 @@ void ASTDumper::VisitAccessSpecDecl(const AccessSpecDecl *D) { } void ASTDumper::VisitFriendDecl(const FriendDecl *D) { - lastChild(); if (TypeSourceInfo *T = D->getFriendType()) dumpType(T->getType()); else @@ -1317,96 +1429,66 @@ void ASTDumper::VisitObjCMethodDecl(const ObjCMethodDecl *D) { dumpName(D); dumpType(D->getReturnType()); - bool OldMoreChildren = hasMoreChildren(); - bool IsVariadic = D->isVariadic(); - bool HasBody = D->hasBody(); - - setMoreChildren(OldMoreChildren || IsVariadic || HasBody); if (D->isThisDeclarationADefinition()) { - lastChild(); dumpDeclContext(D); } else { for (ObjCMethodDecl::param_const_iterator I = D->param_begin(), E = D->param_end(); - I != E; ++I) { - if (I + 1 == E) - lastChild(); + I != E; ++I) dumpDecl(*I); - } } - setMoreChildren(OldMoreChildren || HasBody); - if (IsVariadic) { - lastChild(); - IndentScope Indent(*this); - OS << "..."; - } + if (D->isVariadic()) + dumpChild([=] { OS << "..."; }); - setMoreChildren(OldMoreChildren); - if (HasBody) { - lastChild(); + if (D->hasBody()) dumpStmt(D->getBody()); - } } void ASTDumper::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { dumpName(D); dumpDeclRef(D->getClassInterface()); - if (D->protocol_begin() == D->protocol_end()) - lastChild(); dumpDeclRef(D->getImplementation()); for (ObjCCategoryDecl::protocol_iterator I = D->protocol_begin(), E = D->protocol_end(); - I != E; ++I) { - if (I + 1 == E) - lastChild(); + I != E; ++I) dumpDeclRef(*I); - } } void ASTDumper::VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { dumpName(D); dumpDeclRef(D->getClassInterface()); - lastChild(); dumpDeclRef(D->getCategoryDecl()); } void ASTDumper::VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { dumpName(D); - ChildDumper Children(*this); for (auto *Child : D->protocols()) - Children.dumpRef(Child); + dumpDeclRef(Child); } void ASTDumper::VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { dumpName(D); dumpDeclRef(D->getSuperClass(), "super"); - ChildDumper Children(*this); - Children.dumpRef(D->getImplementation()); + dumpDeclRef(D->getImplementation()); for (auto *Child : D->protocols()) - Children.dumpRef(Child); + dumpDeclRef(Child); } void ASTDumper::VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { dumpName(D); dumpDeclRef(D->getSuperClass(), "super"); - if (D->init_begin() == D->init_end()) - lastChild(); dumpDeclRef(D->getClassInterface()); for (ObjCImplementationDecl::init_const_iterator I = D->init_begin(), E = D->init_end(); - I != E; ++I) { - if (I + 1 == E) - lastChild(); + I != E; ++I) dumpCXXCtorInitializer(*I); - } } void ASTDumper::VisitObjCCompatibleAliasDecl(const ObjCCompatibleAliasDecl *D) { dumpName(D); - lastChild(); dumpDeclRef(D->getClassInterface()); } @@ -1441,15 +1523,10 @@ void ASTDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { OS << " strong"; if (Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) OS << " unsafe_unretained"; - if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) { - if (!(Attrs & ObjCPropertyDecl::OBJC_PR_setter)) - lastChild(); + if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) dumpDeclRef(D->getGetterMethodDecl(), "getter"); - } - if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) { - lastChild(); + if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) dumpDeclRef(D->getSetterMethodDecl(), "setter"); - } } } @@ -1460,7 +1537,6 @@ void ASTDumper::VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { else OS << " dynamic"; dumpDeclRef(D->getPropertyDecl()); - lastChild(); dumpDeclRef(D->getPropertyIvarDecl()); } @@ -1468,30 +1544,27 @@ void ASTDumper::VisitBlockDecl(const BlockDecl *D) { for (auto I : D->params()) dumpDecl(I); - if (D->isVariadic()) { - IndentScope Indent(*this); - OS << "..."; - } + if (D->isVariadic()) + dumpChild([=]{ OS << "..."; }); + + if (D->capturesCXXThis()) + dumpChild([=]{ OS << "capture this"; }); - if (D->capturesCXXThis()) { - IndentScope Indent(*this); - OS << "capture this"; - } for (const auto &I : D->captures()) { - IndentScope Indent(*this); - OS << "capture"; - if (I.isByRef()) - OS << " byref"; - if (I.isNested()) - OS << " nested"; - if (I.getVariable()) { - OS << ' '; - dumpBareDeclRef(I.getVariable()); - } - if (I.hasCopyExpr()) - dumpStmt(I.getCopyExpr()); + dumpChild([=] { + OS << "capture"; + if (I.isByRef()) + OS << " byref"; + if (I.isNested()) + OS << " nested"; + if (I.getVariable()) { + OS << ' '; + dumpBareDeclRef(I.getVariable()); + } + if (I.hasCopyExpr()) + dumpStmt(I.getCopyExpr()); + }); } - lastChild(); dumpStmt(D->getBody()); } @@ -1500,29 +1573,23 @@ void ASTDumper::VisitBlockDecl(const BlockDecl *D) { //===----------------------------------------------------------------------===// void ASTDumper::dumpStmt(const Stmt *S) { - IndentScope Indent(*this); + dumpChild([=] { + if (!S) { + ColorScope Color(*this, NullColor); + OS << "<<<NULL>>>"; + return; + } - if (!S) { - ColorScope Color(*this, NullColor); - OS << "<<<NULL>>>"; - return; - } + if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { + VisitDeclStmt(DS); + return; + } - if (const DeclStmt *DS = dyn_cast<DeclStmt>(S)) { - VisitDeclStmt(DS); - return; - } + ConstStmtVisitor<ASTDumper>::Visit(S); - setMoreChildren(!S->children().empty()); - ConstStmtVisitor<ASTDumper>::Visit(S); - setMoreChildren(false); - for (Stmt::const_child_range CI = S->children(); CI; ++CI) { - Stmt::const_child_range Next = CI; - ++Next; - if (!Next) - lastChild(); - dumpStmt(*CI); - } + for (Stmt::const_child_range CI = S->children(); CI; ++CI) + dumpStmt(*CI); + }); } void ASTDumper::VisitStmt(const Stmt *Node) { @@ -1538,22 +1605,16 @@ void ASTDumper::VisitDeclStmt(const DeclStmt *Node) { VisitStmt(Node); for (DeclStmt::const_decl_iterator I = Node->decl_begin(), E = Node->decl_end(); - I != E; ++I) { - if (I + 1 == E) - lastChild(); + I != E; ++I) dumpDecl(*I); - } } void ASTDumper::VisitAttributedStmt(const AttributedStmt *Node) { VisitStmt(Node); for (ArrayRef<const Attr *>::iterator I = Node->getAttrs().begin(), E = Node->getAttrs().end(); - I != E; ++I) { - if (I + 1 == E) - lastChild(); + I != E; ++I) dumpAttr(*I); - } } void ASTDumper::VisitLabelStmt(const LabelStmt *Node) { @@ -1693,15 +1754,7 @@ void ASTDumper::VisitObjCIvarRefExpr(const ObjCIvarRefExpr *Node) { void ASTDumper::VisitPredefinedExpr(const PredefinedExpr *Node) { VisitExpr(Node); - switch (Node->getIdentType()) { - default: llvm_unreachable("unknown case"); - case PredefinedExpr::Func: OS << " __func__"; break; - case PredefinedExpr::Function: OS << " __FUNCTION__"; break; - case PredefinedExpr::FuncDName: OS << " __FUNCDNAME__"; break; - case PredefinedExpr::LFunction: OS << " L__FUNCTION__"; break; - case PredefinedExpr::PrettyFunction: OS << " __PRETTY_FUNCTION__";break; - case PredefinedExpr::FuncSig: OS << " __FUNCSIG__"; break; - } + OS << " " << PredefinedExpr::getIdentTypeName(Node->getIdentType()); } void ASTDumper::VisitCharacterLiteral(const CharacterLiteral *Node) { @@ -1734,12 +1787,10 @@ void ASTDumper::VisitStringLiteral(const StringLiteral *Str) { void ASTDumper::VisitInitListExpr(const InitListExpr *ILE) { VisitExpr(ILE); if (auto *Filler = ILE->getArrayFiller()) { - if (!ILE->getNumInits()) - lastChild(); - IndentScope Indent(*this); - OS << "array filler"; - lastChild(); - dumpStmt(Filler); + dumpChild([=] { + OS << "array filler"; + dumpStmt(Filler); + }); } if (auto *Field = ILE->getInitializedFieldInUnion()) { OS << " field "; @@ -1805,10 +1856,8 @@ void ASTDumper::VisitBlockExpr(const BlockExpr *Node) { void ASTDumper::VisitOpaqueValueExpr(const OpaqueValueExpr *Node) { VisitExpr(Node); - if (Expr *Source = Node->getSourceExpr()) { - lastChild(); + if (Expr *Source = Node->getSourceExpr()) dumpStmt(Source); - } } // GNU extensions. @@ -2024,27 +2073,24 @@ void ASTDumper::dumpFullComment(const FullComment *C) { } void ASTDumper::dumpComment(const Comment *C) { - IndentScope Indent(*this); - - if (!C) { - ColorScope Color(*this, NullColor); - OS << "<<<NULL>>>"; - return; - } + dumpChild([=] { + if (!C) { + ColorScope Color(*this, NullColor); + OS << "<<<NULL>>>"; + return; + } - { - ColorScope Color(*this, CommentColor); - OS << C->getCommentKindName(); - } - dumpPointer(C); - dumpSourceRange(C->getSourceRange()); - ConstCommentVisitor<ASTDumper>::visit(C); - for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); - I != E; ++I) { - if (I + 1 == E) - lastChild(); - dumpComment(*I); - } + { + ColorScope Color(*this, CommentColor); + OS << C->getCommentKindName(); + } + dumpPointer(C); + dumpSourceRange(C->getSourceRange()); + ConstCommentVisitor<ASTDumper>::visit(C); + for (Comment::child_iterator I = C->child_begin(), E = C->child_end(); + I != E; ++I) + dumpComment(*I); + }); } void ASTDumper::visitTextComment(const TextComment *C) { @@ -2148,6 +2194,23 @@ void ASTDumper::visitVerbatimLineComment(const VerbatimLineComment *C) { } //===----------------------------------------------------------------------===// +// Type method implementations +//===----------------------------------------------------------------------===// + +void QualType::dump(const char *msg) const { + if (msg) + llvm::errs() << msg << ": "; + dump(); +} + +LLVM_DUMP_METHOD void QualType::dump() const { + ASTDumper Dumper(llvm::errs(), nullptr, nullptr); + Dumper.dumpTypeAsChild(*this); +} + +LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); } + +//===----------------------------------------------------------------------===// // Decl method implementations //===----------------------------------------------------------------------===// @@ -2169,13 +2232,14 @@ LLVM_DUMP_METHOD void DeclContext::dumpLookups() const { dumpLookups(llvm::errs()); } -LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS) const { +LLVM_DUMP_METHOD void DeclContext::dumpLookups(raw_ostream &OS, + bool DumpDecls) const { const DeclContext *DC = this; while (!DC->isTranslationUnit()) DC = DC->getParent(); ASTContext &Ctx = cast<TranslationUnitDecl>(DC)->getASTContext(); ASTDumper P(OS, &Ctx.getCommentCommandTraits(), &Ctx.getSourceManager()); - P.dumpLookups(this); + P.dumpLookups(this, DumpDecls); } //===----------------------------------------------------------------------===// diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index b0e0b1dc9e00..2442e8ec25f1 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -151,6 +151,7 @@ namespace clang { Decl *VisitObjCMethodDecl(ObjCMethodDecl *D); Decl *VisitObjCCategoryDecl(ObjCCategoryDecl *D); Decl *VisitObjCProtocolDecl(ObjCProtocolDecl *D); + Decl *VisitLinkageSpecDecl(LinkageSpecDecl *D); Decl *VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); Decl *VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); Decl *VisitObjCImplementationDecl(ObjCImplementationDecl *D); @@ -1622,15 +1623,14 @@ QualType ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { ToEPI.HasTrailingReturn = FromEPI.HasTrailingReturn; ToEPI.TypeQuals = FromEPI.TypeQuals; ToEPI.RefQualifier = FromEPI.RefQualifier; - ToEPI.NumExceptions = ExceptionTypes.size(); - ToEPI.Exceptions = ExceptionTypes.data(); - ToEPI.ConsumedParameters = FromEPI.ConsumedParameters; - 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)); + ToEPI.ExceptionSpec.Type = FromEPI.ExceptionSpec.Type; + ToEPI.ExceptionSpec.Exceptions = ExceptionTypes; + ToEPI.ExceptionSpec.NoexceptExpr = + Importer.Import(FromEPI.ExceptionSpec.NoexceptExpr); + ToEPI.ExceptionSpec.SourceDecl = cast_or_null<FunctionDecl>( + Importer.Import(FromEPI.ExceptionSpec.SourceDecl)); + ToEPI.ExceptionSpec.SourceTemplate = cast_or_null<FunctionDecl>( + Importer.Import(FromEPI.ExceptionSpec.SourceTemplate)); return Importer.getToContext().getFunctionType(ToResultType, ArgTypes, ToEPI); } @@ -2093,10 +2093,11 @@ ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { } case TemplateArgument::Declaration: { - ValueDecl *FromD = From.getAsDecl(); - if (ValueDecl *To = cast_or_null<ValueDecl>(Importer.Import(FromD))) - return TemplateArgument(To, From.isDeclForReferenceParam()); - return TemplateArgument(); + ValueDecl *To = cast_or_null<ValueDecl>(Importer.Import(From.getAsDecl())); + QualType ToType = Importer.Import(From.getParamTypeForDecl()); + if (!To || ToType.isNull()) + return TemplateArgument(); + return TemplateArgument(To, ToType); } case TemplateArgument::NullPtr: { @@ -2253,7 +2254,7 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { } else { SmallVector<NamedDecl *, 4> ConflictingDecls; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Namespace)) continue; @@ -2316,7 +2317,7 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; @@ -2396,7 +2397,7 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { if (!DC->isFunctionOrMethod() && SearchName) { SmallVector<NamedDecl *, 4> ConflictingDecls; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(SearchName, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; @@ -2482,7 +2483,7 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { if (!DC->isFunctionOrMethod()) { SmallVector<NamedDecl *, 4> ConflictingDecls; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(SearchName, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; @@ -2604,7 +2605,7 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; @@ -2656,7 +2657,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; @@ -2712,8 +2713,9 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // 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) { + if (FromEPI.ExceptionSpec.SourceDecl || + FromEPI.ExceptionSpec.SourceTemplate || + FromEPI.ExceptionSpec.NoexceptExpr) { FunctionProtoType::ExtProtoInfo DefaultEPI; FromTy = Importer.getFromContext().getFunctionType( FromFPT->getReturnType(), FromFPT->getParamTypes(), DefaultEPI); @@ -2858,7 +2860,7 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { // Determine whether we've already imported this field. SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->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. @@ -2914,7 +2916,7 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { // Determine whether we've already imported this field. SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (IndirectFieldDecl *FoundField = dyn_cast<IndirectFieldDecl>(FoundDecls[I])) { @@ -2958,9 +2960,12 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { } IndirectFieldDecl *ToIndirectField = IndirectFieldDecl::Create( - Importer.getToContext(), DC, - Loc, Name.getAsIdentifierInfo(), T, - NamedChain, D->getChainingSize()); + Importer.getToContext(), DC, Loc, Name.getAsIdentifierInfo(), T, + NamedChain, D->getChainingSize()); + + for (const auto *Attr : D->attrs()) + ToIndirectField->addAttr(Attr->clone(Importer.getToContext())); + ToIndirectField->setAccess(D->getAccess()); ToIndirectField->setLexicalDeclContext(LexicalDC); Importer.Imported(D, ToIndirectField); @@ -2978,7 +2983,7 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { // Determine whether we've already imported this ivar SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (ObjCIvarDecl *FoundIvar = dyn_cast<ObjCIvarDecl>(FoundDecls[I])) { if (Importer.IsStructurallyEquivalent(D->getType(), @@ -3033,7 +3038,7 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { SmallVector<NamedDecl *, 4> ConflictingDecls; unsigned IDNS = Decl::IDNS_Ordinary; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(IDNS)) continue; @@ -3203,7 +3208,7 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { return nullptr; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (ObjCMethodDecl *FoundMethod = dyn_cast<ObjCMethodDecl>(FoundDecls[I])) { if (FoundMethod->isInstanceMethod() != D->isInstanceMethod()) @@ -3439,7 +3444,7 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { ObjCProtocolDecl *MergeWithProtocol = nullptr; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_ObjCProtocol)) continue; @@ -3466,6 +3471,36 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { return ToProto; } +Decl *ASTNodeImporter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { + DeclContext *DC = Importer.ImportContext(D->getDeclContext()); + DeclContext *LexicalDC = Importer.ImportContext(D->getLexicalDeclContext()); + + SourceLocation ExternLoc = Importer.Import(D->getExternLoc()); + SourceLocation LangLoc = Importer.Import(D->getLocation()); + + bool HasBraces = D->hasBraces(); + + LinkageSpecDecl *ToLinkageSpec = + LinkageSpecDecl::Create(Importer.getToContext(), + DC, + ExternLoc, + LangLoc, + D->getLanguage(), + HasBraces); + + if (HasBraces) { + SourceLocation RBraceLoc = Importer.Import(D->getRBraceLoc()); + ToLinkageSpec->setRBraceLoc(RBraceLoc); + } + + ToLinkageSpec->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(ToLinkageSpec); + + Importer.Imported(D, ToLinkageSpec); + + return ToLinkageSpec; +} + bool ASTNodeImporter::ImportDefinition(ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, ImportDefinitionKind Kind) { @@ -3585,7 +3620,7 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { // Look for an existing interface with the same name. ObjCInterfaceDecl *MergeWithIface = nullptr; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; @@ -3739,7 +3774,7 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { // Check whether we have already imported this property. SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (ObjCPropertyDecl *FoundProp = dyn_cast<ObjCPropertyDecl>(FoundDecls[I])) { @@ -3972,7 +4007,7 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { if (!DC->isFunctionOrMethod()) { SmallVector<NamedDecl *, 4> ConflictingDecls; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; @@ -4161,7 +4196,7 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { "Variable templates cannot be declared at function scope"); SmallVector<NamedDecl *, 4> ConflictingDecls; SmallVector<NamedDecl *, 2> FoundDecls; - DC->localUncachedLookup(Name, FoundDecls); + DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) { if (!FoundDecls[I]->isInIdentifierNamespace(Decl::IDNS_Ordinary)) continue; @@ -4371,7 +4406,7 @@ Expr *ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { Importer.Import(E->getQualifierLoc()), Importer.Import(E->getTemplateKeywordLoc()), ToD, - E->refersToEnclosingLocal(), + E->refersToEnclosingVariableOrCapture(), Importer.Import(E->getLocation()), T, E->getValueKind(), FoundD, @@ -4760,6 +4795,13 @@ NestedNameSpecifier *ASTImporter::Import(NestedNameSpecifier *FromNNS) { case NestedNameSpecifier::Global: return NestedNameSpecifier::GlobalSpecifier(ToContext); + case NestedNameSpecifier::Super: + if (CXXRecordDecl *RD = + cast<CXXRecordDecl>(Import(FromNNS->getAsRecordDecl()))) { + return NestedNameSpecifier::SuperSpecifier(ToContext, RD); + } + return nullptr; + case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { QualType T = Import(QualType(FromNNS->getAsType(), 0u)); @@ -4882,7 +4924,10 @@ SourceLocation ASTImporter::Import(SourceLocation FromLoc) { FromLoc = FromSM.getSpellingLoc(FromLoc); std::pair<FileID, unsigned> Decomposed = FromSM.getDecomposedLoc(FromLoc); SourceManager &ToSM = ToContext.getSourceManager(); - return ToSM.getLocForStartOfFile(Import(Decomposed.first)) + FileID ToFileID = Import(Decomposed.first); + if (ToFileID.isInvalid()) + return SourceLocation(); + return ToSM.getLocForStartOfFile(ToFileID) .getLocWithOffset(Decomposed.second); } @@ -4913,16 +4958,19 @@ FileID ASTImporter::Import(FileID FromID) { // FIXME: We definitely want to re-use the existing MemoryBuffer, rather // than mmap the files several times. const FileEntry *Entry = ToFileManager.getFile(Cache->OrigEntry->getName()); + if (!Entry) + return FileID(); ToID = ToSM.createFileID(Entry, ToIncludeLoc, FromSLoc.getFile().getFileCharacteristic()); } else { // FIXME: We want to re-use the existing MemoryBuffer! const llvm::MemoryBuffer * FromBuf = Cache->getBuffer(FromContext.getDiagnostics(), FromSM); - llvm::MemoryBuffer *ToBuf + std::unique_ptr<llvm::MemoryBuffer> ToBuf = llvm::MemoryBuffer::getMemBufferCopy(FromBuf->getBuffer(), FromBuf->getBufferIdentifier()); - ToID = ToSM.createFileID(ToBuf, FromSLoc.getFile().getFileCharacteristic()); + ToID = ToSM.createFileID(std::move(ToBuf), + FromSLoc.getFile().getFileCharacteristic()); } diff --git a/lib/AST/ASTTypeTraits.cpp b/lib/AST/ASTTypeTraits.cpp index baa8e48779a2..ec0671ceb1b5 100644 --- a/lib/AST/ASTTypeTraits.cpp +++ b/lib/AST/ASTTypeTraits.cpp @@ -62,6 +62,53 @@ bool ASTNodeKind::isBaseOf(NodeKindId Base, NodeKindId Derived, StringRef ASTNodeKind::asStringRef() const { return AllKindInfo[KindId].Name; } +ASTNodeKind ASTNodeKind::getMostDerivedType(ASTNodeKind Kind1, + ASTNodeKind Kind2) { + if (Kind1.isBaseOf(Kind2)) return Kind2; + if (Kind2.isBaseOf(Kind1)) return Kind1; + return ASTNodeKind(); +} + +ASTNodeKind ASTNodeKind::getMostDerivedCommonAncestor(ASTNodeKind Kind1, + ASTNodeKind Kind2) { + NodeKindId Parent = Kind1.KindId; + while (!isBaseOf(Parent, Kind2.KindId, nullptr) && Parent != NKI_None) { + Parent = AllKindInfo[Parent].ParentId; + } + return ASTNodeKind(Parent); +} + +ASTNodeKind ASTNodeKind::getFromNode(const Decl &D) { + switch (D.getKind()) { +#define DECL(DERIVED, BASE) \ + case Decl::DERIVED: return ASTNodeKind(NKI_##DERIVED##Decl); +#define ABSTRACT_DECL(D) +#include "clang/AST/DeclNodes.inc" + }; + llvm_unreachable("invalid decl kind"); +} + +ASTNodeKind ASTNodeKind::getFromNode(const Stmt &S) { + switch (S.getStmtClass()) { + case Stmt::NoStmtClass: return NKI_None; +#define STMT(CLASS, PARENT) \ + case Stmt::CLASS##Class: return ASTNodeKind(NKI_##CLASS); +#define ABSTRACT_STMT(S) +#include "clang/AST/StmtNodes.inc" + } + llvm_unreachable("invalid stmt kind"); +} + +ASTNodeKind ASTNodeKind::getFromNode(const Type &T) { + switch (T.getTypeClass()) { +#define TYPE(Class, Base) \ + case Type::Class: return ASTNodeKind(NKI_##Class##Type); +#define ABSTRACT_TYPE(Class, Base) +#include "clang/AST/TypeNodes.def" + } + llvm_unreachable("invalid type kind"); +} + void DynTypedNode::print(llvm::raw_ostream &OS, const PrintingPolicy &PP) const { if (const TemplateArgument *TA = get<TemplateArgument>()) diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 9006be64f73f..6ce347b4a31c 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -35,7 +35,6 @@ add_clang_library(clangAST ItaniumCXXABI.cpp ItaniumMangle.cpp Mangle.cpp - MangleNumberingContext.cpp MicrosoftCXXABI.cpp MicrosoftMangle.cpp NestedNameSpecifier.cpp diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h index 12b929b88db0..8e9e358525e8 100644 --- a/lib/AST/CXXABI.h +++ b/lib/AST/CXXABI.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_CXXABI_H -#define LLVM_CLANG_AST_CXXABI_H +#ifndef LLVM_CLANG_LIB_AST_CXXABI_H +#define LLVM_CLANG_LIB_AST_CXXABI_H #include "clang/AST/Type.h" diff --git a/lib/AST/Comment.cpp b/lib/AST/Comment.cpp index 4f433467f9bc..d05c5de543ff 100644 --- a/lib/AST/Comment.cpp +++ b/lib/AST/Comment.cpp @@ -157,8 +157,7 @@ void DeclInfo::fill() { case Decl::CXXConversion: { const FunctionDecl *FD = cast<FunctionDecl>(CommentDecl); Kind = FunctionKind; - ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(), - FD->getNumParams()); + ParamVars = llvm::makeArrayRef(FD->param_begin(), FD->getNumParams()); ReturnType = FD->getReturnType(); unsigned NumLists = FD->getNumTemplateParameterLists(); if (NumLists != 0) { @@ -178,8 +177,7 @@ void DeclInfo::fill() { case Decl::ObjCMethod: { const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(CommentDecl); Kind = FunctionKind; - ParamVars = ArrayRef<const ParmVarDecl *>(MD->param_begin(), - MD->param_size()); + ParamVars = llvm::makeArrayRef(MD->param_begin(), MD->param_size()); ReturnType = MD->getReturnType(); IsObjCMethod = true; IsInstanceMethod = MD->isInstanceMethod(); @@ -191,8 +189,7 @@ void DeclInfo::fill() { Kind = FunctionKind; TemplateKind = Template; const FunctionDecl *FD = FTD->getTemplatedDecl(); - ParamVars = ArrayRef<const ParmVarDecl *>(FD->param_begin(), - FD->getNumParams()); + ParamVars = llvm::makeArrayRef(FD->param_begin(), FD->getNumParams()); ReturnType = FD->getReturnType(); TemplateParameters = FTD->getTemplateParameters(); break; @@ -278,9 +275,7 @@ void DeclInfo::fill() { // Is this a typedef for a function type? if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { Kind = FunctionKind; - ArrayRef<ParmVarDecl *> Params = FTL.getParams(); - ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(), - Params.size()); + ParamVars = FTL.getParams(); ReturnType = FTL.getReturnLoc().getType(); break; } @@ -299,9 +294,7 @@ void DeclInfo::fill() { TypeLoc TL = MaybeFunctionTSI->getTypeLoc().getUnqualifiedLoc(); if (FunctionTypeLoc FTL = TL.getAs<FunctionTypeLoc>()) { Kind = FunctionKind; - ArrayRef<ParmVarDecl *> Params = FTL.getParams(); - ParamVars = ArrayRef<const ParmVarDecl *>(Params.data(), - Params.size()); + ParamVars = FTL.getParams(); ReturnType = FTL.getReturnLoc().getType(); } break; diff --git a/lib/AST/CommentCommandTraits.cpp b/lib/AST/CommentCommandTraits.cpp index a7b07a40c985..7378a7c3ac06 100644 --- a/lib/AST/CommentCommandTraits.cpp +++ b/lib/AST/CommentCommandTraits.cpp @@ -89,6 +89,10 @@ CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) { // Value-initialize (=zero-initialize in this case) a new CommandInfo. CommandInfo *Info = new (Allocator) CommandInfo(); Info->Name = Name; + // We only have a limited number of bits to encode command IDs in the + // CommandInfo structure, so the ID numbers can potentially wrap around. + assert((NextID < (1 << CommandInfo::NumCommandIDBits)) + && "Too many commands. We have limited bits for the command ID."); Info->ID = NextID++; RegisteredCommands.push_back(Info); diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index 792a8320449b..06a08bdad45f 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -362,7 +362,7 @@ void Lexer::lexCommentText(Token &T) { } } - const StringRef CommandName(BufferPtr + 1, Length); + StringRef CommandName(BufferPtr + 1, Length); const CommandInfo *Info = Traits.getCommandInfoOrNULL(CommandName); if (!Info) { @@ -531,7 +531,7 @@ void Lexer::lexVerbatimLineText(Token &T) { // Extract current line. const char *Newline = findNewline(BufferPtr, CommentEnd); - const StringRef Text(BufferPtr, Newline - BufferPtr); + StringRef Text(BufferPtr, Newline - BufferPtr); formTokenWithChars(T, Newline, tok::verbatim_line_text); T.setVerbatimLineText(Text); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 7448de2ffbc9..e43c28af9b69 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -29,6 +29,7 @@ #include "clang/Basic/Module.h" #include "clang/Basic/Specifiers.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/Support/ErrorHandling.h" #include <algorithm> @@ -38,6 +39,11 @@ Decl *clang::getPrimaryMergedDecl(Decl *D) { return D->getASTContext().getPrimaryMergedDecl(D); } +// Defined here so that it can be inlined into its direct callers. +bool Decl::isOutOfLine() const { + return !getLexicalDeclContext()->Equals(getDeclContext()); +} + //===----------------------------------------------------------------------===// // NamedDecl Implementation //===----------------------------------------------------------------------===// @@ -613,9 +619,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // Explicitly declared static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) return LinkageInfo(InternalLinkage, DefaultVisibility, false); + } else if (const auto *IFD = dyn_cast<IndirectFieldDecl>(D)) { + // - a data member of an anonymous union. + const VarDecl *VD = IFD->getVarDecl(); + assert(VD && "Expected a VarDecl in this IndirectFieldDecl!"); + return getLVForNamespaceScopeDecl(VD, computation); } - // - a data member of an anonymous union. - assert(!isa<IndirectFieldDecl>(D) && "Didn't expect an IndirectFieldDecl!"); assert(!isa<FieldDecl>(D) && "Didn't expect a FieldDecl!"); if (D->isInAnonymousNamespace()) { @@ -811,6 +820,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // Everything not covered here has no linkage. } else { + // FIXME: A typedef declaration has linkage if it gives a type a name for + // linkage purposes. return LinkageInfo::none(); } @@ -994,6 +1005,19 @@ bool NamedDecl::isLinkageValid() const { getCachedLinkage(); } +ObjCStringFormatFamily NamedDecl::getObjCFStringFormattingFamily() const { + StringRef name = getName(); + if (name.empty()) return SFF_None; + + if (name.front() == 'C') + if (name == "CFStringCreateWithFormat" || + name == "CFStringCreateWithFormatAndArguments" || + name == "CFStringAppendFormat" || + name == "CFStringAppendFormatAndArguments") + return SFF_CFString; + return SFF_None; +} + Linkage NamedDecl::getLinkageInternal() const { // We don't care about visibility here, so ask for the cheapest // possible visibility analysis. @@ -1168,7 +1192,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, } else { const FunctionDecl *FD = cast<FunctionDecl>(OuterD); if (!FD->isInlined() && - FD->getTemplateSpecializationKind() == TSK_Undeclared) + !isTemplateInstantiation(FD->getTemplateSpecializationKind())) return LinkageInfo::none(); LV = getLVForDecl(FD, computation); @@ -2607,7 +2631,7 @@ void FunctionDecl::setDeclsInPrototypeScope(ArrayRef<NamedDecl *> NewDecls) { if (!NewDecls.empty()) { NamedDecl **A = new (getASTContext()) NamedDecl*[NewDecls.size()]; std::copy(NewDecls.begin(), NewDecls.end(), A); - DeclsInPrototypeScope = ArrayRef<NamedDecl *>(A, NewDecls.size()); + DeclsInPrototypeScope = llvm::makeArrayRef(A, NewDecls.size()); // Move declarations introduced in prototype to the function context. for (auto I : NewDecls) { DeclContext *DC = I->getDeclContext(); @@ -3168,8 +3192,11 @@ unsigned FunctionDecl::getMemoryFunctionKind() const { return Builtin::BImemmove; case Builtin::BIstrlcpy: + case Builtin::BI__builtin___strlcpy_chk: return Builtin::BIstrlcpy; + case Builtin::BIstrlcat: + case Builtin::BI__builtin___strlcat_chk: return Builtin::BIstrlcat; case Builtin::BI__builtin_memcmp: @@ -3261,7 +3288,7 @@ bool FieldDecl::isAnonymousStructOrUnion() const { unsigned FieldDecl::getBitWidthValue(const ASTContext &Ctx) const { assert(isBitField() && "not a bitfield"); - Expr *BitWidth = InitializerOrBitWidth.getPointer(); + Expr *BitWidth = static_cast<Expr *>(InitStorage.getPointer()); return BitWidth->EvaluateKnownConstInt(Ctx).getZExtValue(); } @@ -3275,30 +3302,39 @@ unsigned FieldDecl::getFieldIndex() const { unsigned Index = 0; const RecordDecl *RD = getParent(); - for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end(); - I != E; ++I, ++Index) - I->getCanonicalDecl()->CachedFieldIndex = Index + 1; + for (auto *Field : RD->fields()) { + Field->getCanonicalDecl()->CachedFieldIndex = Index + 1; + ++Index; + } assert(CachedFieldIndex && "failed to find field in parent"); return CachedFieldIndex - 1; } SourceRange FieldDecl::getSourceRange() const { - if (const Expr *E = InitializerOrBitWidth.getPointer()) - return SourceRange(getInnerLocStart(), E->getLocEnd()); - return DeclaratorDecl::getSourceRange(); -} + switch (InitStorage.getInt()) { + // All three of these cases store an optional Expr*. + case ISK_BitWidthOrNothing: + case ISK_InClassCopyInit: + case ISK_InClassListInit: + if (const Expr *E = static_cast<const Expr *>(InitStorage.getPointer())) + return SourceRange(getInnerLocStart(), E->getLocEnd()); + // FALLTHROUGH -void FieldDecl::setBitWidth(Expr *Width) { - assert(!InitializerOrBitWidth.getPointer() && !hasInClassInitializer() && - "bit width or initializer already set"); - InitializerOrBitWidth.setPointer(Width); + case ISK_CapturedVLAType: + return DeclaratorDecl::getSourceRange(); + } + llvm_unreachable("bad init storage kind"); } -void FieldDecl::setInClassInitializer(Expr *Init) { - assert(!InitializerOrBitWidth.getPointer() && hasInClassInitializer() && - "bit width or initializer already set"); - InitializerOrBitWidth.setPointer(Init); +void FieldDecl::setCapturedVLAType(const VariableArrayType *VLAType) { + assert((getParent()->isLambda() || getParent()->isCapturedRecord()) && + "capturing type in non-lambda or captured record."); + assert(InitStorage.getInt() == ISK_BitWidthOrNothing && + InitStorage.getPointer() == nullptr && + "bit width, initializer or captured type already set"); + InitStorage.setPointerAndInt(const_cast<VariableArrayType *>(VLAType), + ISK_CapturedVLAType); } //===----------------------------------------------------------------------===// @@ -3521,6 +3557,20 @@ bool RecordDecl::isInjectedClassName() const { cast<RecordDecl>(getDeclContext())->getDeclName() == getDeclName(); } +bool RecordDecl::isLambda() const { + if (auto RD = dyn_cast<CXXRecordDecl>(this)) + return RD->isLambda(); + return false; +} + +bool RecordDecl::isCapturedRecord() const { + return hasAttr<CapturedRecordAttr>(); +} + +void RecordDecl::setCapturedRecord() { + addAttr(CapturedRecordAttr::CreateImplicit(getASTContext())); +} + RecordDecl::field_iterator RecordDecl::field_begin() const { if (hasExternalLexicalStorage() && !LoadedFieldsFromExternalStorage) LoadFieldsFromExternalStorage(); @@ -3578,6 +3628,64 @@ void RecordDecl::LoadFieldsFromExternalStorage() const { /*FieldsAlreadyLoaded=*/false); } +bool RecordDecl::mayInsertExtraPadding(bool EmitRemark) const { + ASTContext &Context = getASTContext(); + if (!Context.getLangOpts().Sanitize.has(SanitizerKind::Address) || + !Context.getLangOpts().SanitizeAddressFieldPadding) + return false; + const auto &Blacklist = Context.getSanitizerBlacklist(); + const CXXRecordDecl *CXXRD = dyn_cast<CXXRecordDecl>(this); + // We may be able to relax some of these requirements. + int ReasonToReject = -1; + if (!CXXRD || CXXRD->isExternCContext()) + ReasonToReject = 0; // is not C++. + else if (CXXRD->hasAttr<PackedAttr>()) + ReasonToReject = 1; // is packed. + else if (CXXRD->isUnion()) + ReasonToReject = 2; // is a union. + else if (CXXRD->isTriviallyCopyable()) + ReasonToReject = 3; // is trivially copyable. + else if (CXXRD->hasTrivialDestructor()) + ReasonToReject = 4; // has trivial destructor. + else if (CXXRD->isStandardLayout()) + ReasonToReject = 5; // is standard layout. + else if (Blacklist.isBlacklistedLocation(getLocation(), "field-padding")) + ReasonToReject = 6; // is in a blacklisted file. + else if (Blacklist.isBlacklistedType(getQualifiedNameAsString(), + "field-padding")) + ReasonToReject = 7; // is blacklisted. + + if (EmitRemark) { + if (ReasonToReject >= 0) + Context.getDiagnostics().Report( + getLocation(), + diag::remark_sanitize_address_insert_extra_padding_rejected) + << getQualifiedNameAsString() << ReasonToReject; + else + Context.getDiagnostics().Report( + getLocation(), + diag::remark_sanitize_address_insert_extra_padding_accepted) + << getQualifiedNameAsString(); + } + return ReasonToReject < 0; +} + +const FieldDecl *RecordDecl::findFirstNamedDataMember() const { + for (const auto *I : fields()) { + if (I->getIdentifier()) + return I; + + if (const RecordType *RT = I->getType()->getAs<RecordType>()) + if (const FieldDecl *NamedDataMember = + RT->getDecl()->findFirstNamedDataMember()) + return NamedDataMember; + } + + // We didn't find a named data member. + return nullptr; +} + + //===----------------------------------------------------------------------===// // BlockDecl Implementation //===----------------------------------------------------------------------===// @@ -3657,6 +3765,13 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) { SourceLocation()); } +void LabelDecl::setMSAsmLabel(StringRef Name) { + char *Buffer = new (getASTContext(), 1) char[Name.size() + 1]; + memcpy(Buffer, Name.data(), Name.size()); + Buffer[Name.size()] = '\0'; + MSAsmName = Buffer; +} + void ValueDecl::anchor() { } bool ValueDecl::isWeak() const { @@ -3892,8 +4007,8 @@ ArrayRef<SourceLocation> ImportDecl::getIdentifierLocs() const { const SourceLocation *StoredLocs = reinterpret_cast<const SourceLocation *>(this + 1); - return ArrayRef<SourceLocation>(StoredLocs, - getNumModuleIdentifiers(getImportedModule())); + return llvm::makeArrayRef(StoredLocs, + getNumModuleIdentifiers(getImportedModule())); } SourceRange ImportDecl::getSourceRange() const { diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 2b1506d191d1..a46787fb0e8f 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -374,8 +374,10 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); + VersionTuple VTI(A->getIntroduced()); + VTI.UseDotAsSeparator(); Out << "introduced in " << PrettyPlatformName << ' ' - << A->getIntroduced() << HintMessage; + << VTI << HintMessage; } return AR_NotYetIntroduced; @@ -386,8 +388,10 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); + VersionTuple VTO(A->getObsoleted()); + VTO.UseDotAsSeparator(); Out << "obsoleted in " << PrettyPlatformName << ' ' - << A->getObsoleted() << HintMessage; + << VTO << HintMessage; } return AR_Unavailable; @@ -398,8 +402,10 @@ static AvailabilityResult CheckAvailability(ASTContext &Context, if (Message) { Message->clear(); llvm::raw_string_ostream Out(*Message); + VersionTuple VTD(A->getDeprecated()); + VTD.UseDotAsSeparator(); Out << "first deprecated in " << PrettyPlatformName << ' ' - << A->getDeprecated() << HintMessage; + << VTD << HintMessage; } return AR_Deprecated; @@ -1296,6 +1302,11 @@ DeclContext::lookup(DeclarationName Name) { if (PrimaryContext != this) return PrimaryContext->lookup(Name); + // If this is a namespace, ensure that any later redeclarations of it have + // been loaded, since they may add names to the result of this lookup. + if (auto *ND = dyn_cast<NamespaceDecl>(this)) + (void)ND->getMostRecentDecl(); + if (hasExternalVisibleStorage()) { if (NeedToReconcileExternalVisibleStorage) reconcileExternalVisibleStorage(); @@ -1430,6 +1441,17 @@ DeclContext *DeclContext::getEnclosingNamespaceContext() { return Ctx->getPrimaryContext(); } +RecordDecl *DeclContext::getOuterLexicalRecordContext() { + // Loop until we find a non-record context. + RecordDecl *OutermostRD = nullptr; + DeclContext *DC = this; + while (DC->isRecord()) { + OutermostRD = cast<RecordDecl>(DC); + DC = DC->getLexicalParent(); + } + return OutermostRD; +} + bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const { // For non-file contexts, this is equivalent to Equals. if (!isFileContext()) diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index ed26c5262a7b..a6d9d411eef3 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -209,7 +209,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, // Now go through all virtual bases of this base and add them. for (const auto &VBase : BaseClassDecl->vbases()) { // Add this base if it's not already in the list. - if (SeenVBaseTypes.insert(C.getCanonicalType(VBase.getType()))) { + if (SeenVBaseTypes.insert(C.getCanonicalType(VBase.getType())).second) { VBases.push_back(&VBase); // C++11 [class.copy]p8: @@ -225,7 +225,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, if (Base->isVirtual()) { // Add this base if it's not already in the list. - if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType))) + if (SeenVBaseTypes.insert(C.getCanonicalType(BaseType)).second) VBases.push_back(Base); // C++0x [meta.unary.prop] is_empty: @@ -677,17 +677,24 @@ void CXXRecordDecl::addedMember(Decl *D) { // // Automatic Reference Counting: the presence of a member of Objective-C pointer type // that does not explicitly have no lifetime makes the class a non-POD. - // However, we delay setting PlainOldData to false in this case so that - // Sema has a chance to diagnostic causes where the same class will be - // non-POD with Automatic Reference Counting but a POD without ARC. - // In this case, the class will become a non-POD class when we complete - // the definition. ASTContext &Context = getASTContext(); QualType T = Context.getBaseElementType(Field->getType()); if (T->isObjCRetainableType() || T.isObjCGCStrong()) { - if (!Context.getLangOpts().ObjCAutoRefCount || - T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) + if (!Context.getLangOpts().ObjCAutoRefCount) { setHasObjectMember(true); + } else if (T.getObjCLifetime() != Qualifiers::OCL_ExplicitNone) { + // 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, move constructor, + // copy assignment operator, move assignment operator, and destructor are + // non-trivial. + setHasObjectMember(true); + struct DefinitionData &Data = data(); + Data.PlainOldData = false; + Data.HasTrivialSpecialMembers = 0; + Data.HasIrrelevantDestructor = false; + } } else if (!T.isCXX98PODType(Context)) data().PlainOldData = false; @@ -720,7 +727,7 @@ void CXXRecordDecl::addedMember(Decl *D) { // brace-or-equal-initializers for non-static data members. // // This rule was removed in C++1y. - if (!getASTContext().getLangOpts().CPlusPlus1y) + if (!getASTContext().getLangOpts().CPlusPlus14) data().Aggregate = false; // C++11 [class]p10: @@ -1254,6 +1261,44 @@ CXXRecordDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { llvm_unreachable("Not a class template or member class specialization"); } +const CXXRecordDecl *CXXRecordDecl::getTemplateInstantiationPattern() const { + // If it's a class template specialization, find the template or partial + // specialization from which it was instantiated. + if (auto *TD = dyn_cast<ClassTemplateSpecializationDecl>(this)) { + auto From = TD->getInstantiatedFrom(); + if (auto *CTD = From.dyn_cast<ClassTemplateDecl *>()) { + while (auto *NewCTD = CTD->getInstantiatedFromMemberTemplate()) { + if (NewCTD->isMemberSpecialization()) + break; + CTD = NewCTD; + } + return CTD->getTemplatedDecl(); + } + if (auto *CTPSD = + From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) { + while (auto *NewCTPSD = CTPSD->getInstantiatedFromMember()) { + if (NewCTPSD->isMemberSpecialization()) + break; + CTPSD = NewCTPSD; + } + return CTPSD; + } + } + + if (MemberSpecializationInfo *MSInfo = getMemberSpecializationInfo()) { + if (isTemplateInstantiation(MSInfo->getTemplateSpecializationKind())) { + const CXXRecordDecl *RD = this; + while (auto *NewRD = RD->getInstantiatedFromMemberClass()) + RD = NewRD; + return RD; + } + } + + assert(!isTemplateInstantiation(this->getTemplateSpecializationKind()) && + "couldn't find pattern for class template instantiation"); + return nullptr; +} + CXXDestructorDecl *CXXRecordDecl::getDestructor() const { ASTContext &Context = getASTContext(); QualType ClassType = Context.getTypeDeclType(this); @@ -1277,19 +1322,6 @@ void CXXRecordDecl::completeDefinition() { void CXXRecordDecl::completeDefinition(CXXFinalOverriderMap *FinalOverriders) { RecordDecl::completeDefinition(); - if (hasObjectMember() && getASTContext().getLangOpts().ObjCAutoRefCount) { - // 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, move constructor, - // copy assignment operator, move assignment operator, and destructor are - // non-trivial. - struct DefinitionData &Data = data(); - Data.PlainOldData = false; - Data.HasTrivialSpecialMembers = 0; - Data.HasIrrelevantDestructor = false; - } - // If the class may be abstract (but hasn't been marked as such), check for // any pure final overriders. if (mayBeAbstract()) { @@ -1799,7 +1831,6 @@ bool CXXConstructorDecl::isConvertingConstructor(bool AllowExplicit) const { bool CXXConstructorDecl::isSpecializationCopyingObject() const { if ((getNumParams() < 1) || (getNumParams() > 1 && !getParamDecl(1)->hasDefaultArg()) || - (getPrimaryTemplate() == nullptr) || (getDescribedFunctionTemplate() != nullptr)) return false; @@ -1970,6 +2001,16 @@ NamespaceDecl *NamespaceDecl::getMostRecentDeclImpl() { void NamespaceAliasDecl::anchor() { } +NamespaceAliasDecl *NamespaceAliasDecl::getNextRedeclarationImpl() { + return getNextRedeclaration(); +} +NamespaceAliasDecl *NamespaceAliasDecl::getPreviousDeclImpl() { + return getPreviousDecl(); +} +NamespaceAliasDecl *NamespaceAliasDecl::getMostRecentDeclImpl() { + return getMostRecentDecl(); +} + NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation UsingLoc, SourceLocation AliasLoc, @@ -1977,15 +2018,16 @@ NamespaceAliasDecl *NamespaceAliasDecl::Create(ASTContext &C, DeclContext *DC, NestedNameSpecifierLoc QualifierLoc, SourceLocation IdentLoc, NamedDecl *Namespace) { + // FIXME: Preserve the aliased namespace as written. if (NamespaceDecl *NS = dyn_cast_or_null<NamespaceDecl>(Namespace)) Namespace = NS->getOriginalNamespace(); - return new (C, DC) NamespaceAliasDecl(DC, UsingLoc, AliasLoc, Alias, + return new (C, DC) NamespaceAliasDecl(C, DC, UsingLoc, AliasLoc, Alias, QualifierLoc, IdentLoc, Namespace); } NamespaceAliasDecl * NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) { - return new (C, ID) NamespaceAliasDecl(nullptr, SourceLocation(), + return new (C, ID) NamespaceAliasDecl(C, nullptr, SourceLocation(), SourceLocation(), nullptr, NestedNameSpecifierLoc(), SourceLocation(), nullptr); diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index 2204dff13739..ed5367514c30 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -93,13 +93,13 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance, return nullptr; } -/// HasUserDeclaredSetterMethod - This routine returns 'true' if a user declared setter -/// method was found in the class, its protocols, its super classes or categories. -/// It also returns 'true' if one of its categories has declared a 'readwrite' property. -/// This is because, user must provide a setter method for the category's 'readwrite' -/// property. -bool -ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property) const { +/// \brief This routine returns 'true' if a user declared setter method was +/// found in the class, its protocols, its super classes or categories. +/// It also returns 'true' if one of its categories has declared a 'readwrite' +/// property. This is because, user must provide a setter method for the +/// category's 'readwrite' property. +bool ObjCContainerDecl::HasUserDeclaredSetterMethod( + const ObjCPropertyDecl *Property) const { Selector Sel = Property->getSetterName(); lookup_const_result R = lookup(Sel); for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end(); @@ -118,9 +118,10 @@ ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property) return true; if (Cat->IsClassExtension()) continue; - // Also search through the categories looking for a 'readwrite' declaration - // of this property. If one found, presumably a setter will be provided - // (properties declared in categories will not get auto-synthesized). + // Also search through the categories looking for a 'readwrite' + // declaration of this property. If one found, presumably a setter will + // be provided (properties declared in categories will not get + // auto-synthesized). for (const auto *P : Cat->properties()) if (P->getIdentifier() == Property->getIdentifier()) { if (P->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) @@ -151,7 +152,7 @@ ObjCContainerDecl::HasUserDeclaredSetterMethod(const ObjCPropertyDecl *Property) ObjCPropertyDecl * ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC, - IdentifierInfo *propertyID) { + const IdentifierInfo *propertyID) { // If this context is a hidden protocol definition, don't find any // property. if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(DC)) { @@ -181,8 +182,8 @@ ObjCPropertyDecl::getDefaultSynthIvarName(ASTContext &Ctx) const { /// FindPropertyDeclaration - Finds declaration of the property given its name /// in 'PropertyId' and returns it. It returns 0, if not found. -ObjCPropertyDecl * -ObjCContainerDecl::FindPropertyDeclaration(IdentifierInfo *PropertyId) const { +ObjCPropertyDecl *ObjCContainerDecl::FindPropertyDeclaration( + const IdentifierInfo *PropertyId) const { // Don't find properties within hidden protocol definitions. if (const ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(this)) { if (const ObjCProtocolDecl *Def = Proto->getDefinition()) @@ -558,36 +559,39 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupMethod(Selector Sel, LoadExternalDefinition(); while (ClassDecl) { + // 1. Look through primary class. if ((MethodDecl = ClassDecl->getMethod(Sel, isInstance))) return MethodDecl; - - // Didn't find one yet - look through protocols. - for (const auto *I : ClassDecl->protocols()) - if ((MethodDecl = I->lookupMethod(Sel, isInstance))) - return MethodDecl; - // Didn't find one yet - now look through categories. - for (const auto *Cat : ClassDecl->visible_categories()) { + // 2. Didn't find one yet - now look through categories. + for (const auto *Cat : ClassDecl->visible_categories()) if ((MethodDecl = Cat->getMethod(Sel, isInstance))) if (C != Cat || !MethodDecl->isImplicit()) return MethodDecl; - if (!shallowCategoryLookup) { + // 3. Didn't find one yet - look through primary class's protocols. + for (const auto *I : ClassDecl->protocols()) + if ((MethodDecl = I->lookupMethod(Sel, isInstance))) + return MethodDecl; + + // 4. Didn't find one yet - now look through categories' protocols + if (!shallowCategoryLookup) + for (const auto *Cat : ClassDecl->visible_categories()) { // Didn't find one yet - look through protocols. const ObjCList<ObjCProtocolDecl> &Protocols = - Cat->getReferencedProtocols(); + Cat->getReferencedProtocols(); for (ObjCList<ObjCProtocolDecl>::iterator I = Protocols.begin(), E = Protocols.end(); I != E; ++I) if ((MethodDecl = (*I)->lookupMethod(Sel, isInstance))) if (C != Cat || !MethodDecl->isImplicit()) return MethodDecl; } - } - + + if (!followSuper) return nullptr; - // Get the super class (if any). + // 5. Get to the super class (if any). ClassDecl = ClassDecl->getSuperClass(); } return nullptr; @@ -849,6 +853,11 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { family = OMF_None; break; + case OMF_initialize: + if (isInstanceMethod() || !getReturnType()->isVoidType()) + family = OMF_None; + break; + case OMF_performSelector: if (!isInstanceMethod() || !getReturnType()->isObjCIdType()) family = OMF_None; @@ -952,6 +961,13 @@ ObjCInterfaceDecl *ObjCMethodDecl::getClassInterface() { llvm_unreachable("unknown method context"); } +SourceRange ObjCMethodDecl::getReturnTypeSourceRange() const { + const auto *TSI = getReturnTypeSourceInfo(); + if (TSI) + return TSI->getTypeLoc().getSourceRange(); + return SourceRange(); +} + static void CollectOverriddenMethodsRecurse(const ObjCContainerDecl *Container, const ObjCMethodDecl *Method, SmallVectorImpl<const ObjCMethodDecl *> &Methods, diff --git a/lib/AST/DeclPrinter.cpp b/lib/AST/DeclPrinter.cpp index e5e5130f695a..c0f3e17693dc 100644 --- a/lib/AST/DeclPrinter.cpp +++ b/lib/AST/DeclPrinter.cpp @@ -87,6 +87,7 @@ namespace { void PrintTemplateParameters(const TemplateParameterList *Params, const TemplateArgumentList *Args = nullptr); void prettyPrintAttributes(Decl *D); + void printDeclType(QualType T, StringRef DeclName, bool Pack = false); }; } @@ -197,6 +198,17 @@ void DeclPrinter::prettyPrintAttributes(Decl *D) { } } +void DeclPrinter::printDeclType(QualType T, StringRef DeclName, bool Pack) { + // Normally, a PackExpansionType is written as T[3]... (for instance, as a + // template argument), but if it is the type of a declaration, the ellipsis + // is placed before the name being declared. + if (auto *PET = T->getAs<PackExpansionType>()) { + Pack = true; + T = PET->getPattern(); + } + T.print(Out, Policy, (Pack ? "..." : "") + DeclName); +} + void DeclPrinter::ProcessDeclGroup(SmallVectorImpl<Decl*>& Decls) { this->Indent(); Decl::printGroup(Decls.data(), Decls.size(), Out, Policy, Indentation); @@ -365,6 +377,9 @@ void DeclPrinter::VisitRecordDecl(RecordDecl *D) { if (!Policy.SuppressSpecifiers && D->isModulePrivate()) Out << "__module_private__ "; Out << D->getKindName(); + + prettyPrintAttributes(D); + if (D->getIdentifier()) Out << ' ' << *D; @@ -647,7 +662,6 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) { Out << *D << ":"; } - void DeclPrinter::VisitVarDecl(VarDecl *D) { if (!Policy.SuppressSpecifiers) { StorageClass SC = D->getStorageClass(); @@ -675,7 +689,7 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { QualType T = D->getTypeSourceInfo() ? D->getTypeSourceInfo()->getType() : D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); - T.print(Out, Policy, D->getName()); + printDeclType(T, D->getName()); Expr *Init = D->getInit(); if (!Policy.SuppressInitializers && Init) { bool ImplicitInit = false; @@ -757,6 +771,9 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { if (!Policy.SuppressSpecifiers && D->isModulePrivate()) Out << "__module_private__ "; Out << D->getKindName(); + + prettyPrintAttributes(D); + if (D->getIdentifier()) Out << ' ' << *D; @@ -773,9 +790,11 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { Out << "virtual "; AccessSpecifier AS = Base->getAccessSpecifierAsWritten(); - if (AS != AS_none) + if (AS != AS_none) { Print(AS); - Out << " " << Base->getType().getAsString(Policy); + Out << " "; + } + Out << Base->getType().getAsString(Policy); if (Base->isPackExpansion()) Out << "..."; @@ -830,7 +849,7 @@ void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params, Out << "class "; if (TTP->isParameterPack()) - Out << "... "; + Out << "..."; Out << *TTP; @@ -843,15 +862,10 @@ void DeclPrinter::PrintTemplateParameters(const TemplateParameterList *Params, }; } else if (const NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { - Out << NTTP->getType().getAsString(Policy); - - if (NTTP->isParameterPack() && !isa<PackExpansionType>(NTTP->getType())) - Out << "..."; - - if (IdentifierInfo *Name = NTTP->getIdentifier()) { - Out << ' '; - Out << Name->getName(); - } + StringRef Name; + if (IdentifierInfo *II = NTTP->getIdentifier()) + Name = II->getName(); + printDeclType(NTTP->getType(), Name, NTTP->isParameterPack()); if (Args) { Out << " = "; @@ -940,11 +954,12 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { if (OMD->isVariadic()) Out << ", ..."; + + prettyPrintAttributes(OMD); if (OMD->getBody() && !Policy.TerseOutput) { Out << ' '; OMD->getBody()->printPretty(Out, nullptr, Policy); - Out << '\n'; } else if (Policy.PolishForDeclaration) Out << ';'; @@ -954,6 +969,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { std::string I = OID->getNameAsString(); ObjCInterfaceDecl *SID = OID->getSuperClass(); + bool eolnOut = false; if (SID) Out << "@implementation " << I << " : " << *SID; else @@ -961,6 +977,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { if (OID->ivar_size() > 0) { Out << "{\n"; + eolnOut = true; Indentation += Policy.Indentation; for (const auto *I : OID->ivars()) { Indent() << I->getASTContext().getUnqualifiedObjCPointerType(I->getType()). @@ -969,7 +986,13 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { Indentation -= Policy.Indentation; Out << "}\n"; } + else if (SID || (OID->decls_begin() != OID->decls_end())) { + Out << "\n"; + eolnOut = true; + } VisitDeclContext(OID, false); + if (!eolnOut) + Out << "\n"; Out << "@end"; } @@ -1008,14 +1031,14 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { Indentation -= Policy.Indentation; Out << "}\n"; } - else if (SID) { + else if (SID || (OID->decls_begin() != OID->decls_end())) { Out << "\n"; eolnOut = true; } VisitDeclContext(OID, false); if (!eolnOut) - Out << ' '; + Out << "\n"; Out << "@end"; // FIXME: implement the rest... } diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 5f559b7e5ce3..712de5056e8d 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -195,12 +195,12 @@ SourceLocation Expr::getExprLoc() const { case Stmt::NoStmtClass: llvm_unreachable("statement without class"); #define ABSTRACT_STMT(type) #define STMT(type, base) \ - case Stmt::type##Class: llvm_unreachable(#type " is not an Expr"); break; + case Stmt::type##Class: break; #define EXPR(type, base) \ case Stmt::type##Class: return getExprLocImpl<type>(this, &type::getExprLoc); #include "clang/AST/StmtNodes.inc" } - llvm_unreachable("unknown statement kind"); + llvm_unreachable("unknown expression kind"); } //===----------------------------------------------------------------------===// @@ -221,11 +221,11 @@ static void computeDeclRefDependence(const ASTContext &Ctx, NamedDecl *D, // (TD) C++ [temp.dep.expr]p3: // An id-expression is type-dependent if it contains: // - // and + // and // // (VD) C++ [temp.dep.constexpr]p2: // An identifier is value-dependent if it is: - + // (TD) - an identifier that was declared with dependent type // (VD) - a name declared with a dependent type, if (T->isDependentType()) { @@ -309,29 +309,11 @@ void DeclRefExpr::computeDependence(const ASTContext &Ctx) { bool InstantiationDependent = false; computeDeclRefDependence(Ctx, getDecl(), getType(), TypeDependent, ValueDependent, InstantiationDependent); - - // (TD) C++ [temp.dep.expr]p3: - // An id-expression is type-dependent if it contains: - // - // and - // - // (VD) C++ [temp.dep.constexpr]p2: - // An identifier is value-dependent if it is: - if (!TypeDependent && !ValueDependent && - hasExplicitTemplateArgs() && - TemplateSpecializationType::anyDependentTemplateArguments( - getTemplateArgs(), - getNumTemplateArgs(), - InstantiationDependent)) { - TypeDependent = true; - ValueDependent = true; - InstantiationDependent = true; - } - - ExprBits.TypeDependent = TypeDependent; - ExprBits.ValueDependent = ValueDependent; - ExprBits.InstantiationDependent = InstantiationDependent; - + + ExprBits.TypeDependent |= TypeDependent; + ExprBits.ValueDependent |= ValueDependent; + ExprBits.InstantiationDependent |= InstantiationDependent; + // Is the declaration a parameter pack? if (getDecl()->isParameterPack()) ExprBits.ContainsUnexpandedParameterPack = true; @@ -340,7 +322,7 @@ void DeclRefExpr::computeDependence(const ASTContext &Ctx) { DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, - ValueDecl *D, bool RefersToEnclosingLocal, + ValueDecl *D, bool RefersToEnclosingVariableOrCapture, const DeclarationNameInfo &NameInfo, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs, @@ -348,14 +330,21 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, : Expr(DeclRefExprClass, T, VK, OK_Ordinary, false, false, false, false), D(D), Loc(NameInfo.getLoc()), DNLoc(NameInfo.getInfo()) { DeclRefExprBits.HasQualifier = QualifierLoc ? 1 : 0; - if (QualifierLoc) + if (QualifierLoc) { getInternalQualifierLoc() = QualifierLoc; + auto *NNS = QualifierLoc.getNestedNameSpecifier(); + if (NNS->isInstantiationDependent()) + ExprBits.InstantiationDependent = true; + if (NNS->containsUnexpandedParameterPack()) + ExprBits.ContainsUnexpandedParameterPack = true; + } DeclRefExprBits.HasFoundDecl = FoundD ? 1 : 0; if (FoundD) getInternalFoundDecl() = FoundD; DeclRefExprBits.HasTemplateKWAndArgsInfo = (TemplateArgs || TemplateKWLoc.isValid()) ? 1 : 0; - DeclRefExprBits.RefersToEnclosingLocal = RefersToEnclosingLocal; + DeclRefExprBits.RefersToEnclosingVariableOrCapture = + RefersToEnclosingVariableOrCapture; if (TemplateArgs) { bool Dependent = false; bool InstantiationDependent = false; @@ -364,8 +353,9 @@ DeclRefExpr::DeclRefExpr(const ASTContext &Ctx, Dependent, InstantiationDependent, ContainsUnexpandedParameterPack); - if (InstantiationDependent) - setInstantiationDependent(true); + assert(!Dependent && "built a DeclRefExpr with dependent template args"); + ExprBits.InstantiationDependent |= InstantiationDependent; + ExprBits.ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack; } else if (TemplateKWLoc.isValid()) { getTemplateKWAndArgsInfo()->initializeFrom(TemplateKWLoc); } @@ -378,14 +368,14 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, - bool RefersToEnclosingLocal, + bool RefersToEnclosingVariableOrCapture, SourceLocation NameLoc, QualType T, ExprValueKind VK, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) { return Create(Context, QualifierLoc, TemplateKWLoc, D, - RefersToEnclosingLocal, + RefersToEnclosingVariableOrCapture, DeclarationNameInfo(D->getDeclName(), NameLoc), T, VK, FoundD, TemplateArgs); } @@ -394,7 +384,7 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, ValueDecl *D, - bool RefersToEnclosingLocal, + bool RefersToEnclosingVariableOrCapture, const DeclarationNameInfo &NameInfo, QualType T, ExprValueKind VK, @@ -416,7 +406,7 @@ DeclRefExpr *DeclRefExpr::Create(const ASTContext &Context, void *Mem = Context.Allocate(Size, llvm::alignOf<DeclRefExpr>()); return new (Mem) DeclRefExpr(Context, QualifierLoc, TemplateKWLoc, D, - RefersToEnclosingLocal, + RefersToEnclosingVariableOrCapture, NameInfo, FoundD, TemplateArgs, T, VK); } @@ -448,6 +438,38 @@ SourceLocation DeclRefExpr::getLocEnd() const { return getNameInfo().getLocEnd(); } +PredefinedExpr::PredefinedExpr(SourceLocation L, QualType FNTy, IdentType IT, + StringLiteral *SL) + : Expr(PredefinedExprClass, FNTy, VK_LValue, OK_Ordinary, + FNTy->isDependentType(), FNTy->isDependentType(), + FNTy->isInstantiationDependentType(), + /*ContainsUnexpandedParameterPack=*/false), + Loc(L), Type(IT), FnName(SL) {} + +StringLiteral *PredefinedExpr::getFunctionName() { + return cast_or_null<StringLiteral>(FnName); +} + +StringRef PredefinedExpr::getIdentTypeName(PredefinedExpr::IdentType IT) { + switch (IT) { + case Func: + return "__func__"; + case Function: + return "__FUNCTION__"; + case FuncDName: + return "__FUNCDNAME__"; + case LFunction: + return "L__FUNCTION__"; + case PrettyFunction: + return "__PRETTY_FUNCTION__"; + case FuncSig: + return "__FUNCSIG__"; + case PrettyFunctionNoVirtual: + break; + } + llvm_unreachable("Unknown ident type for PredefinedExpr"); +} + // FIXME: Maybe this should use DeclPrinter with a special "print predefined // expr" policy instead. std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { @@ -477,6 +499,22 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { } return ""; } + if (auto *BD = dyn_cast<BlockDecl>(CurrentDecl)) { + std::unique_ptr<MangleContext> MC; + MC.reset(Context.createMangleContext()); + SmallString<256> Buffer; + llvm::raw_svector_ostream Out(Buffer); + auto DC = CurrentDecl->getDeclContext(); + if (DC->isFileContext()) + MC->mangleGlobalBlock(BD, /*ID*/ nullptr, Out); + else if (const auto *CD = dyn_cast<CXXConstructorDecl>(DC)) + MC->mangleCtorBlock(CD, /*CT*/ Ctor_Complete, BD, Out); + else if (const auto *DD = dyn_cast<CXXDestructorDecl>(DC)) + MC->mangleDtorBlock(DD, /*DT*/ Dtor_Complete, BD, Out); + else + MC->mangleBlock(DC, BD, Out); + return Out.str(); + } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CurrentDecl)) { if (IT != PrettyFunction && IT != PrettyFunctionNoVirtual && IT != FuncSig) return FD->getNameAsString(); @@ -509,6 +547,7 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { case CC_X86StdCall: POut << "__stdcall "; break; case CC_X86FastCall: POut << "__fastcall "; break; case CC_X86ThisCall: POut << "__thiscall "; break; + case CC_X86VectorCall: POut << "__vectorcall "; break; // Only bother printing the conventions that MSVC knows about. default: break; } @@ -600,9 +639,8 @@ std::string PredefinedExpr::ComputeName(IdentType IT, const Decl *CurrentDecl) { // type deduction and lambdas. For trailing return types resolve the // decltype expression. Otherwise print the real type when this is // not a constructor or destructor. - if ((isa<CXXMethodDecl>(FD) && - cast<CXXMethodDecl>(FD)->getParent()->isLambda()) || - (FT && FT->getReturnType()->getAs<AutoType>())) + if (isa<CXXMethodDecl>(FD) && + cast<CXXMethodDecl>(FD)->getParent()->isLambda()) Proto = "auto " + Proto; else if (FT && FT->getReturnType()->getAs<DecltypeType>()) FT->getReturnType() @@ -1252,7 +1290,7 @@ SourceLocation CallExpr::getLocStart() const { return cast<CXXOperatorCallExpr>(this)->getLocStart(); SourceLocation begin = getCallee()->getLocStart(); - if (begin.isInvalid() && getNumArgs() > 0) + if (begin.isInvalid() && getNumArgs() > 0 && getArg(0)) begin = getArg(0)->getLocStart(); return begin; } @@ -1261,7 +1299,7 @@ SourceLocation CallExpr::getLocEnd() const { return cast<CXXOperatorCallExpr>(this)->getLocEnd(); SourceLocation end = getRParenLoc(); - if (end.isInvalid() && getNumArgs() > 0) + if (end.isInvalid() && getNumArgs() > 0 && getArg(getNumArgs() - 1)) end = getArg(getNumArgs() - 1)->getLocEnd(); return end; } @@ -2734,10 +2772,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, if (ILE->getType()->isRecordType()) { unsigned ElementNo = 0; RecordDecl *RD = ILE->getType()->getAs<RecordType>()->getDecl(); - for (RecordDecl::field_iterator Field = RD->field_begin(), - FieldEnd = RD->field_end(); Field != FieldEnd; ++Field) { + for (const auto *Field : RD->fields()) { // If this is a union, skip all the fields that aren't being initialized. - if (RD->isUnion() && ILE->getInitializedFieldInUnion() != *Field) + if (RD->isUnion() && ILE->getInitializedFieldInUnion() != Field) continue; // Don't emit anonymous bitfields, they just affect layout. @@ -2830,9 +2867,16 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, return false; } -bool Expr::HasSideEffects(const ASTContext &Ctx) const { +bool Expr::HasSideEffects(const ASTContext &Ctx, + bool IncludePossibleEffects) const { + // In circumstances where we care about definite side effects instead of + // potential side effects, we want to ignore expressions that are part of a + // macro expansion as a potential side effect. + if (!IncludePossibleEffects && getExprLoc().isMacroID()) + return false; + if (isInstantiationDependent()) - return true; + return IncludePossibleEffects; switch (getStmtClass()) { case NoStmtClass: @@ -2850,6 +2894,8 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case PackExpansionExprClass: case SubstNonTypeTemplateParmPackExprClass: case FunctionParmPackExprClass: + case TypoExprClass: + case CXXFoldExprClass: llvm_unreachable("shouldn't see dependent / unresolved nodes here"); case DeclRefExprClass: @@ -2883,21 +2929,27 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { return false; case CallExprClass: + case CXXOperatorCallExprClass: + case CXXMemberCallExprClass: + case CUDAKernelCallExprClass: + case BlockExprClass: + case CXXBindTemporaryExprClass: + case UserDefinedLiteralClass: + // We don't know a call definitely has side effects, but we can check the + // call's operands. + if (!IncludePossibleEffects) + break; + return true; + case MSPropertyRefExprClass: case CompoundAssignOperatorClass: case VAArgExprClass: case AtomicExprClass: case StmtExprClass: - case CXXOperatorCallExprClass: - case CXXMemberCallExprClass: - case UserDefinedLiteralClass: case CXXThrowExprClass: case CXXNewExprClass: case CXXDeleteExprClass: case ExprWithCleanupsClass: - case CXXBindTemporaryExprClass: - case BlockExprClass: - case CUDAKernelCallExprClass: // These always have a side-effect. return true; @@ -2933,25 +2985,29 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case InitListExprClass: // FIXME: The children for an InitListExpr doesn't include the array filler. if (const Expr *E = cast<InitListExpr>(this)->getArrayFiller()) - if (E->HasSideEffects(Ctx)) + if (E->HasSideEffects(Ctx, IncludePossibleEffects)) return true; break; case GenericSelectionExprClass: return cast<GenericSelectionExpr>(this)->getResultExpr()-> - HasSideEffects(Ctx); + HasSideEffects(Ctx, IncludePossibleEffects); case ChooseExprClass: - return cast<ChooseExpr>(this)->getChosenSubExpr()->HasSideEffects(Ctx); + return cast<ChooseExpr>(this)->getChosenSubExpr()->HasSideEffects( + Ctx, IncludePossibleEffects); case CXXDefaultArgExprClass: - return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects(Ctx); + return cast<CXXDefaultArgExpr>(this)->getExpr()->HasSideEffects( + Ctx, IncludePossibleEffects); - case CXXDefaultInitExprClass: - if (const Expr *E = cast<CXXDefaultInitExpr>(this)->getExpr()) - return E->HasSideEffects(Ctx); + case CXXDefaultInitExprClass: { + const FieldDecl *FD = cast<CXXDefaultInitExpr>(this)->getField(); + if (const Expr *E = FD->getInClassInitializer()) + return E->HasSideEffects(Ctx, IncludePossibleEffects); // If we've not yet parsed the initializer, assume it has side-effects. return true; + } case CXXDynamicCastExprClass: { // A dynamic_cast expression has side-effects if it can throw. @@ -2966,6 +3022,13 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case CXXReinterpretCastExprClass: case CXXConstCastExprClass: case CXXFunctionalCastExprClass: { + // While volatile reads are side-effecting in both C and C++, we treat them + // as having possible (not definite) side-effects. This allows idiomatic + // code to behave without warning, such as sizeof(*v) for a volatile- + // qualified pointer. + if (!IncludePossibleEffects) + break; + const CastExpr *CE = cast<CastExpr>(this); if (CE->getCastKind() == CK_LValueToRValue && CE->getSubExpr()->getType().isVolatileQualified()) @@ -2981,7 +3044,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case CXXConstructExprClass: case CXXTemporaryObjectExprClass: { const CXXConstructExpr *CE = cast<CXXConstructExpr>(this); - if (!CE->getConstructor()->isTrivial()) + if (!CE->getConstructor()->isTrivial() && IncludePossibleEffects) return true; // A trivial constructor does not add any side-effects of its own. Just look // at its arguments. @@ -3009,7 +3072,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { const Expr *Subexpr = *I; if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Subexpr)) Subexpr = OVE->getSourceExpr(); - if (Subexpr->HasSideEffects(Ctx)) + if (Subexpr->HasSideEffects(Ctx, IncludePossibleEffects)) return true; } return false; @@ -3018,22 +3081,24 @@ bool Expr::HasSideEffects(const ASTContext &Ctx) const { case ObjCBoxedExprClass: case ObjCArrayLiteralClass: case ObjCDictionaryLiteralClass: - case ObjCMessageExprClass: case ObjCSelectorExprClass: case ObjCProtocolExprClass: - case ObjCPropertyRefExprClass: case ObjCIsaExprClass: case ObjCIndirectCopyRestoreExprClass: case ObjCSubscriptRefExprClass: case ObjCBridgedCastExprClass: - // FIXME: Classify these cases better. - return true; + case ObjCMessageExprClass: + case ObjCPropertyRefExprClass: + // FIXME: Classify these cases better. + if (IncludePossibleEffects) + return true; + break; } // Recurse to children. for (const_child_range SubStmts = children(); SubStmts; ++SubStmts) if (const Stmt *S = *SubStmts) - if (cast<Expr>(S)->HasSideEffects(Ctx)) + if (cast<Expr>(S)->HasSideEffects(Ctx, IncludePossibleEffects)) return true; return false; @@ -3279,6 +3344,10 @@ FieldDecl *Expr::getSourceBitField() { return BinOp->getRHS()->getSourceBitField(); } + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) + if (UnOp->isPrefix() && UnOp->isIncrementDecrementOp()) + return UnOp->getSubExpr()->getSourceBitField(); + return nullptr; } @@ -3759,7 +3828,7 @@ DesignatedInitExpr::DesignatedInitExpr(const ASTContext &C, QualType Ty, // Compute type- and value-dependence. Expr *Index = IndexExprs[IndexIdx]; if (Index->isTypeDependent() || Index->isValueDependent()) - ExprBits.ValueDependent = true; + ExprBits.TypeDependent = ExprBits.ValueDependent = true; if (Index->isInstantiationDependent()) ExprBits.InstantiationDependent = true; // Propagate unexpanded parameter packs. @@ -3774,7 +3843,7 @@ DesignatedInitExpr::DesignatedInitExpr(const ASTContext &C, QualType Ty, Expr *End = IndexExprs[IndexIdx + 1]; if (Start->isTypeDependent() || Start->isValueDependent() || End->isTypeDependent() || End->isValueDependent()) { - ExprBits.ValueDependent = true; + ExprBits.TypeDependent = ExprBits.ValueDependent = true; ExprBits.InstantiationDependent = true; } else if (Start->isInstantiationDependent() || End->isInstantiationDependent()) { diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 64c21dd5c4fd..93361666183b 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -909,16 +909,21 @@ LambdaCapture::LambdaCapture(SourceLocation Loc, bool Implicit, case LCK_ByRef: assert(Var && "capture must have a variable!"); break; + case LCK_VLAType: + assert(!Var && "VLA type capture cannot have a variable!"); + Bits |= Capture_ByCopy; + break; } DeclAndBits.setInt(Bits); } LambdaCaptureKind LambdaCapture::getCaptureKind() const { Decl *D = DeclAndBits.getPointer(); + bool CapByCopy = DeclAndBits.getInt() & Capture_ByCopy; if (!D) - return LCK_This; + return CapByCopy ? LCK_VLAType : LCK_This; - return (DeclAndBits.getInt() & Capture_ByCopy) ? LCK_ByCopy : LCK_ByRef; + return CapByCopy ? LCK_ByCopy : LCK_ByRef; } LambdaExpr::LambdaExpr(QualType T, @@ -1073,8 +1078,8 @@ LambdaExpr::getCaptureInitIndexVars(capture_init_iterator Iter) const { "Capture index out-of-range"); VarDecl **IndexVars = getArrayIndexVars(); unsigned *IndexStarts = getArrayIndexStarts(); - return ArrayRef<VarDecl *>(IndexVars + IndexStarts[Index], - IndexVars + IndexStarts[Index + 1]); + return llvm::makeArrayRef(IndexVars + IndexStarts[Index], + IndexVars + IndexStarts[Index + 1]); } CXXRecordDecl *LambdaExpr::getLambdaClass() const { @@ -1399,7 +1404,8 @@ CXXRecordDecl *UnresolvedMemberExpr::getNamingClass() const { // It can't be dependent: after all, we were actually able to do the // lookup. CXXRecordDecl *Record = nullptr; - if (getQualifier()) { + auto *NNS = getQualifier(); + if (NNS && NNS->getKind() != NestedNameSpecifier::Super) { const Type *T = getQualifier()->getAsType(); assert(T && "qualifier in member expression does not name type"); Record = T->getAsCXXRecordDecl(); diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index d3d25308a386..933ea97fa2ba 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -124,10 +124,11 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::ObjCPropertyRefExprClass: // C++ [expr.typeid]p1: The result of a typeid expression is an lvalue of... case Expr::CXXTypeidExprClass: - // Unresolved lookups get classified as lvalues. + // Unresolved lookups and uncorrected typos get classified as lvalues. // FIXME: Is this wise? Should they get their own kind? case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: + case Expr::TypoExprClass: case Expr::CXXDependentScopeMemberExprClass: case Expr::DependentScopeDeclRefExprClass: // ObjC instance variables are lvalues @@ -181,6 +182,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::AsTypeExprClass: case Expr::ObjCIndirectCopyRestoreExprClass: case Expr::AtomicExprClass: + case Expr::CXXFoldExprClass: return Cl::CL_PRValue; // Next come the complicated cases. @@ -613,14 +615,9 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, return Cl::CM_IncompleteType; // Records with any const fields (recursively) are not modifiable. - if (const RecordType *R = CT->getAs<RecordType>()) { - assert((E->getObjectKind() == OK_ObjCProperty || - !Ctx.getLangOpts().CPlusPlus) && - "C++ struct assignment should be resolved by the " - "copy assignment operator."); + if (const RecordType *R = CT->getAs<RecordType>()) if (R->hasConstFields()) return Cl::CM_ConstQualified; - } return Cl::CM_Modifiable; } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 7d7ca9924c85..3d7f2dca7a2f 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -201,6 +201,7 @@ namespace { /// Determine whether this is a one-past-the-end pointer. bool isOnePastTheEnd() const { + assert(!Invalid); if (IsOnePastTheEnd) return true; if (MostDerivedArraySize && @@ -1308,7 +1309,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, } // Does this refer one past the end of some object? - if (Designator.isOnePastTheEnd()) { + if (!Designator.Invalid && Designator.isOnePastTheEnd()) { const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>(); Info.Diag(Loc, diag::note_constexpr_past_end, 1) << !Designator.Entries.empty() << !!VD << VD; @@ -1328,7 +1329,7 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E, // C++1y: A constant initializer for an object o [...] may also invoke // constexpr constructors for o and its subobjects even if those objects // are of non-literal class types. - if (Info.getLangOpts().CPlusPlus1y && This && + if (Info.getLangOpts().CPlusPlus14 && This && Info.EvaluatingDecl == This->getLValueBase()) return true; @@ -1421,6 +1422,17 @@ static bool IsWeakLValue(const LValue &Value) { return Decl && Decl->isWeak(); } +static bool isZeroSized(const LValue &Value) { + const ValueDecl *Decl = GetLValueBaseDecl(Value); + if (Decl && isa<VarDecl>(Decl)) { + QualType Ty = Decl->getType(); + if (Ty->isArrayType()) + return Ty->isIncompleteType() || + Decl->getASTContext().getTypeSize(Ty) == 0; + } + return false; +} + static bool EvalPointerValueAsBool(const APValue &Value, bool &Result) { // A null base expression indicates a null pointer. These are always // evaluatable, and they are false unless the offset is zero. @@ -2020,7 +2032,9 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived, /// Extract the value of a character from a string literal. static APSInt extractStringLiteralCharacter(EvalInfo &Info, const Expr *Lit, uint64_t Index) { - // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant + // FIXME: Support ObjCEncodeExpr, MakeStringConstant + if (auto PE = dyn_cast<PredefinedExpr>(Lit)) + Lit = PE->getFunctionName(); const StringLiteral *S = cast<StringLiteral>(Lit); const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(S->getType()); @@ -2079,6 +2093,64 @@ static void expandArray(APValue &Array, unsigned Index) { Array.swap(NewValue); } +/// Determine whether a type would actually be read by an lvalue-to-rvalue +/// conversion. If it's of class type, we may assume that the copy operation +/// is trivial. Note that this is never true for a union type with fields +/// (because the copy always "reads" the active member) and always true for +/// a non-class type. +static bool isReadByLvalueToRvalueConversion(QualType T) { + CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + if (!RD || (RD->isUnion() && !RD->field_empty())) + return true; + if (RD->isEmpty()) + return false; + + for (auto *Field : RD->fields()) + if (isReadByLvalueToRvalueConversion(Field->getType())) + return true; + + for (auto &BaseSpec : RD->bases()) + if (isReadByLvalueToRvalueConversion(BaseSpec.getType())) + return true; + + return false; +} + +/// Diagnose an attempt to read from any unreadable field within the specified +/// type, which might be a class type. +static bool diagnoseUnreadableFields(EvalInfo &Info, const Expr *E, + QualType T) { + CXXRecordDecl *RD = T->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + if (!RD) + return false; + + if (!RD->hasMutableFields()) + return false; + + for (auto *Field : RD->fields()) { + // If we're actually going to read this field in some way, then it can't + // be mutable. If we're in a union, then assigning to a mutable field + // (even an empty one) can change the active member, so that's not OK. + // FIXME: Add core issue number for the union case. + if (Field->isMutable() && + (RD->isUnion() || isReadByLvalueToRvalueConversion(Field->getType()))) { + Info.Diag(E, diag::note_constexpr_ltor_mutable, 1) << Field; + Info.Note(Field->getLocation(), diag::note_declared_at); + return true; + } + + if (diagnoseUnreadableFields(Info, E, Field->getType())) + return true; + } + + for (auto &BaseSpec : RD->bases()) + if (diagnoseUnreadableFields(Info, E, BaseSpec.getType())) + return true; + + // All mutable fields were empty, and thus not actually read. + return false; +} + /// Kinds of access we can perform on an object, for diagnostics. enum AccessKinds { AK_Read, @@ -2134,6 +2206,14 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj, } if (I == N) { + // If we are reading an object of class type, there may still be more + // things we need to check: if there are any mutable subobjects, we + // cannot perform this read. (This only happens when performing a trivial + // copy or assignment.) + if (ObjType->isRecordType() && handler.AccessKind == AK_Read && + diagnoseUnreadableFields(Info, E, ObjType)) + return handler.failed(); + if (!handler.found(*O, ObjType)) return false; @@ -2490,7 +2570,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, // Unless we're looking at a local variable or argument in a constexpr call, // the variable we're reading must be const. if (!Frame) { - if (Info.getLangOpts().CPlusPlus1y && + if (Info.getLangOpts().CPlusPlus14 && VD == Info.EvaluatingDecl.dyn_cast<const ValueDecl *>()) { // OK, we can read and modify an object if we're in the process of // evaluating its initializer, because its lifetime began in this @@ -2606,7 +2686,7 @@ CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, // // FIXME: Not all local state is mutable. Allow local constant subobjects // to be read here (but take care with 'mutable' fields). - if (Frame && Info.getLangOpts().CPlusPlus1y && + if (Frame && Info.getLangOpts().CPlusPlus14 && (Info.EvalStatus.HasSideEffects || Info.keepEvaluatingAfterFailure())) return CompleteObject(); @@ -2648,10 +2728,10 @@ static bool handleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv, return false; CompleteObject LitObj(&Lit, Base->getType()); return extractSubobject(Info, Conv, LitObj, LVal.Designator, RVal); - } else if (isa<StringLiteral>(Base)) { + } else if (isa<StringLiteral>(Base) || isa<PredefinedExpr>(Base)) { // We represent a string literal array as an lvalue pointing at the // corresponding expression, rather than building an array of chars. - // FIXME: Support PredefinedExpr, ObjCEncodeExpr, MakeStringConstant + // FIXME: Support ObjCEncodeExpr, MakeStringConstant APValue Str(Base, CharUnits::Zero(), APValue::NoLValuePath(), 0); CompleteObject StrObj(&Str, Base->getType()); return extractSubobject(Info, Conv, StrObj, LVal.Designator, RVal); @@ -2668,7 +2748,7 @@ static bool handleAssignment(EvalInfo &Info, const Expr *E, const LValue &LVal, if (LVal.Designator.Invalid) return false; - if (!Info.getLangOpts().CPlusPlus1y) { + if (!Info.getLangOpts().CPlusPlus14) { Info.Diag(E); return false; } @@ -2789,7 +2869,7 @@ static bool handleCompoundAssignment( if (LVal.Designator.Invalid) return false; - if (!Info.getLangOpts().CPlusPlus1y) { + if (!Info.getLangOpts().CPlusPlus14) { Info.Diag(E); return false; } @@ -2938,7 +3018,7 @@ static bool handleIncDec(EvalInfo &Info, const Expr *E, const LValue &LVal, if (LVal.Designator.Invalid) return false; - if (!Info.getLangOpts().CPlusPlus1y) { + if (!Info.getLangOpts().CPlusPlus14) { Info.Diag(E); return false; } @@ -3588,6 +3668,22 @@ static bool CheckConstexprFunction(EvalInfo &Info, SourceLocation CallLoc, return false; } +/// Determine if a class has any fields that might need to be copied by a +/// trivial copy or move operation. +static bool hasFields(const CXXRecordDecl *RD) { + if (!RD || RD->isEmpty()) + return false; + for (auto *FD : RD->fields()) { + if (FD->isUnnamedBitfield()) + continue; + return true; + } + for (auto &Base : RD->bases()) + if (hasFields(Base.getType()->getAsCXXRecordDecl())) + return true; + return false; +} + namespace { typedef SmallVector<APValue, 8> ArgVector; } @@ -3626,8 +3722,12 @@ static bool HandleFunctionCall(SourceLocation CallLoc, // For a trivial copy or move assignment, perform an APValue copy. This is // essential for unions, where the operations performed by the assignment // operator cannot be represented as statements. + // + // Skip this for non-union classes with no fields; in that case, the defaulted + // copy/move does not actually read the object. const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Callee); - if (MD && MD->isDefaulted() && MD->isTrivial()) { + if (MD && MD->isDefaulted() && MD->isTrivial() && + (MD->getParent()->isUnion() || hasFields(MD->getParent()))) { assert(This && (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())); LValue RHS; @@ -3684,11 +3784,18 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, } // For a trivial copy or move constructor, perform an APValue copy. This is - // essential for unions, where the operations performed by the constructor - // cannot be represented by ctor-initializers. + // essential for unions (or classes with anonymous union members), where the + // operations performed by the constructor cannot be represented by + // ctor-initializers. + // + // Skip this for empty non-union classes; we should not perform an + // lvalue-to-rvalue conversion on them because their copy constructor does not + // actually read them. if (Definition->isDefaulted() && ((Definition->isCopyConstructor() && Definition->isTrivial()) || - (Definition->isMoveConstructor() && Definition->isTrivial()))) { + (Definition->isMoveConstructor() && Definition->isTrivial())) && + (Definition->getParent()->isUnion() || + hasFields(Definition->getParent()))) { LValue RHS; RHS.setFrom(Info.Ctx, ArgValues[0]); return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), @@ -3985,7 +4092,7 @@ public: const FunctionDecl *FD = nullptr; LValue *This = nullptr, ThisVal; - ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs()); + auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs()); bool HasQualifier = false; // Extract function decl and 'this' pointer from the callee. @@ -4148,7 +4255,7 @@ public: return VisitUnaryPostIncDec(UO); } bool VisitUnaryPostIncDec(const UnaryOperator *UO) { - if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure()) return Error(UO); LValue LVal; @@ -4573,7 +4680,7 @@ bool LValueExprEvaluator::VisitUnaryImag(const UnaryOperator *E) { } bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) { - if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure()) return Error(UO); if (!this->Visit(UO->getSubExpr())) @@ -4586,7 +4693,7 @@ bool LValueExprEvaluator::VisitUnaryPreIncDec(const UnaryOperator *UO) { bool LValueExprEvaluator::VisitCompoundAssignOperator( const CompoundAssignOperator *CAO) { - if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure()) return Error(CAO); APValue RHS; @@ -4608,7 +4715,7 @@ bool LValueExprEvaluator::VisitCompoundAssignOperator( } bool LValueExprEvaluator::VisitBinAssign(const BinaryOperator *E) { - if (!Info.getLangOpts().CPlusPlus1y && !Info.keepEvaluatingAfterFailure()) + if (!Info.getLangOpts().CPlusPlus14 && !Info.keepEvaluatingAfterFailure()) return Error(E); APValue NewVal; @@ -4733,6 +4840,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { case CK_CPointerToObjCPointerCast: case CK_BlockPointerToObjCPointerCast: case CK_AnyPointerToBlockPointerCast: + case CK_AddressSpaceConversion: if (!Visit(SubExpr)) return false; // Bitcasts to cv void* are static_casts, not reinterpret_casts, so are @@ -4818,6 +4926,38 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) { return ExprEvaluatorBaseTy::VisitCastExpr(E); } +static CharUnits GetAlignOfType(EvalInfo &Info, QualType T) { + // C++ [expr.alignof]p3: + // When alignof is applied to a reference type, the result is the + // alignment of the referenced type. + if (const ReferenceType *Ref = T->getAs<ReferenceType>()) + T = Ref->getPointeeType(); + + // __alignof is defined to return the preferred alignment. + return Info.Ctx.toCharUnitsFromBits( + Info.Ctx.getPreferredTypeAlign(T.getTypePtr())); +} + +static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E) { + E = E->IgnoreParens(); + + // The kinds of expressions that we have special-case logic here for + // should be kept up to date with the special checks for those + // expressions in Sema. + + // alignof decl is always accepted, even if it doesn't make sense: we default + // to 1 in those cases. + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + return Info.Ctx.getDeclAlign(DRE->getDecl(), + /*RefAsPointee*/true); + + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) + return Info.Ctx.getDeclAlign(ME->getMemberDecl(), + /*RefAsPointee*/true); + + return GetAlignOfType(Info, E->getType()); +} + bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { if (IsStringLiteralCall(E)) return Success(E); @@ -4825,7 +4965,71 @@ bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) { switch (E->getBuiltinCallee()) { case Builtin::BI__builtin_addressof: return EvaluateLValue(E->getArg(0), Result, Info); + case Builtin::BI__builtin_assume_aligned: { + // We need to be very careful here because: if the pointer does not have the + // asserted alignment, then the behavior is undefined, and undefined + // behavior is non-constant. + if (!EvaluatePointer(E->getArg(0), Result, Info)) + return false; + + LValue OffsetResult(Result); + APSInt Alignment; + if (!EvaluateInteger(E->getArg(1), Alignment, Info)) + return false; + CharUnits Align = CharUnits::fromQuantity(getExtValue(Alignment)); + + if (E->getNumArgs() > 2) { + APSInt Offset; + if (!EvaluateInteger(E->getArg(2), Offset, Info)) + return false; + + int64_t AdditionalOffset = -getExtValue(Offset); + OffsetResult.Offset += CharUnits::fromQuantity(AdditionalOffset); + } + + // If there is a base object, then it must have the correct alignment. + if (OffsetResult.Base) { + CharUnits BaseAlignment; + if (const ValueDecl *VD = + OffsetResult.Base.dyn_cast<const ValueDecl*>()) { + BaseAlignment = Info.Ctx.getDeclAlign(VD); + } else { + BaseAlignment = + GetAlignOfExpr(Info, OffsetResult.Base.get<const Expr*>()); + } + + if (BaseAlignment < Align) { + Result.Designator.setInvalid(); + // FIXME: Quantities here cast to integers because the plural modifier + // does not work on APSInts yet. + CCEDiag(E->getArg(0), + diag::note_constexpr_baa_insufficient_alignment) << 0 + << (int) BaseAlignment.getQuantity() + << (unsigned) getExtValue(Alignment); + return false; + } + } + + // The offset must also have the correct alignment. + if (OffsetResult.Offset.RoundUpToAlignment(Align) != OffsetResult.Offset) { + Result.Designator.setInvalid(); + APSInt Offset(64, false); + Offset = OffsetResult.Offset.getQuantity(); + if (OffsetResult.Base) + CCEDiag(E->getArg(0), + diag::note_constexpr_baa_insufficient_alignment) << 1 + << (int) getExtValue(Offset) << (unsigned) getExtValue(Alignment); + else + CCEDiag(E->getArg(0), + diag::note_constexpr_baa_value_insufficient_alignment) + << Offset << (unsigned) getExtValue(Alignment); + + return false; + } + + return true; + } default: return ExprEvaluatorBaseTy::VisitCallExpr(E); } @@ -5166,7 +5370,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E) { if (ZeroInit && !ZeroInitialization(E)) return false; - ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs()); + auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs()); return HandleConstructorCall(E->getExprLoc(), This, Args, cast<CXXConstructorDecl>(Definition), Info, Result); @@ -5270,6 +5474,9 @@ public: bool VisitCallExpr(const CallExpr *E) { return VisitConstructExpr(E); } + bool VisitCXXStdInitializerListExpr(const CXXStdInitializerListExpr *E) { + return VisitConstructExpr(E); + } }; } // end anonymous namespace @@ -5645,7 +5852,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, return false; } - ArrayRef<const Expr *> Args(E->getArgs(), E->getNumArgs()); + auto Args = llvm::makeArrayRef(E->getArgs(), E->getNumArgs()); return HandleConstructorCall(E->getExprLoc(), Subobject, Args, cast<CXXConstructorDecl>(Definition), Info, *Value); @@ -5786,8 +5993,6 @@ public: bool VisitSizeOfPackExpr(const SizeOfPackExpr *E); private: - CharUnits GetAlignOfExpr(const Expr *E); - CharUnits GetAlignOfType(QualType T); static QualType GetObjectType(APValue::LValueBase B); bool TryEvaluateBuiltinObjectSize(const CallExpr *E); // FIXME: Missing: array subscript of vector, member of vector @@ -5985,8 +6190,20 @@ bool IntExprEvaluator::TryEvaluateBuiltinObjectSize(const CallExpr *E) { return false; } - // If we can prove the base is null, lower to zero now. - if (!Base.getLValueBase()) return Success(0, E); + if (!Base.getLValueBase()) { + // It is not possible to determine which objects ptr points to at compile time, + // __builtin_object_size should return (size_t) -1 for type 0 or 1 + // and (size_t) 0 for type 2 or 3. + llvm::APSInt TypeIntVaue; + const Expr *ExprType = E->getArg(1); + if (!ExprType->EvaluateAsInt(TypeIntVaue, Info.Ctx)) + return false; + if (TypeIntVaue == 0 || TypeIntVaue == 1) + return Success(-1, E); + if (TypeIntVaue == 2 || TypeIntVaue == 3) + return Success(0, E); + return Error(E); + } QualType T = GetObjectType(Base.getLValueBase()); if (T.isNull() || @@ -6286,6 +6503,27 @@ static bool HasSameBase(const LValue &A, const LValue &B) { A.getLValueCallIndex() == B.getLValueCallIndex(); } +/// \brief Determine whether this is a pointer past the end of the complete +/// object referred to by the lvalue. +static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx, + const LValue &LV) { + // A null pointer can be viewed as being "past the end" but we don't + // choose to look at it that way here. + if (!LV.getLValueBase()) + return false; + + // If the designator is valid and refers to a subobject, we're not pointing + // past the end. + if (!LV.getLValueDesignator().Invalid && + !LV.getLValueDesignator().isOnePastTheEnd()) + return false; + + // We're a past-the-end pointer if we point to the byte after the object, + // no matter what our type or path is. + auto Size = Ctx.getTypeSizeInChars(getType(LV.getLValueBase())); + return LV.getLValueOffset() == Size; +} + namespace { /// \brief Data recursive integer evaluator of certain binary operators. @@ -6605,15 +6843,27 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { QualType LHSTy = E->getLHS()->getType(); QualType RHSTy = E->getRHS()->getType(); - if (LHSTy->isAnyComplexType()) { - assert(RHSTy->isAnyComplexType() && "Invalid comparison"); + if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) { ComplexValue LHS, RHS; - - bool LHSOK = EvaluateComplex(E->getLHS(), LHS, Info); + bool LHSOK; + if (E->getLHS()->getType()->isRealFloatingType()) { + LHSOK = EvaluateFloat(E->getLHS(), LHS.FloatReal, Info); + if (LHSOK) { + LHS.makeComplexFloat(); + LHS.FloatImag = APFloat(LHS.FloatReal.getSemantics()); + } + } else { + LHSOK = EvaluateComplex(E->getLHS(), LHS, Info); + } if (!LHSOK && !Info.keepEvaluatingAfterFailure()) return false; - if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK) + if (E->getRHS()->getType()->isRealFloatingType()) { + if (!EvaluateFloat(E->getRHS(), RHS.FloatReal, Info) || !LHSOK) + return false; + RHS.makeComplexFloat(); + RHS.FloatImag = APFloat(RHS.FloatReal.getSemantics()); + } else if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK) return false; if (LHS.isComplexFloat()) { @@ -6736,6 +6986,18 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // object. if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue)) return Error(E); + // We can't compare the address of the start of one object with the + // past-the-end address of another object, per C++ DR1652. + if ((LHSValue.Base && LHSValue.Offset.isZero() && + isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) || + (RHSValue.Base && RHSValue.Offset.isZero() && + isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))) + return Error(E); + // We can't tell whether an object is at the same address as another + // zero sized object. + if ((RHSValue.Base && isZeroSized(LHSValue)) || + (LHSValue.Base && isZeroSized(RHSValue))) + return Error(E); // Pointers with different bases cannot represent the same object. // (Note that clang defaults to -fmerge-all-constants, which can // lead to inconsistent results for comparisons involving the address @@ -6940,39 +7202,6 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { return ExprEvaluatorBaseTy::VisitBinaryOperator(E); } -CharUnits IntExprEvaluator::GetAlignOfType(QualType T) { - // C++ [expr.alignof]p3: - // When alignof is applied to a reference type, the result is the - // alignment of the referenced type. - if (const ReferenceType *Ref = T->getAs<ReferenceType>()) - T = Ref->getPointeeType(); - - // __alignof is defined to return the preferred alignment. - return Info.Ctx.toCharUnitsFromBits( - Info.Ctx.getPreferredTypeAlign(T.getTypePtr())); -} - -CharUnits IntExprEvaluator::GetAlignOfExpr(const Expr *E) { - E = E->IgnoreParens(); - - // The kinds of expressions that we have special-case logic here for - // should be kept up to date with the special checks for those - // expressions in Sema. - - // alignof decl is always accepted, even if it doesn't make sense: we default - // to 1 in those cases. - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - return Info.Ctx.getDeclAlign(DRE->getDecl(), - /*RefAsPointee*/true); - - if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) - return Info.Ctx.getDeclAlign(ME->getMemberDecl(), - /*RefAsPointee*/true); - - return GetAlignOfType(E->getType()); -} - - /// VisitUnaryExprOrTypeTraitExpr - Evaluate a sizeof, alignof or vec_step with /// a result as the expression's type. bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( @@ -6980,9 +7209,9 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr( switch(E->getKind()) { case UETT_AlignOf: { if (E->isArgumentType()) - return Success(GetAlignOfType(E->getArgumentType()), E); + return Success(GetAlignOfType(Info, E->getArgumentType()), E); else - return Success(GetAlignOfExpr(E->getArgumentExpr()), E); + return Success(GetAlignOfExpr(Info, E->getArgumentExpr()), E); } case UETT_VecStep: { @@ -7732,24 +7961,49 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma) return ExprEvaluatorBaseTy::VisitBinaryOperator(E); - bool LHSOK = Visit(E->getLHS()); + // Track whether the LHS or RHS is real at the type system level. When this is + // the case we can simplify our evaluation strategy. + bool LHSReal = false, RHSReal = false; + + bool LHSOK; + if (E->getLHS()->getType()->isRealFloatingType()) { + LHSReal = true; + APFloat &Real = Result.FloatReal; + LHSOK = EvaluateFloat(E->getLHS(), Real, Info); + if (LHSOK) { + Result.makeComplexFloat(); + Result.FloatImag = APFloat(Real.getSemantics()); + } + } else { + LHSOK = Visit(E->getLHS()); + } if (!LHSOK && !Info.keepEvaluatingAfterFailure()) return false; ComplexValue RHS; - if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK) + if (E->getRHS()->getType()->isRealFloatingType()) { + RHSReal = true; + APFloat &Real = RHS.FloatReal; + if (!EvaluateFloat(E->getRHS(), Real, Info) || !LHSOK) + return false; + RHS.makeComplexFloat(); + RHS.FloatImag = APFloat(Real.getSemantics()); + } else if (!EvaluateComplex(E->getRHS(), RHS, Info) || !LHSOK) return false; - assert(Result.isComplexFloat() == RHS.isComplexFloat() && - "Invalid operands to binary operator."); + assert(!(LHSReal && RHSReal) && + "Cannot have both operands of a complex operation be real."); switch (E->getOpcode()) { default: return Error(E); case BO_Add: if (Result.isComplexFloat()) { Result.getComplexFloatReal().add(RHS.getComplexFloatReal(), APFloat::rmNearestTiesToEven); - Result.getComplexFloatImag().add(RHS.getComplexFloatImag(), - APFloat::rmNearestTiesToEven); + if (LHSReal) + Result.getComplexFloatImag() = RHS.getComplexFloatImag(); + else if (!RHSReal) + Result.getComplexFloatImag().add(RHS.getComplexFloatImag(), + APFloat::rmNearestTiesToEven); } else { Result.getComplexIntReal() += RHS.getComplexIntReal(); Result.getComplexIntImag() += RHS.getComplexIntImag(); @@ -7759,8 +8013,13 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (Result.isComplexFloat()) { Result.getComplexFloatReal().subtract(RHS.getComplexFloatReal(), APFloat::rmNearestTiesToEven); - Result.getComplexFloatImag().subtract(RHS.getComplexFloatImag(), - APFloat::rmNearestTiesToEven); + if (LHSReal) { + Result.getComplexFloatImag() = RHS.getComplexFloatImag(); + Result.getComplexFloatImag().changeSign(); + } else if (!RHSReal) { + Result.getComplexFloatImag().subtract(RHS.getComplexFloatImag(), + APFloat::rmNearestTiesToEven); + } } else { Result.getComplexIntReal() -= RHS.getComplexIntReal(); Result.getComplexIntImag() -= RHS.getComplexIntImag(); @@ -7768,25 +8027,75 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { break; case BO_Mul: if (Result.isComplexFloat()) { + // This is an implementation of complex multiplication according to the + // constraints laid out in C11 Annex G. The implemantion uses the + // following naming scheme: + // (a + ib) * (c + id) ComplexValue LHS = Result; - APFloat &LHS_r = LHS.getComplexFloatReal(); - APFloat &LHS_i = LHS.getComplexFloatImag(); - APFloat &RHS_r = RHS.getComplexFloatReal(); - APFloat &RHS_i = RHS.getComplexFloatImag(); - - APFloat Tmp = LHS_r; - Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven); - Result.getComplexFloatReal() = Tmp; - Tmp = LHS_i; - Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); - Result.getComplexFloatReal().subtract(Tmp, APFloat::rmNearestTiesToEven); - - Tmp = LHS_r; - Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); - Result.getComplexFloatImag() = Tmp; - Tmp = LHS_i; - Tmp.multiply(RHS_r, APFloat::rmNearestTiesToEven); - Result.getComplexFloatImag().add(Tmp, APFloat::rmNearestTiesToEven); + APFloat &A = LHS.getComplexFloatReal(); + APFloat &B = LHS.getComplexFloatImag(); + APFloat &C = RHS.getComplexFloatReal(); + APFloat &D = RHS.getComplexFloatImag(); + APFloat &ResR = Result.getComplexFloatReal(); + APFloat &ResI = Result.getComplexFloatImag(); + if (LHSReal) { + assert(!RHSReal && "Cannot have two real operands for a complex op!"); + ResR = A * C; + ResI = A * D; + } else if (RHSReal) { + ResR = C * A; + ResI = C * B; + } else { + // In the fully general case, we need to handle NaNs and infinities + // robustly. + APFloat AC = A * C; + APFloat BD = B * D; + APFloat AD = A * D; + APFloat BC = B * C; + ResR = AC - BD; + ResI = AD + BC; + if (ResR.isNaN() && ResI.isNaN()) { + bool Recalc = false; + if (A.isInfinity() || B.isInfinity()) { + A = APFloat::copySign( + APFloat(A.getSemantics(), A.isInfinity() ? 1 : 0), A); + B = APFloat::copySign( + APFloat(B.getSemantics(), B.isInfinity() ? 1 : 0), B); + if (C.isNaN()) + C = APFloat::copySign(APFloat(C.getSemantics()), C); + if (D.isNaN()) + D = APFloat::copySign(APFloat(D.getSemantics()), D); + Recalc = true; + } + if (C.isInfinity() || D.isInfinity()) { + C = APFloat::copySign( + APFloat(C.getSemantics(), C.isInfinity() ? 1 : 0), C); + D = APFloat::copySign( + APFloat(D.getSemantics(), D.isInfinity() ? 1 : 0), D); + if (A.isNaN()) + A = APFloat::copySign(APFloat(A.getSemantics()), A); + if (B.isNaN()) + B = APFloat::copySign(APFloat(B.getSemantics()), B); + Recalc = true; + } + if (!Recalc && (AC.isInfinity() || BD.isInfinity() || + AD.isInfinity() || BC.isInfinity())) { + if (A.isNaN()) + A = APFloat::copySign(APFloat(A.getSemantics()), A); + if (B.isNaN()) + B = APFloat::copySign(APFloat(B.getSemantics()), B); + if (C.isNaN()) + C = APFloat::copySign(APFloat(C.getSemantics()), C); + if (D.isNaN()) + D = APFloat::copySign(APFloat(D.getSemantics()), D); + Recalc = true; + } + if (Recalc) { + ResR = APFloat::getInf(A.getSemantics()) * (A * C - B * D); + ResI = APFloat::getInf(A.getSemantics()) * (A * D + B * C); + } + } + } } else { ComplexValue LHS = Result; Result.getComplexIntReal() = @@ -7799,33 +8108,57 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { break; case BO_Div: if (Result.isComplexFloat()) { + // This is an implementation of complex division according to the + // constraints laid out in C11 Annex G. The implemantion uses the + // following naming scheme: + // (a + ib) / (c + id) ComplexValue LHS = Result; - APFloat &LHS_r = LHS.getComplexFloatReal(); - APFloat &LHS_i = LHS.getComplexFloatImag(); - APFloat &RHS_r = RHS.getComplexFloatReal(); - APFloat &RHS_i = RHS.getComplexFloatImag(); - APFloat &Res_r = Result.getComplexFloatReal(); - APFloat &Res_i = Result.getComplexFloatImag(); - - APFloat Den = RHS_r; - Den.multiply(RHS_r, APFloat::rmNearestTiesToEven); - APFloat Tmp = RHS_i; - Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); - Den.add(Tmp, APFloat::rmNearestTiesToEven); - - Res_r = LHS_r; - Res_r.multiply(RHS_r, APFloat::rmNearestTiesToEven); - Tmp = LHS_i; - Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); - Res_r.add(Tmp, APFloat::rmNearestTiesToEven); - Res_r.divide(Den, APFloat::rmNearestTiesToEven); - - Res_i = LHS_i; - Res_i.multiply(RHS_r, APFloat::rmNearestTiesToEven); - Tmp = LHS_r; - Tmp.multiply(RHS_i, APFloat::rmNearestTiesToEven); - Res_i.subtract(Tmp, APFloat::rmNearestTiesToEven); - Res_i.divide(Den, APFloat::rmNearestTiesToEven); + APFloat &A = LHS.getComplexFloatReal(); + APFloat &B = LHS.getComplexFloatImag(); + APFloat &C = RHS.getComplexFloatReal(); + APFloat &D = RHS.getComplexFloatImag(); + APFloat &ResR = Result.getComplexFloatReal(); + APFloat &ResI = Result.getComplexFloatImag(); + if (RHSReal) { + ResR = A / C; + ResI = B / C; + } else { + if (LHSReal) { + // No real optimizations we can do here, stub out with zero. + B = APFloat::getZero(A.getSemantics()); + } + int DenomLogB = 0; + APFloat MaxCD = maxnum(abs(C), abs(D)); + if (MaxCD.isFinite()) { + DenomLogB = ilogb(MaxCD); + C = scalbn(C, -DenomLogB); + D = scalbn(D, -DenomLogB); + } + APFloat Denom = C * C + D * D; + ResR = scalbn((A * C + B * D) / Denom, -DenomLogB); + ResI = scalbn((B * C - A * D) / Denom, -DenomLogB); + if (ResR.isNaN() && ResI.isNaN()) { + if (Denom.isPosZero() && (!A.isNaN() || !B.isNaN())) { + ResR = APFloat::getInf(ResR.getSemantics(), C.isNegative()) * A; + ResI = APFloat::getInf(ResR.getSemantics(), C.isNegative()) * B; + } else if ((A.isInfinity() || B.isInfinity()) && C.isFinite() && + D.isFinite()) { + A = APFloat::copySign( + APFloat(A.getSemantics(), A.isInfinity() ? 1 : 0), A); + B = APFloat::copySign( + APFloat(B.getSemantics(), B.isInfinity() ? 1 : 0), B); + ResR = APFloat::getInf(ResR.getSemantics()) * (A * C + B * D); + ResI = APFloat::getInf(ResI.getSemantics()) * (B * C - A * D); + } else if (MaxCD.isInfinity() && A.isFinite() && B.isFinite()) { + C = APFloat::copySign( + APFloat(C.getSemantics(), C.isInfinity() ? 1 : 0), C); + D = APFloat::copySign( + APFloat(D.getSemantics(), D.isInfinity() ? 1 : 0), D); + ResR = APFloat::getZero(ResR.getSemantics()) * (A * C + B * D); + ResI = APFloat::getZero(ResI.getSemantics()) * (B * C - A * D); + } + } + } } else { if (RHS.getComplexIntReal() == 0 && RHS.getComplexIntImag() == 0) return Error(E, diag::note_expr_divide_by_zero); @@ -7966,6 +8299,7 @@ public: default: return ExprEvaluatorBaseTy::VisitCallExpr(E); case Builtin::BI__assume: + case Builtin::BI__builtin_assume: // The argument is not evaluated! return true; } @@ -8338,6 +8672,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::CXXDeleteExprClass: case Expr::CXXPseudoDestructorExprClass: case Expr::UnresolvedLookupExprClass: + case Expr::TypoExprClass: case Expr::DependentScopeDeclRefExprClass: case Expr::CXXConstructExprClass: case Expr::CXXStdInitializerListExprClass: @@ -8373,6 +8708,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { case Expr::PseudoObjectExprClass: case Expr::AtomicExprClass: case Expr::LambdaExprClass: + case Expr::CXXFoldExprClass: return ICEDiag(IK_NotICE, E->getLocStart()); case Expr::InitListExprClass: { @@ -8682,7 +9018,11 @@ static bool EvaluateCPlusPlus11IntegralConstantExpr(const ASTContext &Ctx, if (!E->isCXX11ConstantExpr(Ctx, &Result, Loc)) return false; - assert(Result.isInt() && "pointer cast to int is not an ICE"); + if (!Result.isInt()) { + if (Loc) *Loc = E->getExprLoc(); + return false; + } + if (Value) *Value = Result.getInt(); return true; } @@ -8751,7 +9091,8 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx, ArgVector ArgValues(Args.size()); for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end(); I != E; ++I) { - if (!Evaluate(ArgValues[I - Args.begin()], Info, *I)) + if ((*I)->isValueDependent() || + !Evaluate(ArgValues[I - Args.begin()], Info, *I)) // If evaluation fails, throw away the argument entirely. ArgValues[I - Args.begin()] = APValue(); if (Info.EvalStatus.HasSideEffects) diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp index b5f8c0f4bc87..378121c8e5b9 100644 --- a/lib/AST/ItaniumCXXABI.cpp +++ b/lib/AST/ItaniumCXXABI.cpp @@ -29,16 +29,64 @@ using namespace clang; namespace { +/// According to Itanium C++ ABI 5.1.2: +/// the name of an anonymous union is considered to be +/// the name of the first named data member found by a pre-order, +/// depth-first, declaration-order walk of the data members of +/// the anonymous union. +/// If there is no such data member (i.e., if all of the data members +/// in the union are unnamed), then there is no way for a program to +/// refer to the anonymous union, and there is therefore no need to mangle its name. +/// +/// Returns the name of anonymous union VarDecl or nullptr if it is not found. +static const IdentifierInfo *findAnonymousUnionVarDeclName(const VarDecl& VD) { + const RecordType *RT = VD.getType()->getAs<RecordType>(); + assert(RT && "type of VarDecl is expected to be RecordType."); + assert(RT->getDecl()->isUnion() && "RecordType is expected to be a union."); + if (const FieldDecl *FD = RT->getDecl()->findFirstNamedDataMember()) { + return FD->getIdentifier(); + } + + return nullptr; +} + /// \brief Keeps track of the mangled names of lambda expressions and block /// literals within a particular context. class ItaniumNumberingContext : public MangleNumberingContext { - llvm::DenseMap<IdentifierInfo*, unsigned> VarManglingNumbers; - llvm::DenseMap<IdentifierInfo*, unsigned> TagManglingNumbers; + llvm::DenseMap<const Type *, unsigned> ManglingNumbers; + llvm::DenseMap<const IdentifierInfo *, unsigned> VarManglingNumbers; + llvm::DenseMap<const IdentifierInfo *, unsigned> TagManglingNumbers; public: + unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override { + const FunctionProtoType *Proto = + CallOperator->getType()->getAs<FunctionProtoType>(); + ASTContext &Context = CallOperator->getASTContext(); + + QualType Key = + Context.getFunctionType(Context.VoidTy, Proto->getParamTypes(), + FunctionProtoType::ExtProtoInfo()); + Key = Context.getCanonicalType(Key); + return ++ManglingNumbers[Key->castAs<FunctionProtoType>()]; + } + + unsigned getManglingNumber(const BlockDecl *BD) override { + const Type *Ty = nullptr; + return ++ManglingNumbers[Ty]; + } + + unsigned getStaticLocalNumber(const VarDecl *VD) override { + return 0; + } + /// Variable decls are numbered by identifier. unsigned getManglingNumber(const VarDecl *VD, unsigned) override { - return ++VarManglingNumbers[VD->getIdentifier()]; + const IdentifierInfo *Identifier = VD->getIdentifier(); + if (!Identifier) { + // VarDecl without an identifier represents an anonymous union declaration. + Identifier = findAnonymousUnionVarDeclName(*VD); + } + return ++VarManglingNumbers[Identifier]; } unsigned getManglingNumber(const TagDecl *TD, unsigned) override { diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 977d6fca2c40..156ad646fa6d 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -117,7 +117,7 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext { typedef std::pair<const DeclContext*, IdentifierInfo*> DiscriminatorKeyTy; llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator; llvm::DenseMap<const NamedDecl*, unsigned> Uniquifier; - + public: explicit ItaniumMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags) @@ -150,6 +150,8 @@ public: void mangleCXXDtor(const CXXDestructorDecl *D, CXXDtorType Type, raw_ostream &) override; + void mangleCXXCtorComdat(const CXXConstructorDecl *D, raw_ostream &) override; + void mangleCXXDtorComdat(const CXXDestructorDecl *D, raw_ostream &) override; void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &) override; void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override; void mangleDynamicAtExitDestructor(const VarDecl *D, @@ -373,6 +375,7 @@ private: NamedDecl *firstQualifierLookup, DeclarationName name, unsigned knownArity); + void mangleCastExpression(const Expr *E, StringRef CastEncoding); void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); @@ -634,13 +637,11 @@ void CXXNameMangler::mangleUnscopedTemplateName(const TemplateDecl *ND) { return; // <template-template-param> ::= <template-param> - if (const TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(ND)) { + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) mangleTemplateParameter(TTP->getIndex()); - return; - } + else + mangleUnscopedName(ND->getTemplatedDecl()); - mangleUnscopedName(ND->getTemplatedDecl()); addSubstitution(ND); } @@ -811,6 +812,9 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, // We never want an 'E' here. return; + case NestedNameSpecifier::Super: + llvm_unreachable("Can't mangle __super specifier"); + case NestedNameSpecifier::Namespace: if (qualifier->getPrefix()) mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, @@ -1046,24 +1050,6 @@ void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier, mangleUnqualifiedName(nullptr, name, knownArity); } -static const FieldDecl *FindFirstNamedDataMember(const RecordDecl *RD) { - assert(RD->isAnonymousStructOrUnion() && - "Expected anonymous struct or union!"); - - for (const auto *I : RD->fields()) { - if (I->getIdentifier()) - return I; - - if (const RecordType *RT = I->getType()->getAs<RecordType>()) - if (const FieldDecl *NamedDataMember = - FindFirstNamedDataMember(RT->getDecl())) - return NamedDataMember; - } - - // We didn't find a named data member. - return nullptr; -} - void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name, unsigned KnownArity) { @@ -1100,9 +1086,9 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { // We must have an anonymous union or struct declaration. - const RecordDecl *RD = + const RecordDecl *RD = cast<RecordDecl>(VD->getType()->getAs<RecordType>()->getDecl()); - + // Itanium C++ ABI 5.1.2: // // For the purposes of mangling, the name of an anonymous union is @@ -1112,14 +1098,16 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, // the data members in the union are unnamed), then there is no way for // a program to refer to the anonymous union, and there is therefore no // need to mangle its name. - const FieldDecl *FD = FindFirstNamedDataMember(RD); + assert(RD->isAnonymousStructOrUnion() + && "Expected anonymous struct or union!"); + const FieldDecl *FD = RD->findFirstNamedDataMember(); // It's actually possible for various reasons for us to get here // with an empty anonymous struct / union. Fortunately, it // doesn't really matter what name we generate. if (!FD) break; assert(FD->getIdentifier() && "Data member name isn't an identifier!"); - + mangleSourceName(FD->getIdentifier()); break; } @@ -1409,8 +1397,8 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) { if (!Number) Number = Context.getBlockId(Block, false); Out << "Ub"; - if (Number > 1) - Out << Number - 2; + if (Number > 0) + Out << Number - 1; Out << '_'; } @@ -1459,6 +1447,9 @@ void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) { // nothing return; + case NestedNameSpecifier::Super: + llvm_unreachable("Can't mangle __super specifier"); + case NestedNameSpecifier::Namespace: mangleName(qualifier->getAsNamespace()); return; @@ -1554,14 +1545,13 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND, return; // <template-template-param> ::= <template-param> - if (const TemplateTemplateParmDecl *TTP - = dyn_cast<TemplateTemplateParmDecl>(ND)) { + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) { mangleTemplateParameter(TTP->getIndex()); - return; + } else { + manglePrefix(getEffectiveDeclContext(ND), NoFunction); + mangleUnqualifiedName(ND->getTemplatedDecl()); } - manglePrefix(getEffectiveDeclContext(ND), NoFunction); - mangleUnqualifiedName(ND->getTemplatedDecl()); addSubstitution(ND); } @@ -1834,6 +1824,19 @@ void CXXNameMangler::mangleObjCMethodName(const ObjCMethodDecl *MD) { Context.mangleObjCMethodName(MD, Out); } +static bool isTypeSubstitutable(Qualifiers Quals, const Type *Ty) { + if (Quals) + return true; + if (Ty->isSpecificBuiltinType(BuiltinType::ObjCSel)) + return true; + if (Ty->isOpenCLSpecificType()) + return true; + if (Ty->isBuiltinType()) + return false; + + return true; +} + void CXXNameMangler::mangleType(QualType T) { // If our type is instantiation-dependent but not dependent, we mangle // it as it was written in the source, removing any top-level sugar. @@ -1875,7 +1878,7 @@ void CXXNameMangler::mangleType(QualType T) { Qualifiers quals = split.Quals; const Type *ty = split.Ty; - bool isSubstitutable = quals || !isa<BuiltinType>(T); + bool isSubstitutable = isTypeSubstitutable(quals, ty); if (isSubstitutable && mangleSubstitution(T)) return; @@ -2301,9 +2304,7 @@ void CXXNameMangler::mangleType(const VectorType *T) { llvm::Triple::ArchType Arch = getASTContext().getTargetInfo().getTriple().getArch(); if ((Arch == llvm::Triple::aarch64 || - Arch == llvm::Triple::aarch64_be || - Arch == llvm::Triple::arm64_be || - Arch == llvm::Triple::arm64) && !Target.isOSDarwin()) + Arch == llvm::Triple::aarch64_be) && !Target.isOSDarwin()) mangleAArch64NeonVectorType(T); else mangleNeonVectorType(T); @@ -2528,6 +2529,18 @@ void CXXNameMangler::mangleMemberExpr(const Expr *base, // <expression> ::= dt <expression> <unresolved-name> // ::= pt <expression> <unresolved-name> if (base) { + + // Ignore member expressions involving anonymous unions. + while (const auto *RT = base->getType()->getAs<RecordType>()) { + if (!RT->getDecl()->isAnonymousStructOrUnion()) + break; + const auto *ME = dyn_cast<MemberExpr>(base); + if (!ME) + break; + base = ME->getBase(); + isArrow = ME->isArrow(); + } + if (base->isImplicitCXXThis()) { // Note: GCC mangles member expressions to the implicit 'this' as // *this., whereas we represent them as this->. The Itanium C++ ABI @@ -2572,12 +2585,23 @@ static bool isParenthesizedADLCallee(const CallExpr *call) { return true; } +void CXXNameMangler::mangleCastExpression(const Expr *E, StringRef CastEncoding) { + const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E); + Out << CastEncoding; + mangleType(ECE->getType()); + mangleExpression(ECE->getSubExpr()); +} + void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { // <expression> ::= <unary operator-name> <expression> // ::= <binary operator-name> <expression> <expression> // ::= <trinary operator-name> <expression> <expression> <expression> // ::= cv <type> expression # conversion with one argument // ::= cv <type> _ <expression>* E # conversion with a different number of arguments + // ::= dc <type> <expression> # dynamic_cast<type> (expression) + // ::= sc <type> <expression> # static_cast<type> (expression) + // ::= cc <type> <expression> # const_cast<type> (expression) + // ::= rc <type> <expression> # reinterpret_cast<type> (expression) // ::= st <type> # sizeof (a type) // ::= at <type> # alignof (a type) // ::= <template-param> @@ -2612,6 +2636,7 @@ recurse: case Expr::ParenListExprClass: case Expr::LambdaExprClass: case Expr::MSPropertyRefExprClass: + case Expr::TypoExprClass: // This should no longer exist in the AST by now. llvm_unreachable("unexpected statement kind"); // FIXME: invent manglings for all these. @@ -2643,7 +2668,6 @@ recurse: case Expr::ArrayTypeTraitExprClass: case Expr::ExpressionTraitExprClass: case Expr::VAArgExprClass: - case Expr::CXXUuidofExprClass: case Expr::CUDAKernelCallExprClass: case Expr::AsTypeExprClass: case Expr::PseudoObjectExprClass: @@ -2658,6 +2682,20 @@ recurse: break; } + case Expr::CXXUuidofExprClass: { + const CXXUuidofExpr *UE = cast<CXXUuidofExpr>(E); + if (UE->isTypeOperand()) { + QualType UuidT = UE->getTypeOperand(Context.getASTContext()); + Out << "u8__uuidoft"; + mangleType(UuidT); + } else { + Expr *UuidExp = UE->getExprOperand(); + Out << "u8__uuidofz"; + mangleExpression(UuidExp, Arity); + } + break; + } + // Even gcc-4.5 doesn't mangle this. case Expr::BinaryConditionalOperatorClass: { DiagnosticsEngine &Diags = Context.getDiags(); @@ -2982,17 +3020,22 @@ recurse: // Fall through to mangle the cast itself. case Expr::CStyleCastExprClass: + case Expr::CXXFunctionalCastExprClass: + mangleCastExpression(E, "cv"); + break; + case Expr::CXXStaticCastExprClass: + mangleCastExpression(E, "sc"); + break; case Expr::CXXDynamicCastExprClass: + mangleCastExpression(E, "dc"); + break; case Expr::CXXReinterpretCastExprClass: + mangleCastExpression(E, "rc"); + break; case Expr::CXXConstCastExprClass: - case Expr::CXXFunctionalCastExprClass: { - const ExplicitCastExpr *ECE = cast<ExplicitCastExpr>(E); - Out << "cv"; - mangleType(ECE->getType()); - mangleExpression(ECE->getSubExpr()); + mangleCastExpression(E, "cc"); break; - } case Expr::CXXOperatorCallExprClass: { const CXXOperatorCallExpr *CE = cast<CXXOperatorCallExpr>(E); @@ -3175,12 +3218,33 @@ recurse: mangleFunctionParam(cast<ParmVarDecl>(Pack)); break; } - + case Expr::MaterializeTemporaryExprClass: { mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr()); break; } - + + case Expr::CXXFoldExprClass: { + auto *FE = cast<CXXFoldExpr>(E); + if (FE->isLeftFold()) + Out << (FE->getInit() ? "fL" : "fl"); + else + Out << (FE->getInit() ? "fR" : "fr"); + + if (FE->getOperator() == BO_PtrMemD) + Out << "ds"; + else + mangleOperatorName( + BinaryOperator::getOverloadedOperator(FE->getOperator()), + /*Arity=*/2); + + if (FE->getLHS()) + mangleExpression(FE->getLHS()); + if (FE->getRHS()) + mangleExpression(FE->getRHS()); + break; + } + case Expr::CXXThisExprClass: Out << "fpT"; break; @@ -3251,8 +3315,8 @@ void CXXNameMangler::mangleFunctionParam(const ParmVarDecl *parm) { void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { // <ctor-dtor-name> ::= C1 # complete object constructor // ::= C2 # base object constructor - // ::= C3 # complete object allocating constructor // + // In addition, C5 is a comdat name with C1 and C2 in it. switch (T) { case Ctor_Complete: Out << "C1"; @@ -3260,8 +3324,8 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { case Ctor_Base: Out << "C2"; break; - case Ctor_CompleteAllocating: - Out << "C3"; + case Ctor_Comdat: + Out << "C5"; break; } } @@ -3271,6 +3335,7 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { // ::= D1 # complete object destructor // ::= D2 # base object destructor // + // In addition, D5 is a comdat name with D1, D2 and, if virtual, D0 in it. switch (T) { case Dtor_Deleting: Out << "D0"; @@ -3281,6 +3346,9 @@ void CXXNameMangler::mangleCXXDtorType(CXXDtorType T) { case Dtor_Base: Out << "D2"; break; + case Dtor_Comdat: + Out << "D5"; + break; } } @@ -3363,7 +3431,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { // and pointer-to-function expressions are represented as a declaration not // an expression. We compensate for it here to produce the correct mangling. ValueDecl *D = A.getAsDecl(); - bool compensateMangling = !A.isDeclForReferenceParam(); + bool compensateMangling = !A.getParamTypeForDecl()->isReferenceType(); if (compensateMangling) { Out << 'X'; mangleOperatorName(OO_Amp, 1); @@ -3674,7 +3742,7 @@ void ItaniumMangleContextImpl::mangleCXXName(const NamedDecl *D, "Mangling declaration"); CXXNameMangler Mangler(*this, Out, D); - return Mangler.mangle(D); + Mangler.mangle(D); } void ItaniumMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D, @@ -3691,6 +3759,18 @@ void ItaniumMangleContextImpl::mangleCXXDtor(const CXXDestructorDecl *D, Mangler.mangle(D); } +void ItaniumMangleContextImpl::mangleCXXCtorComdat(const CXXConstructorDecl *D, + raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out, D, Ctor_Comdat); + Mangler.mangle(D); +} + +void ItaniumMangleContextImpl::mangleCXXDtorComdat(const CXXDestructorDecl *D, + raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out, D, Dtor_Comdat); + Mangler.mangle(D); +} + void ItaniumMangleContextImpl::mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, raw_ostream &Out) { @@ -3851,3 +3931,4 @@ ItaniumMangleContext * ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) { return new ItaniumMangleContextImpl(Context, Diags); } + diff --git a/lib/AST/Mangle.cpp b/lib/AST/Mangle.cpp index fdc00e389350..1a061c4f6632 100644 --- a/lib/AST/Mangle.cpp +++ b/lib/AST/Mangle.cpp @@ -49,10 +49,11 @@ static void mangleFunctionBlock(MangleContext &Context, void MangleContext::anchor() { } -enum StdOrFastCC { - SOF_OTHER, - SOF_FAST, - SOF_STD +enum CCMangling { + CCM_Other, + CCM_Fast, + CCM_Vector, + CCM_Std }; static bool isExternC(const NamedDecl *ND) { @@ -61,20 +62,22 @@ static bool isExternC(const NamedDecl *ND) { return cast<VarDecl>(ND)->isExternC(); } -static StdOrFastCC getStdOrFastCallMangling(const ASTContext &Context, - const NamedDecl *ND) { +static CCMangling getCallingConvMangling(const ASTContext &Context, + const NamedDecl *ND) { const TargetInfo &TI = Context.getTargetInfo(); const llvm::Triple &Triple = TI.getTriple(); - if (!Triple.isOSWindows() || Triple.getArch() != llvm::Triple::x86) - return SOF_OTHER; + if (!Triple.isOSWindows() || + !(Triple.getArch() == llvm::Triple::x86 || + Triple.getArch() == llvm::Triple::x86_64)) + return CCM_Other; if (Context.getLangOpts().CPlusPlus && !isExternC(ND) && TI.getCXXABI() == TargetCXXABI::Microsoft) - return SOF_OTHER; + return CCM_Other; const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND); if (!FD) - return SOF_OTHER; + return CCM_Other; QualType T = FD->getType(); const FunctionType *FT = T->castAs<FunctionType>(); @@ -82,19 +85,21 @@ static StdOrFastCC getStdOrFastCallMangling(const ASTContext &Context, CallingConv CC = FT->getCallConv(); switch (CC) { default: - return SOF_OTHER; + return CCM_Other; case CC_X86FastCall: - return SOF_FAST; + return CCM_Fast; case CC_X86StdCall: - return SOF_STD; + return CCM_Std; + case CC_X86VectorCall: + return CCM_Vector; } } bool MangleContext::shouldMangleDeclName(const NamedDecl *D) { const ASTContext &ASTContext = getASTContext(); - StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D); - if (CC != SOF_OTHER) + CCMangling CC = getCallingConvMangling(ASTContext, D); + if (CC != CCM_Other) return true; // In C, functions with no attributes never need to be mangled. Fastpath them. @@ -131,28 +136,35 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) { } const ASTContext &ASTContext = getASTContext(); - StdOrFastCC CC = getStdOrFastCallMangling(ASTContext, D); + CCMangling CC = getCallingConvMangling(ASTContext, D); bool MCXX = shouldMangleCXXName(D); const TargetInfo &TI = Context.getTargetInfo(); - if (CC == SOF_OTHER || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) { - mangleCXXName(D, Out); + if (CC == CCM_Other || (MCXX && TI.getCXXABI() == TargetCXXABI::Microsoft)) { + if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) + mangleObjCMethodName(OMD, Out); + else + mangleCXXName(D, Out); return; } Out << '\01'; - if (CC == SOF_STD) + if (CC == CCM_Std) Out << '_'; - else + else if (CC == CCM_Fast) Out << '@'; if (!MCXX) Out << D->getIdentifier()->getName(); + else if (const ObjCMethodDecl *OMD = dyn_cast<ObjCMethodDecl>(D)) + mangleObjCMethodName(OMD, Out); else mangleCXXName(D, Out); const FunctionDecl *FD = cast<FunctionDecl>(D); const FunctionType *FT = FD->getType()->castAs<FunctionType>(); const FunctionProtoType *Proto = dyn_cast<FunctionProtoType>(FT); + if (CC == CCM_Vector) + Out << '@'; Out << '@'; if (!Proto) { Out << '0'; @@ -164,9 +176,11 @@ void MangleContext::mangleName(const NamedDecl *D, raw_ostream &Out) { if (!MD->isStatic()) ++ArgWords; for (const auto &AT : Proto->param_types()) - // Size should be aligned to DWORD boundary - ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT), 32) / 32; - Out << 4 * ArgWords; + // Size should be aligned to pointer size. + ArgWords += llvm::RoundUpToAlignment(ASTContext.getTypeSize(AT), + TI.getPointerWidth(0)) / + TI.getPointerWidth(0); + Out << ((TI.getPointerWidth(0) / 8) * ArgWords); } void MangleContext::mangleGlobalBlock(const BlockDecl *BD, @@ -215,16 +229,28 @@ void MangleContext::mangleBlock(const DeclContext *DC, const BlockDecl *BD, if (const ObjCMethodDecl *Method = dyn_cast<ObjCMethodDecl>(DC)) { mangleObjCMethodName(Method, Stream); } else { - const NamedDecl *ND = cast<NamedDecl>(DC); - if (!shouldMangleDeclName(ND) && ND->getIdentifier()) - Stream << ND->getIdentifier()->getName(); - else { - // FIXME: We were doing a mangleUnqualifiedName() before, but that's - // a private member of a class that will soon itself be private to the - // Itanium C++ ABI object. What should we do now? Right now, I'm just - // calling the mangleName() method on the MangleContext; is there a - // better way? - mangleName(ND, Stream); + assert((isa<NamedDecl>(DC) || isa<BlockDecl>(DC)) && + "expected a NamedDecl or BlockDecl"); + if (isa<BlockDecl>(DC)) + for (; DC && isa<BlockDecl>(DC); DC = DC->getParent()) + (void) getBlockId(cast<BlockDecl>(DC), true); + assert((isa<TranslationUnitDecl>(DC) || isa<NamedDecl>(DC)) && + "expected a TranslationUnitDecl or a NamedDecl"); + if (const auto *CD = dyn_cast<CXXConstructorDecl>(DC)) + mangleCtorBlock(CD, /*CT*/ Ctor_Complete, BD, Out); + else if (const auto *DD = dyn_cast<CXXDestructorDecl>(DC)) + mangleDtorBlock(DD, /*DT*/ Dtor_Complete, BD, Out); + else if (auto ND = dyn_cast<NamedDecl>(DC)) { + if (!shouldMangleDeclName(ND) && ND->getIdentifier()) + Stream << ND->getIdentifier()->getName(); + else { + // FIXME: We were doing a mangleUnqualifiedName() before, but that's + // a private member of a class that will soon itself be private to the + // Itanium C++ ABI object. What should we do now? Right now, I'm just + // calling the mangleName() method on the MangleContext; is there a + // better way? + mangleName(ND, Stream); + } } } Stream.flush(); diff --git a/lib/AST/MangleNumberingContext.cpp b/lib/AST/MangleNumberingContext.cpp deleted file mode 100644 index 5f40f0347d0e..000000000000 --- a/lib/AST/MangleNumberingContext.cpp +++ /dev/null @@ -1,45 +0,0 @@ -//===--- MangleNumberingContext.cpp - Context for mangling numbers --------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the LambdaMangleContext class, which keeps track of -// the Itanium C++ ABI mangling numbers for lambda expressions. -// -//===----------------------------------------------------------------------===// - -#include "clang/AST/MangleNumberingContext.h" -#include "clang/AST/ASTContext.h" -#include "clang/AST/DeclCXX.h" - -using namespace clang; - -unsigned -MangleNumberingContext::getManglingNumber(const CXXMethodDecl *CallOperator) { - const FunctionProtoType *Proto - = CallOperator->getType()->getAs<FunctionProtoType>(); - ASTContext &Context = CallOperator->getASTContext(); - - QualType Key = Context.getFunctionType(Context.VoidTy, Proto->getParamTypes(), - FunctionProtoType::ExtProtoInfo()); - Key = Context.getCanonicalType(Key); - return ++ManglingNumbers[Key->castAs<FunctionProtoType>()]; -} - -unsigned -MangleNumberingContext::getManglingNumber(const BlockDecl *BD) { - // FIXME: Compute a BlockPointerType? Not obvious how. - const Type *Ty = nullptr; - return ++ManglingNumbers[Ty]; -} - -unsigned -MangleNumberingContext::getStaticLocalNumber(const VarDecl *VD) { - // FIXME: Compute a BlockPointerType? Not obvious how. - const Type *Ty = nullptr; - return ++ManglingNumbers[Ty]; -} diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index 6870315b2160..0603d3b7b9b5 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -28,7 +28,28 @@ namespace { /// \brief Numbers things which need to correspond across multiple TUs. /// Typically these are things like static locals, lambdas, or blocks. class MicrosoftNumberingContext : public MangleNumberingContext { + llvm::DenseMap<const Type *, unsigned> ManglingNumbers; + unsigned LambdaManglingNumber; + unsigned StaticLocalNumber; + public: + MicrosoftNumberingContext() + : MangleNumberingContext(), LambdaManglingNumber(0), + StaticLocalNumber(0) {} + + unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override { + return ++LambdaManglingNumber; + } + + unsigned getManglingNumber(const BlockDecl *BD) override { + const Type *Ty = nullptr; + return ++ManglingNumbers[Ty]; + } + + unsigned getStaticLocalNumber(const VarDecl *VD) override { + return ++StaticLocalNumber; + } + unsigned getManglingNumber(const VarDecl *VD, unsigned MSLocalManglingNumber) override { return MSLocalManglingNumber; diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index e6a6d09b4845..72f90f67cbdf 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -27,7 +27,6 @@ #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringMap.h" #include "llvm/Support/MathExtras.h" using namespace clang; @@ -161,7 +160,7 @@ public: unsigned &discriminator = Uniquifier[ND]; if (!discriminator) discriminator = ++Discriminator[std::make_pair(DC, ND->getIdentifier())]; - disc = discriminator; + disc = discriminator + 1; return true; } @@ -191,8 +190,8 @@ class MicrosoftCXXNameMangler { const NamedDecl *Structor; unsigned StructorType; - typedef llvm::StringMap<unsigned> BackRefMap; - BackRefMap NameBackReferences; + typedef llvm::SmallVector<std::string, 10> BackRefVec; + BackRefVec NameBackReferences; typedef llvm::DenseMap<void *, unsigned> ArgBackRefMap; ArgBackRefMap TypeBackReferences; @@ -234,7 +233,7 @@ public: QualifierMangleMode QMM = QMM_Mangle); void mangleFunctionType(const FunctionType *T, const FunctionDecl *D = nullptr, - bool ForceInstMethod = false); + bool ForceThisQuals = false); void mangleNestedName(const NamedDecl *ND); private: @@ -279,7 +278,8 @@ private: void mangleTemplateArgs(const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs); - void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA); + void mangleTemplateArg(const TemplateDecl *TD, const TemplateArgument &TA, + const NamedDecl *Parm); }; } @@ -338,9 +338,7 @@ bool MicrosoftMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) { bool MicrosoftMangleContextImpl::shouldMangleStringLiteral(const StringLiteral *SL) { - return SL->isAscii() || SL->isWide(); - // TODO: This needs to be updated when MSVC gains support for Unicode - // literals. + return true; } void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) { @@ -441,7 +439,7 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { mangleQualifiers(Ty.getQualifiers(), false); } else { mangleType(Ty, SR, QMM_Drop); - mangleQualifiers(Ty.getLocalQualifiers(), false); + mangleQualifiers(Ty.getQualifiers(), false); } } @@ -801,10 +799,7 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, void MicrosoftCXXNameMangler::mangleNestedName(const NamedDecl *ND) { // <postfix> ::= <unqualified-name> [<postfix>] // ::= <substitution> [<postfix>] - if (isLambda(ND)) - return; - - const DeclContext *DC = ND->getDeclContext(); + const DeclContext *DC = getEffectiveDeclContext(ND); while (!DC->isTranslationUnit()) { if (isa<TagDecl>(ND) || isa<VarDecl>(ND)) { @@ -856,6 +851,8 @@ void MicrosoftCXXNameMangler::mangleCXXDtorType(CXXDtorType T) { // <operator-name> ::= ?_E # vector deleting destructor // FIXME: Add a vector deleting dtor type. It goes in the vtable, so we need // it. + case Dtor_Comdat: + llvm_unreachable("not expecting a COMDAT"); } llvm_unreachable("Unsupported dtor type?"); } @@ -994,22 +991,14 @@ void MicrosoftCXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, void MicrosoftCXXNameMangler::mangleSourceName(StringRef Name) { // <source name> ::= <identifier> @ - BackRefMap::iterator Found; - if (NameBackReferences.size() < 10) { - size_t Size = NameBackReferences.size(); - bool Inserted; - std::tie(Found, Inserted) = - NameBackReferences.insert(std::make_pair(Name, Size)); - if (Inserted) - Found = NameBackReferences.end(); - } else { - Found = NameBackReferences.find(Name); - } - + BackRefVec::iterator Found = + std::find(NameBackReferences.begin(), NameBackReferences.end(), Name); if (Found == NameBackReferences.end()) { + if (NameBackReferences.size() < 10) + NameBackReferences.push_back(Name); Out << Name << '@'; } else { - Out << Found->second; + Out << (Found - NameBackReferences.begin()); } } @@ -1025,7 +1014,7 @@ void MicrosoftCXXNameMangler::mangleTemplateInstantiationName( // Templates have their own context for back references. ArgBackRefMap OuterArgsContext; - BackRefMap OuterTemplateContext; + BackRefVec OuterTemplateContext; NameBackReferences.swap(OuterTemplateContext); TypeBackReferences.swap(OuterArgsContext); @@ -1051,8 +1040,10 @@ void MicrosoftCXXNameMangler::mangleIntegerLiteral(const llvm::APSInt &Value, // Make sure booleans are encoded as 0/1. if (IsBoolean && Value.getBoolValue()) mangleNumber(1); - else + else if (Value.isSigned()) mangleNumber(Value.getSExtValue()); + else + mangleNumber(Value.getZExtValue()); } void MicrosoftCXXNameMangler::mangleExpression(const Expr *E) { @@ -1104,12 +1095,18 @@ void MicrosoftCXXNameMangler::mangleExpression(const Expr *E) { void MicrosoftCXXNameMangler::mangleTemplateArgs( const TemplateDecl *TD, const TemplateArgumentList &TemplateArgs) { // <template-args> ::= <template-arg>+ + const TemplateParameterList *TPL = TD->getTemplateParameters(); + assert(TPL->size() == TemplateArgs.size() && + "size mismatch between args and parms!"); + + unsigned Idx = 0; for (const TemplateArgument &TA : TemplateArgs.asArray()) - mangleTemplateArg(TD, TA); + mangleTemplateArg(TD, TA, TPL->getParam(Idx++)); } void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, - const TemplateArgument &TA) { + const TemplateArgument &TA, + const NamedDecl *Parm) { // <template-arg> ::= <type> // ::= <integer-literal> // ::= <member-data-pointer> @@ -1142,7 +1139,7 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, else mangle(FD, "$1?"); } else { - mangle(ND, TA.isDeclForReferenceParam() ? "$E?" : "$1?"); + mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?"); } break; } @@ -1172,18 +1169,33 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, case TemplateArgument::Pack: { ArrayRef<TemplateArgument> TemplateArgs = TA.getPackAsArray(); if (TemplateArgs.empty()) { - Out << "$S"; + if (isa<TemplateTypeParmDecl>(Parm) || + isa<TemplateTemplateParmDecl>(Parm)) + Out << "$$V"; + else if (isa<NonTypeTemplateParmDecl>(Parm)) + Out << "$S"; + else + llvm_unreachable("unexpected template parameter decl!"); } else { for (const TemplateArgument &PA : TemplateArgs) - mangleTemplateArg(TD, PA); + mangleTemplateArg(TD, PA, Parm); } break; } - case TemplateArgument::Template: - mangleType(cast<TagDecl>( - TA.getAsTemplate().getAsTemplateDecl()->getTemplatedDecl())); + case TemplateArgument::Template: { + const NamedDecl *ND = + TA.getAsTemplate().getAsTemplateDecl()->getTemplatedDecl(); + if (const auto *TD = dyn_cast<TagDecl>(ND)) { + mangleType(TD); + } else if (isa<TypeAliasDecl>(ND)) { + Out << "$$Y"; + mangleName(ND); + } else { + llvm_unreachable("unexpected template template NamedDecl!"); + } break; } + } } void MicrosoftCXXNameMangler::mangleQualifiers(Qualifiers Quals, @@ -1473,6 +1485,8 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, case BuiltinType::Int128: Out << "_L"; break; case BuiltinType::UInt128: Out << "_M"; break; case BuiltinType::Bool: Out << "_N"; break; + case BuiltinType::Char16: Out << "_S"; break; + case BuiltinType::Char32: Out << "_U"; break; case BuiltinType::WChar_S: case BuiltinType::WChar_U: Out << "_W"; break; @@ -1498,8 +1512,6 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, case BuiltinType::NullPtr: Out << "$$T"; break; - case BuiltinType::Char16: - case BuiltinType::Char32: case BuiltinType::Half: { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -1518,8 +1530,13 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, // 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"; - mangleFunctionType(T); + if (T->getTypeQuals() || T->getRefQualifier() != RQ_None) { + Out << "$$A8@@"; + mangleFunctionType(T, /*D=*/nullptr, /*ForceThisQuals=*/true); + } else { + Out << "$$A6"; + mangleFunctionType(T); + } } void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, SourceRange) { @@ -1528,7 +1545,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, const FunctionDecl *D, - bool ForceInstMethod) { + bool ForceThisQuals) { // <function-type> ::= <this-cvr-qualifiers> <calling-convention> // <return-type> <argument-list> <throw-spec> const FunctionProtoType *Proto = cast<FunctionProtoType>(T); @@ -1536,21 +1553,21 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, SourceRange Range; if (D) Range = D->getSourceRange(); - bool IsStructor = false, IsInstMethod = ForceInstMethod; + bool IsStructor = false, HasThisQuals = ForceThisQuals; if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(D)) { if (MD->isInstance()) - IsInstMethod = true; + HasThisQuals = true; if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) IsStructor = true; } // If this is a C++ instance method, mangle the CVR qualifiers for the // this pointer. - if (IsInstMethod) { + if (HasThisQuals) { Qualifiers Quals = Qualifiers::fromCVRMask(Proto->getTypeQuals()); - manglePointerExtQualifiers(Quals, nullptr); + manglePointerExtQualifiers(Quals, /*PointeeType=*/nullptr); mangleRefQualifier(Proto->getRefQualifier()); - mangleQualifiers(Quals, false); + mangleQualifiers(Quals, /*IsMember=*/false); } mangleCallingConvention(T); @@ -1670,6 +1687,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { // ::= H # __export __stdcall // ::= I # __fastcall // ::= J # __export __fastcall + // ::= Q # __vectorcall // The 'export' calling conventions are from a bygone era // (*cough*Win16*cough*) when functions were declared for export with // that keyword. (It didn't actually export them, it just made them so @@ -1686,6 +1704,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { case CC_X86ThisCall: Out << 'E'; break; case CC_X86StdCall: Out << 'G'; break; case CC_X86FastCall: Out << 'I'; break; + case CC_X86VectorCall: Out << 'Q'; break; } } void MicrosoftCXXNameMangler::mangleThrowSpecification( @@ -2331,7 +2350,7 @@ void MicrosoftMangleContextImpl::mangleReferenceTemporary(const VarDecl *VD, void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD, raw_ostream &Out) { - // TODO: This is not correct, especially with respect to MSVC2013. MSVC2013 + // TODO: This is not correct, especially with respect to VS "14". VS "14" // utilizes thread local variables to implement thread safe, re-entrant // initialization for statics. They no longer differentiate between an // externally visible and non-externally visible static with respect to @@ -2420,14 +2439,10 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, Mangler.getStream() << "\01??_C@_"; // <char-type>: The "kind" of string literal is encoded into the mangled name. - // TODO: This needs to be updated when MSVC gains support for unicode - // literals. - if (SL->isAscii()) - Mangler.getStream() << '0'; - else if (SL->isWide()) + if (SL->isWide()) Mangler.getStream() << '1'; else - llvm_unreachable("unexpected string literal kind!"); + Mangler.getStream() << '0'; // <literal-length>: The next part of the mangled name consists of the length // of the string. @@ -2506,42 +2521,16 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, } else if (isLetter(Byte & 0x7f)) { Mangler.getStream() << '?' << static_cast<char>(Byte & 0x7f); } else { - switch (Byte) { - case ',': - Mangler.getStream() << "?0"; - break; - case '/': - Mangler.getStream() << "?1"; - break; - case '\\': - Mangler.getStream() << "?2"; - break; - case ':': - Mangler.getStream() << "?3"; - break; - case '.': - Mangler.getStream() << "?4"; - break; - case ' ': - Mangler.getStream() << "?5"; - break; - case '\n': - Mangler.getStream() << "?6"; - break; - case '\t': - Mangler.getStream() << "?7"; - break; - case '\'': - Mangler.getStream() << "?8"; - break; - case '-': - Mangler.getStream() << "?9"; - break; - default: - Mangler.getStream() << "?$"; - Mangler.getStream() << static_cast<char>('A' + ((Byte >> 4) & 0xf)); - Mangler.getStream() << static_cast<char>('A' + (Byte & 0xf)); - break; + const char SpecialChars[] = {',', '/', '\\', ':', '.', + ' ', '\n', '\t', '\'', '-'}; + const char *Pos = + std::find(std::begin(SpecialChars), std::end(SpecialChars), Byte); + if (Pos != std::end(SpecialChars)) { + Mangler.getStream() << '?' << (Pos - std::begin(SpecialChars)); + } else { + Mangler.getStream() << "?$"; + Mangler.getStream() << static_cast<char>('A' + ((Byte >> 4) & 0xf)); + Mangler.getStream() << static_cast<char>('A' + (Byte & 0xf)); } } }; @@ -2550,7 +2539,10 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, unsigned NumCharsToMangle = std::min(32U, SL->getLength()); for (unsigned I = 0, E = NumCharsToMangle * SL->getCharByteWidth(); I != E; ++I) - MangleByte(GetBigEndianByte(I)); + if (SL->isWide()) + MangleByte(GetBigEndianByte(I)); + else + MangleByte(GetLittleEndianByte(I)); // Encode the NUL terminator if there is room. if (NumCharsToMangle < 32) diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp index 986b3b53983d..3dc750a81787 100644 --- a/lib/AST/NSAPI.cpp +++ b/lib/AST/NSAPI.cpp @@ -10,6 +10,7 @@ #include "clang/AST/NSAPI.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" +#include "llvm/ADT/StringSwitch.h" using namespace clang; @@ -46,6 +47,10 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const { Sel = Ctx.Selectors.getUnarySelector( &Ctx.Idents.get("stringWithUTF8String")); break; + case NSStr_initWithUTF8String: + Sel = Ctx.Selectors.getUnarySelector( + &Ctx.Idents.get("initWithUTF8String")); + break; case NSStr_stringWithCStringEncoding: { IdentifierInfo *KeyIdents[] = { &Ctx.Idents.get("stringWithCString"), @@ -379,6 +384,32 @@ bool NSAPI::isObjCNSUIntegerType(QualType T) const { return isObjCTypedef(T, "NSUInteger", NSUIntegerId); } +StringRef NSAPI::GetNSIntegralKind(QualType T) const { + if (!Ctx.getLangOpts().ObjC1 || T.isNull()) + return StringRef(); + + while (const TypedefType *TDT = T->getAs<TypedefType>()) { + StringRef NSIntegralResust = + llvm::StringSwitch<StringRef>( + TDT->getDecl()->getDeclName().getAsIdentifierInfo()->getName()) + .Case("int8_t", "int8_t") + .Case("int16_t", "int16_t") + .Case("int32_t", "int32_t") + .Case("NSInteger", "NSInteger") + .Case("int64_t", "int64_t") + .Case("uint8_t", "uint8_t") + .Case("uint16_t", "uint16_t") + .Case("uint32_t", "uint32_t") + .Case("NSUInteger", "NSUInteger") + .Case("uint64_t", "uint64_t") + .Default(StringRef()); + if (!NSIntegralResust.empty()) + return NSIntegralResust; + T = TDT->desugar(); + } + return StringRef(); +} + bool NSAPI::isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const { if (!Ctx.getLangOpts().ObjC1) diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp index 1f041aa49542..50a00502ca9f 100644 --- a/lib/AST/NestedNameSpecifier.cpp +++ b/lib/AST/NestedNameSpecifier.cpp @@ -66,7 +66,7 @@ NestedNameSpecifier::Create(const ASTContext &Context, "Broken nested name specifier"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredNamespaceOrAlias); + Mockup.Prefix.setInt(StoredDecl); Mockup.Specifier = const_cast<NamespaceDecl *>(NS); return FindOrInsert(Context, Mockup); } @@ -82,7 +82,7 @@ NestedNameSpecifier::Create(const ASTContext &Context, "Broken nested name specifier"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(Prefix); - Mockup.Prefix.setInt(StoredNamespaceOrAlias); + Mockup.Prefix.setInt(StoredDecl); Mockup.Specifier = Alias; return FindOrInsert(Context, Mockup); } @@ -118,6 +118,16 @@ NestedNameSpecifier::GlobalSpecifier(const ASTContext &Context) { return Context.GlobalNestedNameSpecifier; } +NestedNameSpecifier * +NestedNameSpecifier::SuperSpecifier(const ASTContext &Context, + CXXRecordDecl *RD) { + NestedNameSpecifier Mockup; + Mockup.Prefix.setPointer(nullptr); + Mockup.Prefix.setInt(StoredDecl); + Mockup.Specifier = RD; + return FindOrInsert(Context, Mockup); +} + NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const { if (!Specifier) return Global; @@ -126,9 +136,12 @@ NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const { case StoredIdentifier: return Identifier; - case StoredNamespaceOrAlias: - return isa<NamespaceDecl>(static_cast<NamedDecl *>(Specifier))? Namespace - : NamespaceAlias; + case StoredDecl: { + NamedDecl *ND = static_cast<NamedDecl *>(Specifier); + if (isa<CXXRecordDecl>(ND)) + return Super; + return isa<NamespaceDecl>(ND) ? Namespace : NamespaceAlias; + } case StoredTypeSpec: return TypeSpec; @@ -140,24 +153,29 @@ NestedNameSpecifier::SpecifierKind NestedNameSpecifier::getKind() const { llvm_unreachable("Invalid NNS Kind!"); } -/// \brief Retrieve the namespace stored in this nested name -/// specifier. +/// \brief Retrieve the namespace stored in this nested name specifier. NamespaceDecl *NestedNameSpecifier::getAsNamespace() const { - if (Prefix.getInt() == StoredNamespaceOrAlias) + if (Prefix.getInt() == StoredDecl) return dyn_cast<NamespaceDecl>(static_cast<NamedDecl *>(Specifier)); return nullptr; } -/// \brief Retrieve the namespace alias stored in this nested name -/// specifier. +/// \brief Retrieve the namespace alias stored in this nested name specifier. NamespaceAliasDecl *NestedNameSpecifier::getAsNamespaceAlias() const { - if (Prefix.getInt() == StoredNamespaceOrAlias) + if (Prefix.getInt() == StoredDecl) return dyn_cast<NamespaceAliasDecl>(static_cast<NamedDecl *>(Specifier)); return nullptr; } +/// \brief Retrieve the record declaration stored in this nested name specifier. +CXXRecordDecl *NestedNameSpecifier::getAsRecordDecl() const { + if (Prefix.getInt() == StoredDecl) + return dyn_cast<CXXRecordDecl>(static_cast<NamedDecl *>(Specifier)); + + return nullptr; +} /// \brief Whether this nested name specifier refers to a dependent /// type or not. @@ -172,6 +190,15 @@ bool NestedNameSpecifier::isDependent() const { case Global: return false; + case Super: { + CXXRecordDecl *RD = static_cast<CXXRecordDecl *>(Specifier); + for (const auto &Base : RD->bases()) + if (Base.getType()->isDependentType()) + return true; + + return false; + } + case TypeSpec: case TypeSpecWithTemplate: return getAsType()->isDependentType(); @@ -191,8 +218,9 @@ bool NestedNameSpecifier::isInstantiationDependent() const { case Namespace: case NamespaceAlias: case Global: + case Super: return false; - + case TypeSpec: case TypeSpecWithTemplate: return getAsType()->isInstantiationDependentType(); @@ -209,6 +237,7 @@ bool NestedNameSpecifier::containsUnexpandedParameterPack() const { case Namespace: case NamespaceAlias: case Global: + case Super: return false; case TypeSpec: @@ -246,6 +275,10 @@ NestedNameSpecifier::print(raw_ostream &OS, case Global: break; + case Super: + OS << "__super"; + break; + case TypeSpecWithTemplate: OS << "template "; // Fall through to print the type. @@ -304,6 +337,7 @@ NestedNameSpecifierLoc::getLocalDataLength(NestedNameSpecifier *Qualifier) { case NestedNameSpecifier::Identifier: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Super: // The location of the identifier or namespace name. Length += sizeof(unsigned); break; @@ -369,6 +403,7 @@ SourceRange NestedNameSpecifierLoc::getLocalSourceRange() const { case NestedNameSpecifier::Identifier: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: + case NestedNameSpecifier::Super: return SourceRange(LoadSourceLocation(Data, Offset), LoadSourceLocation(Data, Offset + sizeof(unsigned))); @@ -552,6 +587,17 @@ void NestedNameSpecifierLocBuilder::MakeGlobal(ASTContext &Context, SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); } +void NestedNameSpecifierLocBuilder::MakeSuper(ASTContext &Context, + CXXRecordDecl *RD, + SourceLocation SuperLoc, + SourceLocation ColonColonLoc) { + Representation = NestedNameSpecifier::SuperSpecifier(Context, RD); + + // Push source-location info into the buffer. + SaveSourceLocation(SuperLoc, Buffer, BufferSize, BufferCapacity); + SaveSourceLocation(ColonColonLoc, Buffer, BufferSize, BufferCapacity); +} + void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange R) { @@ -583,6 +629,7 @@ void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, } case NestedNameSpecifier::Global: + case NestedNameSpecifier::Super: break; } diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index b3deebaecfab..0d070a4bfbfc 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -636,23 +636,12 @@ protected: HasOwnVFPtr(false), FirstNearlyEmptyVBase(nullptr) {} - /// Reset this RecordLayoutBuilder to a fresh state, using the given - /// alignment as the initial alignment. This is used for the - /// correct layout of vb-table pointers in MSVC. - void resetWithTargetAlignment(CharUnits TargetAlignment) { - const ASTContext &Context = this->Context; - EmptySubobjectMap *EmptySubobjects = this->EmptySubobjects; - this->~RecordLayoutBuilder(); - new (this) RecordLayoutBuilder(Context, EmptySubobjects); - Alignment = UnpackedAlignment = TargetAlignment; - } - void Layout(const RecordDecl *D); void Layout(const CXXRecordDecl *D); void Layout(const ObjCInterfaceDecl *D); void LayoutFields(const RecordDecl *D); - void LayoutField(const FieldDecl *D); + void LayoutField(const FieldDecl *D, bool InsertExtraPadding); void LayoutWideBitField(uint64_t FieldSize, uint64_t TypeSize, bool FieldPacked, const FieldDecl *D); void LayoutBitField(const FieldDecl *D); @@ -1104,7 +1093,7 @@ RecordLayoutBuilder::LayoutVirtualBases(const CXXRecordDecl *RD, // Only lay out the virtual base if it's not an indirect primary base. if (!IndirectPrimaryBase) { // Only visit virtual bases once. - if (!VisitedVirtualBases.insert(BaseDecl)) + if (!VisitedVirtualBases.insert(BaseDecl).second) continue; const BaseSubobjectInfo *BaseInfo = VirtualBaseInfo.lookup(BaseDecl); @@ -1331,7 +1320,7 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { // Layout each ivar sequentially. for (const ObjCIvarDecl *IVD = D->all_declared_ivar_begin(); IVD; IVD = IVD->getNextIvar()) - LayoutField(IVD); + LayoutField(IVD, false); // Finally, round the size of the total struct up to the alignment of the // struct itself. @@ -1341,8 +1330,22 @@ void RecordLayoutBuilder::Layout(const ObjCInterfaceDecl *D) { void RecordLayoutBuilder::LayoutFields(const RecordDecl *D) { // Layout each field, for now, just sequentially, respecting alignment. In // the future, this will need to be tweakable by targets. - for (const auto *Field : D->fields()) - LayoutField(Field); + bool InsertExtraPadding = D->mayInsertExtraPadding(/*EmitRemark=*/true); + bool HasFlexibleArrayMember = D->hasFlexibleArrayMember(); + for (auto I = D->field_begin(), End = D->field_end(); I != End; ++I) { + auto Next(I); + ++Next; + LayoutField(*I, + InsertExtraPadding && (Next != End || !HasFlexibleArrayMember)); + } +} + +// Rounds the specified size to have it a multiple of the char size. +static uint64_t +roundUpSizeToCharAlignment(uint64_t Size, + const ASTContext &Context) { + uint64_t CharAlignment = Context.getTargetInfo().getCharAlign(); + return llvm::RoundUpToAlignment(Size, CharAlignment); } void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, @@ -1382,7 +1385,9 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit; if (IsUnion) { - setDataSize(std::max(getDataSizeInBits(), FieldSize)); + uint64_t RoundedFieldSize = roundUpSizeToCharAlignment(FieldSize, + Context); + setDataSize(std::max(getDataSizeInBits(), RoundedFieldSize)); FieldOffset = 0; } else { // The bitfield is allocated starting at the next offset aligned @@ -1413,9 +1418,9 @@ void RecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { bool FieldPacked = Packed || D->hasAttr<PackedAttr>(); uint64_t FieldSize = D->getBitWidthValue(Context); - std::pair<uint64_t, unsigned> FieldInfo = Context.getTypeInfo(D->getType()); - uint64_t TypeSize = FieldInfo.first; - unsigned FieldAlign = FieldInfo.second; + TypeInfo FieldInfo = Context.getTypeInfo(D->getType()); + uint64_t TypeSize = FieldInfo.Width; + unsigned FieldAlign = FieldInfo.Align; // UnfilledBitsInLastUnit is the difference between the end of the // last allocated bitfield (i.e. the first bit offset available for @@ -1607,9 +1612,9 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // For unions, this is just a max operation, as usual. if (IsUnion) { - // FIXME: I think FieldSize should be TypeSize here. - setDataSize(std::max(getDataSizeInBits(), FieldSize)); - + uint64_t RoundedFieldSize = roundUpSizeToCharAlignment(FieldSize, + Context); + setDataSize(std::max(getDataSizeInBits(), RoundedFieldSize)); // For non-zero-width bitfields in ms_struct structs, allocate a new // storage unit if necessary. } else if (IsMsStruct && FieldSize) { @@ -1645,7 +1650,8 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { Context.toCharUnitsFromBits(UnpackedFieldAlign)); } -void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { +void RecordLayoutBuilder::LayoutField(const FieldDecl *D, + bool InsertExtraPadding) { if (D->isBitField()) { LayoutBitField(D); return; @@ -1749,6 +1755,15 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D) { Context.toBits(UnpackedFieldOffset), Context.toBits(UnpackedFieldAlign), FieldPacked, D); + if (InsertExtraPadding) { + CharUnits ASanAlignment = CharUnits::fromQuantity(8); + CharUnits ExtraSizeForAsan = ASanAlignment; + if (FieldSize % ASanAlignment) + ExtraSizeForAsan += + ASanAlignment - CharUnits::fromQuantity(FieldSize % ASanAlignment); + FieldSize += ExtraSizeForAsan; + } + // Reserve space for this field. uint64_t FieldSizeInBits = Context.toBits(FieldSize); if (IsUnion) @@ -2097,7 +2112,7 @@ static bool isMsLayout(const RecordDecl* D) { // * There is a distinction between alignment and required alignment. // __declspec(align) changes the required alignment of a struct. This // alignment is _always_ obeyed, even in the presence of #pragma pack. A -// record inherites required alignment from all of its fields an bases. +// record inherits required alignment from all of its fields and bases. // * __declspec(align) on bitfields has the effect of changing the bitfield's // alignment instead of its required alignment. This is the only known way // to make the alignment of a struct bigger than 8. Interestingly enough @@ -2181,8 +2196,9 @@ public: FieldOffsets.push_back(FieldOffset); } /// \brief Compute the set of virtual bases for which vtordisps are required. - llvm::SmallPtrSet<const CXXRecordDecl *, 2> - computeVtorDispSet(const CXXRecordDecl *RD); + void computeVtorDispSet( + llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet, + const CXXRecordDecl *RD) const; const ASTContext &Context; /// \brief The size of the record being laid out. CharUnits Size; @@ -2203,6 +2219,8 @@ public: CharUnits CurrentBitfieldSize; /// \brief Offset to the virtual base table pointer (if one exists). CharUnits VBPtrOffset; + /// \brief Minimum record size possible. + CharUnits MinEmptyStructSize; /// \brief The size and alignment info of a pointer. ElementInfo PointerInfo; /// \brief The primary base class (if one exists). @@ -2260,12 +2278,18 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( MicrosoftRecordLayoutBuilder::ElementInfo MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( const FieldDecl *FD) { + // Get the alignment of the field type's natural alignment, ignore any + // alignment attributes. ElementInfo Info; std::tie(Info.Size, Info.Alignment) = - Context.getTypeInfoInChars(FD->getType()); - // Respect align attributes. - CharUnits FieldRequiredAlignment = + Context.getTypeInfoInChars(FD->getType()->getUnqualifiedDesugaredType()); + // Respect align attributes on the field. + CharUnits FieldRequiredAlignment = Context.toCharUnitsFromBits(FD->getMaxAlignment()); + // Respect align attributes on the type. + if (Context.isAlignmentRequired(FD->getType())) + FieldRequiredAlignment = std::max( + Context.getTypeAlignInChars(FD->getType()), FieldRequiredAlignment); // Respect attributes applied to subobjects of the field. if (FD->isBitField()) // For some reason __declspec align impacts alignment rather than required @@ -2292,6 +2316,8 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( } void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) { + // For C record layout, zero-sized records always have size 4. + MinEmptyStructSize = CharUnits::fromQuantity(4); initializeLayout(RD); layoutFields(RD); DataSize = Size = Size.RoundUpToAlignment(Alignment); @@ -2301,6 +2327,8 @@ void MicrosoftRecordLayoutBuilder::layout(const RecordDecl *RD) { } void MicrosoftRecordLayoutBuilder::cxxLayout(const CXXRecordDecl *RD) { + // The C++ standard says that empty structs have size 1. + MinEmptyStructSize = CharUnits::One(); initializeLayout(RD); initializeCXXLayout(RD); layoutNonVirtualBases(RD); @@ -2599,14 +2627,14 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { } VtorDispAlignment = std::max(VtorDispAlignment, RequiredAlignment); // Compute the vtordisp set. - llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordispSet = - computeVtorDispSet(RD); + llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtorDispSet; + computeVtorDispSet(HasVtorDispSet, RD); // Iterate through the virtual bases and lay them out. const ASTRecordLayout *PreviousBaseLayout = nullptr; for (const CXXBaseSpecifier &VBase : RD->vbases()) { const CXXRecordDecl *BaseDecl = VBase.getType()->getAsCXXRecordDecl(); const ASTRecordLayout &BaseLayout = Context.getASTRecordLayout(BaseDecl); - bool HasVtordisp = HasVtordispSet.count(BaseDecl); + bool HasVtordisp = HasVtorDispSet.count(BaseDecl) > 0; // Insert padding between two bases if the left first one is zero sized or // contains a zero sized subobject and the right is zero sized or one leads // with a zero sized base. The padding between virtual bases is 4 @@ -2629,7 +2657,7 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { // Respect required alignment. Note that in 32-bit mode Required alignment - // may be 0 nad cause size not to be updated. + // may be 0 and cause size not to be updated. DataSize = Size; if (!RequiredAlignment.isZero()) { Alignment = std::max(Alignment, RequiredAlignment); @@ -2639,11 +2667,15 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { RoundingAlignment = std::max(RoundingAlignment, RequiredAlignment); Size = Size.RoundUpToAlignment(RoundingAlignment); } - // Zero-sized structures have size equal to their alignment. if (Size.isZero()) { EndsWithZeroSizedObject = true; LeadsWithZeroSizedBase = true; - Size = Alignment; + // Zero-sized structures have size equal to their alignment if a + // __declspec(align) came into play. + if (RequiredAlignment >= MinEmptyStructSize) + Size = Alignment; + else + Size = MinEmptyStructSize; } } @@ -2665,10 +2697,9 @@ RequiresVtordisp(const llvm::SmallPtrSetImpl<const CXXRecordDecl *> & return false; } -llvm::SmallPtrSet<const CXXRecordDecl *, 2> -MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) { - llvm::SmallPtrSet<const CXXRecordDecl *, 2> HasVtordispSet; - +void MicrosoftRecordLayoutBuilder::computeVtorDispSet( + llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtordispSet, + const CXXRecordDecl *RD) const { // /vd2 or #pragma vtordisp(2): Always use vtordisps for virtual bases with // vftables. if (RD->getMSVtorDispMode() == MSVtorDispAttr::ForVFTable) { @@ -2678,7 +2709,7 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) { if (Layout.hasExtendableVFPtr()) HasVtordispSet.insert(BaseDecl); } - return HasVtordispSet; + return; } // If any of our bases need a vtordisp for this type, so do we. Check our @@ -2695,7 +2726,7 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) { // * #pragma vtordisp(0) or the /vd0 flag are in use. if ((!RD->hasUserDeclaredConstructor() && !RD->hasUserDeclaredDestructor()) || RD->getMSVtorDispMode() == MSVtorDispAttr::Never) - return HasVtordispSet; + return; // /vd1 or #pragma vtordisp(1): Try to guess based on whether we think it's // possible for a partially constructed object with virtual base overrides to // escape a non-trivial constructor. @@ -2706,9 +2737,9 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) { // vtordisp. llvm::SmallPtrSet<const CXXMethodDecl *, 8> Work; llvm::SmallPtrSet<const CXXRecordDecl *, 2> BasesWithOverriddenMethods; - // Seed the working set with our non-destructor virtual methods. + // Seed the working set with our non-destructor, non-pure virtual methods. for (const CXXMethodDecl *MD : RD->methods()) - if (MD->isVirtual() && !isa<CXXDestructorDecl>(MD)) + if (MD->isVirtual() && !isa<CXXDestructorDecl>(MD) && !MD->isPure()) Work.insert(MD); while (!Work.empty()) { const CXXMethodDecl *MD = *Work.begin(); @@ -2730,7 +2761,6 @@ MicrosoftRecordLayoutBuilder::computeVtorDispSet(const CXXRecordDecl *RD) { RequiresVtordisp(BasesWithOverriddenMethods, BaseDecl)) HasVtordispSet.insert(BaseDecl); } - return HasVtordispSet; } /// \brief Get or compute information about the layout of the specified record diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index a8483dc5bb99..68c7e7278432 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -104,6 +104,26 @@ Stmt *Stmt::IgnoreImplicit() { return s; } +/// \brief Skip no-op (attributed, compound) container stmts and skip captured +/// stmt at the top, if \a IgnoreCaptured is true. +Stmt *Stmt::IgnoreContainers(bool IgnoreCaptured) { + Stmt *S = this; + if (IgnoreCaptured) + if (auto CapS = dyn_cast_or_null<CapturedStmt>(S)) + S = CapS->getCapturedStmt(); + while (true) { + if (auto AS = dyn_cast_or_null<AttributedStmt>(S)) + S = AS->getSubStmt(); + else if (auto CS = dyn_cast_or_null<CompoundStmt>(S)) { + if (CS->size() != 1) + break; + S = CS->body_back(); + } else + break; + } + return S; +} + /// \brief Strip off all label-like statements. /// /// This will strip off label statements, case statements, attributed @@ -254,7 +274,7 @@ SourceLocation Stmt::getLocEnd() const { CompoundStmt::CompoundStmt(const ASTContext &C, ArrayRef<Stmt*> Stmts, SourceLocation LB, SourceLocation RB) - : Stmt(CompoundStmtClass), LBracLoc(LB), RBracLoc(RB) { + : Stmt(CompoundStmtClass), LBraceLoc(LB), RBraceLoc(RB) { CompoundStmtBits.NumStmts = Stmts.size(); assert(CompoundStmtBits.NumStmts == Stmts.size() && "NumStmts doesn't fit in bits of CompoundStmtBits.NumStmts!"); @@ -357,6 +377,11 @@ unsigned AsmStmt::getNumPlusOperands() const { return Res; } +char GCCAsmStmt::AsmStringPiece::getModifier() const { + assert(isOperand() && "Only Operands can have modifiers."); + return isLetter(Str[0]) ? Str[0] : '\0'; +} + StringRef GCCAsmStmt::getClobber(unsigned i) const { return getClobberStringLiteral(i)->getString(); } @@ -517,17 +542,25 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, CurStringPiece.clear(); } - // Handle %x4 and %x[foo] by capturing x as the modifier character. - char Modifier = '\0'; + // Handle operands that have asmSymbolicName (e.g., %x[foo]) and those that + // don't (e.g., %x4). 'x' following the '%' is the constraint modifier. + + const char *Begin = CurPtr - 1; // Points to the character following '%'. + const char *Percent = Begin - 1; // Points to '%'. + if (isLetter(EscapedChar)) { if (CurPtr == StrEnd) { // Premature end. DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } - Modifier = EscapedChar; EscapedChar = *CurPtr++; } + const TargetInfo &TI = C.getTargetInfo(); + const SourceManager &SM = C.getSourceManager(); + const LangOptions &LO = C.getLangOpts(); + + // Handle operands that don't have asmSymbolicName (e.g., %x4). if (isDigit(EscapedChar)) { // %n - Assembler operand n unsigned N = 0; @@ -543,11 +576,21 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, return diag::err_asm_invalid_operand_number; } - Pieces.push_back(AsmStringPiece(N, Modifier)); + // Str contains "x4" (Operand without the leading %). + std::string Str(Begin, CurPtr - Begin); + + // (BeginLoc, EndLoc) represents the range of the operand we are currently + // processing. Unlike Str, the range includes the leading '%'. + SourceLocation BeginLoc = + getAsmString()->getLocationOfByte(Percent - StrStart, SM, LO, TI); + SourceLocation EndLoc = + getAsmString()->getLocationOfByte(CurPtr - StrStart, SM, LO, TI); + + Pieces.push_back(AsmStringPiece(N, Str, BeginLoc, EndLoc)); continue; } - // Handle %[foo], a symbolic operand reference. + // Handle operands that have asmSymbolicName (e.g., %x[foo]). if (EscapedChar == '[') { DiagOffs = CurPtr-StrStart-1; @@ -566,7 +609,18 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, DiagOffs = CurPtr-StrStart; return diag::err_asm_unknown_symbolic_operand_name; } - Pieces.push_back(AsmStringPiece(N, Modifier)); + + // Str contains "x[foo]" (Operand without the leading %). + std::string Str(Begin, NameEnd + 1 - Begin); + + // (BeginLoc, EndLoc) represents the range of the operand we are currently + // processing. Unlike Str, the range includes the leading '%'. + SourceLocation BeginLoc = + getAsmString()->getLocationOfByte(Percent - StrStart, SM, LO, TI); + SourceLocation EndLoc = + getAsmString()->getLocationOfByte(NameEnd + 1 - StrStart, SM, LO, TI); + + Pieces.push_back(AsmStringPiece(N, Str, BeginLoc, EndLoc)); CurPtr = NameEnd+1; continue; @@ -956,20 +1010,22 @@ Expr* ReturnStmt::getRetValue() { return cast_or_null<Expr>(RetExpr); } -SEHTryStmt::SEHTryStmt(bool IsCXXTry, SourceLocation TryLoc, Stmt *TryBlock, - Stmt *Handler, int HandlerIndex, int HandlerParentIndex) - : Stmt(SEHTryStmtClass), IsCXXTry(IsCXXTry), TryLoc(TryLoc), - HandlerIndex(HandlerIndex), HandlerParentIndex(HandlerParentIndex) { - Children[TRY] = TryBlock; +SEHTryStmt::SEHTryStmt(bool IsCXXTry, + SourceLocation TryLoc, + Stmt *TryBlock, + Stmt *Handler) + : Stmt(SEHTryStmtClass), + IsCXXTry(IsCXXTry), + TryLoc(TryLoc) +{ + Children[TRY] = TryBlock; Children[HANDLER] = Handler; } -SEHTryStmt *SEHTryStmt::Create(const ASTContext &C, bool IsCXXTry, +SEHTryStmt* SEHTryStmt::Create(const ASTContext &C, bool IsCXXTry, SourceLocation TryLoc, Stmt *TryBlock, - Stmt *Handler, int HandlerIndex, - int HandlerParentIndex) { - return new (C) SEHTryStmt(IsCXXTry, TryLoc, TryBlock, Handler, HandlerIndex, - HandlerParentIndex); + Stmt *Handler) { + return new(C) SEHTryStmt(IsCXXTry,TryLoc,TryBlock,Handler); } SEHExceptStmt* SEHTryStmt::getExceptHandler() const { @@ -1120,17 +1176,24 @@ StmtRange OMPClause::children() { llvm_unreachable("unknown OMPClause"); } -OMPPrivateClause *OMPPrivateClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef<Expr *> VL) { +void OMPPrivateClause::setPrivateCopies(ArrayRef<Expr *> VL) { + assert(VL.size() == varlist_size() && + "Number of private copies is not the same as the preallocated buffer"); + std::copy(VL.begin(), VL.end(), varlist_end()); +} + +OMPPrivateClause * +OMPPrivateClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc, + ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL) { + // Allocate space for private variables and initializer expressions. void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * VL.size()); - OMPPrivateClause *Clause = new (Mem) OMPPrivateClause(StartLoc, LParenLoc, - EndLoc, VL.size()); + 2 * sizeof(Expr *) * VL.size()); + OMPPrivateClause *Clause = + new (Mem) OMPPrivateClause(StartLoc, LParenLoc, EndLoc, VL.size()); Clause->setVarRefs(VL); + Clause->setPrivateCopies(PrivateVL); return Clause; } @@ -1138,23 +1201,35 @@ OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C, unsigned N) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPPrivateClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * N); + 2 * sizeof(Expr *) * N); return new (Mem) OMPPrivateClause(N); } -OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef<Expr *> VL) { +void OMPFirstprivateClause::setPrivateCopies(ArrayRef<Expr *> VL) { + assert(VL.size() == varlist_size() && + "Number of private copies is not the same as the preallocated buffer"); + std::copy(VL.begin(), VL.end(), varlist_end()); +} + +void OMPFirstprivateClause::setInits(ArrayRef<Expr *> VL) { + assert(VL.size() == varlist_size() && + "Number of inits is not the same as the preallocated buffer"); + std::copy(VL.begin(), VL.end(), getPrivateCopies().end()); +} + +OMPFirstprivateClause * +OMPFirstprivateClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc, + ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL, + ArrayRef<Expr *> InitVL) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * VL.size()); - OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc, - LParenLoc, - EndLoc, - VL.size()); + 3 * sizeof(Expr *) * VL.size()); + OMPFirstprivateClause *Clause = + new (Mem) OMPFirstprivateClause(StartLoc, LParenLoc, EndLoc, VL.size()); Clause->setVarRefs(VL); + Clause->setPrivateCopies(PrivateVL); + Clause->setInits(InitVL); return Clause; } @@ -1162,7 +1237,7 @@ OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C, unsigned N) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPFirstprivateClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * N); + 3 * sizeof(Expr *) * N); return new (Mem) OMPFirstprivateClause(N); } @@ -1306,6 +1381,24 @@ void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) { std::copy(Clauses.begin(), Clauses.end(), getClauses().begin()); } +void OMPLoopDirective::setCounters(ArrayRef<Expr *> A) { + assert(A.size() == getCollapsedNumber() && + "Number of loop counters is not the same as the collapsed number"); + std::copy(A.begin(), A.end(), getCounters().begin()); +} + +void OMPLoopDirective::setUpdates(ArrayRef<Expr *> A) { + assert(A.size() == getCollapsedNumber() && + "Number of counter updates is not the same as the collapsed number"); + std::copy(A.begin(), A.end(), getUpdates().begin()); +} + +void OMPLoopDirective::setFinals(ArrayRef<Expr *> A) { + assert(A.size() == getCollapsedNumber() && + "Number of counter finals is not the same as the collapsed number"); + std::copy(A.begin(), A.end(), getFinals().begin()); +} + OMPReductionClause *OMPReductionClause::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL, @@ -1348,6 +1441,21 @@ OMPFlushClause *OMPFlushClause::CreateEmpty(const ASTContext &C, unsigned N) { return new (Mem) OMPFlushClause(N); } +const OMPClause * +OMPExecutableDirective::getSingleClause(OpenMPClauseKind K) const { + auto ClauseFilter = + [=](const OMPClause *C) -> bool { return C->getClauseKind() == K; }; + OMPExecutableDirective::filtered_clause_iterator<decltype(ClauseFilter)> I( + clauses(), ClauseFilter); + + if (I) { + auto *Clause = *I; + assert(!++I && "There are at least 2 clauses of the specified kind"); + return Clause; + } + return nullptr; +} + OMPParallelDirective *OMPParallelDirective::Create( const ASTContext &C, SourceLocation StartLoc, @@ -1378,15 +1486,27 @@ OMPParallelDirective *OMPParallelDirective::CreateEmpty(const ASTContext &C, OMPSimdDirective * OMPSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, - ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) { + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, + const HelperExprs &Exprs) { unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSimdDirective), llvm::alignOf<OMPClause *>()); void *Mem = - C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + + sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_simd)); OMPSimdDirective *Dir = new (Mem) OMPSimdDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size()); Dir->setClauses(Clauses); Dir->setAssociatedStmt(AssociatedStmt); + Dir->setIterationVariable(Exprs.IterationVarRef); + Dir->setLastIteration(Exprs.LastIteration); + Dir->setCalcLastIteration(Exprs.CalcLastIteration); + Dir->setPreCond(Exprs.PreCond); + Dir->setCond(Exprs.Cond, Exprs.SeparatedCond); + Dir->setInit(Exprs.Init); + Dir->setInc(Exprs.Inc); + Dir->setCounters(Exprs.Counters); + Dir->setUpdates(Exprs.Updates); + Dir->setFinals(Exprs.Finals); return Dir; } @@ -1397,22 +1517,42 @@ OMPSimdDirective *OMPSimdDirective::CreateEmpty(const ASTContext &C, unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPSimdDirective), llvm::alignOf<OMPClause *>()); void *Mem = - C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *)); + C.Allocate(Size + sizeof(OMPClause *) * NumClauses + + sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_simd)); return new (Mem) OMPSimdDirective(CollapsedNum, NumClauses); } OMPForDirective * OMPForDirective::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, - ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) { + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, + const HelperExprs &Exprs) { unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForDirective), llvm::alignOf<OMPClause *>()); void *Mem = - C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + + sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for)); OMPForDirective *Dir = new (Mem) OMPForDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size()); Dir->setClauses(Clauses); Dir->setAssociatedStmt(AssociatedStmt); + Dir->setIterationVariable(Exprs.IterationVarRef); + Dir->setLastIteration(Exprs.LastIteration); + Dir->setCalcLastIteration(Exprs.CalcLastIteration); + Dir->setPreCond(Exprs.PreCond); + Dir->setCond(Exprs.Cond, Exprs.SeparatedCond); + Dir->setInit(Exprs.Init); + Dir->setInc(Exprs.Inc); + Dir->setIsLastIterVariable(Exprs.IL); + Dir->setLowerBoundVariable(Exprs.LB); + Dir->setUpperBoundVariable(Exprs.UB); + Dir->setStrideVariable(Exprs.ST); + Dir->setEnsureUpperBound(Exprs.EUB); + Dir->setNextLowerBound(Exprs.NLB); + Dir->setNextUpperBound(Exprs.NUB); + Dir->setCounters(Exprs.Counters); + Dir->setUpdates(Exprs.Updates); + Dir->setFinals(Exprs.Finals); return Dir; } @@ -1423,10 +1563,57 @@ OMPForDirective *OMPForDirective::CreateEmpty(const ASTContext &C, unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForDirective), llvm::alignOf<OMPClause *>()); void *Mem = - C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *)); + C.Allocate(Size + sizeof(OMPClause *) * NumClauses + + sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for)); return new (Mem) OMPForDirective(CollapsedNum, NumClauses); } +OMPForSimdDirective * +OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, unsigned CollapsedNum, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, + const HelperExprs &Exprs) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForSimdDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + + sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for_simd)); + OMPForSimdDirective *Dir = new (Mem) + OMPForSimdDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setIterationVariable(Exprs.IterationVarRef); + Dir->setLastIteration(Exprs.LastIteration); + Dir->setCalcLastIteration(Exprs.CalcLastIteration); + Dir->setPreCond(Exprs.PreCond); + Dir->setCond(Exprs.Cond, Exprs.SeparatedCond); + Dir->setInit(Exprs.Init); + Dir->setInc(Exprs.Inc); + Dir->setIsLastIterVariable(Exprs.IL); + Dir->setLowerBoundVariable(Exprs.LB); + Dir->setUpperBoundVariable(Exprs.UB); + Dir->setStrideVariable(Exprs.ST); + Dir->setEnsureUpperBound(Exprs.EUB); + Dir->setNextLowerBound(Exprs.NLB); + Dir->setNextUpperBound(Exprs.NUB); + Dir->setCounters(Exprs.Counters); + Dir->setUpdates(Exprs.Updates); + Dir->setFinals(Exprs.Finals); + return Dir; +} + +OMPForSimdDirective *OMPForSimdDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, + EmptyShell) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPForSimdDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * NumClauses + + sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_for_simd)); + return new (Mem) OMPForSimdDirective(CollapsedNum, NumClauses); +} + OMPSectionsDirective *OMPSectionsDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) { @@ -1537,19 +1724,36 @@ OMPCriticalDirective *OMPCriticalDirective::CreateEmpty(const ASTContext &C, return new (Mem) OMPCriticalDirective(); } -OMPParallelForDirective * -OMPParallelForDirective::Create(const ASTContext &C, SourceLocation StartLoc, - SourceLocation EndLoc, unsigned CollapsedNum, - ArrayRef<OMPClause *> Clauses, - Stmt *AssociatedStmt) { +OMPParallelForDirective *OMPParallelForDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, + const HelperExprs &Exprs) { unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective), llvm::alignOf<OMPClause *>()); - void *Mem = - C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + + sizeof(Stmt *) * + numLoopChildren(CollapsedNum, OMPD_parallel_for)); OMPParallelForDirective *Dir = new (Mem) OMPParallelForDirective(StartLoc, EndLoc, CollapsedNum, Clauses.size()); Dir->setClauses(Clauses); Dir->setAssociatedStmt(AssociatedStmt); + Dir->setIterationVariable(Exprs.IterationVarRef); + Dir->setLastIteration(Exprs.LastIteration); + Dir->setCalcLastIteration(Exprs.CalcLastIteration); + Dir->setPreCond(Exprs.PreCond); + Dir->setCond(Exprs.Cond, Exprs.SeparatedCond); + Dir->setInit(Exprs.Init); + Dir->setInc(Exprs.Inc); + Dir->setIsLastIterVariable(Exprs.IL); + Dir->setLowerBoundVariable(Exprs.LB); + Dir->setUpperBoundVariable(Exprs.UB); + Dir->setStrideVariable(Exprs.ST); + Dir->setEnsureUpperBound(Exprs.EUB); + Dir->setNextLowerBound(Exprs.NLB); + Dir->setNextUpperBound(Exprs.NUB); + Dir->setCounters(Exprs.Counters); + Dir->setUpdates(Exprs.Updates); + Dir->setFinals(Exprs.Finals); return Dir; } @@ -1558,11 +1762,57 @@ OMPParallelForDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses, unsigned CollapsedNum, EmptyShell) { unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForDirective), llvm::alignOf<OMPClause *>()); - void *Mem = - C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *)); + void *Mem = C.Allocate(Size + sizeof(OMPClause *) * NumClauses + + sizeof(Stmt *) * + numLoopChildren(CollapsedNum, OMPD_parallel_for)); return new (Mem) OMPParallelForDirective(CollapsedNum, NumClauses); } +OMPParallelForSimdDirective *OMPParallelForSimdDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, + const HelperExprs &Exprs) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForSimdDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = C.Allocate( + Size + sizeof(OMPClause *) * Clauses.size() + + sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_parallel_for_simd)); + OMPParallelForSimdDirective *Dir = new (Mem) OMPParallelForSimdDirective( + StartLoc, EndLoc, CollapsedNum, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setIterationVariable(Exprs.IterationVarRef); + Dir->setLastIteration(Exprs.LastIteration); + Dir->setCalcLastIteration(Exprs.CalcLastIteration); + Dir->setPreCond(Exprs.PreCond); + Dir->setCond(Exprs.Cond, Exprs.SeparatedCond); + Dir->setInit(Exprs.Init); + Dir->setInc(Exprs.Inc); + Dir->setIsLastIterVariable(Exprs.IL); + Dir->setLowerBoundVariable(Exprs.LB); + Dir->setUpperBoundVariable(Exprs.UB); + Dir->setStrideVariable(Exprs.ST); + Dir->setEnsureUpperBound(Exprs.EUB); + Dir->setNextLowerBound(Exprs.NLB); + Dir->setNextUpperBound(Exprs.NUB); + Dir->setCounters(Exprs.Counters); + Dir->setUpdates(Exprs.Updates); + Dir->setFinals(Exprs.Finals); + return Dir; +} + +OMPParallelForSimdDirective * +OMPParallelForSimdDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, EmptyShell) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPParallelForSimdDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = C.Allocate( + Size + sizeof(OMPClause *) * NumClauses + + sizeof(Stmt *) * numLoopChildren(CollapsedNum, OMPD_parallel_for_simd)); + return new (Mem) OMPParallelForSimdDirective(CollapsedNum, NumClauses); +} + OMPParallelSectionsDirective *OMPParallelSectionsDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) { @@ -1678,3 +1928,103 @@ OMPFlushDirective *OMPFlushDirective::CreateEmpty(const ASTContext &C, return new (Mem) OMPFlushDirective(NumClauses); } +OMPOrderedDirective *OMPOrderedDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + Stmt *AssociatedStmt) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPOrderedDirective), + llvm::alignOf<Stmt *>()); + void *Mem = C.Allocate(Size + sizeof(Stmt *)); + OMPOrderedDirective *Dir = new (Mem) OMPOrderedDirective(StartLoc, EndLoc); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPOrderedDirective *OMPOrderedDirective::CreateEmpty(const ASTContext &C, + EmptyShell) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPOrderedDirective), + llvm::alignOf<Stmt *>()); + void *Mem = C.Allocate(Size + sizeof(Stmt *)); + return new (Mem) OMPOrderedDirective(); +} + +OMPAtomicDirective * +OMPAtomicDirective::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt, Expr *X, Expr *V, Expr *E) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + + 4 * sizeof(Stmt *)); + OMPAtomicDirective *Dir = + new (Mem) OMPAtomicDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setX(X); + Dir->setV(V); + Dir->setExpr(E); + return Dir; +} + +OMPAtomicDirective *OMPAtomicDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + EmptyShell) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * NumClauses + 4 * sizeof(Stmt *)); + return new (Mem) OMPAtomicDirective(NumClauses); +} + +OMPTargetDirective *OMPTargetDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTargetDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPTargetDirective *Dir = + new (Mem) OMPTargetDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPTargetDirective *OMPTargetDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + EmptyShell) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTargetDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *)); + return new (Mem) OMPTargetDirective(NumClauses); +} + +OMPTeamsDirective *OMPTeamsDirective::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, + Stmt *AssociatedStmt) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTeamsDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + OMPTeamsDirective *Dir = + new (Mem) OMPTeamsDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPTeamsDirective *OMPTeamsDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + EmptyShell) { + unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPTeamsDirective), + llvm::alignOf<OMPClause *>()); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *)); + return new (Mem) OMPTeamsDirective(NumClauses); +} + diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 1fdad9f4272c..927a679244b5 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -665,6 +665,22 @@ void OMPClausePrinter::VisitOMPMergeableClause(OMPMergeableClause *) { OS << "mergeable"; } +void OMPClausePrinter::VisitOMPReadClause(OMPReadClause *) { OS << "read"; } + +void OMPClausePrinter::VisitOMPWriteClause(OMPWriteClause *) { OS << "write"; } + +void OMPClausePrinter::VisitOMPUpdateClause(OMPUpdateClause *) { + OS << "update"; +} + +void OMPClausePrinter::VisitOMPCaptureClause(OMPCaptureClause *) { + OS << "capture"; +} + +void OMPClausePrinter::VisitOMPSeqCstClause(OMPSeqCstClause *) { + OS << "seq_cst"; +} + template<typename T> void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) { for (typename T::varlist_iterator I = Node->varlist_begin(), @@ -820,6 +836,11 @@ void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) { PrintOMPExecutableDirective(Node); } +void StmtPrinter::VisitOMPForSimdDirective(OMPForSimdDirective *Node) { + Indent() << "#pragma omp for simd "; + PrintOMPExecutableDirective(Node); +} + void StmtPrinter::VisitOMPSectionsDirective(OMPSectionsDirective *Node) { Indent() << "#pragma omp sections "; PrintOMPExecutableDirective(Node); @@ -855,6 +876,12 @@ void StmtPrinter::VisitOMPParallelForDirective(OMPParallelForDirective *Node) { PrintOMPExecutableDirective(Node); } +void StmtPrinter::VisitOMPParallelForSimdDirective( + OMPParallelForSimdDirective *Node) { + Indent() << "#pragma omp parallel for simd "; + PrintOMPExecutableDirective(Node); +} + void StmtPrinter::VisitOMPParallelSectionsDirective( OMPParallelSectionsDirective *Node) { Indent() << "#pragma omp parallel sections "; @@ -886,6 +913,26 @@ void StmtPrinter::VisitOMPFlushDirective(OMPFlushDirective *Node) { PrintOMPExecutableDirective(Node); } +void StmtPrinter::VisitOMPOrderedDirective(OMPOrderedDirective *Node) { + Indent() << "#pragma omp ordered"; + PrintOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPAtomicDirective(OMPAtomicDirective *Node) { + Indent() << "#pragma omp atomic "; + PrintOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPTargetDirective(OMPTargetDirective *Node) { + Indent() << "#pragma omp target "; + PrintOMPExecutableDirective(Node); +} + +void StmtPrinter::VisitOMPTeamsDirective(OMPTeamsDirective *Node) { + Indent() << "#pragma omp teams "; + PrintOMPExecutableDirective(Node); +} + //===----------------------------------------------------------------------===// // Expr printing methods. //===----------------------------------------------------------------------===// @@ -957,28 +1004,7 @@ void StmtPrinter::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *Node) { } void StmtPrinter::VisitPredefinedExpr(PredefinedExpr *Node) { - switch (Node->getIdentType()) { - default: - llvm_unreachable("unknown case"); - case PredefinedExpr::Func: - OS << "__func__"; - break; - case PredefinedExpr::Function: - OS << "__FUNCTION__"; - break; - case PredefinedExpr::FuncDName: - OS << "__FUNCDNAME__"; - break; - case PredefinedExpr::FuncSig: - OS << "__FUNCSIG__"; - break; - case PredefinedExpr::LFunction: - OS << "L__FUNCTION__"; - break; - case PredefinedExpr::PrettyFunction: - OS << "__PRETTY_FUNCTION__"; - break; - } + OS << PredefinedExpr::getIdentTypeName(Node->getIdentType()); } void StmtPrinter::VisitCharacterLiteral(CharacterLiteral *Node) { @@ -1716,6 +1742,8 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { case LCK_ByCopy: OS << C->getCapturedVar()->getName(); break; + case LCK_VLAType: + llvm_unreachable("VLA type in explicit captures."); } if (C->isInitCapture()) @@ -1994,6 +2022,20 @@ void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){ PrintExpr(Node->GetTemporaryExpr()); } +void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) { + OS << "("; + if (E->getLHS()) { + PrintExpr(E->getLHS()); + OS << " " << BinaryOperator::getOpcodeStr(E->getOperator()) << " "; + } + OS << "..."; + if (E->getRHS()) { + OS << " " << BinaryOperator::getOpcodeStr(E->getOperator()) << " "; + PrintExpr(E->getRHS()); + } + OS << ")"; +} + // Obj-C void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) { @@ -2138,6 +2180,11 @@ void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) { PrintExpr(Node->getSourceExpr()); } +void StmtPrinter::VisitTypoExpr(TypoExpr *Node) { + // TODO: Print something reasonable for a TypoExpr, if necessary. + assert(false && "Cannot print TypoExpr nodes"); +} + void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) { OS << "__builtin_astype("; PrintExpr(Node->getSrcExpr()); diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index f44f25c96aba..d1f25d63b3f9 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -310,18 +310,38 @@ void OMPClauseProfiler::VisitOMPUntiedClause(const OMPUntiedClause *) {} void OMPClauseProfiler::VisitOMPMergeableClause(const OMPMergeableClause *) {} +void OMPClauseProfiler::VisitOMPReadClause(const OMPReadClause *) {} + +void OMPClauseProfiler::VisitOMPWriteClause(const OMPWriteClause *) {} + +void OMPClauseProfiler::VisitOMPUpdateClause(const OMPUpdateClause *) {} + +void OMPClauseProfiler::VisitOMPCaptureClause(const OMPCaptureClause *) {} + +void OMPClauseProfiler::VisitOMPSeqCstClause(const OMPSeqCstClause *) {} + template<typename T> void OMPClauseProfiler::VisitOMPClauseList(T *Node) { - for (auto *I : Node->varlists()) - Profiler->VisitStmt(I); + for (auto *E : Node->varlists()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) { VisitOMPClauseList(C); + for (auto *E : C->private_copies()) { + Profiler->VisitStmt(E); + } } -void OMPClauseProfiler::VisitOMPFirstprivateClause( - const OMPFirstprivateClause *C) { +void +OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) { VisitOMPClauseList(C); + for (auto *E : C->private_copies()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->inits()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) { @@ -368,16 +388,24 @@ StmtProfiler::VisitOMPExecutableDirective(const OMPExecutableDirective *S) { P.Visit(*I); } +void StmtProfiler::VisitOMPLoopDirective(const OMPLoopDirective *S) { + VisitOMPExecutableDirective(S); +} + void StmtProfiler::VisitOMPParallelDirective(const OMPParallelDirective *S) { VisitOMPExecutableDirective(S); } void StmtProfiler::VisitOMPSimdDirective(const OMPSimdDirective *S) { - VisitOMPExecutableDirective(S); + VisitOMPLoopDirective(S); } void StmtProfiler::VisitOMPForDirective(const OMPForDirective *S) { - VisitOMPExecutableDirective(S); + VisitOMPLoopDirective(S); +} + +void StmtProfiler::VisitOMPForSimdDirective(const OMPForSimdDirective *S) { + VisitOMPLoopDirective(S); } void StmtProfiler::VisitOMPSectionsDirective(const OMPSectionsDirective *S) { @@ -403,7 +431,12 @@ void StmtProfiler::VisitOMPCriticalDirective(const OMPCriticalDirective *S) { void StmtProfiler::VisitOMPParallelForDirective(const OMPParallelForDirective *S) { - VisitOMPExecutableDirective(S); + VisitOMPLoopDirective(S); +} + +void StmtProfiler::VisitOMPParallelForSimdDirective( + const OMPParallelForSimdDirective *S) { + VisitOMPLoopDirective(S); } void StmtProfiler::VisitOMPParallelSectionsDirective( @@ -431,6 +464,22 @@ void StmtProfiler::VisitOMPFlushDirective(const OMPFlushDirective *S) { VisitOMPExecutableDirective(S); } +void StmtProfiler::VisitOMPOrderedDirective(const OMPOrderedDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPAtomicDirective(const OMPAtomicDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPTargetDirective(const OMPTargetDirective *S) { + VisitOMPExecutableDirective(S); +} + +void StmtProfiler::VisitOMPTeamsDirective(const OMPTeamsDirective *S) { + VisitOMPExecutableDirective(S); +} + void StmtProfiler::VisitExpr(const Expr *S) { VisitStmt(S); } @@ -452,6 +501,7 @@ void StmtProfiler::VisitPredefinedExpr(const PredefinedExpr *S) { void StmtProfiler::VisitIntegerLiteral(const IntegerLiteral *S) { VisitExpr(S); S->getValue().Profile(ID); + ID.AddInteger(S->getType()->castAs<BuiltinType>()->getKind()); } void StmtProfiler::VisitCharacterLiteral(const CharacterLiteral *S) { @@ -464,6 +514,7 @@ void StmtProfiler::VisitFloatingLiteral(const FloatingLiteral *S) { VisitExpr(S); S->getValue().Profile(ID); ID.AddBoolean(S->isExact()); + ID.AddInteger(S->getType()->castAs<BuiltinType>()->getKind()); } void StmtProfiler::VisitImaginaryLiteral(const ImaginaryLiteral *S) { @@ -1018,6 +1069,8 @@ StmtProfiler::VisitLambdaExpr(const LambdaExpr *S) { VisitDecl(C->getCapturedVar()); ID.AddBoolean(C->isPackExpansion()); break; + case LCK_VLAType: + llvm_unreachable("VLA type in explicit captures."); } } // Note: If we actually needed to be able to match lambda @@ -1187,10 +1240,19 @@ void StmtProfiler::VisitMaterializeTemporaryExpr( VisitExpr(S); } +void StmtProfiler::VisitCXXFoldExpr(const CXXFoldExpr *S) { + VisitExpr(S); + ID.AddInteger(S->getOperator()); +} + void StmtProfiler::VisitOpaqueValueExpr(const OpaqueValueExpr *E) { VisitExpr(E); } +void StmtProfiler::VisitTypoExpr(const TypoExpr *E) { + VisitExpr(E); +} + void StmtProfiler::VisitObjCStringLiteral(const ObjCStringLiteral *S) { VisitExpr(S); } diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index ac6a754fe733..f8b73cb8f89a 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -33,11 +33,26 @@ using namespace clang; /// \param TemplArg the TemplateArgument instance to print. /// /// \param Out the raw_ostream instance to use for printing. +/// +/// \param Policy the printing policy for EnumConstantDecl printing. static void printIntegral(const TemplateArgument &TemplArg, - raw_ostream &Out) { + raw_ostream &Out, const PrintingPolicy& Policy) { const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr(); const llvm::APSInt &Val = TemplArg.getAsIntegral(); + if (const EnumType *ET = T->getAs<EnumType>()) { + for (const EnumConstantDecl* ECD : ET->getDecl()->enumerators()) { + // In Sema::CheckTemplateArugment, enum template arguments value are + // extended to the size of the integer underlying the enum type. This + // may create a size difference between the enum value and template + // argument value, requiring isSameValue here instead of operator==. + if (llvm::APSInt::isSameValue(ECD->getInitVal(), Val)) { + ECD->printQualifiedName(Out, Policy); + return; + } + } + } + if (T->isBooleanType()) { Out << (Val.getBoolValue() ? "true" : "false"); } else if (T->isCharType()) { @@ -90,7 +105,8 @@ bool TemplateArgument::isDependent() const { llvm_unreachable("Should not have a NULL template argument"); case Type: - return getAsType()->isDependentType(); + return getAsType()->isDependentType() || + isa<PackExpansionType>(getAsType()); case Template: return getAsTemplate().isDependent(); @@ -111,7 +127,8 @@ bool TemplateArgument::isDependent() const { return false; case Expression: - return (getAsExpr()->isTypeDependent() || getAsExpr()->isValueDependent()); + return (getAsExpr()->isTypeDependent() || getAsExpr()->isValueDependent() || + isa<PackExpansionExpr>(getAsExpr())); case Pack: for (const auto &P : pack_elements()) @@ -294,8 +311,7 @@ bool TemplateArgument::structurallyEquals(const TemplateArgument &Other) const { return TypeOrValue.V == Other.TypeOrValue.V; case Declaration: - return getAsDecl() == Other.getAsDecl() && - isDeclForReferenceParam() && Other.isDeclForReferenceParam(); + return getAsDecl() == Other.getAsDecl(); case Integral: return getIntegralType() == Other.getIntegralType() && @@ -377,7 +393,7 @@ void TemplateArgument::print(const PrintingPolicy &Policy, break; case Integral: { - printIntegral(*this, Out); + printIntegral(*this, Out, Policy); break; } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 167787430294..e4f364d04f86 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -70,7 +70,7 @@ bool QualType::isConstant(QualType T, ASTContext &Ctx) { if (const ArrayType *AT = Ctx.getAsArrayType(T)) return AT->getElementType().isConstant(Ctx); - return false; + return T.getAddressSpace() == LangAS::opencl_constant; } unsigned ConstantArrayType::getNumAddressingBits(ASTContext &Context, @@ -378,9 +378,10 @@ bool Type::isInterfaceType() const { return false; } bool Type::isStructureOrClassType() const { - if (const RecordType *RT = getAs<RecordType>()) - return RT->getDecl()->isStruct() || RT->getDecl()->isClass() || - RT->getDecl()->isInterface(); + if (const RecordType *RT = getAs<RecordType>()) { + RecordDecl *RD = RT->getDecl(); + return RD->isStruct() || RD->isClass() || RD->isInterface(); + } return false; } bool Type::isVoidPointerType() const { @@ -540,10 +541,13 @@ const CXXRecordDecl *Type::getPointeeCXXRecordDecl() const { } CXXRecordDecl *Type::getAsCXXRecordDecl() const { - if (const RecordType *RT = getAs<RecordType>()) - return dyn_cast<CXXRecordDecl>(RT->getDecl()); - else if (const InjectedClassNameType *Injected - = getAs<InjectedClassNameType>()) + return dyn_cast_or_null<CXXRecordDecl>(getAsTagDecl()); +} + +TagDecl *Type::getAsTagDecl() const { + if (const auto *TT = getAs<TagType>()) + return cast<TagDecl>(TT->getDecl()); + if (const auto *Injected = getAs<InjectedClassNameType>()) return Injected->getDecl(); return nullptr; @@ -1147,7 +1151,7 @@ bool Type::isLiteralType(const ASTContext &Ctx) const { // C++1y [basic.types]p10: // A type is a literal type if it is: // -- cv void; or - if (Ctx.getLangOpts().CPlusPlus1y && isVoidType()) + if (Ctx.getLangOpts().CPlusPlus14 && isVoidType()) return true; // C++11 [basic.types]p10: @@ -1577,6 +1581,7 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_X86FastCall: return "fastcall"; case CC_X86ThisCall: return "thiscall"; case CC_X86Pascal: return "pascal"; + case CC_X86VectorCall: return "vectorcall"; case CC_X86_64Win64: return "ms_abi"; case CC_X86_64SysV: return "sysv_abi"; case CC_AAPCS: return "aapcs"; @@ -1591,18 +1596,21 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, QualType canonical, const ExtProtoInfo &epi) - : FunctionType(FunctionProto, result, epi.TypeQuals, canonical, + : FunctionType(FunctionProto, result, canonical, result->isDependentType(), result->isInstantiationDependentType(), result->isVariablyModifiedType(), result->containsUnexpandedParameterPack(), epi.ExtInfo), - NumParams(params.size()), NumExceptions(epi.NumExceptions), - ExceptionSpecType(epi.ExceptionSpecType), + NumParams(params.size()), + NumExceptions(epi.ExceptionSpec.Exceptions.size()), + ExceptionSpecType(epi.ExceptionSpec.Type), HasAnyConsumedParams(epi.ConsumedParameters != nullptr), - Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn), - RefQualifier(epi.RefQualifier) { + Variadic(epi.Variadic), HasTrailingReturn(epi.HasTrailingReturn) { assert(NumParams == params.size() && "function has too many parameters"); + FunctionTypeBits.TypeQuals = epi.TypeQuals; + FunctionTypeBits.RefQualifier = epi.RefQualifier; + // Fill in the trailing argument array. QualType *argSlot = reinterpret_cast<QualType*>(this+1); for (unsigned i = 0; i != NumParams; ++i) { @@ -1620,36 +1628,38 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, if (getExceptionSpecType() == EST_Dynamic) { // Fill in the exception array. QualType *exnSlot = argSlot + NumParams; - for (unsigned i = 0, e = epi.NumExceptions; i != e; ++i) { - if (epi.Exceptions[i]->isDependentType()) - setDependent(); - else if (epi.Exceptions[i]->isInstantiationDependentType()) + unsigned I = 0; + for (QualType ExceptionType : epi.ExceptionSpec.Exceptions) { + // Note that a dependent exception specification does *not* make + // a type dependent; it's not even part of the C++ type system. + if (ExceptionType->isInstantiationDependentType()) setInstantiationDependent(); - - if (epi.Exceptions[i]->containsUnexpandedParameterPack()) + + if (ExceptionType->containsUnexpandedParameterPack()) setContainsUnexpandedParameterPack(); - exnSlot[i] = epi.Exceptions[i]; + exnSlot[I++] = ExceptionType; } } else if (getExceptionSpecType() == EST_ComputedNoexcept) { // Store the noexcept expression and context. Expr **noexSlot = reinterpret_cast<Expr **>(argSlot + NumParams); - *noexSlot = epi.NoexceptExpr; - - if (epi.NoexceptExpr) { - if (epi.NoexceptExpr->isValueDependent() - || epi.NoexceptExpr->isTypeDependent()) - setDependent(); - else if (epi.NoexceptExpr->isInstantiationDependent()) + *noexSlot = epi.ExceptionSpec.NoexceptExpr; + + if (epi.ExceptionSpec.NoexceptExpr) { + if (epi.ExceptionSpec.NoexceptExpr->isValueDependent() || + epi.ExceptionSpec.NoexceptExpr->isInstantiationDependent()) setInstantiationDependent(); + + if (epi.ExceptionSpec.NoexceptExpr->containsUnexpandedParameterPack()) + setContainsUnexpandedParameterPack(); } } else if (getExceptionSpecType() == EST_Uninstantiated) { // Store the function decl from which we will resolve our // exception specification. FunctionDecl **slot = reinterpret_cast<FunctionDecl **>(argSlot + NumParams); - slot[0] = epi.ExceptionSpecDecl; - slot[1] = epi.ExceptionSpecTemplate; + slot[0] = epi.ExceptionSpec.SourceDecl; + slot[1] = epi.ExceptionSpec.SourceTemplate; // This exception specification doesn't make the type dependent, because // it's not instantiated as part of instantiating the type. } else if (getExceptionSpecType() == EST_Unevaluated) { @@ -1657,7 +1667,7 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, // exception specification. FunctionDecl **slot = reinterpret_cast<FunctionDecl **>(argSlot + NumParams); - slot[0] = epi.ExceptionSpecDecl; + slot[0] = epi.ExceptionSpec.SourceDecl; } if (epi.ConsumedParameters) { @@ -1667,6 +1677,18 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, } } +bool FunctionProtoType::hasDependentExceptionSpec() const { + if (Expr *NE = getNoexceptExpr()) + return NE->isValueDependent(); + for (QualType ET : exceptions()) + // A pack expansion with a non-dependent pattern is still dependent, + // because we don't know whether the pattern is in the exception spec + // or not (that depends on whether the pack has 0 expansions). + if (ET->isDependentType() || ET->getAs<PackExpansionType>()) + return true; + return false; +} + FunctionProtoType::NoexceptResult FunctionProtoType::getNoexceptSpec(const ASTContext &ctx) const { ExceptionSpecificationType est = getExceptionSpecType(); @@ -1755,20 +1777,21 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result, assert(!(unsigned(epi.Variadic) & ~1) && !(unsigned(epi.TypeQuals) & ~255) && !(unsigned(epi.RefQualifier) & ~3) && - !(unsigned(epi.ExceptionSpecType) & ~7) && + !(unsigned(epi.ExceptionSpec.Type) & ~15) && "Values larger than expected."); ID.AddInteger(unsigned(epi.Variadic) + (epi.TypeQuals << 1) + (epi.RefQualifier << 9) + - (epi.ExceptionSpecType << 11)); - if (epi.ExceptionSpecType == EST_Dynamic) { - for (unsigned i = 0; i != epi.NumExceptions; ++i) - ID.AddPointer(epi.Exceptions[i].getAsOpaquePtr()); - } else if (epi.ExceptionSpecType == EST_ComputedNoexcept && epi.NoexceptExpr){ - epi.NoexceptExpr->Profile(ID, Context, false); - } else if (epi.ExceptionSpecType == EST_Uninstantiated || - epi.ExceptionSpecType == EST_Unevaluated) { - ID.AddPointer(epi.ExceptionSpecDecl->getCanonicalDecl()); + (epi.ExceptionSpec.Type << 11)); + if (epi.ExceptionSpec.Type == EST_Dynamic) { + for (QualType Ex : epi.ExceptionSpec.Exceptions) + ID.AddPointer(Ex.getAsOpaquePtr()); + } else if (epi.ExceptionSpec.Type == EST_ComputedNoexcept && + epi.ExceptionSpec.NoexceptExpr) { + epi.ExceptionSpec.NoexceptExpr->Profile(ID, Context, false); + } else if (epi.ExceptionSpec.Type == EST_Uninstantiated || + epi.ExceptionSpec.Type == EST_Unevaluated) { + ID.AddPointer(epi.ExceptionSpec.SourceDecl->getCanonicalDecl()); } if (epi.ConsumedParameters) { for (unsigned i = 0; i != NumParams; ++i) @@ -1909,6 +1932,7 @@ bool AttributedType::isCallingConv() const { case attr_fastcall: case attr_stdcall: case attr_thiscall: + case attr_vectorcall: case attr_pascal: case attr_ms_abi: case attr_sysv_abi: @@ -1976,32 +2000,14 @@ anyDependentTemplateArguments(const TemplateArgumentLoc *Args, unsigned N, return false; } -#ifndef NDEBUG -static bool -anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N, - bool &InstantiationDependent) { - for (unsigned i = 0; i != N; ++i) { - if (Args[i].isDependent()) { - InstantiationDependent = true; - return true; - } - - if (Args[i].isInstantiationDependent()) - InstantiationDependent = true; - } - return false; -} -#endif - TemplateSpecializationType:: TemplateSpecializationType(TemplateName T, const TemplateArgument *Args, unsigned NumArgs, QualType Canon, QualType AliasedType) : Type(TemplateSpecialization, Canon.isNull()? QualType(this, 0) : Canon, - Canon.isNull()? T.isDependent() : Canon->isDependentType(), - Canon.isNull()? T.isDependent() - : Canon->isInstantiationDependentType(), + Canon.isNull()? true : Canon->isDependentType(), + Canon.isNull()? true : Canon->isInstantiationDependentType(), false, T.containsUnexpandedParameterPack()), Template(T), NumArgs(NumArgs), TypeAlias(!AliasedType.isNull()) { @@ -2011,18 +2017,11 @@ TemplateSpecializationType(TemplateName T, T.getKind() == TemplateName::SubstTemplateTemplateParm || T.getKind() == TemplateName::SubstTemplateTemplateParmPack) && "Unexpected template name for TemplateSpecializationType"); - bool InstantiationDependent; - (void)InstantiationDependent; - assert((!Canon.isNull() || - T.isDependent() || - ::anyDependentTemplateArguments(Args, NumArgs, - InstantiationDependent)) && - "No canonical type for non-dependent class template specialization"); TemplateArgument *TemplateArgs = reinterpret_cast<TemplateArgument *>(this + 1); for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { - // Update dependent and variably-modified bits. + // Update instantiation-dependent and variably-modified bits. // If the canonical type exists and is non-dependent, the template // specialization type can be non-dependent even if one of the type // arguments is. Given: @@ -2030,17 +2029,13 @@ TemplateSpecializationType(TemplateName T, // U<T> is always non-dependent, irrespective of the type T. // However, U<Ts> contains an unexpanded parameter pack, even though // its expansion (and thus its desugared type) doesn't. - if (Canon.isNull() && Args[Arg].isDependent()) - setDependent(); - else if (Args[Arg].isInstantiationDependent()) + if (Args[Arg].isInstantiationDependent()) setInstantiationDependent(); - if (Args[Arg].getKind() == TemplateArgument::Type && Args[Arg].getAsType()->isVariablyModifiedType()) setVariablyModified(); if (Args[Arg].containsUnexpandedParameterPack()) setContainsUnexpandedParameterPack(); - new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]); } diff --git a/lib/AST/TypeLoc.cpp b/lib/AST/TypeLoc.cpp index 208d695632a0..c069eb061739 100644 --- a/lib/AST/TypeLoc.cpp +++ b/lib/AST/TypeLoc.cpp @@ -312,6 +312,14 @@ TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { return TL; } +void TypeOfTypeLoc::initializeLocal(ASTContext &Context, + SourceLocation Loc) { + TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo> + ::initializeLocal(Context, Loc); + this->getLocalData()->UnderlyingTInfo = Context.getTrivialTypeSourceInfo( + getUnderlyingType(), Loc); +} + void ElaboratedTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setElaboratedKeywordLoc(Loc); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 061473eb848d..e36fc175c449 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -673,6 +673,9 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, case CC_X86ThisCall: OS << " __attribute__((thiscall))"; break; + case CC_X86VectorCall: + OS << " __attribute__((vectorcall))"; + break; case CC_X86Pascal: OS << " __attribute__((pascal))"; break; @@ -1235,6 +1238,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case AttributedType::attr_fastcall: OS << "fastcall"; break; case AttributedType::attr_stdcall: OS << "stdcall"; break; case AttributedType::attr_thiscall: OS << "thiscall"; break; + case AttributedType::attr_vectorcall: OS << "vectorcall"; break; case AttributedType::attr_pascal: OS << "pascal"; break; case AttributedType::attr_ms_abi: OS << "ms_abi"; break; case AttributedType::attr_sysv_abi: OS << "sysv_abi"; break; @@ -1428,18 +1432,6 @@ PrintTemplateArgumentList(raw_ostream &OS, OS << '>'; } -void QualType::dump(const char *msg) const { - if (msg) - llvm::errs() << msg << ": "; - LangOptions LO; - print(llvm::errs(), PrintingPolicy(LO), "identifier"); - llvm::errs() << '\n'; -} - -LLVM_DUMP_METHOD void QualType::dump() const { dump(nullptr); } - -LLVM_DUMP_METHOD void Type::dump() const { QualType(this, 0).dump(); } - std::string Qualifiers::getAsString() const { LangOptions LO; return getAsString(PrintingPolicy(LO)); @@ -1498,6 +1490,9 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, case LangAS::opencl_constant: OS << "__constant"; break; + case LangAS::opencl_generic: + OS << "__generic"; + break; default: OS << "__attribute__((address_space("; OS << addrspace; diff --git a/lib/AST/VTTBuilder.cpp b/lib/AST/VTTBuilder.cpp index c213d1cef6aa..53461ebbb812 100644 --- a/lib/AST/VTTBuilder.cpp +++ b/lib/AST/VTTBuilder.cpp @@ -105,7 +105,7 @@ VTTBuilder::LayoutSecondaryVirtualPointers(BaseSubobject Base, CharUnits BaseOffset; if (I.isVirtual()) { // Ignore virtual bases that we've already visited. - if (!VBases.insert(BaseDecl)) + if (!VBases.insert(BaseDecl).second) continue; BaseOffset = MostDerivedClassLayout.getVBaseClassOffset(BaseDecl); @@ -157,7 +157,7 @@ void VTTBuilder::LayoutVirtualVTTs(const CXXRecordDecl *RD, // Check if this is a virtual base. if (I.isVirtual()) { // Check if we've seen this base before. - if (!VBases.insert(BaseDecl)) + if (!VBases.insert(BaseDecl).second) continue; CharUnits BaseOffset = diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index fa1127f58f9b..ddb1f057ac8e 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -64,7 +64,7 @@ public: /// Method - The method decl of the overrider. const CXXMethodDecl *Method; - /// VirtualBase - The virtual base class subobject of this overridder. + /// VirtualBase - The virtual base class subobject of this overrider. /// Note that this records the closest derived virtual base class subobject. const CXXRecordDecl *VirtualBase; @@ -389,7 +389,7 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base, CharUnits BaseOffset; if (B.isVirtual()) { - if (!VisitedVirtualBases.insert(BaseDecl)) { + if (!VisitedVirtualBases.insert(BaseDecl).second) { // We've visited this base before. continue; } @@ -748,7 +748,7 @@ VCallAndVBaseOffsetBuilder::AddVBaseOffsets(const CXXRecordDecl *RD, const CXXRecordDecl *BaseDecl = B.getType()->getAsCXXRecordDecl(); // Check if this is a virtual base that we haven't visited before. - if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl)) { + if (B.isVirtual() && VisitedVirtualBases.insert(BaseDecl).second) { CharUnits Offset = LayoutClassLayout.getVBaseClassOffset(BaseDecl) - OffsetInLayoutClass; @@ -1105,7 +1105,7 @@ namespace { bool visit(const CXXMethodDecl *MD) { // Don't recurse on this method if we've already collected it. - return Methods->insert(MD); + return Methods->insert(MD).second; } }; } @@ -1842,7 +1842,7 @@ void ItaniumVTableBuilder::DeterminePrimaryVirtualBases( CharUnits BaseOffsetInLayoutClass; if (B.isVirtual()) { - if (!VBases.insert(BaseDecl)) + if (!VBases.insert(BaseDecl).second) continue; const ASTRecordLayout &LayoutClassLayout = @@ -1870,8 +1870,9 @@ void ItaniumVTableBuilder::LayoutVTablesForVirtualBases( // Check if this base needs a vtable. (If it's virtual, not a primary base // of some other class, and we haven't visited it before). - if (B.isVirtual() && BaseDecl->isDynamicClass() && - !PrimaryVirtualBases.count(BaseDecl) && VBases.insert(BaseDecl)) { + if (B.isVirtual() && BaseDecl->isDynamicClass() && + !PrimaryVirtualBases.count(BaseDecl) && + VBases.insert(BaseDecl).second) { const ASTRecordLayout &MostDerivedClassLayout = Context.getASTRecordLayout(MostDerivedClass); CharUnits BaseOffset = @@ -2390,6 +2391,7 @@ namespace { // first vfptr whose table provides a compatible overridden method. In many // cases, this permits the original vf-table entry to directly call // the method instead of passing through a thunk. +// See example before VFTableBuilder::ComputeThisOffset below. // // A compatible overridden method is one which does not have a non-trivial // covariant-return adjustment. @@ -2412,6 +2414,9 @@ namespace { // a) a user-defined ctor/dtor // and // b) a method overriding a method in a virtual base. +// +// To get a better understanding of this code, +// you might want to see examples in test/CodeGenCXX/microsoft-abi-vtables-*.cpp class VFTableBuilder { public: @@ -2464,11 +2469,18 @@ private: /// or used for vcalls in the most derived class. bool Shadowed; - MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex) + /// UsesExtraSlot - Indicates if this vftable slot was created because + /// any of the overridden slots required a return adjusting thunk. + bool UsesExtraSlot; + + MethodInfo(uint64_t VBTableIndex, uint64_t VFTableIndex, + bool UsesExtraSlot = false) : VBTableIndex(VBTableIndex), VFTableIndex(VFTableIndex), - Shadowed(false) {} + Shadowed(false), UsesExtraSlot(UsesExtraSlot) {} - MethodInfo() : VBTableIndex(0), VFTableIndex(0), Shadowed(false) {} + MethodInfo() + : VBTableIndex(0), VFTableIndex(0), Shadowed(false), + UsesExtraSlot(false) {} }; typedef llvm::DenseMap<const CXXMethodDecl *, MethodInfo> MethodInfoMapTy; @@ -2525,8 +2537,6 @@ private: } } - bool NeedsReturnAdjustingThunk(const CXXMethodDecl *MD); - /// AddMethods - Add the methods of this base subobject and the relevant /// subbases to the vftable we're currently laying out. void AddMethods(BaseSubobject Base, unsigned BaseDepth, @@ -2534,13 +2544,15 @@ private: BasesSetVectorTy &VisitedBases); void LayoutVFTable() { - // FIXME: add support for RTTI when we have proper LLVM support for symbols - // pointing to the middle of a section. + // RTTI data goes before all other entries. + if (HasRTTIComponent) + Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); BasesSetVectorTy VisitedBases; AddMethods(BaseSubobject(MostDerivedClass, CharUnits::Zero()), 0, nullptr, VisitedBases); - assert(Components.size() && "vftable can't be empty"); + assert((HasRTTIComponent ? Components.size() - 1 : Components.size()) && + "vftable can't be empty"); assert(MethodVFTableLocations.empty()); for (MethodInfoMapTy::const_iterator I = MethodInfoMap.begin(), @@ -2561,13 +2573,6 @@ private: } } - void ErrorUnsupported(StringRef Feature, SourceLocation Location) { - clang::DiagnosticsEngine &Diags = Context.getDiagnostics(); - unsigned DiagID = Diags.getCustomDiagID( - DiagnosticsEngine::Error, "v-table layout for %0 is not supported yet"); - Diags.Report(Context.getFullLoc(Location), DiagID) << Feature; - } - public: VFTableBuilder(MicrosoftVTableContext &VTables, const CXXRecordDecl *MostDerivedClass, const VPtrInfo *Which) @@ -2581,8 +2586,6 @@ public: // definition of the vftable. HasRTTIComponent = Context.getLangOpts().RTTIData && !MostDerivedClass->hasAttr<DLLImportAttr>(); - if (HasRTTIComponent) - Components.push_back(VTableComponent::MakeRTTI(MostDerivedClass)); LayoutVFTable(); @@ -2634,7 +2637,7 @@ struct InitialOverriddenDefinitionCollector { if (OverriddenMD->size_overridden_methods() == 0) Bases.insert(OverriddenMD->getParent()); // Don't recurse on this method if we've already collected it. - return VisitedOverriddenMethods.insert(OverriddenMD); + return VisitedOverriddenMethods.insert(OverriddenMD).second; } }; @@ -2644,6 +2647,60 @@ static bool BaseInSet(const CXXBaseSpecifier *Specifier, return Bases->count(Specifier->getType()->getAsCXXRecordDecl()); } +// Let's study one class hierarchy as an example: +// struct A { +// virtual void f(); +// int x; +// }; +// +// struct B : virtual A { +// virtual void f(); +// }; +// +// Record layouts: +// struct A: +// 0 | (A vftable pointer) +// 4 | int x +// +// struct B: +// 0 | (B vbtable pointer) +// 4 | struct A (virtual base) +// 4 | (A vftable pointer) +// 8 | int x +// +// Let's assume we have a pointer to the A part of an object of dynamic type B: +// B b; +// A *a = (A*)&b; +// a->f(); +// +// In this hierarchy, f() belongs to the vftable of A, so B::f() expects +// "this" parameter to point at the A subobject, which is B+4. +// In the B::f() prologue, it adjusts "this" back to B by subtracting 4, +// performed as a *static* adjustment. +// +// Interesting thing happens when we alter the relative placement of A and B +// subobjects in a class: +// struct C : virtual B { }; +// +// C c; +// A *a = (A*)&c; +// a->f(); +// +// Respective record layout is: +// 0 | (C vbtable pointer) +// 4 | struct A (virtual base) +// 4 | (A vftable pointer) +// 8 | int x +// 12 | struct B (virtual base) +// 12 | (B vbtable pointer) +// +// The final overrider of f() in class C is still B::f(), so B+4 should be +// passed as "this" to that code. However, "a" points at B-8, so the respective +// vftable entry should hold a thunk that adds 12 to the "this" argument before +// performing a tail call to B::f(). +// +// With this example in mind, we can now calculate the 'this' argument offset +// for the given method, relative to the beginning of the MostDerivedClass. CharUnits VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) { InitialOverriddenDefinitionCollector Collector; @@ -2723,6 +2780,104 @@ VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) { return Ret; } +// Things are getting even more complex when the "this" adjustment has to +// use a dynamic offset instead of a static one, or even two dynamic offsets. +// This is sometimes required when a virtual call happens in the middle of +// a non-most-derived class construction or destruction. +// +// Let's take a look at the following example: +// struct A { +// virtual void f(); +// }; +// +// void foo(A *a) { a->f(); } // Knows nothing about siblings of A. +// +// struct B : virtual A { +// virtual void f(); +// B() { +// foo(this); +// } +// }; +// +// struct C : virtual B { +// virtual void f(); +// }; +// +// Record layouts for these classes are: +// struct A +// 0 | (A vftable pointer) +// +// struct B +// 0 | (B vbtable pointer) +// 4 | (vtordisp for vbase A) +// 8 | struct A (virtual base) +// 8 | (A vftable pointer) +// +// struct C +// 0 | (C vbtable pointer) +// 4 | (vtordisp for vbase A) +// 8 | struct A (virtual base) // A precedes B! +// 8 | (A vftable pointer) +// 12 | struct B (virtual base) +// 12 | (B vbtable pointer) +// +// When one creates an object of type C, the C constructor: +// - initializes all the vbptrs, then +// - calls the A subobject constructor +// (initializes A's vfptr with an address of A vftable), then +// - calls the B subobject constructor +// (initializes A's vfptr with an address of B vftable and vtordisp for A), +// that in turn calls foo(), then +// - initializes A's vfptr with an address of C vftable and zeroes out the +// vtordisp +// FIXME: if a structor knows it belongs to MDC, why doesn't it use a vftable +// without vtordisp thunks? +// FIXME: how are vtordisp handled in the presence of nooverride/final? +// +// When foo() is called, an object with a layout of class C has a vftable +// referencing B::f() that assumes a B layout, so the "this" adjustments are +// incorrect, unless an extra adjustment is done. This adjustment is called +// "vtordisp adjustment". Vtordisp basically holds the difference between the +// actual location of a vbase in the layout class and the location assumed by +// the vftable of the class being constructed/destructed. Vtordisp is only +// needed if "this" escapes a +// structor (or we can't prove otherwise). +// [i.e. vtordisp is a dynamic adjustment for a static adjustment, which is an +// estimation of a dynamic adjustment] +// +// foo() gets a pointer to the A vbase and doesn't know anything about B or C, +// so it just passes that pointer as "this" in a virtual call. +// If there was no vtordisp, that would just dispatch to B::f(). +// However, B::f() assumes B+8 is passed as "this", +// yet the pointer foo() passes along is B-4 (i.e. C+8). +// An extra adjustment is needed, so we emit a thunk into the B vftable. +// This vtordisp thunk subtracts the value of vtordisp +// from the "this" argument (-12) before making a tailcall to B::f(). +// +// Let's consider an even more complex example: +// struct D : virtual B, virtual C { +// D() { +// foo(this); +// } +// }; +// +// struct D +// 0 | (D vbtable pointer) +// 4 | (vtordisp for vbase A) +// 8 | struct A (virtual base) // A precedes both B and C! +// 8 | (A vftable pointer) +// 12 | struct B (virtual base) // B precedes C! +// 12 | (B vbtable pointer) +// 16 | struct C (virtual base) +// 16 | (C vbtable pointer) +// +// When D::D() calls foo(), we find ourselves in a thunk that should tailcall +// to C::f(), which assumes C+8 as its "this" parameter. This time, foo() +// passes along A, which is C-8. The A vtordisp holds +// "D.vbptr[index_of_A] - offset_of_A_in_D" +// and we statically know offset_of_A_in_D, so can get a pointer to D. +// When we know it, we can make an extra vbtable lookup to locate the C vbase +// and one extra static adjustment to calculate the expected value of C+8. void VFTableBuilder::CalculateVtordispAdjustment( FinalOverriders::OverriderInfo Overrider, CharUnits ThisOffset, ThisAdjustment &TA) { @@ -2740,9 +2895,9 @@ void VFTableBuilder::CalculateVtordispAdjustment( // OK, now we know we need to use a vtordisp thunk. // The implicit vtordisp field is located right before the vbase. - CharUnits VFPtrVBaseOffset = VBaseMapEntry->second.VBaseOffset; + CharUnits OffsetOfVBaseWithVFPtr = VBaseMapEntry->second.VBaseOffset; TA.Virtual.Microsoft.VtordispOffset = - (VFPtrVBaseOffset - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4; + (OffsetOfVBaseWithVFPtr - WhichVFPtr.FullOffsetInMDC).getQuantity() - 4; // A simple vtordisp thunk will suffice if the final overrider is defined // in either the most derived class or its non-virtual base. @@ -2753,7 +2908,7 @@ void VFTableBuilder::CalculateVtordispAdjustment( // Otherwise, we need to do use the dynamic offset of the final overrider // in order to get "this" adjustment right. TA.Virtual.Microsoft.VBPtrOffset = - (VFPtrVBaseOffset + WhichVFPtr.NonVirtualOffset - + (OffsetOfVBaseWithVFPtr + WhichVFPtr.NonVirtualOffset - MostDerivedClassLayout.getVBPtrOffset()).getQuantity(); TA.Virtual.Microsoft.VBOffsetOffset = Context.getTypeSizeInChars(Context.IntTy).getQuantity() * @@ -2789,24 +2944,6 @@ static void GroupNewVirtualOverloads( VirtualMethods.append(Groups[I].rbegin(), Groups[I].rend()); } -/// We need a return adjusting thunk for this method if its return type is -/// not trivially convertible to the return type of any of its overridden -/// methods. -bool VFTableBuilder::NeedsReturnAdjustingThunk(const CXXMethodDecl *MD) { - OverriddenMethodsSetTy OverriddenMethods; - ComputeAllOverriddenMethods(MD, OverriddenMethods); - for (OverriddenMethodsSetTy::iterator I = OverriddenMethods.begin(), - E = OverriddenMethods.end(); - I != E; ++I) { - const CXXMethodDecl *OverriddenMD = *I; - BaseOffset Adjustment = - ComputeReturnAdjustmentBaseOffset(Context, MD, OverriddenMD); - if (!Adjustment.isEmpty()) - return true; - } - return false; -} - static bool isDirectVBase(const CXXRecordDecl *Base, const CXXRecordDecl *RD) { for (const auto &B : RD->bases()) { if (B.isVirtual() && B.getType()->getAsCXXRecordDecl() == Base) @@ -2866,20 +3003,21 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, for (unsigned I = 0, E = VirtualMethods.size(); I != E; ++I) { const CXXMethodDecl *MD = VirtualMethods[I]; - FinalOverriders::OverriderInfo Overrider = + FinalOverriders::OverriderInfo FinalOverrider = Overriders.getOverrider(MD, Base.getBaseOffset()); - const CXXMethodDecl *OverriderMD = Overrider.Method; + const CXXMethodDecl *FinalOverriderMD = FinalOverrider.Method; const CXXMethodDecl *OverriddenMD = FindNearestOverriddenMethod(MD, VisitedBases); ThisAdjustment ThisAdjustmentOffset; - bool ReturnAdjustingThunk = false; - CharUnits ThisOffset = ComputeThisOffset(Overrider); + bool ReturnAdjustingThunk = false, ForceReturnAdjustmentMangling = false; + CharUnits ThisOffset = ComputeThisOffset(FinalOverrider); ThisAdjustmentOffset.NonVirtual = (ThisOffset - WhichVFPtr.FullOffsetInMDC).getQuantity(); - if ((OverriddenMD || OverriderMD != MD) && + if ((OverriddenMD || FinalOverriderMD != MD) && WhichVFPtr.getVBaseWithVPtr()) - CalculateVtordispAdjustment(Overrider, ThisOffset, ThisAdjustmentOffset); + CalculateVtordispAdjustment(FinalOverrider, ThisOffset, + ThisAdjustmentOffset); if (OverriddenMD) { // If MD overrides anything in this vftable, we need to update the entries. @@ -2892,7 +3030,16 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, MethodInfo &OverriddenMethodInfo = OverriddenMDIterator->second; - if (!NeedsReturnAdjustingThunk(MD)) { + // Let's check if the overrider requires any return adjustments. + // We must create a new slot if the MD's return type is not trivially + // convertible to the OverriddenMD's one. + // Once a chain of method overrides adds a return adjusting vftable slot, + // all subsequent overrides will also use an extra method slot. + ReturnAdjustingThunk = !ComputeReturnAdjustmentBaseOffset( + Context, MD, OverriddenMD).isEmpty() || + OverriddenMethodInfo.UsesExtraSlot; + + if (!ReturnAdjustingThunk) { // No return adjustment needed - just replace the overridden method info // with the current info. MethodInfo MI(OverriddenMethodInfo.VBTableIndex, @@ -2911,8 +3058,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, // Force a special name mangling for a return-adjusting thunk // unless the method is the final overrider without this adjustment. - ReturnAdjustingThunk = - !(MD == OverriderMD && ThisAdjustmentOffset.isEmpty()); + ForceReturnAdjustmentMangling = + !(MD == FinalOverriderMD && ThisAdjustmentOffset.isEmpty()); } else if (Base.getBaseOffset() != WhichVFPtr.FullOffsetInMDC || MD->size_overridden_methods()) { // Skip methods that don't belong to the vftable of the current class, @@ -2926,7 +3073,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, unsigned VBIndex = LastVBase ? VTables.getVBTableIndex(MostDerivedClass, LastVBase) : 0; MethodInfo MI(VBIndex, - HasRTTIComponent ? Components.size() - 1 : Components.size()); + HasRTTIComponent ? Components.size() - 1 : Components.size(), + ReturnAdjustingThunk); assert(!MethodInfoMap.count(MD) && "Should not have method info for this method yet!"); @@ -2936,12 +3084,12 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, // We don't want to do this for pure virtual member functions. BaseOffset ReturnAdjustmentOffset; ReturnAdjustment ReturnAdjustment; - if (!OverriderMD->isPure()) { + if (!FinalOverriderMD->isPure()) { ReturnAdjustmentOffset = - ComputeReturnAdjustmentBaseOffset(Context, OverriderMD, MD); + ComputeReturnAdjustmentBaseOffset(Context, FinalOverriderMD, MD); } if (!ReturnAdjustmentOffset.isEmpty()) { - ReturnAdjustingThunk = true; + ForceReturnAdjustmentMangling = true; ReturnAdjustment.NonVirtual = ReturnAdjustmentOffset.NonVirtualOffset.getQuantity(); if (ReturnAdjustmentOffset.VirtualBase) { @@ -2955,8 +3103,9 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, } } - AddMethod(OverriderMD, ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment, - ReturnAdjustingThunk ? MD : nullptr)); + AddMethod(FinalOverriderMD, + ThunkInfo(ThisAdjustmentOffset, ReturnAdjustment, + ForceReturnAdjustmentMangling ? MD : nullptr)); } } @@ -3039,10 +3188,8 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) { if (MD->isPure()) Out << " [pure]"; - if (MD->isDeleted()) { - ErrorUnsupported("deleted methods", MD->getLocation()); + if (MD->isDeleted()) Out << " [deleted]"; - } ThunkInfo Thunk = VTableThunks.lookup(I); if (!Thunk.isEmpty()) @@ -3131,7 +3278,7 @@ void VFTableBuilder::dumpLayout(raw_ostream &Out) { } static bool setsIntersect(const llvm::SmallPtrSet<const CXXRecordDecl *, 4> &A, - const ArrayRef<const CXXRecordDecl *> &B) { + ArrayRef<const CXXRecordDecl *> B) { for (ArrayRef<const CXXRecordDecl *>::iterator I = B.begin(), E = B.end(); I != E; ++I) { if (A.count(*I)) @@ -3201,10 +3348,6 @@ void MicrosoftVTableContext::computeVTablePaths(bool ForVBTables, if (P->MangledPath.empty() || P->MangledPath.back() != Base) P->NextBaseToMangle = Base; - // Keep track of the full path. - // FIXME: Why do we need this? - P->PathToBaseWithVPtr.insert(P->PathToBaseWithVPtr.begin(), Base); - // Keep track of which vtable the derived class is going to extend with // new methods or bases. We append to either the vftable of our primary // base, or the first non-virtual base that has a vbtable. @@ -3292,6 +3435,58 @@ MicrosoftVTableContext::~MicrosoftVTableContext() { llvm::DeleteContainerSeconds(VBaseInfo); } +static bool +findPathForVPtr(ASTContext &Context, const ASTRecordLayout &MostDerivedLayout, + const CXXRecordDecl *RD, CharUnits Offset, + llvm::SmallPtrSetImpl<const CXXRecordDecl *> &VBasesSeen, + VPtrInfo::BasePath &FullPath, VPtrInfo *Info) { + if (RD == Info->BaseWithVPtr && Offset == Info->FullOffsetInMDC) { + Info->PathToBaseWithVPtr = FullPath; + return true; + } + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + // Recurse with non-virtual bases first. + // FIXME: Does this need to be in layout order? Virtual bases will be in base + // specifier order, which isn't necessarily layout order. + SmallVector<CXXBaseSpecifier, 4> Bases(RD->bases_begin(), RD->bases_end()); + std::stable_partition(Bases.begin(), Bases.end(), + [](CXXBaseSpecifier bs) { return !bs.isVirtual(); }); + + for (const auto &B : Bases) { + const CXXRecordDecl *Base = B.getType()->getAsCXXRecordDecl(); + CharUnits NewOffset; + if (!B.isVirtual()) + NewOffset = Offset + Layout.getBaseClassOffset(Base); + else { + if (!VBasesSeen.insert(Base).second) + return false; + NewOffset = MostDerivedLayout.getVBaseClassOffset(Base); + } + FullPath.push_back(Base); + if (findPathForVPtr(Context, MostDerivedLayout, Base, NewOffset, VBasesSeen, + FullPath, Info)) + return true; + FullPath.pop_back(); + } + return false; +} + +static void computeFullPathsForVFTables(ASTContext &Context, + const CXXRecordDecl *RD, + VPtrInfoVector &Paths) { + llvm::SmallPtrSet<const CXXRecordDecl*, 4> VBasesSeen; + const ASTRecordLayout &MostDerivedLayout = Context.getASTRecordLayout(RD); + VPtrInfo::BasePath FullPath; + for (VPtrInfo *Info : Paths) { + findPathForVPtr(Context, MostDerivedLayout, RD, CharUnits::Zero(), + VBasesSeen, FullPath, Info); + VBasesSeen.clear(); + FullPath.clear(); + } +} + void MicrosoftVTableContext::computeVTableRelatedInformation( const CXXRecordDecl *RD) { assert(RD->isDynamicClass()); @@ -3304,6 +3499,7 @@ void MicrosoftVTableContext::computeVTableRelatedInformation( VPtrInfoVector *VFPtrs = new VPtrInfoVector(); computeVTablePaths(/*ForVBTables=*/false, RD, *VFPtrs); + computeFullPathsForVFTables(Context, RD, *VFPtrs); VFPtrLocations[RD] = VFPtrs; MethodVFTableLocationsTy NewMethodLocations; diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp index 23708e2ff0c7..fa7968a805c4 100644 --- a/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/lib/ASTMatchers/ASTMatchFinder.cpp @@ -20,7 +20,11 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Timer.h" #include <deque> +#include <memory> #include <set> namespace clang { @@ -53,7 +57,7 @@ static const unsigned MaxMemoizationEntries = 10000; // FIXME: Benchmark whether memoization of non-pointer typed nodes // provides enough benefit for the additional amount of code. struct MatchKey { - uint64_t MatcherID; + DynTypedMatcher::MatcherIDType MatcherID; ast_type_traits::DynTypedNode Node; BoundNodesTreeBuilder BoundNodes; @@ -292,28 +296,33 @@ private: class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>, public ASTMatchFinder { public: - MatchASTVisitor( - std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > * - MatcherCallbackPairs) - : MatcherCallbackPairs(MatcherCallbackPairs), ActiveASTContext(nullptr) {} + MatchASTVisitor(const MatchFinder::MatchersByType *Matchers, + const MatchFinder::MatchFinderOptions &Options) + : Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {} + + ~MatchASTVisitor() { + if (Options.CheckProfiling) { + Options.CheckProfiling->Records = std::move(TimeByBucket); + } + } void onStartOfTranslationUnit() { - for (std::vector<std::pair<internal::DynTypedMatcher, - MatchCallback *> >::const_iterator - I = MatcherCallbackPairs->begin(), - E = MatcherCallbackPairs->end(); - I != E; ++I) { - I->second->onStartOfTranslationUnit(); + const bool EnableCheckProfiling = Options.CheckProfiling.hasValue(); + TimeBucketRegion Timer; + for (MatchCallback *MC : Matchers->AllCallbacks) { + if (EnableCheckProfiling) + Timer.setBucket(&TimeByBucket[MC->getID()]); + MC->onStartOfTranslationUnit(); } } void onEndOfTranslationUnit() { - for (std::vector<std::pair<internal::DynTypedMatcher, - MatchCallback *> >::const_iterator - I = MatcherCallbackPairs->begin(), - E = MatcherCallbackPairs->end(); - I != E; ++I) { - I->second->onEndOfTranslationUnit(); + const bool EnableCheckProfiling = Options.CheckProfiling.hasValue(); + TimeBucketRegion Timer; + for (MatchCallback *MC : Matchers->AllCallbacks) { + if (EnableCheckProfiling) + Timer.setBucket(&TimeByBucket[MC->getID()]); + MC->onEndOfTranslationUnit(); } } @@ -372,7 +381,7 @@ public: BoundNodesTreeBuilder *Builder, int MaxDepth, TraversalKind Traversal, BindKind Bind) { // For AST-nodes that don't have an identity, we can't memoize. - if (!Node.getMemoizationData()) + if (!Node.getMemoizationData() || !Builder->isComparable()) return matchesRecursively(Node, Matcher, Builder, MaxDepth, Traversal, Bind); @@ -392,9 +401,12 @@ public: Result.Nodes = *Builder; Result.ResultOfMatch = matchesRecursively(Node, Matcher, &Result.Nodes, MaxDepth, Traversal, Bind); - ResultCache[Key] = Result; - *Builder = Result.Nodes; - return Result.ResultOfMatch; + + MemoizedMatchResult &CachedResult = ResultCache[Key]; + CachedResult = std::move(Result); + + *Builder = CachedResult.Nodes; + return CachedResult.ResultOfMatch; } // Matches children or descendants of 'Node' with 'BaseMatcher'. @@ -447,22 +459,27 @@ public: // Matches all registered matchers on the given node and calls the // result callback for every node that matches. - void match(const ast_type_traits::DynTypedNode& Node) { - for (std::vector<std::pair<internal::DynTypedMatcher, - MatchCallback *> >::const_iterator - I = MatcherCallbackPairs->begin(), - E = MatcherCallbackPairs->end(); - I != E; ++I) { - BoundNodesTreeBuilder Builder; - if (I->first.matches(Node, this, &Builder)) { - MatchVisitor Visitor(ActiveASTContext, I->second); - Builder.visitMatches(&Visitor); - } + void match(const ast_type_traits::DynTypedNode &Node) { + // FIXME: Improve this with a switch or a visitor pattern. + if (auto *N = Node.get<Decl>()) { + match(*N); + } else if (auto *N = Node.get<Stmt>()) { + match(*N); + } else if (auto *N = Node.get<Type>()) { + match(*N); + } else if (auto *N = Node.get<QualType>()) { + match(*N); + } else if (auto *N = Node.get<NestedNameSpecifier>()) { + match(*N); + } else if (auto *N = Node.get<NestedNameSpecifierLoc>()) { + match(*N); + } else if (auto *N = Node.get<TypeLoc>()) { + match(*N); } } template <typename T> void match(const T &Node) { - match(ast_type_traits::DynTypedNode::create(Node)); + matchDispatch(&Node); } // Implements ASTMatchFinder::getASTContext. @@ -475,6 +492,116 @@ public: bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; } private: + class TimeBucketRegion { + public: + TimeBucketRegion() : Bucket(nullptr) {} + ~TimeBucketRegion() { setBucket(nullptr); } + + /// \brief Start timing for \p NewBucket. + /// + /// If there was a bucket already set, it will finish the timing for that + /// other bucket. + /// \p NewBucket will be timed until the next call to \c setBucket() or + /// until the \c TimeBucketRegion is destroyed. + /// If \p NewBucket is the same as the currently timed bucket, this call + /// does nothing. + void setBucket(llvm::TimeRecord *NewBucket) { + if (Bucket != NewBucket) { + auto Now = llvm::TimeRecord::getCurrentTime(true); + if (Bucket) + *Bucket += Now; + if (NewBucket) + *NewBucket -= Now; + Bucket = NewBucket; + } + } + + private: + llvm::TimeRecord *Bucket; + }; + + /// \brief Runs all the \p Matchers on \p Node. + /// + /// Used by \c matchDispatch() below. + template <typename T, typename MC> + void matchWithoutFilter(const T &Node, const MC &Matchers) { + const bool EnableCheckProfiling = Options.CheckProfiling.hasValue(); + TimeBucketRegion Timer; + for (const auto &MP : Matchers) { + if (EnableCheckProfiling) + Timer.setBucket(&TimeByBucket[MP.second->getID()]); + BoundNodesTreeBuilder Builder; + if (MP.first.matches(Node, this, &Builder)) { + MatchVisitor Visitor(ActiveASTContext, MP.second); + Builder.visitMatches(&Visitor); + } + } + } + + void matchWithFilter(const ast_type_traits::DynTypedNode &DynNode) { + auto Kind = DynNode.getNodeKind(); + auto it = MatcherFiltersMap.find(Kind); + const auto &Filter = + it != MatcherFiltersMap.end() ? it->second : getFilterForKind(Kind); + + if (Filter.empty()) + return; + + const bool EnableCheckProfiling = Options.CheckProfiling.hasValue(); + TimeBucketRegion Timer; + auto &Matchers = this->Matchers->DeclOrStmt; + for (unsigned short I : Filter) { + auto &MP = Matchers[I]; + if (EnableCheckProfiling) + Timer.setBucket(&TimeByBucket[MP.second->getID()]); + BoundNodesTreeBuilder Builder; + if (MP.first.matchesNoKindCheck(DynNode, this, &Builder)) { + MatchVisitor Visitor(ActiveASTContext, MP.second); + Builder.visitMatches(&Visitor); + } + } + } + + const std::vector<unsigned short> & + getFilterForKind(ast_type_traits::ASTNodeKind Kind) { + auto &Filter = MatcherFiltersMap[Kind]; + auto &Matchers = this->Matchers->DeclOrStmt; + assert((Matchers.size() < USHRT_MAX) && "Too many matchers."); + for (unsigned I = 0, E = Matchers.size(); I != E; ++I) { + if (Matchers[I].first.canMatchNodesOfKind(Kind)) { + Filter.push_back(I); + } + } + return Filter; + } + + /// @{ + /// \brief Overloads to pair the different node types to their matchers. + void matchDispatch(const Decl *Node) { + return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node)); + } + void matchDispatch(const Stmt *Node) { + return matchWithFilter(ast_type_traits::DynTypedNode::create(*Node)); + } + + void matchDispatch(const Type *Node) { + matchWithoutFilter(QualType(Node, 0), Matchers->Type); + } + void matchDispatch(const TypeLoc *Node) { + matchWithoutFilter(*Node, Matchers->TypeLoc); + } + void matchDispatch(const QualType *Node) { + matchWithoutFilter(*Node, Matchers->Type); + } + void matchDispatch(const NestedNameSpecifier *Node) { + matchWithoutFilter(*Node, Matchers->NestedNameSpecifier); + } + void matchDispatch(const NestedNameSpecifierLoc *Node) { + matchWithoutFilter(*Node, Matchers->NestedNameSpecifierLoc); + } + void matchDispatch(const void *) { /* Do nothing. */ } + /// @} + // Returns whether an ancestor of \p Node matches \p Matcher. // // The order of matching ((which can lead to different nodes being bound in @@ -497,11 +624,7 @@ private: assert(Node.getMemoizationData() && "Invariant broken: only nodes that support memoization may be " "used in the parent map."); - ASTContext::ParentVector Parents = ActiveASTContext->getParents(Node); - if (Parents.empty()) { - assert(false && "Found node that is not in the parent map."); - return false; - } + MatchKey Key; Key.MatcherID = Matcher.getID(); Key.Node = Node; @@ -514,9 +637,13 @@ private: *Builder = I->second.Nodes; return I->second.ResultOfMatch; } + MemoizedMatchResult Result; Result.ResultOfMatch = false; Result.Nodes = *Builder; + + const auto &Parents = ActiveASTContext->getParents(Node); + assert(!Parents.empty() && "Found node that is not in the parent map."); if (Parents.size() == 1) { // Only one parent - do recursive memoization. const ast_type_traits::DynTypedNode Parent = Parents[0]; @@ -543,25 +670,24 @@ private: break; } if (MatchMode != ASTMatchFinder::AMM_ParentOnly) { - ASTContext::ParentVector Ancestors = - ActiveASTContext->getParents(Queue.front()); - for (ASTContext::ParentVector::const_iterator I = Ancestors.begin(), - E = Ancestors.end(); - I != E; ++I) { + for (const auto &Parent : + ActiveASTContext->getParents(Queue.front())) { // Make sure we do not visit the same node twice. // Otherwise, we'll visit the common ancestors as often as there // are splits on the way down. - if (Visited.insert(I->getMemoizationData()).second) - Queue.push_back(*I); + if (Visited.insert(Parent.getMemoizationData()).second) + Queue.push_back(Parent); } } Queue.pop_front(); } } - ResultCache[Key] = Result; - *Builder = Result.Nodes; - return Result.ResultOfMatch; + MemoizedMatchResult &CachedResult = ResultCache[Key]; + CachedResult = std::move(Result); + + *Builder = CachedResult.Nodes; + return CachedResult.ResultOfMatch; } // Implements a BoundNodesTree::Visitor that calls a MatchCallback with @@ -588,22 +714,35 @@ private: BoundNodesTreeBuilder *Builder) { const Type *const CanonicalType = ActiveASTContext->getCanonicalType(TypeNode); - const std::set<const TypedefNameDecl *> &Aliases = - TypeAliases[CanonicalType]; - for (std::set<const TypedefNameDecl*>::const_iterator - It = Aliases.begin(), End = Aliases.end(); - It != End; ++It) { + for (const TypedefNameDecl *Alias : TypeAliases.lookup(CanonicalType)) { BoundNodesTreeBuilder Result(*Builder); - if (Matcher.matches(**It, this, &Result)) { - *Builder = Result; + if (Matcher.matches(*Alias, this, &Result)) { + *Builder = std::move(Result); return true; } } return false; } - std::vector<std::pair<internal::DynTypedMatcher, MatchCallback *> > *const - MatcherCallbackPairs; + /// \brief Bucket to record map. + /// + /// Used to get the appropriate bucket for each matcher. + llvm::StringMap<llvm::TimeRecord> TimeByBucket; + + const MatchFinder::MatchersByType *Matchers; + + /// \brief Filtered list of matcher indices for each matcher kind. + /// + /// \c Decl and \c Stmt toplevel matchers usually apply to a specific node + /// kind (and derived kinds) so it is a waste to try every matcher on every + /// node. + /// We precalculate a list of matchers that pass the toplevel restrict check. + /// This also allows us to skip the restrict check at matching time. See + /// use \c matchesNoKindCheck() above. + llvm::DenseMap<ast_type_traits::ASTNodeKind, std::vector<unsigned short>> + MatcherFiltersMap; + + const MatchFinder::MatchFinderOptions &Options; ASTContext *ActiveASTContext; // Maps a canonical type to its TypedefDecls. @@ -680,7 +819,7 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration, } BoundNodesTreeBuilder Result(*Builder); if (Base.matches(*ClassDecl, this, &Result)) { - *Builder = Result; + *Builder = std::move(Result); return true; } if (classIsDerivedFrom(ClassDecl, Base, Builder)) @@ -731,7 +870,8 @@ bool MatchASTVisitor::TraverseNestedNameSpecifierLoc( 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()); + if (NNS.hasQualifier()) + match(*NNS.getNestedNameSpecifier()); return RecursiveASTVisitor<MatchASTVisitor>::TraverseNestedNameSpecifierLoc(NNS); } @@ -765,38 +905,45 @@ MatchFinder::MatchResult::MatchResult(const BoundNodes &Nodes, MatchFinder::MatchCallback::~MatchCallback() {} MatchFinder::ParsingDoneTestCallback::~ParsingDoneTestCallback() {} -MatchFinder::MatchFinder() : ParsingDone(nullptr) {} +MatchFinder::MatchFinder(MatchFinderOptions Options) + : Options(std::move(Options)), ParsingDone(nullptr) {} MatchFinder::~MatchFinder() {} void MatchFinder::addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.DeclOrStmt.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } void MatchFinder::addMatcher(const TypeMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.Type.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } void MatchFinder::addMatcher(const StatementMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.DeclOrStmt.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } void MatchFinder::addMatcher(const NestedNameSpecifierMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.NestedNameSpecifier.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } void MatchFinder::addMatcher(const NestedNameSpecifierLocMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.NestedNameSpecifierLoc.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch, MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch, Action)); + Matchers.TypeLoc.push_back(std::make_pair(NodeMatch, Action)); + Matchers.AllCallbacks.push_back(Action); } bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, @@ -823,19 +970,19 @@ bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, return false; } -ASTConsumer *MatchFinder::newASTConsumer() { - return new internal::MatchASTConsumer(this, ParsingDone); +std::unique_ptr<ASTConsumer> MatchFinder::newASTConsumer() { + return llvm::make_unique<internal::MatchASTConsumer>(this, ParsingDone); } void MatchFinder::match(const clang::ast_type_traits::DynTypedNode &Node, ASTContext &Context) { - internal::MatchASTVisitor Visitor(&MatcherCallbackPairs); + internal::MatchASTVisitor Visitor(&Matchers, Options); Visitor.set_active_ast_context(&Context); Visitor.match(Node); } void MatchFinder::matchAST(ASTContext &Context) { - internal::MatchASTVisitor Visitor(&MatcherCallbackPairs); + internal::MatchASTVisitor Visitor(&Matchers, Options); Visitor.set_active_ast_context(&Context); Visitor.onStartOfTranslationUnit(); Visitor.TraverseDecl(Context.getTranslationUnitDecl()); @@ -847,5 +994,7 @@ void MatchFinder::registerTestCallbackAfterParsing( ParsingDone = NewParsingDone; } +StringRef MatchFinder::MatchCallback::getID() const { return "<unknown>"; } + } // end namespace ast_matchers } // end namespace clang diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp index 47b8b6d2f27a..2c482e38dc08 100644 --- a/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -13,25 +13,219 @@ #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/ManagedStatic.h" namespace clang { namespace ast_matchers { namespace internal { +bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + +bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + +bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + +bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + + void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { if (Bindings.empty()) Bindings.push_back(BoundNodesMap()); - for (unsigned i = 0, e = Bindings.size(); i != e; ++i) { - ResultVisitor->visitMatch(BoundNodes(Bindings[i])); + for (BoundNodesMap &Binding : Bindings) { + ResultVisitor->visitMatch(BoundNodes(Binding)); } } -DynTypedMatcher::MatcherStorage::~MatcherStorage() {} +namespace { -void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { - for (unsigned i = 0, e = Other.Bindings.size(); i != e; ++i) { - Bindings.push_back(Other.Bindings[i]); +typedef bool (*VariadicOperatorFunction)( + const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); + +template <VariadicOperatorFunction Func> +class VariadicMatcher : public DynMatcherInterface { +public: + VariadicMatcher(std::vector<DynTypedMatcher> InnerMatchers) + : InnerMatchers(std::move(InnerMatchers)) {} + + bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + return Func(DynNode, Finder, Builder, InnerMatchers); + } + +private: + std::vector<DynTypedMatcher> InnerMatchers; +}; + +class IdDynMatcher : public DynMatcherInterface { + public: + IdDynMatcher(StringRef ID, + const IntrusiveRefCntPtr<DynMatcherInterface> &InnerMatcher) + : ID(ID), InnerMatcher(InnerMatcher) {} + + bool dynMatches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const override { + bool Result = InnerMatcher->dynMatches(DynNode, Finder, Builder); + if (Result) Builder->setBinding(ID, DynNode); + return Result; + } + + private: + const std::string ID; + const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher; +}; + +/// \brief A matcher that always returns true. +/// +/// We only ever need one instance of this matcher, so we create a global one +/// and reuse it to reduce the overhead of the matcher and increase the chance +/// of cache hits. +class TrueMatcherImpl : public DynMatcherInterface { +public: + TrueMatcherImpl() { + Retain(); // Reference count will never become zero. + } + bool dynMatches(const ast_type_traits::DynTypedNode &, ASTMatchFinder *, + BoundNodesTreeBuilder *) const override { + return true; + } +}; +static llvm::ManagedStatic<TrueMatcherImpl> TrueMatcherInstance; + +} // namespace + +DynTypedMatcher DynTypedMatcher::constructVariadic( + DynTypedMatcher::VariadicOperator Op, + std::vector<DynTypedMatcher> InnerMatchers) { + assert(InnerMatchers.size() > 0 && "Array must not be empty."); + assert(std::all_of(InnerMatchers.begin(), InnerMatchers.end(), + [&InnerMatchers](const DynTypedMatcher &M) { + return InnerMatchers[0].SupportedKind.isSame(M.SupportedKind); + }) && + "SupportedKind must match!"); + + auto SupportedKind = InnerMatchers[0].SupportedKind; + // We must relax the restrict kind here. + // The different operators might deal differently with a mismatch. + // Make it the same as SupportedKind, since that is the broadest type we are + // allowed to accept. + auto RestrictKind = SupportedKind; + + switch (Op) { + case VO_AllOf: + // In the case of allOf() we must pass all the checks, so making + // RestrictKind the most restrictive can save us time. This way we reject + // invalid types earlier and we can elide the kind checks inside the + // matcher. + for (auto &IM : InnerMatchers) { + RestrictKind = ast_type_traits::ASTNodeKind::getMostDerivedType( + RestrictKind, IM.RestrictKind); + } + return DynTypedMatcher( + SupportedKind, RestrictKind, + new VariadicMatcher<AllOfVariadicOperator>(std::move(InnerMatchers))); + + case VO_AnyOf: + return DynTypedMatcher( + SupportedKind, RestrictKind, + new VariadicMatcher<AnyOfVariadicOperator>(std::move(InnerMatchers))); + + case VO_EachOf: + return DynTypedMatcher( + SupportedKind, RestrictKind, + new VariadicMatcher<EachOfVariadicOperator>(std::move(InnerMatchers))); + + case VO_UnaryNot: + // FIXME: Implement the Not operator to take a single matcher instead of a + // vector. + return DynTypedMatcher( + SupportedKind, RestrictKind, + new VariadicMatcher<NotUnaryOperator>(std::move(InnerMatchers))); } + llvm_unreachable("Invalid Op value."); +} + +DynTypedMatcher DynTypedMatcher::trueMatcher( + ast_type_traits::ASTNodeKind NodeKind) { + return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance); +} + +bool DynTypedMatcher::canMatchNodesOfKind( + ast_type_traits::ASTNodeKind Kind) const { + return RestrictKind.isBaseOf(Kind); +} + +DynTypedMatcher DynTypedMatcher::dynCastTo( + const ast_type_traits::ASTNodeKind Kind) const { + auto Copy = *this; + Copy.SupportedKind = Kind; + Copy.RestrictKind = + ast_type_traits::ASTNodeKind::getMostDerivedType(Kind, RestrictKind); + return Copy; +} + +bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + if (RestrictKind.isBaseOf(DynNode.getNodeKind()) && + Implementation->dynMatches(DynNode, Finder, Builder)) { + return true; + } + // Delete all bindings when a matcher does not match. + // This prevents unexpected exposure of bound nodes in unmatches + // branches of the match tree. + Builder->removeBindings([](const BoundNodesMap &) { return true; }); + return false; +} + +bool DynTypedMatcher::matchesNoKindCheck( + const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + assert(RestrictKind.isBaseOf(DynNode.getNodeKind())); + if (Implementation->dynMatches(DynNode, Finder, Builder)) { + return true; + } + // Delete all bindings when a matcher does not match. + // This prevents unexpected exposure of bound nodes in unmatches + // branches of the match tree. + Builder->removeBindings([](const BoundNodesMap &) { return true; }); + return false; +} + +llvm::Optional<DynTypedMatcher> DynTypedMatcher::tryBind(StringRef ID) const { + if (!AllowBind) return llvm::None; + auto Result = *this; + Result.Implementation = new IdDynMatcher(ID, Result.Implementation); + return Result; +} + +bool DynTypedMatcher::canConvertTo(ast_type_traits::ASTNodeKind To) const { + const auto From = getSupportedKind(); + auto QualKind = ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>(); + auto TypeKind = ast_type_traits::ASTNodeKind::getFromNodeKind<Type>(); + /// Mimic the implicit conversions of Matcher<>. + /// - From Matcher<Type> to Matcher<QualType> + if (From.isSame(TypeKind) && To.isSame(QualKind)) return true; + /// - From Matcher<Base> to Matcher<Derived> + return From.isBaseOf(To); +} + +void BoundNodesTreeBuilder::addMatch(const BoundNodesTreeBuilder &Other) { + Bindings.append(Other.Bindings.begin(), Other.Bindings.end()); } bool NotUnaryOperator(const ast_type_traits::DynTypedNode DynNode, @@ -61,8 +255,8 @@ bool AllOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, // allOf leads to one matcher for each alternative in the first // matcher combined with each alternative in the second matcher. // Thus, we can reuse the same Builder. - for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { - if (!InnerMatchers[i].matches(DynNode, Finder, Builder)) + for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { + if (!InnerMatcher.matchesNoKindCheck(DynNode, Finder, Builder)) return false; } return true; @@ -74,14 +268,14 @@ bool EachOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, ArrayRef<DynTypedMatcher> InnerMatchers) { BoundNodesTreeBuilder Result; bool Matched = false; - for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { + for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { BoundNodesTreeBuilder BuilderInner(*Builder); - if (InnerMatchers[i].matches(DynNode, Finder, &BuilderInner)) { + if (InnerMatcher.matches(DynNode, Finder, &BuilderInner)) { Matched = true; Result.addMatch(BuilderInner); } } - *Builder = Result; + *Builder = std::move(Result); return Matched; } @@ -89,16 +283,62 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers) { - for (size_t i = 0, e = InnerMatchers.size(); i != e; ++i) { + for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { BoundNodesTreeBuilder Result = *Builder; - if (InnerMatchers[i].matches(DynNode, Finder, &Result)) { - *Builder = Result; + if (InnerMatcher.matches(DynNode, Finder, &Result)) { + *Builder = std::move(Result); return true; } } return false; } +HasNameMatcher::HasNameMatcher(StringRef NameRef) + : UseUnqualifiedMatch(NameRef.find("::") == NameRef.npos), Name(NameRef) { + assert(!Name.empty()); +} + +bool HasNameMatcher::matchesNodeUnqualified(const NamedDecl &Node) const { + assert(UseUnqualifiedMatch); + if (Node.getIdentifier()) { + // Simple name. + return Name == Node.getName(); + } + if (Node.getDeclName()) { + // Name needs to be constructed. + llvm::SmallString<128> NodeName; + llvm::raw_svector_ostream OS(NodeName); + Node.printName(OS); + return Name == OS.str(); + } + return false; +} + +bool HasNameMatcher::matchesNodeFull(const NamedDecl &Node) const { + llvm::SmallString<128> NodeName = StringRef("::"); + llvm::raw_svector_ostream OS(NodeName); + Node.printQualifiedName(OS); + const StringRef FullName = OS.str(); + const StringRef Pattern = Name; + + if (Pattern.startswith("::")) + return FullName == Pattern; + + return FullName.endswith(Pattern) && + FullName.drop_back(Pattern.size()).endswith("::"); +} + +bool HasNameMatcher::matchesNode(const NamedDecl &Node) const { + // FIXME: There is still room for improvement, but it would require copying a + // lot of the logic from NamedDecl::printQualifiedName(). The benchmarks do + // not show like that extra complexity is needed right now. + if (UseUnqualifiedMatch) { + assert(matchesNodeUnqualified(Node) == matchesNodeFull(Node)); + return matchesNodeUnqualified(Node); + } + return matchesNodeFull(Node); +} + } // end namespace internal } // end namespace ast_matchers } // end namespace clang diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h index 6e144cd26ed9..b78bc0381990 100644 --- a/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/lib/ASTMatchers/Dynamic/Marshallers.h @@ -17,8 +17,8 @@ /// //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H -#define LLVM_CLANG_AST_MATCHERS_DYNAMIC_MARSHALLERS_H +#ifndef LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H +#define LLVM_CLANG_LIB_ASTMATCHERS_DYNAMIC_MARSHALLERS_H #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/Dynamic/Diagnostics.h" @@ -30,48 +30,8 @@ namespace clang { namespace ast_matchers { namespace dynamic { - namespace internal { -struct ArgKind { - enum Kind { - AK_Matcher, - AK_Unsigned, - AK_String - }; - ArgKind(Kind K) - : K(K) {} - ArgKind(ast_type_traits::ASTNodeKind MatcherKind) - : K(AK_Matcher), MatcherKind(MatcherKind) {} - - std::string asString() const { - switch (getArgKind()) { - case AK_Matcher: - return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str(); - case AK_Unsigned: - return "unsigned"; - case AK_String: - return "string"; - } - llvm_unreachable("unhandled ArgKind"); - } - - Kind getArgKind() const { return K; } - ast_type_traits::ASTNodeKind getMatcherKind() const { - assert(K == AK_Matcher); - return MatcherKind; - } - - bool operator<(const ArgKind &Other) const { - if (K == AK_Matcher && Other.K == AK_Matcher) - return MatcherKind < Other.MatcherKind; - return K < Other.K; - } - -private: - Kind K; - ast_type_traits::ASTNodeKind MatcherKind; -}; /// \brief Helper template class to just from argument type to the right is/get /// functions in VariantValue. @@ -116,6 +76,27 @@ template <> struct ArgTypeTraits<unsigned> { } }; +template <> struct ArgTypeTraits<attr::Kind> { +private: + static attr::Kind getAttrKind(llvm::StringRef AttrKind) { + return llvm::StringSwitch<attr::Kind>(AttrKind) +#define ATTR(X) .Case("attr::" #X, attr:: X) +#include "clang/Basic/AttrList.inc" + .Default(attr::Kind(-1)); + } +public: + static bool is(const VariantValue &Value) { + return Value.isString() && + getAttrKind(Value.getString()) != attr::Kind(-1); + } + static attr::Kind get(const VariantValue &Value) { + return getAttrKind(Value.getString()); + } + static ArgKind getKind() { + return ArgKind(ArgKind::AK_String); + } +}; + /// \brief Matcher descriptor interface. /// /// Provides a \c create() method that constructs the matcher from the provided @@ -161,16 +142,10 @@ inline bool isRetKindConvertibleTo( ArrayRef<ast_type_traits::ASTNodeKind> RetKinds, ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, ast_type_traits::ASTNodeKind *LeastDerivedKind) { - for (ArrayRef<ast_type_traits::ASTNodeKind>::const_iterator - i = RetKinds.begin(), - e = RetKinds.end(); - i != e; ++i) { - unsigned Distance; - if (i->isBaseOf(Kind, &Distance)) { - if (Specificity) - *Specificity = 100 - Distance; + for (const ast_type_traits::ASTNodeKind &NodeKind : RetKinds) { + if (ArgKind(NodeKind).isConvertibleTo(Kind, Specificity)) { if (LeastDerivedKind) - *LeastDerivedKind = *i; + *LeastDerivedKind = NodeKind; return true; } } @@ -322,8 +297,8 @@ variadicMatcherDescriptor(StringRef MatcherName, const SourceRange &NameRange, VariantMatcher Out; if (!HasError) { - Out = outvalueToVariantMatcher( - Func(ArrayRef<const ArgT *>(InnerArgs, Args.size()))); + Out = outvalueToVariantMatcher(Func(llvm::makeArrayRef(InnerArgs, + Args.size()))); } for (size_t i = 0, e = Args.size(); i != e; ++i) { @@ -498,7 +473,7 @@ private: template <typename FromTypeList> inline void collect(FromTypeList); - const StringRef Name; + StringRef Name; std::vector<MatcherDescriptor *> &Out; }; @@ -581,15 +556,15 @@ private: /// \brief Variadic operator marshaller function. class VariadicOperatorMatcherDescriptor : public MatcherDescriptor { public: - typedef ast_matchers::internal::VariadicOperatorFunction VarFunc; + typedef DynTypedMatcher::VariadicOperator VarOp; VariadicOperatorMatcherDescriptor(unsigned MinCount, unsigned MaxCount, - VarFunc Func, StringRef MatcherName) - : MinCount(MinCount), MaxCount(MaxCount), Func(Func), + VarOp Op, StringRef MatcherName) + : MinCount(MinCount), MaxCount(MaxCount), Op(Op), MatcherName(MatcherName) {} virtual VariantMatcher create(const SourceRange &NameRange, ArrayRef<ParserValue> Args, - Diagnostics *Error) const { + Diagnostics *Error) const override { if (Args.size() < MinCount || MaxCount < Args.size()) { const std::string MaxStr = (MaxCount == UINT_MAX ? "" : Twine(MaxCount)).str(); @@ -609,17 +584,17 @@ public: } InnerArgs.push_back(Value.getMatcher()); } - return VariantMatcher::VariadicOperatorMatcher(Func, std::move(InnerArgs)); + return VariantMatcher::VariadicOperatorMatcher(Op, std::move(InnerArgs)); } - bool isVariadic() const { return true; } - unsigned getNumArgs() const { return 0; } + bool isVariadic() const override { return true; } + unsigned getNumArgs() const override { return 0; } void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, - std::vector<ArgKind> &Kinds) const { + std::vector<ArgKind> &Kinds) const override { Kinds.push_back(ThisKind); } bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, - ast_type_traits::ASTNodeKind *LeastDerivedKind) const { + ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { if (Specificity) *Specificity = 1; if (LeastDerivedKind) @@ -631,7 +606,7 @@ public: private: const unsigned MinCount; const unsigned MaxCount; - const VarFunc Func; + const VarOp Op; const StringRef MatcherName; }; @@ -724,7 +699,7 @@ MatcherDescriptor * makeMatcherAutoMarshall(ast_matchers::internal::VariadicOperatorMatcherFunc< MinCount, MaxCount> Func, StringRef MatcherName) { - return new VariadicOperatorMatcherDescriptor(MinCount, MaxCount, Func.Func, + return new VariadicOperatorMatcherDescriptor(MinCount, MaxCount, Func.Op, MatcherName); } diff --git a/lib/ASTMatchers/Dynamic/Parser.cpp b/lib/ASTMatchers/Dynamic/Parser.cpp index 25629d99a7cc..9930c530c081 100644 --- a/lib/ASTMatchers/Dynamic/Parser.cpp +++ b/lib/ASTMatchers/Dynamic/Parser.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/CharInfo.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/Twine.h" +#include "llvm/Support/ManagedStatic.h" #include <string> #include <vector> @@ -258,8 +259,14 @@ private: Parser::Sema::~Sema() {} -VariantValue Parser::Sema::getNamedValue(StringRef Name) { - return VariantValue(); +std::vector<ArgKind> Parser::Sema::getAcceptedCompletionTypes( + llvm::ArrayRef<std::pair<MatcherCtor, unsigned>> Context) { + return std::vector<ArgKind>(); +} + +std::vector<MatcherCompletion> +Parser::Sema::getMatcherCompletions(llvm::ArrayRef<ArgKind> AcceptedTypes) { + return std::vector<MatcherCompletion>(); } struct Parser::ScopedContextEntry { @@ -288,7 +295,9 @@ bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) { if (Tokenizer->nextTokenKind() != TokenInfo::TK_OpenParen) { // Parse as a named value. - if (const VariantValue NamedValue = S->getNamedValue(NameToken.Text)) { + if (const VariantValue NamedValue = + NamedValues ? NamedValues->lookup(NameToken.Text) + : VariantValue()) { *Value = NamedValue; return true; } @@ -379,7 +388,7 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken, Tokenizer->consumeNextToken(); // consume the period. const TokenInfo BindToken = Tokenizer->consumeNextToken(); if (BindToken.Kind == TokenInfo::TK_CodeCompletion) { - addCompletion(BindToken, "bind(\"", "bind"); + addCompletion(BindToken, MatcherCompletion("bind(\"", "bind", 1)); return false; } @@ -427,13 +436,28 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken, // If the prefix of this completion matches the completion token, add it to // Completions minus the prefix. -void Parser::addCompletion(const TokenInfo &CompToken, StringRef TypedText, - StringRef Decl) { - if (TypedText.size() >= CompToken.Text.size() && - TypedText.substr(0, CompToken.Text.size()) == CompToken.Text) { - Completions.push_back( - MatcherCompletion(TypedText.substr(CompToken.Text.size()), Decl)); +void Parser::addCompletion(const TokenInfo &CompToken, + const MatcherCompletion& Completion) { + if (StringRef(Completion.TypedText).startswith(CompToken.Text) && + Completion.Specificity > 0) { + Completions.emplace_back(Completion.TypedText.substr(CompToken.Text.size()), + Completion.MatcherDecl, Completion.Specificity); + } +} + +std::vector<MatcherCompletion> Parser::getNamedValueCompletions( + ArrayRef<ArgKind> AcceptedTypes) { + if (!NamedValues) return std::vector<MatcherCompletion>(); + std::vector<MatcherCompletion> Result; + for (const auto &Entry : *NamedValues) { + unsigned Specificity; + if (Entry.getValue().isConvertibleTo(AcceptedTypes, &Specificity)) { + std::string Decl = + (Entry.getValue().getTypeAsString() + " " + Entry.getKey()).str(); + Result.emplace_back(Entry.getKey(), Decl, Specificity); + } } + return Result; } void Parser::addExpressionCompletions() { @@ -449,12 +473,13 @@ void Parser::addExpressionCompletions() { return; } - std::vector<MatcherCompletion> RegCompletions = - Registry::getCompletions(ContextStack); - for (std::vector<MatcherCompletion>::iterator I = RegCompletions.begin(), - E = RegCompletions.end(); - I != E; ++I) { - addCompletion(CompToken, I->TypedText, I->MatcherDecl); + auto AcceptedTypes = S->getAcceptedCompletionTypes(ContextStack); + for (const auto &Completion : S->getMatcherCompletions(AcceptedTypes)) { + addCompletion(CompToken, Completion); + } + + for (const auto &Completion : getNamedValueCompletions(AcceptedTypes)) { + addCompletion(CompToken, Completion); } } @@ -494,9 +519,12 @@ bool Parser::parseExpressionImpl(VariantValue *Value) { llvm_unreachable("Unknown token kind."); } +static llvm::ManagedStatic<Parser::RegistrySema> DefaultRegistrySema; + Parser::Parser(CodeTokenizer *Tokenizer, Sema *S, - Diagnostics *Error) - : Tokenizer(Tokenizer), S(S), Error(Error) {} + const NamedValueMap *NamedValues, Diagnostics *Error) + : Tokenizer(Tokenizer), S(S ? S : &*DefaultRegistrySema), + NamedValues(NamedValues), Error(Error) {} Parser::RegistrySema::~RegistrySema() {} @@ -516,16 +544,22 @@ VariantMatcher Parser::RegistrySema::actOnMatcherExpression( } } -bool Parser::parseExpression(StringRef Code, VariantValue *Value, - Diagnostics *Error) { - RegistrySema S; - return parseExpression(Code, &S, Value, Error); +std::vector<ArgKind> Parser::RegistrySema::getAcceptedCompletionTypes( + ArrayRef<std::pair<MatcherCtor, unsigned>> Context) { + return Registry::getAcceptedCompletionTypes(Context); +} + +std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions( + ArrayRef<ArgKind> AcceptedTypes) { + return Registry::getMatcherCompletions(AcceptedTypes); } bool Parser::parseExpression(StringRef Code, Sema *S, + const NamedValueMap *NamedValues, VariantValue *Value, Diagnostics *Error) { CodeTokenizer Tokenizer(Code, Error); - if (!Parser(&Tokenizer, S, Error).parseExpressionImpl(Value)) return false; + if (!Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value)) + return false; if (Tokenizer.peekNextToken().Kind != TokenInfo::TK_Eof) { Error->addError(Tokenizer.peekNextToken().Range, Error->ET_ParserTrailingCode); @@ -535,28 +569,31 @@ bool Parser::parseExpression(StringRef Code, Sema *S, } std::vector<MatcherCompletion> -Parser::completeExpression(StringRef Code, unsigned CompletionOffset) { +Parser::completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S, + const NamedValueMap *NamedValues) { Diagnostics Error; CodeTokenizer Tokenizer(Code, &Error, CompletionOffset); - RegistrySema S; - Parser P(&Tokenizer, &S, &Error); + Parser P(&Tokenizer, S, NamedValues, &Error); VariantValue Dummy; P.parseExpressionImpl(&Dummy); - return P.Completions; -} + // Sort by specificity, then by name. + std::sort(P.Completions.begin(), P.Completions.end(), + [](const MatcherCompletion &A, const MatcherCompletion &B) { + if (A.Specificity != B.Specificity) + return A.Specificity > B.Specificity; + return A.TypedText < B.TypedText; + }); -llvm::Optional<DynTypedMatcher> -Parser::parseMatcherExpression(StringRef Code, Diagnostics *Error) { - RegistrySema S; - return parseMatcherExpression(Code, &S, Error); + return P.Completions; } llvm::Optional<DynTypedMatcher> -Parser::parseMatcherExpression(StringRef Code, Parser::Sema *S, +Parser::parseMatcherExpression(StringRef Code, Sema *S, + const NamedValueMap *NamedValues, Diagnostics *Error) { VariantValue Value; - if (!parseExpression(Code, S, &Value, Error)) + if (!parseExpression(Code, S, NamedValues, &Value, Error)) return llvm::Optional<DynTypedMatcher>(); if (!Value.isMatcher()) { Error->addError(SourceRange(), Error->ET_ParserNotAMatcher); diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 4bc50a0f2a96..d550a89cad49 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -101,8 +101,8 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(argumentCountIs); REGISTER_MATCHER(arraySubscriptExpr); REGISTER_MATCHER(arrayType); - REGISTER_MATCHER(asString); REGISTER_MATCHER(asmStmt); + REGISTER_MATCHER(asString); REGISTER_MATCHER(atomicType); REGISTER_MATCHER(autoType); REGISTER_MATCHER(binaryOperator); @@ -111,7 +111,6 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(boolLiteral); REGISTER_MATCHER(breakStmt); REGISTER_MATCHER(builtinType); - REGISTER_MATCHER(cStyleCastExpr); REGISTER_MATCHER(callExpr); REGISTER_MATCHER(caseStmt); REGISTER_MATCHER(castExpr); @@ -123,18 +122,20 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(compoundLiteralExpr); REGISTER_MATCHER(compoundStmt); REGISTER_MATCHER(conditionalOperator); - REGISTER_MATCHER(constCastExpr); REGISTER_MATCHER(constantArrayType); + REGISTER_MATCHER(constCastExpr); REGISTER_MATCHER(constructExpr); REGISTER_MATCHER(constructorDecl); REGISTER_MATCHER(containsDeclaration); REGISTER_MATCHER(continueStmt); + REGISTER_MATCHER(cStyleCastExpr); REGISTER_MATCHER(ctorInitializer); + REGISTER_MATCHER(CUDAKernelCallExpr); REGISTER_MATCHER(decl); + REGISTER_MATCHER(declaratorDecl); REGISTER_MATCHER(declCountIs); REGISTER_MATCHER(declRefExpr); REGISTER_MATCHER(declStmt); - REGISTER_MATCHER(declaratorDecl); REGISTER_MATCHER(defaultArgExpr); REGISTER_MATCHER(defaultStmt); REGISTER_MATCHER(deleteExpr); @@ -147,6 +148,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(enumConstantDecl); REGISTER_MATCHER(enumDecl); REGISTER_MATCHER(equalsBoundNode); + REGISTER_MATCHER(equalsIntegralValue); REGISTER_MATCHER(explicitCastExpr); REGISTER_MATCHER(expr); REGISTER_MATCHER(exprWithCleanups); @@ -160,10 +162,10 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(forRangeStmt); REGISTER_MATCHER(forStmt); REGISTER_MATCHER(friendDecl); + REGISTER_MATCHER(functionalCastExpr); REGISTER_MATCHER(functionDecl); REGISTER_MATCHER(functionTemplateDecl); REGISTER_MATCHER(functionType); - REGISTER_MATCHER(functionalCastExpr); REGISTER_MATCHER(gotoStmt); REGISTER_MATCHER(has); REGISTER_MATCHER(hasAncestor); @@ -175,19 +177,21 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasAnyUsingShadowDecl); REGISTER_MATCHER(hasArgument); REGISTER_MATCHER(hasArgumentOfType); + REGISTER_MATCHER(hasAttr); REGISTER_MATCHER(hasBase); REGISTER_MATCHER(hasBody); REGISTER_MATCHER(hasCanonicalType); REGISTER_MATCHER(hasCaseConstant); REGISTER_MATCHER(hasCondition); REGISTER_MATCHER(hasConditionVariableStatement); - REGISTER_MATCHER(hasDeclContext); REGISTER_MATCHER(hasDeclaration); + REGISTER_MATCHER(hasDeclContext); REGISTER_MATCHER(hasDeducedType); REGISTER_MATCHER(hasDescendant); REGISTER_MATCHER(hasDestinationType); REGISTER_MATCHER(hasEitherOperand); REGISTER_MATCHER(hasElementType); + REGISTER_MATCHER(hasElse); REGISTER_MATCHER(hasFalseExpression); REGISTER_MATCHER(hasGlobalStorage); REGISTER_MATCHER(hasImplicitDestinationType); @@ -198,6 +202,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasLocalQualifiers); REGISTER_MATCHER(hasLocalStorage); REGISTER_MATCHER(hasLoopInit); + REGISTER_MATCHER(hasLoopVariable); REGISTER_MATCHER(hasMethod); REGISTER_MATCHER(hasName); REGISTER_MATCHER(hasObjectExpression); @@ -206,6 +211,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasParameter); REGISTER_MATCHER(hasParent); REGISTER_MATCHER(hasQualifier); + REGISTER_MATCHER(hasRangeInit); REGISTER_MATCHER(hasRHS); REGISTER_MATCHER(hasSingleDecl); REGISTER_MATCHER(hasSize); @@ -213,6 +219,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasSourceExpression); REGISTER_MATCHER(hasTargetDecl); REGISTER_MATCHER(hasTemplateArgument); + REGISTER_MATCHER(hasThen); REGISTER_MATCHER(hasTrueExpression); REGISTER_MATCHER(hasTypeLoc); REGISTER_MATCHER(hasUnaryOperand); @@ -230,22 +237,30 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(isConst); REGISTER_MATCHER(isConstQualified); REGISTER_MATCHER(isDefinition); + REGISTER_MATCHER(isDeleted); REGISTER_MATCHER(isExplicitTemplateSpecialization); REGISTER_MATCHER(isExpr); REGISTER_MATCHER(isExternC); REGISTER_MATCHER(isImplicit); + REGISTER_MATCHER(isExpansionInFileMatching); + REGISTER_MATCHER(isExpansionInMainFile); + REGISTER_MATCHER(isInstantiated); + REGISTER_MATCHER(isExpansionInSystemHeader); REGISTER_MATCHER(isInteger); + REGISTER_MATCHER(isIntegral); + REGISTER_MATCHER(isInTemplateInstantiation); REGISTER_MATCHER(isListInitialization); REGISTER_MATCHER(isOverride); REGISTER_MATCHER(isPrivate); REGISTER_MATCHER(isProtected); REGISTER_MATCHER(isPublic); + REGISTER_MATCHER(isPure); REGISTER_MATCHER(isTemplateInstantiation); REGISTER_MATCHER(isVirtual); REGISTER_MATCHER(isWritten); - REGISTER_MATCHER(lValueReferenceType); REGISTER_MATCHER(labelStmt); REGISTER_MATCHER(lambdaExpr); + REGISTER_MATCHER(lValueReferenceType); REGISTER_MATCHER(matchesName); REGISTER_MATCHER(materializeTemporaryExpr); REGISTER_MATCHER(member); @@ -254,8 +269,8 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(memberPointerType); REGISTER_MATCHER(methodDecl); REGISTER_MATCHER(namedDecl); - REGISTER_MATCHER(namesType); REGISTER_MATCHER(namespaceDecl); + REGISTER_MATCHER(namesType); REGISTER_MATCHER(nestedNameSpecifier); REGISTER_MATCHER(nestedNameSpecifierLoc); REGISTER_MATCHER(newExpr); @@ -271,15 +286,16 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(pointee); REGISTER_MATCHER(pointerType); REGISTER_MATCHER(qualType); - REGISTER_MATCHER(rValueReferenceType); REGISTER_MATCHER(recordDecl); REGISTER_MATCHER(recordType); REGISTER_MATCHER(referenceType); REGISTER_MATCHER(refersToDeclaration); + REGISTER_MATCHER(refersToIntegralType); REGISTER_MATCHER(refersToType); REGISTER_MATCHER(reinterpretCastExpr); - REGISTER_MATCHER(returnStmt); REGISTER_MATCHER(returns); + REGISTER_MATCHER(returnStmt); + REGISTER_MATCHER(rValueReferenceType); REGISTER_MATCHER(sizeOfExpr); REGISTER_MATCHER(specifiesNamespace); REGISTER_MATCHER(specifiesType); @@ -288,8 +304,11 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(staticCastExpr); REGISTER_MATCHER(stmt); REGISTER_MATCHER(stringLiteral); + REGISTER_MATCHER(substNonTypeTemplateParmExpr); REGISTER_MATCHER(switchCase); REGISTER_MATCHER(switchStmt); + REGISTER_MATCHER(templateArgument); + REGISTER_MATCHER(templateArgumentCountIs); REGISTER_MATCHER(templateSpecializationType); REGISTER_MATCHER(temporaryObjectExpr); REGISTER_MATCHER(thisExpr); @@ -298,8 +317,9 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(to); REGISTER_MATCHER(tryStmt); REGISTER_MATCHER(type); - REGISTER_MATCHER(typeLoc); + REGISTER_MATCHER(typedefDecl); REGISTER_MATCHER(typedefType); + REGISTER_MATCHER(typeLoc); REGISTER_MATCHER(unaryExprOrTypeTraitExpr); REGISTER_MATCHER(unaryOperator); REGISTER_MATCHER(unaryTransformType); @@ -308,8 +328,11 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(unresolvedUsingValueDecl); REGISTER_MATCHER(userDefinedLiteral); REGISTER_MATCHER(usingDecl); + REGISTER_MATCHER(usingDirectiveDecl); + REGISTER_MATCHER(valueDecl); REGISTER_MATCHER(varDecl); REGISTER_MATCHER(variableArrayType); + REGISTER_MATCHER(voidType); REGISTER_MATCHER(whileStmt); REGISTER_MATCHER(withInitializer); } @@ -353,77 +376,63 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, return OS; } -struct ReverseSpecificityThenName { - bool operator()(const std::pair<unsigned, std::string> &A, - const std::pair<unsigned, std::string> &B) const { - return A.first > B.first || (A.first == B.first && A.second < B.second); - } -}; - -} +} // namespace -std::vector<MatcherCompletion> Registry::getCompletions( - ArrayRef<std::pair<MatcherCtor, unsigned> > Context) { +std::vector<ArgKind> Registry::getAcceptedCompletionTypes( + ArrayRef<std::pair<MatcherCtor, unsigned>> Context) { ASTNodeKind InitialTypes[] = { - ASTNodeKind::getFromNodeKind<Decl>(), - ASTNodeKind::getFromNodeKind<QualType>(), - ASTNodeKind::getFromNodeKind<Type>(), - ASTNodeKind::getFromNodeKind<Stmt>(), - ASTNodeKind::getFromNodeKind<NestedNameSpecifier>(), - ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>(), - ASTNodeKind::getFromNodeKind<TypeLoc>() - }; - ArrayRef<ASTNodeKind> InitialTypesRef(InitialTypes); + ASTNodeKind::getFromNodeKind<Decl>(), + ASTNodeKind::getFromNodeKind<QualType>(), + ASTNodeKind::getFromNodeKind<Type>(), + ASTNodeKind::getFromNodeKind<Stmt>(), + ASTNodeKind::getFromNodeKind<NestedNameSpecifier>(), + ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>(), + ASTNodeKind::getFromNodeKind<TypeLoc>()}; // Starting with the above seed of acceptable top-level matcher types, compute // the acceptable type set for the argument indicated by each context element. - std::set<ASTNodeKind> TypeSet(InitialTypesRef.begin(), InitialTypesRef.end()); - for (ArrayRef<std::pair<MatcherCtor, unsigned> >::iterator - CtxI = Context.begin(), - CtxE = Context.end(); - CtxI != CtxE; ++CtxI) { - std::vector<internal::ArgKind> NextTypeSet; - for (std::set<ASTNodeKind>::iterator I = TypeSet.begin(), E = TypeSet.end(); - I != E; ++I) { - if (CtxI->first->isConvertibleTo(*I) && - (CtxI->first->isVariadic() || - CtxI->second < CtxI->first->getNumArgs())) - CtxI->first->getArgKinds(*I, CtxI->second, NextTypeSet); + std::set<ArgKind> TypeSet(std::begin(InitialTypes), std::end(InitialTypes)); + for (const auto &CtxEntry : Context) { + MatcherCtor Ctor = CtxEntry.first; + unsigned ArgNumber = CtxEntry.second; + std::vector<ArgKind> NextTypeSet; + for (const ArgKind &Kind : TypeSet) { + if (Kind.getArgKind() == Kind.AK_Matcher && + Ctor->isConvertibleTo(Kind.getMatcherKind()) && + (Ctor->isVariadic() || ArgNumber < Ctor->getNumArgs())) + Ctor->getArgKinds(Kind.getMatcherKind(), ArgNumber, NextTypeSet); } TypeSet.clear(); - for (std::vector<internal::ArgKind>::iterator I = NextTypeSet.begin(), - E = NextTypeSet.end(); - I != E; ++I) { - if (I->getArgKind() == internal::ArgKind::AK_Matcher) - TypeSet.insert(I->getMatcherKind()); - } + TypeSet.insert(NextTypeSet.begin(), NextTypeSet.end()); } + return std::vector<ArgKind>(TypeSet.begin(), TypeSet.end()); +} - typedef std::map<std::pair<unsigned, std::string>, MatcherCompletion, - ReverseSpecificityThenName> CompletionsTy; - CompletionsTy Completions; +std::vector<MatcherCompletion> +Registry::getMatcherCompletions(ArrayRef<ArgKind> AcceptedTypes) { + std::vector<MatcherCompletion> Completions; - // TypeSet now contains the list of acceptable types for the argument we are - // completing. Search the registry for acceptable matchers. + // Search the registry for acceptable matchers. for (ConstructorMap::const_iterator I = RegistryData->constructors().begin(), E = RegistryData->constructors().end(); I != E; ++I) { std::set<ASTNodeKind> RetKinds; unsigned NumArgs = I->second->isVariadic() ? 1 : I->second->getNumArgs(); bool IsPolymorphic = I->second->isPolymorphic(); - std::vector<std::vector<internal::ArgKind> > ArgsKinds(NumArgs); + std::vector<std::vector<ArgKind>> ArgsKinds(NumArgs); unsigned MaxSpecificity = 0; - for (std::set<ASTNodeKind>::iterator TI = TypeSet.begin(), - TE = TypeSet.end(); - TI != TE; ++TI) { + for (const ArgKind& Kind : AcceptedTypes) { + if (Kind.getArgKind() != Kind.AK_Matcher) + continue; unsigned Specificity; ASTNodeKind LeastDerivedKind; - if (I->second->isConvertibleTo(*TI, &Specificity, &LeastDerivedKind)) { + if (I->second->isConvertibleTo(Kind.getMatcherKind(), &Specificity, + &LeastDerivedKind)) { if (MaxSpecificity < Specificity) MaxSpecificity = Specificity; RetKinds.insert(LeastDerivedKind); for (unsigned Arg = 0; Arg != NumArgs; ++Arg) - I->second->getArgKinds(*TI, Arg, ArgsKinds[Arg]); + I->second->getArgKinds(Kind.getMatcherKind(), Arg, ArgsKinds[Arg]); if (IsPolymorphic) break; } @@ -437,24 +446,25 @@ std::vector<MatcherCompletion> Registry::getCompletions( OS << "Matcher<T> " << I->first() << "(Matcher<T>"; } else { OS << "Matcher<" << RetKinds << "> " << I->first() << "("; - for (std::vector<std::vector<internal::ArgKind> >::iterator - KI = ArgsKinds.begin(), - KE = ArgsKinds.end(); - KI != KE; ++KI) { - if (KI != ArgsKinds.begin()) + for (const std::vector<ArgKind> &Arg : ArgsKinds) { + if (&Arg != &ArgsKinds[0]) OS << ", "; - // This currently assumes that a matcher may not overload a - // non-matcher, and all non-matcher overloads have identical - // arguments. - if ((*KI)[0].getArgKind() == internal::ArgKind::AK_Matcher) { - std::set<ASTNodeKind> MatcherKinds; - std::transform( - KI->begin(), KI->end(), - std::inserter(MatcherKinds, MatcherKinds.end()), - std::mem_fun_ref(&internal::ArgKind::getMatcherKind)); + + bool FirstArgKind = true; + std::set<ASTNodeKind> MatcherKinds; + // Two steps. First all non-matchers, then matchers only. + for (const ArgKind &AK : Arg) { + if (AK.getArgKind() == ArgKind::AK_Matcher) { + MatcherKinds.insert(AK.getMatcherKind()); + } else { + if (!FirstArgKind) OS << "|"; + FirstArgKind = false; + OS << AK.asString(); + } + } + if (!MatcherKinds.empty()) { + if (!FirstArgKind) OS << "|"; OS << "Matcher<" << MatcherKinds << ">"; - } else { - OS << (*KI)[0].asString(); } } } @@ -466,19 +476,14 @@ std::vector<MatcherCompletion> Registry::getCompletions( TypedText += "("; if (ArgsKinds.empty()) TypedText += ")"; - else if (ArgsKinds[0][0].getArgKind() == internal::ArgKind::AK_String) + else if (ArgsKinds[0][0].getArgKind() == ArgKind::AK_String) TypedText += "\""; - Completions[std::make_pair(MaxSpecificity, I->first())] = - MatcherCompletion(TypedText, OS.str()); + Completions.emplace_back(TypedText, OS.str(), MaxSpecificity); } } - std::vector<MatcherCompletion> RetVal; - for (CompletionsTy::iterator I = Completions.begin(), E = Completions.end(); - I != E; ++I) - RetVal.push_back(I->second); - return RetVal; + return Completions; } // static diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp index 18c989432f46..a88b70701234 100644 --- a/lib/ASTMatchers/Dynamic/VariantValue.cpp +++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -20,26 +20,88 @@ namespace clang { namespace ast_matchers { namespace dynamic { -VariantMatcher::MatcherOps::~MatcherOps() {} +std::string ArgKind::asString() const { + switch (getArgKind()) { + case AK_Matcher: + return (Twine("Matcher<") + MatcherKind.asStringRef() + ">").str(); + case AK_Unsigned: + return "unsigned"; + case AK_String: + return "string"; + } + llvm_unreachable("unhandled ArgKind"); +} + +bool ArgKind::isConvertibleTo(ArgKind To, unsigned *Specificity) const { + if (K != To.K) + return false; + if (K != AK_Matcher) { + if (Specificity) + *Specificity = 1; + return true; + } + unsigned Distance; + if (!MatcherKind.isBaseOf(To.MatcherKind, &Distance)) + return false; + + if (Specificity) + *Specificity = 100 - Distance; + return true; +} + +bool +VariantMatcher::MatcherOps::canConstructFrom(const DynTypedMatcher &Matcher, + bool &IsExactMatch) const { + IsExactMatch = Matcher.getSupportedKind().isSame(NodeKind); + return Matcher.canConvertTo(NodeKind); +} + +llvm::Optional<DynTypedMatcher> +VariantMatcher::MatcherOps::constructVariadicOperator( + DynTypedMatcher::VariadicOperator Op, + ArrayRef<VariantMatcher> InnerMatchers) const { + std::vector<DynTypedMatcher> DynMatchers; + for (const auto &InnerMatcher : InnerMatchers) { + // Abort if any of the inner matchers can't be converted to + // Matcher<T>. + if (!InnerMatcher.Value) + return llvm::None; + llvm::Optional<DynTypedMatcher> Inner = + InnerMatcher.Value->getTypedMatcher(*this); + if (!Inner) + return llvm::None; + DynMatchers.push_back(*Inner); + } + return DynTypedMatcher::constructVariadic(Op, DynMatchers); +} + VariantMatcher::Payload::~Payload() {} class VariantMatcher::SinglePayload : public VariantMatcher::Payload { public: SinglePayload(const DynTypedMatcher &Matcher) : Matcher(Matcher) {} - virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const { + llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { return Matcher; } - virtual std::string getTypeAsString() const { + std::string getTypeAsString() const override { return (Twine("Matcher<") + Matcher.getSupportedKind().asStringRef() + ">") .str(); } - virtual void makeTypedMatcher(MatcherOps &Ops) const { + llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const override { bool Ignore; if (Ops.canConstructFrom(Matcher, Ignore)) - Ops.constructFrom(Matcher); + return Matcher; + return llvm::None; + } + + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const override { + return ArgKind(Matcher.getSupportedKind()) + .isConvertibleTo(Kind, Specificity); } private: @@ -51,15 +113,15 @@ public: PolymorphicPayload(std::vector<DynTypedMatcher> MatchersIn) : Matchers(std::move(MatchersIn)) {} - virtual ~PolymorphicPayload() {} + ~PolymorphicPayload() override {} - virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const { + llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { if (Matchers.size() != 1) return llvm::Optional<DynTypedMatcher>(); return Matchers[0]; } - virtual std::string getTypeAsString() const { + std::string getTypeAsString() const override { std::string Inner; for (size_t i = 0, e = Matchers.size(); i != e; ++i) { if (i != 0) @@ -69,7 +131,8 @@ public: return (Twine("Matcher<") + Inner + ">").str(); } - virtual void makeTypedMatcher(MatcherOps &Ops) const { + llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const override { bool FoundIsExact = false; const DynTypedMatcher *Found = nullptr; int NumFound = 0; @@ -89,7 +152,23 @@ public: } // We only succeed if we found exactly one, or if we found an exact match. if (Found && (FoundIsExact || NumFound == 1)) - Ops.constructFrom(*Found); + return *Found; + return llvm::None; + } + + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const override { + unsigned MaxSpecificity = 0; + for (const DynTypedMatcher &Matcher : Matchers) { + unsigned ThisSpecificity; + if (ArgKind(Matcher.getSupportedKind()) + .isConvertibleTo(Kind, &ThisSpecificity)) { + MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity); + } + } + if (Specificity) + *Specificity = MaxSpecificity; + return MaxSpecificity > 0; } const std::vector<DynTypedMatcher> Matchers; @@ -97,15 +176,15 @@ public: class VariantMatcher::VariadicOpPayload : public VariantMatcher::Payload { public: - VariadicOpPayload(ast_matchers::internal::VariadicOperatorFunction Func, + VariadicOpPayload(DynTypedMatcher::VariadicOperator Op, std::vector<VariantMatcher> Args) - : Func(Func), Args(std::move(Args)) {} + : Op(Op), Args(std::move(Args)) {} - virtual llvm::Optional<DynTypedMatcher> getSingleMatcher() const { + llvm::Optional<DynTypedMatcher> getSingleMatcher() const override { return llvm::Optional<DynTypedMatcher>(); } - virtual std::string getTypeAsString() const { + std::string getTypeAsString() const override { std::string Inner; for (size_t i = 0, e = Args.size(); i != e; ++i) { if (i != 0) @@ -115,12 +194,22 @@ public: return Inner; } - virtual void makeTypedMatcher(MatcherOps &Ops) const { - Ops.constructVariadicOperator(Func, Args); + llvm::Optional<DynTypedMatcher> + getTypedMatcher(const MatcherOps &Ops) const override { + return Ops.constructVariadicOperator(Op, Args); + } + + bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, + unsigned *Specificity) const override { + for (const VariantMatcher &Matcher : Args) { + if (!Matcher.isConvertibleTo(Kind, Specificity)) + return false; + } + return true; } private: - const ast_matchers::internal::VariadicOperatorFunction Func; + const DynTypedMatcher::VariadicOperator Op; const std::vector<VariantMatcher> Args; }; @@ -136,9 +225,9 @@ VariantMatcher::PolymorphicMatcher(std::vector<DynTypedMatcher> Matchers) { } VariantMatcher VariantMatcher::VariadicOperatorMatcher( - ast_matchers::internal::VariadicOperatorFunction Func, + DynTypedMatcher::VariadicOperator Op, std::vector<VariantMatcher> Args) { - return VariantMatcher(new VariadicOpPayload(Func, std::move(Args))); + return VariantMatcher(new VariadicOpPayload(Op, std::move(Args))); } llvm::Optional<DynTypedMatcher> VariantMatcher::getSingleMatcher() const { @@ -251,6 +340,43 @@ void VariantValue::setMatcher(const VariantMatcher &NewValue) { Value.Matcher = new VariantMatcher(NewValue); } +bool VariantValue::isConvertibleTo(ArgKind Kind, unsigned *Specificity) const { + switch (Kind.getArgKind()) { + case ArgKind::AK_Unsigned: + if (!isUnsigned()) + return false; + *Specificity = 1; + return true; + + case ArgKind::AK_String: + if (!isString()) + return false; + *Specificity = 1; + return true; + + case ArgKind::AK_Matcher: + if (!isMatcher()) + return false; + return getMatcher().isConvertibleTo(Kind.getMatcherKind(), Specificity); + } + llvm_unreachable("Invalid Type"); +} + +bool VariantValue::isConvertibleTo(ArrayRef<ArgKind> Kinds, + unsigned *Specificity) const { + unsigned MaxSpecificity = 0; + for (const ArgKind& Kind : Kinds) { + unsigned ThisSpecificity; + if (!isConvertibleTo(Kind, &ThisSpecificity)) + continue; + MaxSpecificity = std::max(MaxSpecificity, ThisSpecificity); + } + if (Specificity && MaxSpecificity > 0) { + *Specificity = MaxSpecificity; + } + return MaxSpecificity > 0; +} + std::string VariantValue::getTypeAsString() const { switch (Type) { case VT_String: return "String"; diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index 90d4b13b88be..be66f32e77be 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -69,8 +69,9 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, bool addTemporaryDtors, bool synthesizeBodies, bool addStaticInitBranch, - bool addCXXNewAllocator) - : SynthesizeBodies(synthesizeBodies) + bool addCXXNewAllocator, + CodeInjector *injector) + : Injector(injector), SynthesizeBodies(synthesizeBodies) { cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; cfgBuildOptions.AddImplicitDtors = addImplicitDtors; @@ -84,8 +85,8 @@ void AnalysisDeclContextManager::clear() { llvm::DeleteContainerSeconds(Contexts); } -static BodyFarm &getBodyFarm(ASTContext &C) { - static BodyFarm *BF = new BodyFarm(C); +static BodyFarm &getBodyFarm(ASTContext &C, CodeInjector *injector = nullptr) { + static BodyFarm *BF = new BodyFarm(C, injector); return *BF; } @@ -94,7 +95,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { Stmt *Body = FD->getBody(); if (!Body && Manager && Manager->synthesizeBodies()) { - Body = getBodyFarm(getASTContext()).getBody(FD); + Body = getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(FD); if (Body) IsAutosynthesized = true; } @@ -103,7 +104,7 @@ Stmt *AnalysisDeclContext::getBody(bool &IsAutosynthesized) const { else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { Stmt *Body = MD->getBody(); if (!Body && Manager && Manager->synthesizeBodies()) { - Body = getBodyFarm(getASTContext()).getBody(MD); + Body = getBodyFarm(getASTContext(), Manager->Injector.get()).getBody(MD); if (Body) IsAutosynthesized = true; } @@ -128,6 +129,13 @@ bool AnalysisDeclContext::isBodyAutosynthesized() const { return Tmp; } +bool AnalysisDeclContext::isBodyAutosynthesizedFromModelFile() const { + bool Tmp; + Stmt *Body = getBody(Tmp); + return Tmp && Body->getLocStart().isValid(); +} + + const ImplicitParamDecl *AnalysisDeclContext::getSelfDecl() const { if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) return MD->getSelfDecl(); @@ -181,8 +189,7 @@ CFG *AnalysisDeclContext::getCFG() { return getUnoptimizedCFG(); if (!builtCFG) { - cfg.reset(CFG::buildCFG(D, getBody(), - &D->getASTContext(), cfgBuildOptions)); + cfg = CFG::buildCFG(D, getBody(), &D->getASTContext(), cfgBuildOptions); // Even when the cfg is not successfully built, we don't // want to try building it again. builtCFG = true; @@ -200,8 +207,8 @@ CFG *AnalysisDeclContext::getUnoptimizedCFG() { if (!builtCompleteCFG) { SaveAndRestore<bool> NotPrune(cfgBuildOptions.PruneTriviallyFalseEdges, false); - completeCFG.reset(CFG::buildCFG(D, getBody(), &D->getASTContext(), - cfgBuildOptions)); + completeCFG = + CFG::buildCFG(D, getBody(), &D->getASTContext(), cfgBuildOptions); // Even when the cfg is not successfully built, we don't // want to try building it again. builtCompleteCFG = true; @@ -474,7 +481,7 @@ public: // Non-local variables are also directly modified. if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) { if (!VD->hasLocalStorage()) { - if (Visited.insert(VD)) + if (Visited.insert(VD).second) BEVals.push_back(VD, BC); } } diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp index 316a18b421b5..7d1b23575293 100644 --- a/lib/Analysis/BodyFarm.cpp +++ b/lib/Analysis/BodyFarm.cpp @@ -17,6 +17,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" +#include "clang/Analysis/CodeInjector.h" #include "llvm/ADT/StringSwitch.h" using namespace clang; @@ -114,7 +115,7 @@ DeclRefExpr *ASTMaker::makeDeclRefExpr(const VarDecl *D) { /* QualifierLoc = */ NestedNameSpecifierLoc(), /* TemplateKWLoc = */ SourceLocation(), /* D = */ const_cast<VarDecl*>(D), - /* isEnclosingLocal = */ false, + /* RefersToEnclosingVariableOrCapture = */ false, /* NameLoc = */ SourceLocation(), /* T = */ D->getType(), /* VK = */ VK_LValue); @@ -223,10 +224,8 @@ static Stmt *create_dispatch_once(ASTContext &C, const FunctionDecl *D) { PredicateTy); // (3) Create the compound statement. - Stmt *Stmts[2]; - Stmts[0] = B; - Stmts[1] = CE; - CompoundStmt *CS = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2)); + Stmt *Stmts[] = { B, CE }; + CompoundStmt *CS = M.makeCompound(Stmts); // (4) Create the 'if' condition. ImplicitCastExpr *LValToRval = @@ -337,7 +336,7 @@ static Stmt *create_OSAtomicCompareAndSwap(ASTContext &C, const FunctionDecl *D) Expr *RetVal = isBoolean ? M.makeIntegralCastToBoolean(BoolVal) : M.makeIntegralCast(BoolVal, ResultTy); Stmts[1] = M.makeReturn(RetVal); - CompoundStmt *Body = M.makeCompound(ArrayRef<Stmt*>(Stmts, 2)); + CompoundStmt *Body = M.makeCompound(Stmts); // Construct the else clause. BoolVal = M.makeObjCBool(false); @@ -383,6 +382,7 @@ Stmt *BodyFarm::getBody(const FunctionDecl *D) { } if (FF) { Val = FF(C, D); } + else if (Injector) { Val = Injector->getBody(D); } return Val.getValue(); } diff --git a/lib/Analysis/BodyFarm.h b/lib/Analysis/BodyFarm.h index 2d200fb755c1..91379437231d 100644 --- a/lib/Analysis/BodyFarm.h +++ b/lib/Analysis/BodyFarm.h @@ -12,8 +12,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_CLANG_ANALYSIS_BODYFARM_H -#define LLVM_CLANG_ANALYSIS_BODYFARM_H +#ifndef LLVM_CLANG_LIB_ANALYSIS_BODYFARM_H +#define LLVM_CLANG_LIB_ANALYSIS_BODYFARM_H #include "clang/Basic/LLVM.h" #include "llvm/ADT/DenseMap.h" @@ -27,10 +27,11 @@ class FunctionDecl; class ObjCMethodDecl; class ObjCPropertyDecl; class Stmt; +class CodeInjector; class BodyFarm { public: - BodyFarm(ASTContext &C) : C(C) {} + BodyFarm(ASTContext &C, CodeInjector *injector) : C(C), Injector(injector) {} /// Factory method for creating bodies for ordinary functions. Stmt *getBody(const FunctionDecl *D); @@ -43,6 +44,7 @@ private: ASTContext &C; BodyMap Bodies; + CodeInjector *Injector; }; } diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 842a385fbcdb..d9073aa63b16 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -234,6 +234,12 @@ public: } }; +TryResult bothKnownTrue(TryResult R1, TryResult R2) { + if (!R1.isKnown() || !R2.isKnown()) + return TryResult(); + return TryResult(R1.isTrue() && R2.isTrue()); +} + class reverse_children { llvm::SmallVector<Stmt *, 12> childrenBuf; ArrayRef<Stmt*> children; @@ -300,7 +306,7 @@ class CFGBuilder { CFGBlock *SwitchTerminatedBlock; CFGBlock *DefaultCaseBlock; CFGBlock *TryTerminatedBlock; - + // Current position in local scope. LocalScope::const_iterator ScopePos; @@ -343,7 +349,7 @@ public: cachedEntry(nullptr), lastLookup(nullptr) {} // buildCFG - Used by external clients to construct the CFG. - CFG* buildCFG(const Decl *D, Stmt *Statement); + std::unique_ptr<CFG> buildCFG(const Decl *D, Stmt *Statement); bool alwaysAdd(const Stmt *stmt); @@ -410,16 +416,80 @@ private: CFGBlock *VisitChildren(Stmt *S); CFGBlock *VisitNoRecurse(Expr *E, AddStmtChoice asc); + /// When creating the CFG for temporary destructors, we want to mirror the + /// branch structure of the corresponding constructor calls. + /// Thus, while visiting a statement for temporary destructors, we keep a + /// context to keep track of the following information: + /// - whether a subexpression is executed unconditionally + /// - if a subexpression is executed conditionally, the first + /// CXXBindTemporaryExpr we encounter in that subexpression (which + /// corresponds to the last temporary destructor we have to call for this + /// subexpression) and the CFG block at that point (which will become the + /// successor block when inserting the decision point). + /// + /// That way, we can build the branch structure for temporary destructors as + /// follows: + /// 1. If a subexpression is executed unconditionally, we add the temporary + /// destructor calls to the current block. + /// 2. If a subexpression is executed conditionally, when we encounter a + /// CXXBindTemporaryExpr: + /// a) If it is the first temporary destructor call in the subexpression, + /// we remember the CXXBindTemporaryExpr and the current block in the + /// TempDtorContext; we start a new block, and insert the temporary + /// destructor call. + /// b) Otherwise, add the temporary destructor call to the current block. + /// 3. When we finished visiting a conditionally executed subexpression, + /// and we found at least one temporary constructor during the visitation + /// (2.a has executed), we insert a decision block that uses the + /// CXXBindTemporaryExpr as terminator, and branches to the current block + /// if the CXXBindTemporaryExpr was marked executed, and otherwise + /// branches to the stored successor. + struct TempDtorContext { + TempDtorContext() + : IsConditional(false), KnownExecuted(true), Succ(nullptr), + TerminatorExpr(nullptr) {} + + TempDtorContext(TryResult KnownExecuted) + : IsConditional(true), KnownExecuted(KnownExecuted), Succ(nullptr), + TerminatorExpr(nullptr) {} + + /// Returns whether we need to start a new branch for a temporary destructor + /// call. This is the case when the the temporary destructor is + /// conditionally executed, and it is the first one we encounter while + /// visiting a subexpression - other temporary destructors at the same level + /// will be added to the same block and are executed under the same + /// condition. + bool needsTempDtorBranch() const { + return IsConditional && !TerminatorExpr; + } + + /// Remember the successor S of a temporary destructor decision branch for + /// the corresponding CXXBindTemporaryExpr E. + void setDecisionPoint(CFGBlock *S, CXXBindTemporaryExpr *E) { + Succ = S; + TerminatorExpr = E; + } + + const bool IsConditional; + const TryResult KnownExecuted; + CFGBlock *Succ; + CXXBindTemporaryExpr *TerminatorExpr; + }; + // Visitors to walk an AST and generate destructors of temporaries in // full expression. - CFGBlock *VisitForTemporaryDtors(Stmt *E, bool BindToTemporary = false); - CFGBlock *VisitChildrenForTemporaryDtors(Stmt *E); - CFGBlock *VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E); - CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors(CXXBindTemporaryExpr *E, - bool BindToTemporary); - CFGBlock * - VisitConditionalOperatorForTemporaryDtors(AbstractConditionalOperator *E, - bool BindToTemporary); + CFGBlock *VisitForTemporaryDtors(Stmt *E, bool BindToTemporary, + TempDtorContext &Context); + CFGBlock *VisitChildrenForTemporaryDtors(Stmt *E, TempDtorContext &Context); + CFGBlock *VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E, + TempDtorContext &Context); + CFGBlock *VisitCXXBindTemporaryExprForTemporaryDtors( + CXXBindTemporaryExpr *E, bool BindToTemporary, TempDtorContext &Context); + CFGBlock *VisitConditionalOperatorForTemporaryDtors( + AbstractConditionalOperator *E, bool BindToTemporary, + TempDtorContext &Context); + void InsertTempDtorDecisionBlock(const TempDtorContext &Context, + CFGBlock *FalseSucc = nullptr); // NYS == Not Yet Supported CFGBlock *NYS() { @@ -901,7 +971,7 @@ static const VariableArrayType *FindVA(const Type *t) { /// body (compound statement). The ownership of the returned CFG is /// transferred to the caller. If CFG construction fails, this method returns /// NULL. -CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { +std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { assert(cfg.get()); if (!Statement) return nullptr; @@ -973,7 +1043,7 @@ CFG* CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { // Create an empty entry block that has no predecessors. cfg->setEntry(createBlock()); - return cfg.release(); + return std::move(cfg); } /// createBlock - Used to lazily create blocks that are connected @@ -1000,21 +1070,19 @@ CFGBlock *CFGBuilder::addInitializer(CXXCtorInitializer *I) { if (!BuildOpts.AddInitializers) return Block; - bool IsReference = false; bool HasTemporaries = false; // Destructors of temporaries in initialization expression should be called // after initialization finishes. Expr *Init = I->getInit(); if (Init) { - if (FieldDecl *FD = I->getAnyMember()) - IsReference = FD->getType()->isReferenceType(); HasTemporaries = isa<ExprWithCleanups>(Init); if (BuildOpts.AddTemporaryDtors && HasTemporaries) { // Generate destructors for temporaries in initialization expression. + TempDtorContext Context; VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(), - IsReference); + /*BindToTemporary=*/false, Context); } } @@ -1946,7 +2014,6 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { return Block; } - bool IsReference = false; bool HasTemporaries = false; // Guard static initializers under a branch. @@ -1968,13 +2035,13 @@ CFGBlock *CFGBuilder::VisitDeclSubExpr(DeclStmt *DS) { // after initialization finishes. Expr *Init = VD->getInit(); if (Init) { - IsReference = VD->getType()->isReferenceType(); HasTemporaries = isa<ExprWithCleanups>(Init); if (BuildOpts.AddTemporaryDtors && HasTemporaries) { // Generate destructors for temporaries in initialization expression. + TempDtorContext Context; VisitForTemporaryDtors(cast<ExprWithCleanups>(Init)->getSubExpr(), - IsReference); + /*BindToTemporary=*/false, Context); } } @@ -3354,7 +3421,8 @@ CFGBlock *CFGBuilder::VisitExprWithCleanups(ExprWithCleanups *E, if (BuildOpts.AddTemporaryDtors) { // If adding implicit destructors visit the full expression for adding // destructors of temporaries. - VisitForTemporaryDtors(E->getSubExpr()); + TempDtorContext Context; + VisitForTemporaryDtors(E->getSubExpr(), false, Context); // Full expression has to be added as CFGStmt so it will be sequenced // before destructors of it's temporaries. @@ -3463,7 +3531,8 @@ CFGBlock *CFGBuilder::VisitIndirectGotoStmt(IndirectGotoStmt *I) { return addStmt(I->getTarget()); } -CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary) { +CFGBlock *CFGBuilder::VisitForTemporaryDtors(Stmt *E, bool BindToTemporary, + TempDtorContext &Context) { assert(BuildOpts.AddImplicitDtors && BuildOpts.AddTemporaryDtors); tryAgain: @@ -3473,32 +3542,52 @@ tryAgain: } switch (E->getStmtClass()) { default: - return VisitChildrenForTemporaryDtors(E); + return VisitChildrenForTemporaryDtors(E, Context); case Stmt::BinaryOperatorClass: - return VisitBinaryOperatorForTemporaryDtors(cast<BinaryOperator>(E)); + return VisitBinaryOperatorForTemporaryDtors(cast<BinaryOperator>(E), + Context); case Stmt::CXXBindTemporaryExprClass: return VisitCXXBindTemporaryExprForTemporaryDtors( - cast<CXXBindTemporaryExpr>(E), BindToTemporary); + cast<CXXBindTemporaryExpr>(E), BindToTemporary, Context); case Stmt::BinaryConditionalOperatorClass: case Stmt::ConditionalOperatorClass: return VisitConditionalOperatorForTemporaryDtors( - cast<AbstractConditionalOperator>(E), BindToTemporary); + cast<AbstractConditionalOperator>(E), BindToTemporary, Context); case Stmt::ImplicitCastExprClass: // For implicit cast we want BindToTemporary to be passed further. E = cast<CastExpr>(E)->getSubExpr(); goto tryAgain; + case Stmt::CXXFunctionalCastExprClass: + // For functional cast we want BindToTemporary to be passed further. + E = cast<CXXFunctionalCastExpr>(E)->getSubExpr(); + goto tryAgain; + case Stmt::ParenExprClass: E = cast<ParenExpr>(E)->getSubExpr(); goto tryAgain; - case Stmt::MaterializeTemporaryExprClass: - E = cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(); + case Stmt::MaterializeTemporaryExprClass: { + const MaterializeTemporaryExpr* MTE = cast<MaterializeTemporaryExpr>(E); + BindToTemporary = (MTE->getStorageDuration() != SD_FullExpression); + SmallVector<const Expr *, 2> CommaLHSs; + SmallVector<SubobjectAdjustment, 2> Adjustments; + // Find the expression whose lifetime needs to be extended. + E = const_cast<Expr *>( + cast<MaterializeTemporaryExpr>(E) + ->GetTemporaryExpr() + ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments)); + // Visit the skipped comma operator left-hand sides for other temporaries. + for (const Expr *CommaLHS : CommaLHSs) { + VisitForTemporaryDtors(const_cast<Expr *>(CommaLHS), + /*BindToTemporary=*/false, Context); + } goto tryAgain; + } case Stmt::BlockExprClass: // Don't recurse into blocks; their subexpressions don't get evaluated @@ -3511,7 +3600,8 @@ tryAgain: auto *LE = cast<LambdaExpr>(E); CFGBlock *B = Block; for (Expr *Init : LE->capture_inits()) { - if (CFGBlock *R = VisitForTemporaryDtors(Init)) + if (CFGBlock *R = VisitForTemporaryDtors( + Init, /*BindToTemporary=*/false, Context)) B = R; } return B; @@ -3527,7 +3617,13 @@ tryAgain: } } -CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E) { +CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E, + TempDtorContext &Context) { + if (isa<LambdaExpr>(E)) { + // Do not visit the children of lambdas; they have their own CFGs. + return Block; + } + // When visiting children for destructors we want to visit them in reverse // order that they will appear in the CFG. Because the CFG is built // bottom-up, this means we visit them in their natural order, which @@ -3535,165 +3631,126 @@ CFGBlock *CFGBuilder::VisitChildrenForTemporaryDtors(Stmt *E) { CFGBlock *B = Block; for (Stmt::child_range I = E->children(); I; ++I) { if (Stmt *Child = *I) - if (CFGBlock *R = VisitForTemporaryDtors(Child)) + if (CFGBlock *R = VisitForTemporaryDtors(Child, false, Context)) B = R; } return B; } -CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors(BinaryOperator *E) { +CFGBlock *CFGBuilder::VisitBinaryOperatorForTemporaryDtors( + BinaryOperator *E, TempDtorContext &Context) { if (E->isLogicalOp()) { - // Destructors for temporaries in LHS expression should be called after - // those for RHS expression. Even if this will unnecessarily create a block, - // this block will be used at least by the full expression. - autoCreateBlock(); - CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getLHS()); - if (badCFG) - return nullptr; - - Succ = ConfluenceBlock; - Block = nullptr; - CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS()); - - if (RHSBlock) { - if (badCFG) - return nullptr; + VisitForTemporaryDtors(E->getLHS(), false, Context); + TryResult RHSExecuted = tryEvaluateBool(E->getLHS()); + if (RHSExecuted.isKnown() && E->getOpcode() == BO_LOr) + RHSExecuted.negate(); + + // We do not know at CFG-construction time whether the right-hand-side was + // executed, thus we add a branch node that depends on the temporary + // constructor call. + TempDtorContext RHSContext( + bothKnownTrue(Context.KnownExecuted, RHSExecuted)); + VisitForTemporaryDtors(E->getRHS(), false, RHSContext); + InsertTempDtorDecisionBlock(RHSContext); - // If RHS expression did produce destructors we need to connect created - // blocks to CFG in same manner as for binary operator itself. - CFGBlock *LHSBlock = createBlock(false); - LHSBlock->setTerminator(CFGTerminator(E, true)); - - // For binary operator LHS block is before RHS in list of predecessors - // of ConfluenceBlock. - std::reverse(ConfluenceBlock->pred_begin(), - ConfluenceBlock->pred_end()); - - // See if this is a known constant. - TryResult KnownVal = tryEvaluateBool(E->getLHS()); - if (KnownVal.isKnown() && (E->getOpcode() == BO_LOr)) - KnownVal.negate(); - - // Link LHSBlock with RHSBlock exactly the same way as for binary operator - // itself. - if (E->getOpcode() == BO_LOr) { - addSuccessor(LHSBlock, KnownVal.isTrue() ? nullptr : ConfluenceBlock); - addSuccessor(LHSBlock, KnownVal.isFalse() ? nullptr : RHSBlock); - } else { - assert (E->getOpcode() == BO_LAnd); - addSuccessor(LHSBlock, KnownVal.isFalse() ? nullptr : RHSBlock); - addSuccessor(LHSBlock, KnownVal.isTrue() ? nullptr : ConfluenceBlock); - } - - Block = LHSBlock; - return LHSBlock; - } - - Block = ConfluenceBlock; - return ConfluenceBlock; + return Block; } if (E->isAssignmentOp()) { // For assignment operator (=) LHS expression is visited // before RHS expression. For destructors visit them in reverse order. - CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS()); - CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS()); + CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), false, Context); + CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context); return LHSBlock ? LHSBlock : RHSBlock; } // For any other binary operator RHS expression is visited before // LHS expression (order of children). For destructors visit them in reverse // order. - CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS()); - CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS()); + CFGBlock *LHSBlock = VisitForTemporaryDtors(E->getLHS(), false, Context); + CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getRHS(), false, Context); return RHSBlock ? RHSBlock : LHSBlock; } CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors( - CXXBindTemporaryExpr *E, bool BindToTemporary) { + CXXBindTemporaryExpr *E, bool BindToTemporary, TempDtorContext &Context) { // First add destructors for temporaries in subexpression. - CFGBlock *B = VisitForTemporaryDtors(E->getSubExpr()); + CFGBlock *B = VisitForTemporaryDtors(E->getSubExpr(), false, Context); if (!BindToTemporary) { // If lifetime of temporary is not prolonged (by assigning to constant // reference) add destructor for it. - // If the destructor is marked as a no-return destructor, we need to create - // a new block for the destructor which does not have as a successor - // anything built thus far. Control won't flow out of this block. const CXXDestructorDecl *Dtor = E->getTemporary()->getDestructor(); + if (Dtor->isNoReturn()) { - Succ = B; + // If the destructor is marked as a no-return destructor, we need to + // create a new block for the destructor which does not have as a + // successor anything built thus far. Control won't flow out of this + // block. + if (B) Succ = B; Block = createNoReturnBlock(); + } else if (Context.needsTempDtorBranch()) { + // If we need to introduce a branch, we add a new block that we will hook + // up to a decision block later. + if (B) Succ = B; + Block = createBlock(); } else { autoCreateBlock(); } - + if (Context.needsTempDtorBranch()) { + Context.setDecisionPoint(Succ, E); + } appendTemporaryDtor(Block, E); + B = Block; } return B; } -CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors( - AbstractConditionalOperator *E, bool BindToTemporary) { - // First add destructors for condition expression. Even if this will - // unnecessarily create a block, this block will be used at least by the full - // expression. - autoCreateBlock(); - CFGBlock *ConfluenceBlock = VisitForTemporaryDtors(E->getCond()); - if (badCFG) - return nullptr; - if (BinaryConditionalOperator *BCO - = dyn_cast<BinaryConditionalOperator>(E)) { - ConfluenceBlock = VisitForTemporaryDtors(BCO->getCommon()); - if (badCFG) - return nullptr; - } - - // Try to add block with destructors for LHS expression. - CFGBlock *LHSBlock = nullptr; - Succ = ConfluenceBlock; - Block = nullptr; - LHSBlock = VisitForTemporaryDtors(E->getTrueExpr(), BindToTemporary); - if (badCFG) - return nullptr; - - // Try to add block with destructors for RHS expression; - Succ = ConfluenceBlock; - Block = nullptr; - CFGBlock *RHSBlock = VisitForTemporaryDtors(E->getFalseExpr(), - BindToTemporary); - if (badCFG) - return nullptr; - - if (!RHSBlock && !LHSBlock) { - // If neither LHS nor RHS expression had temporaries to destroy don't create - // more blocks. - Block = ConfluenceBlock; - return Block; +void CFGBuilder::InsertTempDtorDecisionBlock(const TempDtorContext &Context, + CFGBlock *FalseSucc) { + if (!Context.TerminatorExpr) { + // If no temporary was found, we do not need to insert a decision point. + return; } + assert(Context.TerminatorExpr); + CFGBlock *Decision = createBlock(false); + Decision->setTerminator(CFGTerminator(Context.TerminatorExpr, true)); + addSuccessor(Decision, Block, !Context.KnownExecuted.isFalse()); + addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ, + !Context.KnownExecuted.isTrue()); + Block = Decision; +} - Block = createBlock(false); - Block->setTerminator(CFGTerminator(E, true)); - assert(Block->getTerminator().isTemporaryDtorsBranch()); - - // See if this is a known constant. - const TryResult &KnownVal = tryEvaluateBool(E->getCond()); - - if (LHSBlock) { - addSuccessor(Block, LHSBlock, !KnownVal.isFalse()); - } else if (KnownVal.isFalse()) { - addSuccessor(Block, nullptr); +CFGBlock *CFGBuilder::VisitConditionalOperatorForTemporaryDtors( + AbstractConditionalOperator *E, bool BindToTemporary, + TempDtorContext &Context) { + VisitForTemporaryDtors(E->getCond(), false, Context); + CFGBlock *ConditionBlock = Block; + CFGBlock *ConditionSucc = Succ; + TryResult ConditionVal = tryEvaluateBool(E->getCond()); + TryResult NegatedVal = ConditionVal; + if (NegatedVal.isKnown()) NegatedVal.negate(); + + TempDtorContext TrueContext( + bothKnownTrue(Context.KnownExecuted, ConditionVal)); + VisitForTemporaryDtors(E->getTrueExpr(), BindToTemporary, TrueContext); + CFGBlock *TrueBlock = Block; + + Block = ConditionBlock; + Succ = ConditionSucc; + TempDtorContext FalseContext( + bothKnownTrue(Context.KnownExecuted, NegatedVal)); + VisitForTemporaryDtors(E->getFalseExpr(), BindToTemporary, FalseContext); + + if (TrueContext.TerminatorExpr && FalseContext.TerminatorExpr) { + InsertTempDtorDecisionBlock(FalseContext, TrueBlock); + } else if (TrueContext.TerminatorExpr) { + Block = TrueBlock; + InsertTempDtorDecisionBlock(TrueContext); } else { - addSuccessor(Block, ConfluenceBlock); - std::reverse(ConfluenceBlock->pred_begin(), ConfluenceBlock->pred_end()); + InsertTempDtorDecisionBlock(FalseContext); } - - if (!RHSBlock) - RHSBlock = ConfluenceBlock; - - addSuccessor(Block, RHSBlock, !KnownVal.isTrue()); - return Block; } @@ -3718,10 +3775,9 @@ CFGBlock *CFG::createBlock() { return &back(); } -/// buildCFG - Constructs a CFG from an AST. Ownership of the returned -/// CFG is returned to the caller. -CFG* CFG::buildCFG(const Decl *D, Stmt *Statement, ASTContext *C, - const BuildOptions &BO) { +/// buildCFG - Constructs a CFG from an AST. +std::unique_ptr<CFG> CFG::buildCFG(const Decl *D, Stmt *Statement, + ASTContext *C, const BuildOptions &BO) { CFGBuilder Builder(C, BO); return Builder.buildCFG(D, Statement); } diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 461ffb0900bb..1df093d85098 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -11,6 +11,7 @@ add_clang_library(clangAnalysis CallGraph.cpp CocoaConventions.cpp Consumed.cpp + CodeInjector.cpp Dominators.cpp FormatString.cpp LiveVariables.cpp diff --git a/lib/Analysis/CallGraph.cpp b/lib/Analysis/CallGraph.cpp index f41a96d30ea5..91a8492eaa54 100644 --- a/lib/Analysis/CallGraph.cpp +++ b/lib/Analysis/CallGraph.cpp @@ -110,14 +110,13 @@ CallGraph::~CallGraph() { bool CallGraph::includeInGraph(const Decl *D) { assert(D); - if (!D->getBody()) + if (!D->hasBody()) return false; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { // We skip function template definitions, as their semantics is // only determined when they are instantiated. - if (!FD->isThisDeclarationADefinition() || - FD->isDependentContext()) + if (FD->isDependentContext()) return false; IdentifierInfo *II = FD->getIdentifier(); @@ -125,11 +124,6 @@ bool CallGraph::includeInGraph(const Decl *D) { return false; } - if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) { - if (!ID->isThisDeclarationADefinition()) - return false; - } - return true; } @@ -152,6 +146,9 @@ CallGraphNode *CallGraph::getNode(const Decl *F) const { } CallGraphNode *CallGraph::getOrInsertNode(Decl *F) { + if (F && !isa<ObjCMethodDecl>(F)) + F = F->getCanonicalDecl(); + CallGraphNode *&Node = FunctionMap[F]; if (Node) return Node; diff --git a/lib/Analysis/CodeInjector.cpp b/lib/Analysis/CodeInjector.cpp new file mode 100644 index 000000000000..76bf364444d1 --- /dev/null +++ b/lib/Analysis/CodeInjector.cpp @@ -0,0 +1,15 @@ +//===-- CodeInjector.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Analysis/CodeInjector.h" + +using namespace clang; + +CodeInjector::CodeInjector() {} +CodeInjector::~CodeInjector() {} diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp index 851b97e5bc1d..8c663d856f6a 100644 --- a/lib/Analysis/FormatString.cpp +++ b/lib/Analysis/FormatString.cpp @@ -244,6 +244,8 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, ++I; lmKind = LengthModifier::AsInt3264; break; + case 'w': + lmKind = LengthModifier::AsWide; ++I; break; } LengthModifier lm(lmPosition, lmKind); FS.setLengthModifier(lm); @@ -504,6 +506,8 @@ analyze_format_string::LengthModifier::toString() const { return "a"; case AsMAllocate: return "m"; + case AsWide: + return "w"; case None: return ""; } @@ -550,6 +554,9 @@ const char *ConversionSpecifier::toString() const { // GlibC specific specifiers. case PrintErrno: return "m"; + + // MS specific specifiers. + case ZArg: return "Z"; } return nullptr; } @@ -608,8 +615,21 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { return true; // Handle most integer flags - case LengthModifier::AsChar: case LengthModifier::AsShort: + if (Target.getTriple().isOSMSVCRT()) { + switch (CS.getKind()) { + case ConversionSpecifier::cArg: + case ConversionSpecifier::CArg: + case ConversionSpecifier::sArg: + case ConversionSpecifier::SArg: + case ConversionSpecifier::ZArg: + return true; + default: + break; + } + } + // Fall through. + case LengthModifier::AsChar: case LengthModifier::AsLongLong: case LengthModifier::AsQuad: case LengthModifier::AsIntMax: @@ -632,7 +652,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { } // Handle 'l' flag - case LengthModifier::AsLong: + case LengthModifier::AsLong: // or AsWideChar switch (CS.getKind()) { case ConversionSpecifier::dArg: case ConversionSpecifier::DArg: @@ -655,6 +675,7 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { case ConversionSpecifier::cArg: case ConversionSpecifier::sArg: case ConversionSpecifier::ScanListArg: + case ConversionSpecifier::ZArg: return true; default: return false; @@ -719,6 +740,17 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { default: return false; } + case LengthModifier::AsWide: + switch (CS.getKind()) { + case ConversionSpecifier::cArg: + case ConversionSpecifier::CArg: + case ConversionSpecifier::sArg: + case ConversionSpecifier::SArg: + case ConversionSpecifier::ZArg: + return Target.getTriple().isOSMSVCRT(); + default: + return false; + } } llvm_unreachable("Invalid LengthModifier Kind!"); } @@ -741,6 +773,7 @@ bool FormatSpecifier::hasStandardLengthModifier() const { case LengthModifier::AsInt32: case LengthModifier::AsInt3264: case LengthModifier::AsInt64: + case LengthModifier::AsWide: return false; } llvm_unreachable("Invalid LengthModifier Kind!"); @@ -778,6 +811,7 @@ bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt) case ConversionSpecifier::DArg: case ConversionSpecifier::OArg: case ConversionSpecifier::UArg: + case ConversionSpecifier::ZArg: return false; } llvm_unreachable("Invalid ConversionSpecifier Kind!"); diff --git a/lib/Analysis/FormatStringParsing.h b/lib/Analysis/FormatStringParsing.h index fba318042cb0..e1652964b8c2 100644 --- a/lib/Analysis/FormatStringParsing.h +++ b/lib/Analysis/FormatStringParsing.h @@ -1,5 +1,5 @@ -#ifndef LLVM_CLANG_FORMAT_PARSING_H -#define LLVM_CLANG_FORMAT_PARSING_H +#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H +#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H #include "clang/AST/ASTContext.h" #include "clang/AST/Type.h" diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 3d6fc039fd77..86b679cb155b 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -82,7 +82,6 @@ namespace { class LiveVariablesImpl { public: AnalysisDeclContext &analysisContext; - std::vector<LiveVariables::LivenessValues> cfgBlockValues; llvm::ImmutableSet<const Stmt *>::Factory SSetFact; llvm::ImmutableSet<const VarDecl *>::Factory DSetFact; llvm::DenseMap<const CFGBlock *, LiveVariables::LivenessValues> blocksEndToLiveness; diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 082a8327a346..146635b88702 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -54,7 +54,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, const char *E, unsigned &argIndex, const LangOptions &LO, - const TargetInfo &Target) { + const TargetInfo &Target, + bool Warn) { using namespace clang::analyze_format_string; using namespace clang::analyze_printf; @@ -83,7 +84,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, if (I == E) { // No more characters left? - H.HandleIncompleteSpecifier(Start, E - Start); + if (Warn) + H.HandleIncompleteSpecifier(Start, E - Start); return true; } @@ -93,7 +95,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, if (I == E) { // No more characters left? - H.HandleIncompleteSpecifier(Start, E - Start); + if (Warn) + H.HandleIncompleteSpecifier(Start, E - Start); return true; } @@ -118,7 +121,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, if (I == E) { // No more characters left? - H.HandleIncompleteSpecifier(Start, E - Start); + if (Warn) + H.HandleIncompleteSpecifier(Start, E - Start); return true; } @@ -129,7 +133,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, if (I == E) { // No more characters left? - H.HandleIncompleteSpecifier(Start, E - Start); + if (Warn) + H.HandleIncompleteSpecifier(Start, E - Start); return true; } @@ -137,7 +142,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, if (*I == '.') { ++I; if (I == E) { - H.HandleIncompleteSpecifier(Start, E - Start); + if (Warn) + H.HandleIncompleteSpecifier(Start, E - Start); return true; } @@ -147,7 +153,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, if (I == E) { // No more characters left? - H.HandleIncompleteSpecifier(Start, E - Start); + if (Warn) + H.HandleIncompleteSpecifier(Start, E - Start); return true; } } @@ -155,7 +162,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, // Look for the length modifier. if (ParseLengthModifier(FS, I, E, LO) && I == E) { // No more characters left? - H.HandleIncompleteSpecifier(Start, E - Start); + if (Warn) + H.HandleIncompleteSpecifier(Start, E - Start); return true; } @@ -198,7 +206,7 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; - // Apple-specific + // Apple-specific. case 'D': if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::DArg; @@ -211,6 +219,10 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::UArg; break; + // MS specific. + case 'Z': + if (Target.getTriple().isOSMSVCRT()) + k = ConversionSpecifier::ZArg; } PrintfConversionSpecifier CS(conversionPosition, k); FS.setConversionSpecifier(CS); @@ -235,7 +247,7 @@ bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, // Keep looking for a format specifier until we have exhausted the string. while (I != E) { const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, - LO, Target); + LO, Target, true); // Did a fail-stop error of any kind occur when parsing the specifier? // If so, don't do any more processing. if (FSR.shouldStop()) @@ -253,6 +265,34 @@ bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, return false; } +bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I, + const char *E, + const LangOptions &LO, + const TargetInfo &Target) { + + unsigned argIndex = 0; + + // Keep looking for a %s format specifier until we have exhausted the string. + FormatStringHandler H; + while (I != E) { + const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, + LO, Target, false); + // 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 false; + // Did we exhaust the string or encounter an error that + // we can recover from? + if (!FSR.hasValue()) + continue; + const analyze_printf::PrintfSpecifier &FS = FSR.getValue(); + // Return true if this a %s format specifier. + if (FS.getConversionSpecifier().getKind() == ConversionSpecifier::Kind::sArg) + return true; + } + return false; +} + //===----------------------------------------------------------------------===// // Methods on PrintfSpecifier. //===----------------------------------------------------------------------===// @@ -266,9 +306,14 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, if (CS.getKind() == ConversionSpecifier::cArg) switch (LM.getKind()) { - case LengthModifier::None: return Ctx.IntTy; + case LengthModifier::None: + return Ctx.IntTy; case LengthModifier::AsLong: + case LengthModifier::AsWide: return ArgType(ArgType::WIntTy, "wint_t"); + case LengthModifier::AsShort: + if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) + return Ctx.IntTy; default: return ArgType::Invalid(); } @@ -303,6 +348,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, return ArgType(Ctx.getPointerDiffType(), "ptrdiff_t"); case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: + case LengthModifier::AsWide: return ArgType::Invalid(); } @@ -337,6 +383,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, return ArgType(); case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: + case LengthModifier::AsWide: return ArgType::Invalid(); } @@ -372,6 +419,7 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, case LengthModifier::AsInt32: case LengthModifier::AsInt3264: case LengthModifier::AsInt64: + case LengthModifier::AsWide: return ArgType::Invalid(); } } @@ -384,15 +432,23 @@ ArgType PrintfSpecifier::getArgType(ASTContext &Ctx, "const unichar *"); return ArgType(ArgType::WCStrTy, "wchar_t *"); } + if (LM.getKind() == LengthModifier::AsWide) + return ArgType(ArgType::WCStrTy, "wchar_t *"); return ArgType::CStrTy; case ConversionSpecifier::SArg: if (IsObjCLiteral) return ArgType(Ctx.getPointerType(Ctx.UnsignedShortTy.withConst()), "const unichar *"); + if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && + LM.getKind() == LengthModifier::AsShort) + return ArgType::CStrTy; return ArgType(ArgType::WCStrTy, "wchar_t *"); case ConversionSpecifier::CArg: if (IsObjCLiteral) return ArgType(Ctx.UnsignedShortTy, "unichar"); + if (Ctx.getTargetInfo().getTriple().isOSMSVCRT() && + LM.getKind() == LengthModifier::AsShort) + return Ctx.IntTy; return ArgType(Ctx.WideCharTy, "wchar_t"); case ConversionSpecifier::pArg: return ArgType::CPointerTy; diff --git a/lib/Analysis/ReachableCode.cpp b/lib/Analysis/ReachableCode.cpp index b4a72a7f8006..8165b09f4080 100644 --- a/lib/Analysis/ReachableCode.cpp +++ b/lib/Analysis/ReachableCode.cpp @@ -13,15 +13,15 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/Analyses/ReachableCode.h" -#include "clang/Lex/Preprocessor.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" -#include "clang/AST/StmtCXX.h" #include "clang/AST/ParentMap.h" +#include "clang/AST/StmtCXX.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "clang/Basic/SourceManager.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallVector.h" diff --git a/lib/Analysis/ScanfFormatString.cpp b/lib/Analysis/ScanfFormatString.cpp index ed286274950b..d484d8e828cb 100644 --- a/lib/Analysis/ScanfFormatString.cpp +++ b/lib/Analysis/ScanfFormatString.cpp @@ -257,6 +257,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsMAllocate: case LengthModifier::AsInt32: case LengthModifier::AsInt3264: + case LengthModifier::AsWide: return ArgType::Invalid(); } @@ -295,6 +296,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsMAllocate: case LengthModifier::AsInt32: case LengthModifier::AsInt3264: + case LengthModifier::AsWide: return ArgType::Invalid(); } @@ -326,10 +328,14 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::None: return ArgType::PtrTo(ArgType::AnyCharTy); case LengthModifier::AsLong: + case LengthModifier::AsWide: return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t")); case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: return ArgType::PtrTo(ArgType::CStrTy); + case LengthModifier::AsShort: + if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) + return ArgType::PtrTo(ArgType::AnyCharTy); default: return ArgType::Invalid(); } @@ -338,10 +344,14 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { // FIXME: Mac OS X specific? switch (LM.getKind()) { case LengthModifier::None: + case LengthModifier::AsWide: return ArgType::PtrTo(ArgType(Ctx.getWideCharType(), "wchar_t")); case LengthModifier::AsAllocate: case LengthModifier::AsMAllocate: return ArgType::PtrTo(ArgType(ArgType::WCStrTy, "wchar_t *")); + case LengthModifier::AsShort: + if (Ctx.getTargetInfo().getTriple().isOSMSVCRT()) + return ArgType::PtrTo(ArgType::AnyCharTy); default: return ArgType::Invalid(); } @@ -378,6 +388,7 @@ ArgType ScanfSpecifier::getArgType(ASTContext &Ctx) const { case LengthModifier::AsMAllocate: case LengthModifier::AsInt32: case LengthModifier::AsInt3264: + case LengthModifier::AsWide: return ArgType::Invalid(); } diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index 11df61f80fa0..a986c587f869 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -22,10 +22,10 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/Analyses/ThreadSafety.h" +#include "clang/Analysis/Analyses/ThreadSafetyCommon.h" #include "clang/Analysis/Analyses/ThreadSafetyLogical.h" #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" -#include "clang/Analysis/Analyses/ThreadSafetyCommon.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/CFGStmtMap.h" @@ -40,762 +40,111 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <ostream> +#include <sstream> #include <utility> #include <vector> -using namespace clang; -using namespace thread_safety; + +namespace clang { +namespace threadSafety { // Key method definition ThreadSafetyHandler::~ThreadSafetyHandler() {} -namespace { - -/// SExpr implements a simple expression language that is used to store, -/// compare, and pretty-print C++ expressions. Unlike a clang Expr, a SExpr -/// does not capture surface syntax, and it does not distinguish between -/// C++ concepts, like pointers and references, that have no real semantic -/// differences. This simplicity allows SExprs to be meaningfully compared, -/// e.g. -/// (x) = x -/// (*this).foo = this->foo -/// *&a = a -/// -/// Thread-safety analysis works by comparing lock expressions. Within the -/// body of a function, an expression such as "x->foo->bar.mu" will resolve to -/// a particular mutex object at run-time. Subsequent occurrences of the same -/// expression (where "same" means syntactic equality) will refer to the same -/// run-time object if three conditions hold: -/// (1) Local variables in the expression, such as "x" have not changed. -/// (2) Values on the heap that affect the expression have not changed. -/// (3) The expression involves only pure function calls. -/// -/// The current implementation assumes, but does not verify, that multiple uses -/// of the same lock expression satisfies these criteria. -class SExpr { -private: - enum ExprOp { - 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 - - public: - SExprNode(ExprOp O, unsigned F, const void* D) - : Op(static_cast<unsigned char>(O)), - Flags(static_cast<unsigned char>(F)), Sz(1), Data(D) - { } - - unsigned size() const { return Sz; } - void setSize(unsigned S) { Sz = S; } - - ExprOp kind() const { return static_cast<ExprOp>(Op); } - - const NamedDecl* getNamedDecl() const { - assert(Op == EOP_NVar || Op == EOP_LVar || Op == EOP_Dot); - return reinterpret_cast<const NamedDecl*>(Data); - } - - const NamedDecl* getFunctionDecl() const { - assert(Op == EOP_Call || Op == EOP_MCall); - return reinterpret_cast<const NamedDecl*>(Data); - } - - bool isArrow() const { return Op == EOP_Dot && Flags == 1; } - void setArrow(bool A) { Flags = A ? 1 : 0; } - - unsigned arity() const { - switch (Op) { - 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; - } - - bool operator==(const SExprNode& Other) const { - // Ignore flags and size -- they don't matter. - return (Op == Other.Op && - Data == Other.Data); - } - - bool operator!=(const SExprNode& Other) const { - return !(*this == Other); - } - - bool matches(const SExprNode& Other) const { - return (*this == Other) || - (Op == EOP_Wildcard) || - (Other.Op == EOP_Wildcard); - } - }; - - - /// \brief Encapsulates the lexical context of a function call. The lexical - /// context includes the arguments to the call, including the implicit object - /// argument. When an attribute containing a mutex expression is attached to - /// a method, the expression may refer to formal parameters of the method. - /// Actual arguments must be substituted for formal parameters to derive - /// the appropriate mutex expression in the lexical context where the function - /// is called. PrevCtx holds the context in which the arguments themselves - /// should be evaluated; multiple calling contexts can be chained together - /// by the lock_returned attribute. - struct CallingContext { - const NamedDecl* AttrDecl; // The decl to which the attribute is attached. - const Expr* SelfArg; // Implicit object argument -- e.g. 'this' - bool SelfArrow; // is Self referred to with -> or .? - unsigned NumArgs; // Number of funArgs - const Expr* const* FunArgs; // Function arguments - CallingContext* PrevCtx; // The previous context; or 0 if none. - - CallingContext(const NamedDecl *D) - : AttrDecl(D), SelfArg(nullptr), SelfArrow(false), NumArgs(0), - FunArgs(nullptr), PrevCtx(nullptr) {} - }; - - typedef SmallVector<SExprNode, 4> NodeVector; - -private: - // A SExpr is a list of SExprNodes in prefix order. The Size field allows - // the list to be traversed as a tree. - NodeVector NodeVec; - -private: - unsigned make(ExprOp O, unsigned F = 0, const void *D = nullptr) { - NodeVec.push_back(SExprNode(O, F, D)); - return NodeVec.size() - 1; - } - - unsigned makeNop() { - return make(EOP_Nop); - } - - unsigned makeWildcard() { - return make(EOP_Wildcard); - } - - unsigned makeUniversal() { - return make(EOP_Universal); - } - - unsigned makeNamedVar(const NamedDecl *D) { - return make(EOP_NVar, 0, D); - } - - unsigned makeLocalVar(const NamedDecl *D) { - return make(EOP_LVar, 0, D); - } - - unsigned makeThis() { - return make(EOP_This); - } - - unsigned makeDot(const NamedDecl *D, bool Arrow) { - return make(EOP_Dot, Arrow ? 1 : 0, D); - } - - unsigned makeCall(unsigned NumArgs, const NamedDecl *D) { - return make(EOP_Call, 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 nullptr; - } - - unsigned makeMCall(unsigned NumArgs, const CXXMethodDecl *D) { - return make(EOP_MCall, NumArgs, getFirstVirtualDecl(D)); - } - - unsigned makeIndex() { - return make(EOP_Index); - } - - unsigned makeUnary() { - return make(EOP_Unary); - } - - unsigned makeBinary() { - return make(EOP_Binary); - } - - unsigned makeUnknown(unsigned Arity) { - return make(EOP_Unknown, Arity); - } - - inline bool isCalleeArrow(const Expr *E) { - const MemberExpr *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts()); - return ME ? ME->isArrow() : false; - } - - /// Build an SExpr from the given C++ expression. - /// Recursive function that terminates on DeclRefExpr. - /// Note: this function merely creates a SExpr; it does not check to - /// ensure that the original expression is a valid mutex expression. - /// - /// NDeref returns the number of Derefence and AddressOf operations - /// preceding the Expr; this is used to decide whether to pretty-print - /// SExprs with . or ->. - unsigned buildSExpr(const Expr *Exp, CallingContext *CallCtx, - int *NDeref = nullptr) { - if (!Exp) - return 0; - - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Exp)) { - const NamedDecl *ND = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl()); - const ParmVarDecl *PV = dyn_cast_or_null<ParmVarDecl>(ND); - if (PV) { - const FunctionDecl *FD = - cast<FunctionDecl>(PV->getDeclContext())->getCanonicalDecl(); - unsigned i = PV->getFunctionScopeIndex(); +class TILPrinter : + public til::PrettyPrinter<TILPrinter, llvm::raw_ostream> {}; - if (CallCtx && CallCtx->FunArgs && - FD == CallCtx->AttrDecl->getCanonicalDecl()) { - // Substitute call arguments for references to function parameters - assert(i < CallCtx->NumArgs); - return buildSExpr(CallCtx->FunArgs[i], CallCtx->PrevCtx, NDeref); - } - // Map the param back to the param of the original function declaration. - makeNamedVar(FD->getParamDecl(i)); - return 1; - } - // Not a function parameter -- just store the reference. - makeNamedVar(ND); - return 1; - } else if (isa<CXXThisExpr>(Exp)) { - // Substitute parent for 'this' - if (CallCtx && CallCtx->SelfArg) { - if (!CallCtx->SelfArrow && NDeref) - // 'this' is a pointer, but self is not, so need to take address. - --(*NDeref); - return buildSExpr(CallCtx->SelfArg, CallCtx->PrevCtx, NDeref); - } - else { - makeThis(); - return 1; - } - } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(Exp)) { - const NamedDecl *ND = ME->getMemberDecl(); - int ImplicitDeref = ME->isArrow() ? 1 : 0; - unsigned Root = makeDot(ND, false); - unsigned Sz = buildSExpr(ME->getBase(), CallCtx, &ImplicitDeref); - NodeVec[Root].setArrow(ImplicitDeref > 0); - NodeVec[Root].setSize(Sz + 1); - return Sz + 1; - } else if (const 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. - const CXXMethodDecl *MD = CMCE->getMethodDecl()->getMostRecentDecl(); - if (LockReturnedAttr* At = MD->getAttr<LockReturnedAttr>()) { - CallingContext LRCallCtx(CMCE->getMethodDecl()); - LRCallCtx.SelfArg = CMCE->getImplicitObjectArgument(); - LRCallCtx.SelfArrow = isCalleeArrow(CMCE->getCallee()); - LRCallCtx.NumArgs = CMCE->getNumArgs(); - LRCallCtx.FunArgs = CMCE->getArgs(); - LRCallCtx.PrevCtx = CallCtx; - return buildSExpr(At->getArg(), &LRCallCtx); - } - // Hack to treat smart pointers and iterators as pointers; - // ignore any method named get(). - if (CMCE->getMethodDecl()->getNameAsString() == "get" && - CMCE->getNumArgs() == 0) { - if (NDeref && isCalleeArrow(CMCE->getCallee())) - ++(*NDeref); - return buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx, NDeref); - } - unsigned NumCallArgs = CMCE->getNumArgs(); - unsigned Root = makeMCall(NumCallArgs, CMCE->getMethodDecl()); - unsigned Sz = buildSExpr(CMCE->getImplicitObjectArgument(), CallCtx); - const Expr* const* CallArgs = CMCE->getArgs(); - for (unsigned i = 0; i < NumCallArgs; ++i) { - Sz += buildSExpr(CallArgs[i], CallCtx); - } - NodeVec[Root].setSize(Sz + 1); - return Sz + 1; - } else if (const CallExpr *CE = dyn_cast<CallExpr>(Exp)) { - const FunctionDecl *FD = CE->getDirectCallee()->getMostRecentDecl(); - if (LockReturnedAttr* At = FD->getAttr<LockReturnedAttr>()) { - CallingContext LRCallCtx(CE->getDirectCallee()); - LRCallCtx.NumArgs = CE->getNumArgs(); - LRCallCtx.FunArgs = CE->getArgs(); - LRCallCtx.PrevCtx = CallCtx; - return buildSExpr(At->getArg(), &LRCallCtx); - } - // Treat smart pointers and iterators as pointers; - // ignore the * and -> operators. - if (const CXXOperatorCallExpr *OE = dyn_cast<CXXOperatorCallExpr>(CE)) { - OverloadedOperatorKind k = OE->getOperator(); - if (k == OO_Star) { - if (NDeref) ++(*NDeref); - return buildSExpr(OE->getArg(0), CallCtx, NDeref); - } - else if (k == OO_Arrow) { - return buildSExpr(OE->getArg(0), CallCtx, NDeref); - } - } - unsigned NumCallArgs = CE->getNumArgs(); - unsigned Root = makeCall(NumCallArgs, nullptr); - unsigned Sz = buildSExpr(CE->getCallee(), CallCtx); - const Expr* const* CallArgs = CE->getArgs(); - for (unsigned i = 0; i < NumCallArgs; ++i) { - Sz += buildSExpr(CallArgs[i], CallCtx); - } - NodeVec[Root].setSize(Sz+1); - return Sz+1; - } else if (const BinaryOperator *BOE = dyn_cast<BinaryOperator>(Exp)) { - unsigned Root = makeBinary(); - unsigned Sz = buildSExpr(BOE->getLHS(), CallCtx); - Sz += buildSExpr(BOE->getRHS(), CallCtx); - NodeVec[Root].setSize(Sz); - return Sz; - } else if (const UnaryOperator *UOE = dyn_cast<UnaryOperator>(Exp)) { - // Ignore & and * operators -- they're no-ops. - // However, we try to figure out whether the expression is a pointer, - // so we can use . and -> appropriately in error messages. - if (UOE->getOpcode() == UO_Deref) { - if (NDeref) ++(*NDeref); - return buildSExpr(UOE->getSubExpr(), CallCtx, NDeref); - } - if (UOE->getOpcode() == UO_AddrOf) { - if (DeclRefExpr* DRE = dyn_cast<DeclRefExpr>(UOE->getSubExpr())) { - if (DRE->getDecl()->isCXXInstanceMember()) { - // This is a pointer-to-member expression, e.g. &MyClass::mu_. - // We interpret this syntax specially, as a wildcard. - unsigned Root = makeDot(DRE->getDecl(), false); - makeWildcard(); - NodeVec[Root].setSize(2); - return 2; - } - } - if (NDeref) --(*NDeref); - return buildSE |