diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-05-27 18:47:56 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-05-27 18:47:56 +0000 |
commit | 5e20cdd81c44a443562a09007668ffdf76c455af (patch) | |
tree | dbbd4047878da71c1a706e26ce05b4e7791b14cc /lib | |
parent | d5f23b0b7528b5c3caed1ba14f897cc4aaa9e3c3 (diff) | |
download | src-5e20cdd81c44a443562a09007668ffdf76c455af.tar.gz src-5e20cdd81c44a443562a09007668ffdf76c455af.zip |
Vendor import of clang trunk r238337:vendor/clang/clang-trunk-r238337
Notes
Notes:
svn path=/vendor/clang/dist/; revision=283627
svn path=/vendor/clang/clang-trunk-r238337/; revision=283628; tag=vendor/clang/clang-trunk-r238337
Diffstat (limited to 'lib')
321 files changed, 38669 insertions, 16497 deletions
diff --git a/lib/ARCMigrate/ARCMT.cpp b/lib/ARCMigrate/ARCMT.cpp index dddc886a269c..f266eaf83968 100644 --- a/lib/ARCMigrate/ARCMT.cpp +++ b/lib/ARCMigrate/ARCMT.cpp @@ -124,7 +124,7 @@ public: } } - virtual ~CaptureDiagnosticConsumer() { + ~CaptureDiagnosticConsumer() override { assert(!HasBegunSourceFile && "FinishCapture not called!"); } @@ -432,7 +432,7 @@ public: ARCMTMacroTrackerPPCallbacks(std::vector<SourceLocation> &ARCMTMacroLocs) : ARCMTMacroLocs(ARCMTMacroLocs) { } - void MacroExpands(const Token &MacroNameTok, const MacroDirective *MD, + void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, SourceRange Range, const MacroArgs *Args) override { if (MacroNameTok.getIdentifierInfo()->getName() == getARCMTMacroName()) ARCMTMacroLocs.push_back(MacroNameTok.getLocation()); @@ -465,7 +465,7 @@ public: if (Listener) Listener->start(ctx); } - ~RewritesApplicator() { + ~RewritesApplicator() override { if (Listener) Listener->finish(); } diff --git a/lib/ARCMigrate/ObjCMT.cpp b/lib/ARCMigrate/ObjCMT.cpp index 52c424c000f8..a43879c23655 100644 --- a/lib/ARCMigrate/ObjCMT.cpp +++ b/lib/ARCMigrate/ObjCMT.cpp @@ -48,7 +48,7 @@ class ObjCMigrateASTConsumer : public ASTConsumer { }; void migrateDecl(Decl *D); - void migrateObjCInterfaceDecl(ASTContext &Ctx, ObjCContainerDecl *D); + void migrateObjCContainerDecl(ASTContext &Ctx, ObjCContainerDecl *D); void migrateProtocolConformance(ASTContext &Ctx, const ObjCImplementationDecl *ImpDecl); void CacheObjCNSIntegerTypedefed(const TypedefDecl *TypedefDcl); @@ -245,17 +245,16 @@ namespace { (Msg->getReceiverKind() != ObjCMessageExpr::Instance && Msg->getReceiverKind() != ObjCMessageExpr::SuperInstance)) return false; + if (const Expr *Receiver = Msg->getInstanceReceiver()) + if (Receiver->getType()->isObjCBuiltinType()) + 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; @@ -305,6 +304,10 @@ namespace { BegLoc = PP.getLocForEndOfToken(BegLoc); SourceLocation EndLoc = RHS->getLocStart(); EndLoc = EndLoc.getLocWithOffset(-1); + const char *colon = PP.getSourceManager().getCharacterData(EndLoc); + // Add a space after '=' if there is no space between RHS and '=' + if (colon && colon[0] == ':') + PropertyDotString += " "; SourceRange Range(BegLoc, EndLoc); commit.replace(Range, PropertyDotString); // remove '[' ']' @@ -465,7 +468,7 @@ static void rewriteToObjCProperty(const ObjCMethodDecl *Getter, ASTContext &Context = NS.getASTContext(); bool LParenAdded = false; std::string PropertyString = "@property "; - if (UseNsIosOnlyMacro && Context.Idents.get("NS_NONATOMIC_IOSONLY").hasMacroDefinition()) { + if (UseNsIosOnlyMacro && NS.isMacroDefined("NS_NONATOMIC_IOSONLY")) { PropertyString += "(NS_NONATOMIC_IOSONLY"; LParenAdded = true; } else if (!Atomic) { @@ -575,7 +578,7 @@ static bool IsCategoryNameWithDeprecatedSuffix(ObjCContainerDecl *D) { return false; } -void ObjCMigrateASTConsumer::migrateObjCInterfaceDecl(ASTContext &Ctx, +void ObjCMigrateASTConsumer::migrateObjCContainerDecl(ASTContext &Ctx, ObjCContainerDecl *D) { if (D->isDeprecated() || IsCategoryNameWithDeprecatedSuffix(D)) return; @@ -616,7 +619,7 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, if (Property->getPropertyImplementation() == ObjCPropertyDecl::Optional) continue; HasAtleastOneRequiredProperty = true; - DeclContext::lookup_const_result R = IDecl->lookup(Property->getDeclName()); + DeclContext::lookup_result R = IDecl->lookup(Property->getDeclName()); if (R.size() == 0) { // Relax the rule and look into class's implementation for a synthesize // or dynamic declaration. Class is implementing a property coming from @@ -647,7 +650,7 @@ ClassImplementsAllMethodsAndProperties(ASTContext &Ctx, continue; if (MD->getImplementationControl() == ObjCMethodDecl::Optional) continue; - DeclContext::lookup_const_result R = ImpDecl->lookup(MD->getDeclName()); + DeclContext::lookup_result R = ImpDecl->lookup(MD->getDeclName()); if (R.size() == 0) return false; bool match = false; @@ -768,19 +771,34 @@ static void rewriteToNSMacroDecl(ASTContext &Ctx, const TypedefDecl *TypedefDcl, const NSAPI &NS, edit::Commit &commit, bool IsNSIntegerType) { - QualType EnumUnderlyingT = EnumDcl->getPromotionType(); - assert(!EnumUnderlyingT.isNull() + QualType DesignatedEnumType = EnumDcl->getIntegerType(); + assert(!DesignatedEnumType.isNull() && "rewriteToNSMacroDecl - underlying enum type is null"); PrintingPolicy Policy(Ctx.getPrintingPolicy()); - std::string TypeString = EnumUnderlyingT.getAsString(Policy); + std::string TypeString = DesignatedEnumType.getAsString(Policy); std::string ClassString = IsNSIntegerType ? "NS_ENUM(" : "NS_OPTIONS("; ClassString += TypeString; ClassString += ", "; ClassString += TypedefDcl->getIdentifier()->getName(); ClassString += ')'; - SourceRange R(EnumDcl->getLocStart(), EnumDcl->getLocStart()); + SourceLocation EndLoc; + if (EnumDcl->getIntegerTypeSourceInfo()) { + TypeSourceInfo *TSourceInfo = EnumDcl->getIntegerTypeSourceInfo(); + TypeLoc TLoc = TSourceInfo->getTypeLoc(); + EndLoc = TLoc.getLocEnd(); + const char *lbrace = Ctx.getSourceManager().getCharacterData(EndLoc); + unsigned count = 0; + if (lbrace) + while (lbrace[count] != '{') + ++count; + if (count > 0) + EndLoc = EndLoc.getLocWithOffset(count-1); + } + else + EndLoc = EnumDcl->getLocStart(); + SourceRange R(EnumDcl->getLocStart(), EndLoc); commit.replace(R, ClassString); // This is to remove spaces between '}' and typedef name. SourceLocation StartTypedefLoc = EnumDcl->getLocEnd(); @@ -902,7 +920,7 @@ bool ObjCMigrateASTConsumer::migrateNSEnumDecl(ASTContext &Ctx, const EnumDecl *EnumDcl, const TypedefDecl *TypedefDcl) { if (!EnumDcl->isCompleteDefinition() || EnumDcl->getIdentifier() || - EnumDcl->isDeprecated() || EnumDcl->getIntegerTypeSourceInfo()) + EnumDcl->isDeprecated()) return false; if (!TypedefDcl) { if (NSIntegerTypedefed) { @@ -1259,7 +1277,7 @@ void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx, QualType RT = OM->getReturnType(); if (!TypeIsInnerPointer(RT) || - !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition()) + !NSAPIObj->isMacroDefined("NS_RETURNS_INNER_POINTER")) return; edit::Commit commit(*Editor); @@ -1270,9 +1288,9 @@ void ObjCMigrateASTConsumer::migrateNsReturnsInnerPointer(ASTContext &Ctx, void ObjCMigrateASTConsumer::migratePropertyNsReturnsInnerPointer(ASTContext &Ctx, ObjCPropertyDecl *P) { QualType T = P->getType(); - + if (!TypeIsInnerPointer(T) || - !Ctx.Idents.get("NS_RETURNS_INNER_POINTER").hasMacroDefinition()) + !NSAPIObj->isMacroDefined("NS_RETURNS_INNER_POINTER")) return; edit::Commit commit(*Editor); commit.insertBefore(P->getLocEnd(), " NS_RETURNS_INNER_POINTER "); @@ -1390,7 +1408,7 @@ static bool AuditedType (QualType AT) { void ObjCMigrateASTConsumer::AnnotateImplicitBridging(ASTContext &Ctx) { if (CFFunctionIBCandidates.empty()) return; - if (!Ctx.Idents.get("CF_IMPLICIT_BRIDGING_ENABLED").hasMacroDefinition()) { + if (!NSAPIObj->isMacroDefined("CF_IMPLICIT_BRIDGING_ENABLED")) { CFFunctionIBCandidates.clear(); FileId = FileID(); return; @@ -1465,16 +1483,14 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, RetEffect Ret = CE.getReturnValue(); const char *AnnotationString = nullptr; if (Ret.getObjKind() == RetEffect::CF) { - if (Ret.isOwned() && - Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition()) + if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED")) AnnotationString = " CF_RETURNS_RETAINED"; else if (Ret.notOwned() && - Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition()) + NSAPIObj->isMacroDefined("CF_RETURNS_NOT_RETAINED")) AnnotationString = " CF_RETURNS_NOT_RETAINED"; } else if (Ret.getObjKind() == RetEffect::ObjC) { - if (Ret.isOwned() && - Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition()) + if (Ret.isOwned() && NSAPIObj->isMacroDefined("NS_RETURNS_RETAINED")) AnnotationString = " NS_RETURNS_RETAINED"; } @@ -1491,13 +1507,13 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, const ParmVarDecl *pd = *pi; ArgEffect AE = AEArgs[i]; if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>() && - Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { + NSAPIObj->isMacroDefined("CF_CONSUMED")) { edit::Commit commit(*Editor); commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); Editor->commit(commit); } else if (AE == DecRefMsg && !pd->hasAttr<NSConsumedAttr>() && - Ctx.Idents.get("NS_CONSUMED").hasMacroDefinition()) { + NSAPIObj->isMacroDefined("NS_CONSUMED")) { edit::Commit commit(*Editor); commit.insertBefore(pd->getLocation(), "NS_CONSUMED "); Editor->commit(commit); @@ -1582,11 +1598,10 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, RetEffect Ret = CE.getReturnValue(); const char *AnnotationString = nullptr; if (Ret.getObjKind() == RetEffect::CF) { - if (Ret.isOwned() && - Ctx.Idents.get("CF_RETURNS_RETAINED").hasMacroDefinition()) + if (Ret.isOwned() && NSAPIObj->isMacroDefined("CF_RETURNS_RETAINED")) AnnotationString = " CF_RETURNS_RETAINED"; else if (Ret.notOwned() && - Ctx.Idents.get("CF_RETURNS_NOT_RETAINED").hasMacroDefinition()) + NSAPIObj->isMacroDefined("CF_RETURNS_NOT_RETAINED")) AnnotationString = " CF_RETURNS_NOT_RETAINED"; } else if (Ret.getObjKind() == RetEffect::ObjC) { @@ -1600,8 +1615,7 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, break; default: - if (Ret.isOwned() && - Ctx.Idents.get("NS_RETURNS_RETAINED").hasMacroDefinition()) + if (Ret.isOwned() && NSAPIObj->isMacroDefined("NS_RETURNS_RETAINED")) AnnotationString = " NS_RETURNS_RETAINED"; break; } @@ -1620,7 +1634,7 @@ void ObjCMigrateASTConsumer::AddCFAnnotations(ASTContext &Ctx, const ParmVarDecl *pd = *pi; ArgEffect AE = AEArgs[i]; if (AE == DecRef && !pd->hasAttr<CFConsumedAttr>() && - Ctx.Idents.get("CF_CONSUMED").hasMacroDefinition()) { + NSAPIObj->isMacroDefined("CF_CONSUMED")) { edit::Commit commit(*Editor); commit.insertBefore(pd->getLocation(), "CF_CONSUMED "); Editor->commit(commit); @@ -1640,12 +1654,12 @@ void ObjCMigrateASTConsumer::migrateAddMethodAnnotation( MethodDecl->hasAttr<NSReturnsRetainedAttr>() || MethodDecl->hasAttr<NSReturnsNotRetainedAttr>() || MethodDecl->hasAttr<NSReturnsAutoreleasedAttr>()); - - if (CE.getReceiver() == DecRefMsg && + + if (CE.getReceiver() == DecRefMsg && !MethodDecl->hasAttr<NSConsumesSelfAttr>() && MethodDecl->getMethodFamily() != OMF_init && MethodDecl->getMethodFamily() != OMF_release && - Ctx.Idents.get("NS_CONSUMES_SELF").hasMacroDefinition()) { + NSAPIObj->isMacroDefined("NS_CONSUMES_SELF")) { edit::Commit commit(*Editor); commit.insertBefore(MethodDecl->getLocEnd(), " NS_CONSUMES_SELF"); Editor->commit(commit); @@ -1711,7 +1725,7 @@ void ObjCMigrateASTConsumer::inferDesignatedInitializers( const ObjCInterfaceDecl *IFace = ImplD->getClassInterface(); if (!IFace || IFace->hasDesignatedInitializers()) return; - if (!Ctx.Idents.get("NS_DESIGNATED_INITIALIZER").hasMacroDefinition()) + if (!NSAPIObj->isMacroDefined("NS_DESIGNATED_INITIALIZER")) return; for (const auto *MD : ImplD->instance_methods()) { @@ -1772,9 +1786,7 @@ public: : SourceMgr(SM), OS(OS) { OS << "[\n"; } - ~JSONEditWriter() { - OS << "]\n"; - } + ~JSONEditWriter() override { OS << "]\n"; } private: struct EntryWriter { @@ -1858,13 +1870,16 @@ void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D)) if (canModify(CDecl)) - migrateObjCInterfaceDecl(Ctx, CDecl); + migrateObjCContainerDecl(Ctx, CDecl); if (ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(*D)) { if (canModify(CatDecl)) - migrateObjCInterfaceDecl(Ctx, CatDecl); + migrateObjCContainerDecl(Ctx, CatDecl); } - else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D)) + else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(*D)) { ObjCProtocolDecls.insert(PDecl->getCanonicalDecl()); + if (canModify(PDecl)) + migrateObjCContainerDecl(Ctx, PDecl); + } else if (const ObjCImplementationDecl *ImpDecl = dyn_cast<ObjCImplementationDecl>(*D)) { if ((ASTMigrateActions & FrontendOptions::ObjCMT_ProtocolConformance) && diff --git a/lib/ARCMigrate/PlistReporter.cpp b/lib/ARCMigrate/PlistReporter.cpp index 53398b27af49..9a51690c0ce7 100644 --- a/lib/ARCMigrate/PlistReporter.cpp +++ b/lib/ARCMigrate/PlistReporter.cpp @@ -100,16 +100,18 @@ void arcmt::writeARCDiagsToPlist(const std::string &outPath, // Output the location of the bug. o << " <key>location</key>\n"; - EmitLocation(o, SM, LangOpts, D.getLocation(), FM, 2); + EmitLocation(o, SM, D.getLocation(), FM, 2); // Output the ranges (if any). - StoredDiagnostic::range_iterator RI = D.range_begin(), RE = D.range_end(); - - if (RI != RE) { + if (!D.getRanges().empty()) { o << " <key>ranges</key>\n"; o << " <array>\n"; - for (; RI != RE; ++RI) - EmitRange(o, SM, LangOpts, *RI, FM, 4); + for (auto &R : D.getRanges()) { + CharSourceRange ExpansionRange(SM.getExpansionRange(R.getAsRange()), + R.isTokenRange()); + EmitRange(o, SM, Lexer::getAsCharRange(ExpansionRange, SM, LangOpts), + FM, 4); + } o << " </array>\n"; } diff --git a/lib/ARCMigrate/TransAPIUses.cpp b/lib/ARCMigrate/TransAPIUses.cpp index 544cb0addfcd..40c8a070f813 100644 --- a/lib/ARCMigrate/TransAPIUses.cpp +++ b/lib/ARCMigrate/TransAPIUses.cpp @@ -95,7 +95,7 @@ public: Pass.TA.clearDiagnostic(diag::err_unavailable, diag::err_unavailable_message, E->getSelectorLoc(0)); - Pass.TA.replace(E->getSourceRange(), getNilString(Pass.Ctx)); + Pass.TA.replace(E->getSourceRange(), getNilString(Pass)); } return true; } diff --git a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp index bcbc9e9612ba..7db1a1c378cc 100644 --- a/lib/ARCMigrate/TransRetainReleaseDealloc.cpp +++ b/lib/ARCMigrate/TransRetainReleaseDealloc.cpp @@ -145,7 +145,7 @@ public: // when an exception is thrown. Pass.TA.replace(RecContainer->getSourceRange(), RecRange); std::string str = " = "; - str += getNilString(Pass.Ctx); + str += getNilString(Pass); Pass.TA.insertAfterToken(RecRange.getEnd(), str); return true; } diff --git a/lib/ARCMigrate/TransUnusedInitDelegate.cpp b/lib/ARCMigrate/TransUnusedInitDelegate.cpp index 98571c035dd5..70370ecc4e90 100644 --- a/lib/ARCMigrate/TransUnusedInitDelegate.cpp +++ b/lib/ARCMigrate/TransUnusedInitDelegate.cpp @@ -58,7 +58,7 @@ public: SourceRange ExprRange = ME->getSourceRange(); Pass.TA.insert(ExprRange.getBegin(), "if (!(self = "); std::string retStr = ")) return "; - retStr += getNilString(Pass.Ctx); + retStr += getNilString(Pass); Pass.TA.insertAfterToken(ExprRange.getEnd(), retStr); } return true; diff --git a/lib/ARCMigrate/Transforms.cpp b/lib/ARCMigrate/Transforms.cpp index 6ff7b6b9db87..56d3af7233bf 100644 --- a/lib/ARCMigrate/Transforms.cpp +++ b/lib/ARCMigrate/Transforms.cpp @@ -16,6 +16,7 @@ #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Lexer.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/DenseSet.h" @@ -212,11 +213,8 @@ bool trans::isGlobalVar(Expr *E) { return false; } -StringRef trans::getNilString(ASTContext &Ctx) { - if (Ctx.Idents.get("nil").hasMacroDefinition()) - return "nil"; - else - return "0"; +StringRef trans::getNilString(MigrationPass &Pass) { + return Pass.SemaRef.PP.isMacroDefined("nil") ? "nil" : "0"; } namespace { diff --git a/lib/ARCMigrate/Transforms.h b/lib/ARCMigrate/Transforms.h index 12551d261d36..7e3dd34e7607 100644 --- a/lib/ARCMigrate/Transforms.h +++ b/lib/ARCMigrate/Transforms.h @@ -180,7 +180,7 @@ SourceLocation findSemiAfterLocation(SourceLocation loc, ASTContext &Ctx, bool hasSideEffects(Expr *E, ASTContext &Ctx); bool isGlobalVar(Expr *E); /// \brief Returns "nil" or "0" if 'nil' macro is not actually defined. -StringRef getNilString(ASTContext &Ctx); +StringRef getNilString(MigrationPass &Pass); template <typename BODY_TRANS> class BodyTransform : public RecursiveASTVisitor<BodyTransform<BODY_TRANS> > { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c9fb80ceaae2..4a831d90e645 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -738,9 +738,9 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, FILEDecl(nullptr), jmp_bufDecl(nullptr), sigjmp_bufDecl(nullptr), ucontext_tDecl(nullptr), BlockDescriptorType(nullptr), BlockDescriptorExtendedType(nullptr), cudaConfigureCallDecl(nullptr), - FirstLocalImport(), LastLocalImport(), + FirstLocalImport(), LastLocalImport(), ExternCContext(nullptr), SourceMgr(SM), LangOpts(LOpts), - SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFile, SM)), + SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)), AddrSpaceMap(nullptr), Target(nullptr), PrintingPolicy(LOpts), Idents(idents), Selectors(sels), BuiltinInfo(builtins), DeclarationNames(*this), ExternalSource(nullptr), Listener(nullptr), @@ -866,6 +866,38 @@ void ASTContext::PrintStats() const { BumpAlloc.PrintStats(); } +void ASTContext::mergeDefinitionIntoModule(NamedDecl *ND, Module *M, + bool NotifyListeners) { + if (NotifyListeners) + if (auto *Listener = getASTMutationListener()) + Listener->RedefinedHiddenDefinition(ND, M); + + if (getLangOpts().ModulesLocalVisibility) + MergedDefModules[ND].push_back(M); + else + ND->setHidden(false); +} + +void ASTContext::deduplicateMergedDefinitonsFor(NamedDecl *ND) { + auto It = MergedDefModules.find(ND); + if (It == MergedDefModules.end()) + return; + + auto &Merged = It->second; + llvm::DenseSet<Module*> Found; + for (Module *&M : Merged) + if (!Found.insert(M).second) + M = nullptr; + Merged.erase(std::remove(Merged.begin(), Merged.end(), nullptr), Merged.end()); +} + +ExternCContextDecl *ASTContext::getExternCContextDecl() const { + if (!ExternCContext) + ExternCContext = ExternCContextDecl::Create(*this, getTranslationUnitDecl()); + + return ExternCContext; +} + RecordDecl *ASTContext::buildImplicitRecord(StringRef Name, RecordDecl::TagKind TK) const { SourceLocation Loc; @@ -877,6 +909,8 @@ RecordDecl *ASTContext::buildImplicitRecord(StringRef Name, NewDecl = RecordDecl::Create(*this, TK, getTranslationUnitDecl(), Loc, Loc, &Idents.get(Name)); NewDecl->setImplicit(); + NewDecl->addAttr(TypeVisibilityAttr::CreateImplicit( + const_cast<ASTContext &>(*this), TypeVisibilityAttr::Default)); return NewDecl; } @@ -1326,7 +1360,7 @@ CharUnits ASTContext::getDeclAlign(const Decl *D, bool ForAlignof) const { } Align = std::max(Align, getPreferredTypeAlign(T.getTypePtr())); if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (VD->hasGlobalStorage()) + if (VD->hasGlobalStorage() && !ForAlignof) Align = std::max(Align, getTargetInfo().getMinGlobalAlign()); } } @@ -1669,13 +1703,23 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { break; } - if (const EnumType *ET = dyn_cast<EnumType>(TT)) - return getTypeInfo(ET->getDecl()->getIntegerType()); + if (const EnumType *ET = dyn_cast<EnumType>(TT)) { + const EnumDecl *ED = ET->getDecl(); + TypeInfo Info = + getTypeInfo(ED->getIntegerType()->getUnqualifiedDesugaredType()); + if (unsigned AttrAlign = ED->getMaxAlignment()) { + Info.Align = AttrAlign; + Info.AlignIsRequired = true; + } + return Info; + } const RecordType *RT = cast<RecordType>(TT); - const ASTRecordLayout &Layout = getASTRecordLayout(RT->getDecl()); + const RecordDecl *RD = RT->getDecl(); + const ASTRecordLayout &Layout = getASTRecordLayout(RD); Width = toBits(Layout.getSize()); Align = toBits(Layout.getAlignment()); + AlignIsRequired = RD->hasAttr<AlignedAttr>(); break; } @@ -1778,13 +1822,20 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { TypeInfo TI = getTypeInfo(T); unsigned ABIAlign = TI.Align; + T = T->getBaseElementTypeUnsafe(); + + // The preferred alignment of member pointers is that of a pointer. + if (T->isMemberPointerType()) + return getPreferredTypeAlign(getPointerDiffType().getTypePtr()); + if (Target->getTriple().getArch() == llvm::Triple::xcore) return ABIAlign; // Never overalign on XCore. // Double and long long should be naturally aligned if possible. - T = T->getBaseElementTypeUnsafe(); if (const ComplexType *CT = T->getAs<ComplexType>()) T = CT->getElementType().getTypePtr(); + if (const EnumType *ET = T->getAs<EnumType>()) + T = ET->getDecl()->getIntegerType().getTypePtr(); if (T->isSpecificBuiltinType(BuiltinType::Double) || T->isSpecificBuiltinType(BuiltinType::LongLong) || T->isSpecificBuiltinType(BuiltinType::ULongLong)) @@ -1796,6 +1847,13 @@ unsigned ASTContext::getPreferredTypeAlign(const Type *T) const { return ABIAlign; } +/// getTargetDefaultAlignForAttributeAligned - Return the default alignment +/// for __attribute__((aligned)) on this target, to be used if no alignment +/// value is specified. +unsigned ASTContext::getTargetDefaultAlignForAttributeAligned(void) const { + return getTargetInfo().getDefaultAlignForAttributeAligned(); +} + /// getAlignOfGlobalVar - Return the alignment in bits that should be given /// to a global variable of the specified type. unsigned ASTContext::getAlignOfGlobalVar(QualType T) const { @@ -3337,7 +3395,7 @@ ASTContext::getElaboratedType(ElaboratedTypeKeyword Keyword, (void)CheckT; } - T = new (*this) ElaboratedType(Keyword, NNS, NamedType, Canon); + T = new (*this, TypeAlignment) ElaboratedType(Keyword, NNS, NamedType, Canon); Types.push_back(T); ElaboratedTypes.InsertNode(T, InsertPos); return QualType(T, 0); @@ -3361,7 +3419,7 @@ ASTContext::getParenType(QualType InnerType) const { (void)CheckT; } - T = new (*this) ParenType(InnerType, Canon); + T = new (*this, TypeAlignment) ParenType(InnerType, Canon); Types.push_back(T); ParenTypes.InsertNode(T, InsertPos); return QualType(T, 0); @@ -3390,7 +3448,7 @@ QualType ASTContext::getDependentNameType(ElaboratedTypeKeyword Keyword, if (T) return QualType(T, 0); - T = new (*this) DependentNameType(Keyword, NNS, Name, Canon); + T = new (*this, TypeAlignment) DependentNameType(Keyword, NNS, Name, Canon); Types.push_back(T); DependentNameTypes.InsertNode(T, InsertPos); return QualType(T, 0); @@ -3492,7 +3550,8 @@ QualType ASTContext::getPackExpansionType(QualType Pattern, } } - T = new (*this) PackExpansionType(Pattern, Canon, NumExpansions); + T = new (*this, TypeAlignment) + PackExpansionType(Pattern, Canon, NumExpansions); Types.push_back(T); PackExpansionTypes.InsertNode(T, InsertPos); return QualType(T, 0); @@ -3500,9 +3559,9 @@ QualType ASTContext::getPackExpansionType(QualType Pattern, /// CmpProtocolNames - Comparison predicate for sorting protocols /// alphabetically. -static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, - const ObjCProtocolDecl *RHS) { - return LHS->getDeclName() < RHS->getDeclName(); +static int CmpProtocolNames(ObjCProtocolDecl *const *LHS, + ObjCProtocolDecl *const *RHS) { + return DeclarationName::compare((*LHS)->getDeclName(), (*RHS)->getDeclName()); } static bool areSortedAndUniqued(ObjCProtocolDecl * const *Protocols, @@ -3513,7 +3572,7 @@ static bool areSortedAndUniqued(ObjCProtocolDecl * const *Protocols, return false; for (unsigned i = 1; i != NumProtocols; ++i) - if (!CmpProtocolNames(Protocols[i-1], Protocols[i]) || + if (CmpProtocolNames(&Protocols[i - 1], &Protocols[i]) >= 0 || Protocols[i]->getCanonicalDecl() != Protocols[i]) return false; return true; @@ -3524,7 +3583,7 @@ static void SortAndUniqueProtocols(ObjCProtocolDecl **Protocols, ObjCProtocolDecl **ProtocolsEnd = Protocols+NumProtocols; // Sort protocols, keyed by name. - std::sort(Protocols, Protocols+NumProtocols, CmpProtocolNames); + llvm::array_pod_sort(Protocols, ProtocolsEnd, CmpProtocolNames); // Canonicalize. for (unsigned I = 0, N = NumProtocols; I != N; ++I) @@ -4325,6 +4384,19 @@ QualType ASTContext::getSignatureParameterType(QualType T) const { return T.getUnqualifiedType(); } +QualType ASTContext::getExceptionObjectType(QualType T) const { + // C++ [except.throw]p3: + // A throw-expression initializes a temporary object, called the exception + // object, the type of which is determined by removing any top-level + // cv-qualifiers from the static type of the operand of throw and adjusting + // the type from "array of T" or "function returning T" to "pointer to T" + // or "pointer to function returning T", [...] + T = getVariableArrayDecayedType(T); + if (T->isArrayType() || T->isFunctionType()) + T = getDecayedType(T); + return T.getUnqualifiedType(); +} + /// getArrayDecayedType - Return the properly qualified result of decaying the /// specified array type to a pointer. This operation is non-trivial when /// handling typedefs etc. The canonical type of "T" must be an array type, @@ -4859,7 +4931,7 @@ CharUnits ASTContext::getObjCEncodingTypeSize(QualType type) const { bool ASTContext::isMSStaticDataMemberInlineDefinition(const VarDecl *VD) const { return getLangOpts().MSVCCompat && VD->isStaticDataMember() && VD->getType()->isIntegralOrEnumerationType() && - !VD->getFirstDecl()->isOutOfLine() && VD->getFirstDecl()->hasInit(); + VD->isFirstDecl() && !VD->isOutOfLine() && VD->hasInit(); } static inline @@ -7544,7 +7616,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, break; case 'U': assert(!Signed && "Can't use both 'S' and 'U' modifiers!"); - assert(!Unsigned && "Can't use 'S' modifier multiple times!"); + assert(!Unsigned && "Can't use 'U' modifier multiple times!"); Unsigned = true; break; case 'L': @@ -7579,7 +7651,7 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, break; case 'h': assert(HowLong == 0 && !Signed && !Unsigned && - "Bad modifiers used with 'f'!"); + "Bad modifiers used with 'h'!"); Type = Context.HalfTy; break; case 'f': @@ -7806,6 +7878,9 @@ QualType ASTContext::GetBuiltinType(unsigned Id, ArgTypes.push_back(Ty); } + if (Id == Builtin::BI__GetExceptionInfo) + return QualType(); + assert((TypeStr[0] != '.' || TypeStr[1] == 0) && "'.' should only occur at end of builtin type list!"); @@ -7909,7 +7984,7 @@ static GVALinkage basicGVALinkageForVariable(const ASTContext &Context, while (LexicalContext && !isa<FunctionDecl>(LexicalContext)) LexicalContext = LexicalContext->getLexicalParent(); - // Let the static local variable inherit it's linkage from the nearest + // Let the static local variable inherit its linkage from the nearest // enclosing function. if (LexicalContext) StaticLocalLinkage = @@ -8042,7 +8117,9 @@ CallingConv ASTContext::getDefaultCallingConvention(bool IsVariadic, if (IsCXXMethod) return ABI->getDefaultMethodCallConv(IsVariadic); - return (LangOpts.MRTD && !IsVariadic) ? CC_X86StdCall : CC_C; + if (LangOpts.MRTD && !IsVariadic) return CC_X86StdCall; + + return Target->getDefaultCallingConv(TargetInfo::CCMT_Unknown); } bool ASTContext::isNearlyEmpty(const CXXRecordDecl *RD) const { @@ -8161,6 +8238,31 @@ MangleNumberingContext *ASTContext::createMangleNumberingContext() const { return ABI->createMangleNumberingContext(); } +const CXXConstructorDecl * +ASTContext::getCopyConstructorForExceptionObject(CXXRecordDecl *RD) { + return ABI->getCopyConstructorForExceptionObject( + cast<CXXRecordDecl>(RD->getFirstDecl())); +} + +void ASTContext::addCopyConstructorForExceptionObject(CXXRecordDecl *RD, + CXXConstructorDecl *CD) { + return ABI->addCopyConstructorForExceptionObject( + cast<CXXRecordDecl>(RD->getFirstDecl()), + cast<CXXConstructorDecl>(CD->getFirstDecl())); +} + +void ASTContext::addDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx, Expr *DAE) { + ABI->addDefaultArgExprForConstructor( + cast<CXXConstructorDecl>(CD->getFirstDecl()), ParmIdx, DAE); +} + +Expr *ASTContext::getDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx) { + return ABI->getDefaultArgExprForConstructor( + cast<CXXConstructorDecl>(CD->getFirstDecl()), ParmIdx); +} + void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { ParamIndices[D] = index; } diff --git a/lib/AST/ASTDumper.cpp b/lib/AST/ASTDumper.cpp index ebf5e651ef9a..60cbb0601138 100644 --- a/lib/AST/ASTDumper.cpp +++ b/lib/AST/ASTDumper.cpp @@ -508,6 +508,8 @@ namespace { void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *Node); void VisitCXXConstructExpr(const CXXConstructExpr *Node); void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node); + void VisitCXXNewExpr(const CXXNewExpr *Node); + void VisitCXXDeleteExpr(const CXXDeleteExpr *Node); void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node); void VisitExprWithCleanups(const ExprWithCleanups *Node); void VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *Node); @@ -516,6 +518,7 @@ namespace { VisitExpr(Node); dumpDecl(Node->getLambdaClass()); } + void VisitSizeOfPackExpr(const SizeOfPackExpr *Node); // ObjC void VisitObjCAtCatchStmt(const ObjCAtCatchStmt *Node); @@ -974,8 +977,10 @@ void ASTDumper::dumpDecl(const Decl *D) { dumpSourceRange(D->getSourceRange()); OS << ' '; dumpLocation(D->getLocation()); - if (Module *M = D->getOwningModule()) + if (Module *M = D->getImportedOwningModule()) OS << " in " << M->getFullModuleName(); + else if (Module *M = D->getLocalOwningModule()) + OS << " in (local) " << M->getFullModuleName(); if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) if (ND->isHidden()) OS << " hidden"; @@ -1099,10 +1104,13 @@ void ASTDumper::VisitFunctionDecl(const FunctionDecl *D) { E = D->getDeclsInPrototypeScope().end(); I != E; ++I) dumpDecl(*I); - for (FunctionDecl::param_const_iterator I = D->param_begin(), - E = D->param_end(); - I != E; ++I) - dumpDecl(*I); + if (!D->param_begin() && D->getNumParams()) + dumpChild([=] { OS << "<<NULL params x " << D->getNumParams() << ">>"; }); + else + for (FunctionDecl::param_const_iterator I = D->param_begin(), + E = D->param_end(); + I != E; ++I) + dumpDecl(*I); if (const CXXConstructorDecl *C = dyn_cast<CXXConstructorDecl>(D)) for (CXXConstructorDecl::init_const_iterator I = C->init_begin(), @@ -1913,6 +1921,32 @@ void ASTDumper::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Node) { dumpCXXTemporary(Node->getTemporary()); } +void ASTDumper::VisitCXXNewExpr(const CXXNewExpr *Node) { + VisitExpr(Node); + if (Node->isGlobalNew()) + OS << " global"; + if (Node->isArray()) + OS << " array"; + if (Node->getOperatorNew()) { + OS << ' '; + dumpBareDeclRef(Node->getOperatorNew()); + } + // We could dump the deallocation function used in case of error, but it's + // usually not that interesting. +} + +void ASTDumper::VisitCXXDeleteExpr(const CXXDeleteExpr *Node) { + VisitExpr(Node); + if (Node->isGlobalDelete()) + OS << " global"; + if (Node->isArrayForm()) + OS << " array"; + if (Node->getOperatorDelete()) { + OS << ' '; + dumpBareDeclRef(Node->getOperatorDelete()); + } +} + void ASTDumper::VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Node) { VisitExpr(Node); @@ -1934,6 +1968,13 @@ void ASTDumper::dumpCXXTemporary(const CXXTemporary *Temporary) { OS << ")"; } +void ASTDumper::VisitSizeOfPackExpr(const SizeOfPackExpr *Node) { + VisitExpr(Node); + dumpPointer(Node->getPack()); + dumpName(Node->getPack()); +} + + //===----------------------------------------------------------------------===// // Obj-C Expressions //===----------------------------------------------------------------------===// @@ -2255,6 +2296,11 @@ LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS, SourceManager &SM) const { P.dumpStmt(this); } +LLVM_DUMP_METHOD void Stmt::dump(raw_ostream &OS) const { + ASTDumper P(OS, nullptr, nullptr); + P.dumpStmt(this); +} + LLVM_DUMP_METHOD void Stmt::dump() const { ASTDumper P(llvm::errs(), nullptr, nullptr); P.dumpStmt(this); diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index 2442e8ec25f1..911f1681ce61 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -67,6 +67,7 @@ namespace clang { // FIXME: DependentDecltypeType QualType VisitRecordType(const RecordType *T); QualType VisitEnumType(const EnumType *T); + QualType VisitAttributedType(const AttributedType *T); // FIXME: TemplateTypeParmType // FIXME: SubstTemplateTypeParmType QualType VisitTemplateSpecializationType(const TemplateSpecializationType *T); @@ -80,7 +81,7 @@ namespace clang { // Importing declarations bool ImportDeclParts(NamedDecl *D, DeclContext *&DC, DeclContext *&LexicalDC, DeclarationName &Name, - SourceLocation &Loc); + NamedDecl *&ToD, SourceLocation &Loc); void ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD = nullptr); void ImportDeclarationNameLoc(const DeclarationNameInfo &From, DeclarationNameInfo& To); @@ -167,7 +168,44 @@ namespace clang { Decl *VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); // Importing statements + DeclGroupRef ImportDeclGroup(DeclGroupRef DG); + Stmt *VisitStmt(Stmt *S); + Stmt *VisitDeclStmt(DeclStmt *S); + Stmt *VisitNullStmt(NullStmt *S); + Stmt *VisitCompoundStmt(CompoundStmt *S); + Stmt *VisitCaseStmt(CaseStmt *S); + Stmt *VisitDefaultStmt(DefaultStmt *S); + Stmt *VisitLabelStmt(LabelStmt *S); + Stmt *VisitAttributedStmt(AttributedStmt *S); + Stmt *VisitIfStmt(IfStmt *S); + Stmt *VisitSwitchStmt(SwitchStmt *S); + Stmt *VisitWhileStmt(WhileStmt *S); + Stmt *VisitDoStmt(DoStmt *S); + Stmt *VisitForStmt(ForStmt *S); + Stmt *VisitGotoStmt(GotoStmt *S); + Stmt *VisitIndirectGotoStmt(IndirectGotoStmt *S); + Stmt *VisitContinueStmt(ContinueStmt *S); + Stmt *VisitBreakStmt(BreakStmt *S); + Stmt *VisitReturnStmt(ReturnStmt *S); + // FIXME: GCCAsmStmt + // FIXME: MSAsmStmt + // FIXME: SEHExceptStmt + // FIXME: SEHFinallyStmt + // FIXME: SEHTryStmt + // FIXME: SEHLeaveStmt + // FIXME: CapturedStmt + Stmt *VisitCXXCatchStmt(CXXCatchStmt *S); + Stmt *VisitCXXTryStmt(CXXTryStmt *S); + Stmt *VisitCXXForRangeStmt(CXXForRangeStmt *S); + // FIXME: MSDependentExistsStmt + Stmt *VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); + Stmt *VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); + Stmt *VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S); + Stmt *VisitObjCAtTryStmt(ObjCAtTryStmt *S); + Stmt *VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); + Stmt *VisitObjCAtThrowStmt(ObjCAtThrowStmt *S); + Stmt *VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S); // Importing expressions Expr *VisitExpr(Expr *E); @@ -181,6 +219,9 @@ namespace clang { Expr *VisitCompoundAssignOperator(CompoundAssignOperator *E); Expr *VisitImplicitCastExpr(ImplicitCastExpr *E); Expr *VisitCStyleCastExpr(CStyleCastExpr *E); + Expr *VisitCXXConstructExpr(CXXConstructExpr *E); + Expr *VisitMemberExpr(MemberExpr *E); + Expr *VisitCallExpr(CallExpr *E); }; } using namespace clang; @@ -1724,6 +1765,27 @@ QualType ASTNodeImporter::VisitEnumType(const EnumType *T) { return Importer.getToContext().getTagDeclType(ToDecl); } +QualType ASTNodeImporter::VisitAttributedType(const AttributedType *T) { + QualType FromModifiedType = T->getModifiedType(); + QualType FromEquivalentType = T->getEquivalentType(); + QualType ToModifiedType; + QualType ToEquivalentType; + + if (!FromModifiedType.isNull()) { + ToModifiedType = Importer.Import(FromModifiedType); + if (ToModifiedType.isNull()) + return QualType(); + } + if (!FromEquivalentType.isNull()) { + ToEquivalentType = Importer.Import(FromEquivalentType); + if (ToEquivalentType.isNull()) + return QualType(); + } + + return Importer.getToContext().getAttributedType(T->getAttrKind(), + ToModifiedType, ToEquivalentType); +} + QualType ASTNodeImporter::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { TemplateName ToTemplate = Importer.Import(T->getTemplateName()); @@ -1808,6 +1870,7 @@ ASTNodeImporter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC, DeclContext *&LexicalDC, DeclarationName &Name, + NamedDecl *&ToD, SourceLocation &Loc) { // Import the context of this declaration. DC = Importer.ImportContext(D->getDeclContext()); @@ -1828,6 +1891,7 @@ bool ASTNodeImporter::ImportDeclParts(NamedDecl *D, DeclContext *&DC, // Import the location of this declaration. Loc = Importer.Import(D->getLocation()); + ToD = cast_or_null<NamedDecl>(Importer.GetAlreadyImportedOrNull(D)); return false; } @@ -2009,7 +2073,7 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To, bool ASTNodeImporter::ImportDefinition(VarDecl *From, VarDecl *To, ImportDefinitionKind Kind) { - if (To->getDefinition()) + if (To->getAnyInitializer()) return false; // FIXME: Can we really import any initializer? Alternatively, we could force @@ -2239,8 +2303,11 @@ Decl *ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; NamespaceDecl *MergeWithNamespace = nullptr; if (!Name) { @@ -2307,8 +2374,11 @@ Decl *ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // If this typedef is not in block scope, determine whether we've // seen a typedef with the same name (that we can merge with) or any @@ -2381,8 +2451,11 @@ Decl *ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // Figure out what enum name we're looking for. unsigned IDNS = Decl::IDNS_Tag; @@ -2466,8 +2539,11 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // Figure out what structure name we're looking for. unsigned IDNS = Decl::IDNS_Tag; @@ -2592,8 +2668,11 @@ Decl *ASTNodeImporter::VisitEnumConstantDecl(EnumConstantDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; QualType T = Importer.Import(D->getType()); if (T.isNull()) @@ -2648,8 +2727,11 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // Try to find a function in our own ("to") context with the same name, same // type, and in the same context as the function we're importing. @@ -2741,10 +2823,11 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // Create the imported function. TypeSourceInfo *TInfo = Importer.Import(D->getTypeSourceInfo()); FunctionDecl *ToFunction = nullptr; + SourceLocation InnerLocStart = Importer.Import(D->getInnerLocStart()); if (CXXConstructorDecl *FromConstructor = dyn_cast<CXXConstructorDecl>(D)) { ToFunction = CXXConstructorDecl::Create(Importer.getToContext(), cast<CXXRecordDecl>(DC), - D->getInnerLocStart(), + InnerLocStart, NameInfo, T, TInfo, FromConstructor->isExplicit(), D->isInlineSpecified(), @@ -2753,7 +2836,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } else if (isa<CXXDestructorDecl>(D)) { ToFunction = CXXDestructorDecl::Create(Importer.getToContext(), cast<CXXRecordDecl>(DC), - D->getInnerLocStart(), + InnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), D->isImplicit()); @@ -2761,7 +2844,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { = dyn_cast<CXXConversionDecl>(D)) { ToFunction = CXXConversionDecl::Create(Importer.getToContext(), cast<CXXRecordDecl>(DC), - D->getInnerLocStart(), + InnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), FromConversion->isExplicit(), @@ -2770,7 +2853,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } else if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(D)) { ToFunction = CXXMethodDecl::Create(Importer.getToContext(), cast<CXXRecordDecl>(DC), - D->getInnerLocStart(), + InnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(), Method->isInlineSpecified(), @@ -2778,7 +2861,7 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { Importer.Import(D->getLocEnd())); } else { ToFunction = FunctionDecl::Create(Importer.getToContext(), DC, - D->getInnerLocStart(), + InnerLocStart, NameInfo, T, TInfo, D->getStorageClass(), D->isInlineSpecified(), D->hasWrittenPrototype(), @@ -2809,6 +2892,13 @@ Decl *ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { ToFunction->setType(T); } + // Import the body, if any. + if (Stmt *FromBody = D->getBody()) { + if (Stmt *ToBody = Importer.Import(FromBody)) { + ToFunction->setBody(ToBody); + } + } + // FIXME: Other bits to merge? // Add this function to the lexical context. @@ -2855,8 +2945,11 @@ Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // Determine whether we've already imported this field. SmallVector<NamedDecl *, 2> FoundDecls; @@ -2911,8 +3004,11 @@ Decl *ASTNodeImporter::VisitIndirectFieldDecl(IndirectFieldDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // Determine whether we've already imported this field. SmallVector<NamedDecl *, 2> FoundDecls; @@ -2978,8 +3074,11 @@ Decl *ASTNodeImporter::VisitObjCIvarDecl(ObjCIvarDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // Determine whether we've already imported this ivar SmallVector<NamedDecl *, 2> FoundDecls; @@ -3028,8 +3127,11 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // Try to find a variable in our own ("to") context with the same name and // in the same context as the variable we're importing. @@ -3137,6 +3239,10 @@ Decl *ASTNodeImporter::VisitVarDecl(VarDecl *D) { Importer.Imported(D, ToVar); LexicalDC->addDeclInternal(ToVar); + if (!D->isFileVarDecl() && + D->isUsed()) + ToVar->setIsUsed(); + // Merge the initializer. if (ImportDefinition(D, ToVar)) return nullptr; @@ -3196,6 +3302,10 @@ Decl *ASTNodeImporter::VisitParmVarDecl(ParmVarDecl *D) { T, TInfo, D->getStorageClass(), /*FIXME: Default argument*/nullptr); ToParm->setHasInheritedDefaultArg(D->hasInheritedDefaultArg()); + + if (D->isUsed()) + ToParm->setIsUsed(); + return Importer.Imported(D, ToParm); } @@ -3204,8 +3314,11 @@ Decl *ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; SmallVector<NamedDecl *, 2> FoundDecls; DC->getRedeclContext()->localUncachedLookup(Name, FoundDecls); @@ -3315,8 +3428,11 @@ Decl *ASTNodeImporter::VisitObjCCategoryDecl(ObjCCategoryDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; ObjCInterfaceDecl *ToInterface = cast_or_null<ObjCInterfaceDecl>(Importer.Import(D->getClassInterface())); @@ -3439,8 +3555,11 @@ Decl *ASTNodeImporter::VisitObjCProtocolDecl(ObjCProtocolDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; ObjCProtocolDecl *MergeWithProtocol = nullptr; SmallVector<NamedDecl *, 2> FoundDecls; @@ -3614,8 +3733,11 @@ Decl *ASTNodeImporter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // Look for an existing interface with the same name. ObjCInterfaceDecl *MergeWithIface = nullptr; @@ -3769,8 +3891,11 @@ Decl *ASTNodeImporter::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // Check whether we have already imported this property. SmallVector<NamedDecl *, 2> FoundDecls; @@ -4000,8 +4125,11 @@ Decl *ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // We may already have a template of the same name; try to find and match it. if (!DC->isFunctionOrMethod()) { @@ -4188,8 +4316,11 @@ Decl *ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { DeclContext *DC, *LexicalDC; DeclarationName Name; SourceLocation Loc; - if (ImportDeclParts(D, DC, LexicalDC, Name, Loc)) + NamedDecl *ToD; + if (ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) return nullptr; + if (ToD) + return ToD; // We may already have a template of the same name; try to find and match it. assert(!DC->isFunctionOrMethod() && @@ -4371,10 +4502,457 @@ Decl *ASTNodeImporter::VisitVarTemplateSpecializationDecl( // Import Statements //---------------------------------------------------------------------------- -Stmt *ASTNodeImporter::VisitStmt(Stmt *S) { - Importer.FromDiag(S->getLocStart(), diag::err_unsupported_ast_node) - << S->getStmtClassName(); - return nullptr; +DeclGroupRef ASTNodeImporter::ImportDeclGroup(DeclGroupRef DG) { + if (DG.isNull()) + return DeclGroupRef::Create(Importer.getToContext(), nullptr, 0); + size_t NumDecls = DG.end() - DG.begin(); + SmallVector<Decl *, 1> ToDecls(NumDecls); + auto &_Importer = this->Importer; + std::transform(DG.begin(), DG.end(), ToDecls.begin(), + [&_Importer](Decl *D) -> Decl * { + return _Importer.Import(D); + }); + return DeclGroupRef::Create(Importer.getToContext(), + ToDecls.begin(), + NumDecls); +} + + Stmt *ASTNodeImporter::VisitStmt(Stmt *S) { + Importer.FromDiag(S->getLocStart(), diag::err_unsupported_ast_node) + << S->getStmtClassName(); + return nullptr; + } + +Stmt *ASTNodeImporter::VisitDeclStmt(DeclStmt *S) { + DeclGroupRef ToDG = ImportDeclGroup(S->getDeclGroup()); + for (Decl *ToD : ToDG) { + if (!ToD) + return nullptr; + } + SourceLocation ToStartLoc = Importer.Import(S->getStartLoc()); + SourceLocation ToEndLoc = Importer.Import(S->getEndLoc()); + return new (Importer.getToContext()) DeclStmt(ToDG, ToStartLoc, ToEndLoc); +} + +Stmt *ASTNodeImporter::VisitNullStmt(NullStmt *S) { + SourceLocation ToSemiLoc = Importer.Import(S->getSemiLoc()); + return new (Importer.getToContext()) NullStmt(ToSemiLoc, + S->hasLeadingEmptyMacro()); +} + +Stmt *ASTNodeImporter::VisitCompoundStmt(CompoundStmt *S) { + SmallVector<Stmt *, 4> ToStmts(S->size()); + auto &_Importer = this->Importer; + std::transform(S->body_begin(), S->body_end(), ToStmts.begin(), + [&_Importer](Stmt *CS) -> Stmt * { + return _Importer.Import(CS); + }); + for (Stmt *ToS : ToStmts) { + if (!ToS) + return nullptr; + } + SourceLocation ToLBraceLoc = Importer.Import(S->getLBracLoc()); + SourceLocation ToRBraceLoc = Importer.Import(S->getRBracLoc()); + return new (Importer.getToContext()) CompoundStmt(Importer.getToContext(), + ToStmts, + ToLBraceLoc, ToRBraceLoc); +} + +Stmt *ASTNodeImporter::VisitCaseStmt(CaseStmt *S) { + Expr *ToLHS = Importer.Import(S->getLHS()); + if (!ToLHS) + return nullptr; + Expr *ToRHS = Importer.Import(S->getRHS()); + if (!ToRHS && S->getRHS()) + return nullptr; + SourceLocation ToCaseLoc = Importer.Import(S->getCaseLoc()); + SourceLocation ToEllipsisLoc = Importer.Import(S->getEllipsisLoc()); + SourceLocation ToColonLoc = Importer.Import(S->getColonLoc()); + return new (Importer.getToContext()) CaseStmt(ToLHS, ToRHS, + ToCaseLoc, ToEllipsisLoc, + ToColonLoc); +} + +Stmt *ASTNodeImporter::VisitDefaultStmt(DefaultStmt *S) { + SourceLocation ToDefaultLoc = Importer.Import(S->getDefaultLoc()); + SourceLocation ToColonLoc = Importer.Import(S->getColonLoc()); + Stmt *ToSubStmt = Importer.Import(S->getSubStmt()); + if (!ToSubStmt && S->getSubStmt()) + return nullptr; + return new (Importer.getToContext()) DefaultStmt(ToDefaultLoc, ToColonLoc, + ToSubStmt); +} + +Stmt *ASTNodeImporter::VisitLabelStmt(LabelStmt *S) { + SourceLocation ToIdentLoc = Importer.Import(S->getIdentLoc()); + LabelDecl *ToLabelDecl = + cast_or_null<LabelDecl>(Importer.Import(S->getDecl())); + if (!ToLabelDecl && S->getDecl()) + return nullptr; + Stmt *ToSubStmt = Importer.Import(S->getSubStmt()); + if (!ToSubStmt && S->getSubStmt()) + return nullptr; + return new (Importer.getToContext()) LabelStmt(ToIdentLoc, ToLabelDecl, + ToSubStmt); +} + +Stmt *ASTNodeImporter::VisitAttributedStmt(AttributedStmt *S) { + SourceLocation ToAttrLoc = Importer.Import(S->getAttrLoc()); + ArrayRef<const Attr*> FromAttrs(S->getAttrs()); + SmallVector<const Attr *, 1> ToAttrs(FromAttrs.size()); + ASTContext &_ToContext = Importer.getToContext(); + std::transform(FromAttrs.begin(), FromAttrs.end(), ToAttrs.begin(), + [&_ToContext](const Attr *A) -> const Attr * { + return A->clone(_ToContext); + }); + for (const Attr *ToA : ToAttrs) { + if (!ToA) + return nullptr; + } + Stmt *ToSubStmt = Importer.Import(S->getSubStmt()); + if (!ToSubStmt && S->getSubStmt()) + return nullptr; + return AttributedStmt::Create(Importer.getToContext(), ToAttrLoc, + ToAttrs, ToSubStmt); +} + +Stmt *ASTNodeImporter::VisitIfStmt(IfStmt *S) { + SourceLocation ToIfLoc = Importer.Import(S->getIfLoc()); + VarDecl *ToConditionVariable = nullptr; + if (VarDecl *FromConditionVariable = S->getConditionVariable()) { + ToConditionVariable = + dyn_cast_or_null<VarDecl>(Importer.Import(FromConditionVariable)); + if (!ToConditionVariable) + return nullptr; + } + Expr *ToCondition = Importer.Import(S->getCond()); + if (!ToCondition && S->getCond()) + return nullptr; + Stmt *ToThenStmt = Importer.Import(S->getThen()); + if (!ToThenStmt && S->getThen()) + return nullptr; + SourceLocation ToElseLoc = Importer.Import(S->getElseLoc()); + Stmt *ToElseStmt = Importer.Import(S->getElse()); + if (!ToElseStmt && S->getElse()) + return nullptr; + return new (Importer.getToContext()) IfStmt(Importer.getToContext(), + ToIfLoc, ToConditionVariable, + ToCondition, ToThenStmt, + ToElseLoc, ToElseStmt); +} + +Stmt *ASTNodeImporter::VisitSwitchStmt(SwitchStmt *S) { + VarDecl *ToConditionVariable = nullptr; + if (VarDecl *FromConditionVariable = S->getConditionVariable()) { + ToConditionVariable = + dyn_cast_or_null<VarDecl>(Importer.Import(FromConditionVariable)); + if (!ToConditionVariable) + return nullptr; + } + Expr *ToCondition = Importer.Import(S->getCond()); + if (!ToCondition && S->getCond()) + return nullptr; + SwitchStmt *ToStmt = new (Importer.getToContext()) SwitchStmt( + Importer.getToContext(), ToConditionVariable, + ToCondition); + Stmt *ToBody = Importer.Import(S->getBody()); + if (!ToBody && S->getBody()) + return nullptr; + ToStmt->setBody(ToBody); + ToStmt->setSwitchLoc(Importer.Import(S->getSwitchLoc())); + // Now we have to re-chain the cases. + SwitchCase *LastChainedSwitchCase = nullptr; + for (SwitchCase *SC = S->getSwitchCaseList(); SC != nullptr; + SC = SC->getNextSwitchCase()) { + SwitchCase *ToSC = dyn_cast_or_null<SwitchCase>(Importer.Import(SC)); + if (!ToSC) + return nullptr; + if (LastChainedSwitchCase) + LastChainedSwitchCase->setNextSwitchCase(ToSC); + else + ToStmt->setSwitchCaseList(ToSC); + LastChainedSwitchCase = ToSC; + } + return ToStmt; +} + +Stmt *ASTNodeImporter::VisitWhileStmt(WhileStmt *S) { + VarDecl *ToConditionVariable = nullptr; + if (VarDecl *FromConditionVariable = S->getConditionVariable()) { + ToConditionVariable = + dyn_cast_or_null<VarDecl>(Importer.Import(FromConditionVariable)); + if (!ToConditionVariable) + return nullptr; + } + Expr *ToCondition = Importer.Import(S->getCond()); + if (!ToCondition && S->getCond()) + return nullptr; + Stmt *ToBody = Importer.Import(S->getBody()); + if (!ToBody && S->getBody()) + return nullptr; + SourceLocation ToWhileLoc = Importer.Import(S->getWhileLoc()); + return new (Importer.getToContext()) WhileStmt(Importer.getToContext(), + ToConditionVariable, + ToCondition, ToBody, + ToWhileLoc); +} + +Stmt *ASTNodeImporter::VisitDoStmt(DoStmt *S) { + Stmt *ToBody = Importer.Import(S->getBody()); + if (!ToBody && S->getBody()) + return nullptr; + Expr *ToCondition = Importer.Import(S->getCond()); + if (!ToCondition && S->getCond()) + return nullptr; + SourceLocation ToDoLoc = Importer.Import(S->getDoLoc()); + SourceLocation ToWhileLoc = Importer.Import(S->getWhileLoc()); + SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc()); + return new (Importer.getToContext()) DoStmt(ToBody, ToCondition, + ToDoLoc, ToWhileLoc, + ToRParenLoc); +} + +Stmt *ASTNodeImporter::VisitForStmt(ForStmt *S) { + Stmt *ToInit = Importer.Import(S->getInit()); + if (!ToInit && S->getInit()) + return nullptr; + Expr *ToCondition = Importer.Import(S->getCond()); + if (!ToCondition && S->getCond()) + return nullptr; + VarDecl *ToConditionVariable = nullptr; + if (VarDecl *FromConditionVariable = S->getConditionVariable()) { + ToConditionVariable = + dyn_cast_or_null<VarDecl>(Importer.Import(FromConditionVariable)); + if (!ToConditionVariable) + return nullptr; + } + Expr *ToInc = Importer.Import(S->getInc()); + if (!ToInc && S->getInc()) + return nullptr; + Stmt *ToBody = Importer.Import(S->getBody()); + if (!ToBody && S->getBody()) + return nullptr; + SourceLocation ToForLoc = Importer.Import(S->getForLoc()); + SourceLocation ToLParenLoc = Importer.Import(S->getLParenLoc()); + SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc()); + return new (Importer.getToContext()) ForStmt(Importer.getToContext(), + ToInit, ToCondition, + ToConditionVariable, + ToInc, ToBody, + ToForLoc, ToLParenLoc, + ToRParenLoc); +} + +Stmt *ASTNodeImporter::VisitGotoStmt(GotoStmt *S) { + LabelDecl *ToLabel = nullptr; + if (LabelDecl *FromLabel = S->getLabel()) { + ToLabel = dyn_cast_or_null<LabelDecl>(Importer.Import(FromLabel)); + if (!ToLabel) + return nullptr; + } + SourceLocation ToGotoLoc = Importer.Import(S->getGotoLoc()); + SourceLocation ToLabelLoc = Importer.Import(S->getLabelLoc()); + return new (Importer.getToContext()) GotoStmt(ToLabel, + ToGotoLoc, ToLabelLoc); +} + +Stmt *ASTNodeImporter::VisitIndirectGotoStmt(IndirectGotoStmt *S) { + SourceLocation ToGotoLoc = Importer.Import(S->getGotoLoc()); + SourceLocation ToStarLoc = Importer.Import(S->getStarLoc()); + Expr *ToTarget = Importer.Import(S->getTarget()); + if (!ToTarget && S->getTarget()) + return nullptr; + return new (Importer.getToContext()) IndirectGotoStmt(ToGotoLoc, ToStarLoc, + ToTarget); +} + +Stmt *ASTNodeImporter::VisitContinueStmt(ContinueStmt *S) { + SourceLocation ToContinueLoc = Importer.Import(S->getContinueLoc()); + return new (Importer.getToContext()) ContinueStmt(ToContinueLoc); +} + +Stmt *ASTNodeImporter::VisitBreakStmt(BreakStmt *S) { + SourceLocation ToBreakLoc = Importer.Import(S->getBreakLoc()); + return new (Importer.getToContext()) BreakStmt(ToBreakLoc); +} + +Stmt *ASTNodeImporter::VisitReturnStmt(ReturnStmt *S) { + SourceLocation ToRetLoc = Importer.Import(S->getReturnLoc()); + Expr *ToRetExpr = Importer.Import(S->getRetValue()); + if (!ToRetExpr && S->getRetValue()) + return nullptr; + VarDecl *NRVOCandidate = const_cast<VarDecl*>(S->getNRVOCandidate()); + VarDecl *ToNRVOCandidate = cast_or_null<VarDecl>(Importer.Import(NRVOCandidate)); + if (!ToNRVOCandidate && NRVOCandidate) + return nullptr; + return new (Importer.getToContext()) ReturnStmt(ToRetLoc, ToRetExpr, + ToNRVOCandidate); +} + +Stmt *ASTNodeImporter::VisitCXXCatchStmt(CXXCatchStmt *S) { + SourceLocation ToCatchLoc = Importer.Import(S->getCatchLoc()); + VarDecl *ToExceptionDecl = nullptr; + if (VarDecl *FromExceptionDecl = S->getExceptionDecl()) { + ToExceptionDecl = + dyn_cast_or_null<VarDecl>(Importer.Import(FromExceptionDecl)); + if (!ToExceptionDecl) + return nullptr; + } + Stmt *ToHandlerBlock = Importer.Import(S->getHandlerBlock()); + if (!ToHandlerBlock && S->getHandlerBlock()) + return nullptr; + return new (Importer.getToContext()) CXXCatchStmt(ToCatchLoc, + ToExceptionDecl, + ToHandlerBlock); +} + +Stmt *ASTNodeImporter::VisitCXXTryStmt(CXXTryStmt *S) { + SourceLocation ToTryLoc = Importer.Import(S->getTryLoc()); + Stmt *ToTryBlock = Importer.Import(S->getTryBlock()); + if (!ToTryBlock && S->getTryBlock()) + return nullptr; + SmallVector<Stmt *, 1> ToHandlers(S->getNumHandlers()); + for (unsigned HI = 0, HE = S->getNumHandlers(); HI != HE; ++HI) { + CXXCatchStmt *FromHandler = S->getHandler(HI); + if (Stmt *ToHandler = Importer.Import(FromHandler)) + ToHandlers[HI] = ToHandler; + else + return nullptr; + } + return CXXTryStmt::Create(Importer.getToContext(), ToTryLoc, ToTryBlock, + ToHandlers); +} + +Stmt *ASTNodeImporter::VisitCXXForRangeStmt(CXXForRangeStmt *S) { + DeclStmt *ToRange = + dyn_cast_or_null<DeclStmt>(Importer.Import(S->getRangeStmt())); + if (!ToRange && S->getRangeStmt()) + return nullptr; + DeclStmt *ToBeginEnd = + dyn_cast_or_null<DeclStmt>(Importer.Import(S->getBeginEndStmt())); + if (!ToBeginEnd && S->getBeginEndStmt()) + return nullptr; + Expr *ToCond = Importer.Import(S->getCond()); + if (!ToCond && S->getCond()) + return nullptr; + Expr *ToInc = Importer.Import(S->getInc()); + if (!ToInc && S->getInc()) + return nullptr; + DeclStmt *ToLoopVar = + dyn_cast_or_null<DeclStmt>(Importer.Import(S->getLoopVarStmt())); + if (!ToLoopVar && S->getLoopVarStmt()) + return nullptr; + Stmt *ToBody = Importer.Import(S->getBody()); + if (!ToBody && S->getBody()) + return nullptr; + SourceLocation ToForLoc = Importer.Import(S->getForLoc()); + SourceLocation ToColonLoc = Importer.Import(S->getColonLoc()); + SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc()); + return new (Importer.getToContext()) CXXForRangeStmt(ToRange, ToBeginEnd, + ToCond, ToInc, + ToLoopVar, ToBody, + ToForLoc, ToColonLoc, + ToRParenLoc); +} + +Stmt *ASTNodeImporter::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { + Stmt *ToElem = Importer.Import(S->getElement()); + if (!ToElem && S->getElement()) + return nullptr; + Expr *ToCollect = Importer.Import(S->getCollection()); + if (!ToCollect && S->getCollection()) + return nullptr; + Stmt *ToBody = Importer.Import(S->getBody()); + if (!ToBody && S->getBody()) + return nullptr; + SourceLocation ToForLoc = Importer.Import(S->getForLoc()); + SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc()); + return new (Importer.getToContext()) ObjCForCollectionStmt(ToElem, + ToCollect, + ToBody, ToForLoc, + ToRParenLoc); +} + +Stmt *ASTNodeImporter::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { + SourceLocation ToAtCatchLoc = Importer.Import(S->getAtCatchLoc()); + SourceLocation ToRParenLoc = Importer.Import(S->getRParenLoc()); + VarDecl *ToExceptionDecl = nullptr; + if (VarDecl *FromExceptionDecl = S->getCatchParamDecl()) { + ToExceptionDecl = + dyn_cast_or_null<VarDecl>(Importer.Import(FromExceptionDecl)); + if (!ToExceptionDecl) + return nullptr; + } + Stmt *ToBody = Importer.Import(S->getCatchBody()); + if (!ToBody && S->getCatchBody()) + return nullptr; + return new (Importer.getToContext()) ObjCAtCatchStmt(ToAtCatchLoc, + ToRParenLoc, + ToExceptionDecl, + ToBody); +} + +Stmt *ASTNodeImporter::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { + SourceLocation ToAtFinallyLoc = Importer.Import(S->getAtFinallyLoc()); + Stmt *ToAtFinallyStmt = Importer.Import(S->getFinallyBody()); + if (!ToAtFinallyStmt && S->getFinallyBody()) + return nullptr; + return new (Importer.getToContext()) ObjCAtFinallyStmt(ToAtFinallyLoc, + ToAtFinallyStmt); +} + +Stmt *ASTNodeImporter::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { + SourceLocation ToAtTryLoc = Importer.Import(S->getAtTryLoc()); + Stmt *ToAtTryStmt = Importer.Import(S->getTryBody()); + if (!ToAtTryStmt && S->getTryBody()) + return nullptr; + SmallVector<Stmt *, 1> ToCatchStmts(S->getNumCatchStmts()); + for (unsigned CI = 0, CE = S->getNumCatchStmts(); CI != CE; ++CI) { + ObjCAtCatchStmt *FromCatchStmt = S->getCatchStmt(CI); + if (Stmt *ToCatchStmt = Importer.Import(FromCatchStmt)) + ToCatchStmts[CI] = ToCatchStmt; + else + return nullptr; + } + Stmt *ToAtFinallyStmt = Importer.Import(S->getFinallyStmt()); + if (!ToAtFinallyStmt && S->getFinallyStmt()) + return nullptr; + return ObjCAtTryStmt::Create(Importer.getToContext(), + ToAtTryLoc, ToAtTryStmt, + ToCatchStmts.begin(), ToCatchStmts.size(), + ToAtFinallyStmt); +} + +Stmt *ASTNodeImporter::VisitObjCAtSynchronizedStmt + (ObjCAtSynchronizedStmt *S) { + SourceLocation ToAtSynchronizedLoc = + Importer.Import(S->getAtSynchronizedLoc()); + Expr *ToSynchExpr = Importer.Import(S->getSynchExpr()); + if (!ToSynchExpr && S->getSynchExpr()) + return nullptr; + Stmt *ToSynchBody = Importer.Import(S->getSynchBody()); + if (!ToSynchBody && S->getSynchBody()) + return nullptr; + return new (Importer.getToContext()) ObjCAtSynchronizedStmt( + ToAtSynchronizedLoc, ToSynchExpr, ToSynchBody); +} + +Stmt *ASTNodeImporter::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { + SourceLocation ToAtThrowLoc = Importer.Import(S->getThrowLoc()); + Expr *ToThrow = Importer.Import(S->getThrowExpr()); + if (!ToThrow && S->getThrowExpr()) + return nullptr; + return new (Importer.getToContext()) ObjCAtThrowStmt(ToAtThrowLoc, ToThrow); +} + +Stmt *ASTNodeImporter::VisitObjCAutoreleasePoolStmt + (ObjCAutoreleasePoolStmt *S) { + SourceLocation ToAtLoc = Importer.Import(S->getAtLoc()); + Stmt *ToSubStmt = Importer.Import(S->getSubStmt()); + if (!ToSubStmt && S->getSubStmt()) + return nullptr; + return new (Importer.getToContext()) ObjCAutoreleasePoolStmt(ToAtLoc, + ToSubStmt); } //---------------------------------------------------------------------------- @@ -4585,6 +5163,107 @@ Expr *ASTNodeImporter::VisitCStyleCastExpr(CStyleCastExpr *E) { Importer.Import(E->getRParenLoc())); } +Expr *ASTNodeImporter::VisitCXXConstructExpr(CXXConstructExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + CXXConstructorDecl *ToCCD = + dyn_cast<CXXConstructorDecl>(Importer.Import(E->getConstructor())); + if (!ToCCD && E->getConstructor()) + return nullptr; + + size_t NumArgs = E->getNumArgs(); + SmallVector<Expr *, 1> ToArgs(NumArgs); + ASTImporter &_Importer = Importer; + std::transform(E->arg_begin(), E->arg_end(), ToArgs.begin(), + [&_Importer](Expr *AE) -> Expr * { + return _Importer.Import(AE); + }); + for (Expr *ToA : ToArgs) { + if (!ToA) + return nullptr; + } + + return CXXConstructExpr::Create(Importer.getToContext(), T, + Importer.Import(E->getLocation()), + ToCCD, E->isElidable(), + ToArgs, E->hadMultipleCandidates(), + E->isListInitialization(), + E->isStdInitListInitialization(), + E->requiresZeroInitialization(), + E->getConstructionKind(), + Importer.Import(E->getParenOrBraceRange())); +} + +Expr *ASTNodeImporter::VisitMemberExpr(MemberExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + Expr *ToBase = Importer.Import(E->getBase()); + if (!ToBase && E->getBase()) + return nullptr; + + ValueDecl *ToMember = dyn_cast<ValueDecl>(Importer.Import(E->getMemberDecl())); + if (!ToMember && E->getMemberDecl()) + return nullptr; + + DeclAccessPair ToFoundDecl = DeclAccessPair::make( + dyn_cast<NamedDecl>(Importer.Import(E->getFoundDecl().getDecl())), + E->getFoundDecl().getAccess()); + + DeclarationNameInfo ToMemberNameInfo( + Importer.Import(E->getMemberNameInfo().getName()), + Importer.Import(E->getMemberNameInfo().getLoc())); + + if (E->hasExplicitTemplateArgs()) { + return nullptr; // FIXME: handle template arguments + } + + return MemberExpr::Create(Importer.getToContext(), ToBase, + E->isArrow(), + Importer.Import(E->getOperatorLoc()), + Importer.Import(E->getQualifierLoc()), + Importer.Import(E->getTemplateKeywordLoc()), + ToMember, ToFoundDecl, ToMemberNameInfo, + nullptr, T, E->getValueKind(), + E->getObjectKind()); +} + +Expr *ASTNodeImporter::VisitCallExpr(CallExpr *E) { + QualType T = Importer.Import(E->getType()); + if (T.isNull()) + return nullptr; + + Expr *ToCallee = Importer.Import(E->getCallee()); + if (!ToCallee && E->getCallee()) + return nullptr; + + unsigned NumArgs = E->getNumArgs(); + + llvm::SmallVector<Expr *, 2> ToArgs(NumArgs); + + for (unsigned ai = 0, ae = NumArgs; ai != ae; ++ai) { + Expr *FromArg = E->getArg(ai); + Expr *ToArg = Importer.Import(FromArg); + if (!ToArg) + return nullptr; + ToArgs[ai] = ToArg; + } + + Expr **ToArgs_Copied = new (Importer.getToContext()) + Expr*[NumArgs]; + + for (unsigned ai = 0, ae = NumArgs; ai != ae; ++ai) + ToArgs_Copied[ai] = ToArgs[ai]; + + return new (Importer.getToContext()) + CallExpr(Importer.getToContext(), ToCallee, + ArrayRef<Expr*>(ToArgs_Copied, NumArgs), T, E->getValueKind(), + Importer.Import(E->getRParenLoc())); +} + ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, ASTContext &FromContext, FileManager &FromFileManager, bool MinimalImport) @@ -4636,6 +5315,17 @@ TypeSourceInfo *ASTImporter::Import(TypeSourceInfo *FromTSI) { FromTSI->getTypeLoc().getLocStart()); } +Decl *ASTImporter::GetAlreadyImportedOrNull(Decl *FromD) { + llvm::DenseMap<Decl *, Decl *>::iterator Pos = ImportedDecls.find(FromD); + if (Pos != ImportedDecls.end()) { + Decl *ToD = Pos->second; + ASTNodeImporter(*this).ImportDefinitionIfNeeded(FromD, ToD); + return ToD; + } else { + return nullptr; + } +} + Decl *ASTImporter::Import(Decl *FromD) { if (!FromD) return nullptr; @@ -4927,8 +5617,9 @@ SourceLocation ASTImporter::Import(SourceLocation FromLoc) { FileID ToFileID = Import(Decomposed.first); if (ToFileID.isInvalid()) return SourceLocation(); - return ToSM.getLocForStartOfFile(ToFileID) - .getLocWithOffset(Decomposed.second); + SourceLocation ret = ToSM.getLocForStartOfFile(ToFileID) + .getLocWithOffset(Decomposed.second); + return ret; } SourceRange ASTImporter::Import(SourceRange FromRange) { @@ -4952,7 +5643,7 @@ FileID ASTImporter::Import(FileID FromID) { // Map the FileID for to the "to" source manager. FileID ToID; const SrcMgr::ContentCache *Cache = FromSLoc.getFile().getContentCache(); - if (Cache->OrigEntry) { + if (Cache->OrigEntry && Cache->OrigEntry->getDir()) { // FIXME: We probably want to use getVirtualFile(), so we don't hit the // disk again // FIXME: We definitely want to re-use the existing MemoryBuffer, rather diff --git a/lib/AST/AttrImpl.cpp b/lib/AST/AttrImpl.cpp index 0bf6bcd9092e..cb608700133c 100644 --- a/lib/AST/AttrImpl.cpp +++ b/lib/AST/AttrImpl.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This file contains out-of-line virtual methods for Attr classes. +// This file contains out-of-line methods for Attr classes. // //===----------------------------------------------------------------------===// @@ -18,10 +18,4 @@ #include "llvm/ADT/StringSwitch.h" using namespace clang; -Attr::~Attr() { } - -void InheritableAttr::anchor() { } - -void InheritableParamAttr::anchor() { } - #include "clang/AST/AttrImpl.inc" diff --git a/lib/AST/CXXABI.h b/lib/AST/CXXABI.h index 8e9e358525e8..dad226474fa7 100644 --- a/lib/AST/CXXABI.h +++ b/lib/AST/CXXABI.h @@ -20,6 +20,8 @@ namespace clang { class ASTContext; +class CXXConstructorDecl; +class Expr; class MemberPointerType; class MangleNumberingContext; @@ -41,6 +43,20 @@ public: /// Returns a new mangling number context for this C++ ABI. virtual MangleNumberingContext *createMangleNumberingContext() const = 0; + + /// Adds a mapping from class to copy constructor for this C++ ABI. + virtual void addCopyConstructorForExceptionObject(CXXRecordDecl *, + CXXConstructorDecl *) = 0; + + /// Retrieves the mapping from class to copy constructor for this C++ ABI. + virtual const CXXConstructorDecl * + getCopyConstructorForExceptionObject(CXXRecordDecl *) = 0; + + virtual void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx, Expr *DAE) = 0; + + virtual Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx) = 0; }; /// Creates an instance of a C++ ABI class. diff --git a/lib/AST/CXXInheritance.cpp b/lib/AST/CXXInheritance.cpp index 6e80ee7c28a1..800c8f83b880 100644 --- a/lib/AST/CXXInheritance.cpp +++ b/lib/AST/CXXInheritance.cpp @@ -318,48 +318,36 @@ bool CXXRecordDecl::lookupInBases(BaseMatchesCallback *BaseMatches, // // FIXME: This is an O(N^2) algorithm, but DPG doesn't see an easy // way to make it any faster. - for (CXXBasePaths::paths_iterator P = Paths.begin(), PEnd = Paths.end(); - P != PEnd; /* increment in loop */) { - bool Hidden = false; - - for (CXXBasePath::iterator PE = P->begin(), PEEnd = P->end(); - PE != PEEnd && !Hidden; ++PE) { - if (PE->Base->isVirtual()) { - CXXRecordDecl *VBase = nullptr; - if (const RecordType *Record = PE->Base->getType()->getAs<RecordType>()) - VBase = cast<CXXRecordDecl>(Record->getDecl()); - if (!VBase) + Paths.Paths.remove_if([&Paths](const CXXBasePath &Path) { + for (const CXXBasePathElement &PE : Path) { + if (!PE.Base->isVirtual()) + continue; + + CXXRecordDecl *VBase = nullptr; + if (const RecordType *Record = PE.Base->getType()->getAs<RecordType>()) + VBase = cast<CXXRecordDecl>(Record->getDecl()); + if (!VBase) + break; + + // The declaration(s) we found along this path were found in a + // subobject of a virtual base. Check whether this virtual + // base is a subobject of any other path; if so, then the + // declaration in this path are hidden by that patch. + for (const CXXBasePath &HidingP : Paths) { + CXXRecordDecl *HidingClass = nullptr; + if (const RecordType *Record = + HidingP.back().Base->getType()->getAs<RecordType>()) + HidingClass = cast<CXXRecordDecl>(Record->getDecl()); + if (!HidingClass) break; - // The declaration(s) we found along this path were found in a - // subobject of a virtual base. Check whether this virtual - // base is a subobject of any other path; if so, then the - // declaration in this path are hidden by that patch. - for (CXXBasePaths::paths_iterator HidingP = Paths.begin(), - HidingPEnd = Paths.end(); - HidingP != HidingPEnd; - ++HidingP) { - CXXRecordDecl *HidingClass = nullptr; - if (const RecordType *Record - = HidingP->back().Base->getType()->getAs<RecordType>()) - HidingClass = cast<CXXRecordDecl>(Record->getDecl()); - if (!HidingClass) - break; - - if (HidingClass->isVirtuallyDerivedFrom(VBase)) { - Hidden = true; - break; - } - } + if (HidingClass->isVirtuallyDerivedFrom(VBase)) + return true; } } + return false; + }); - if (Hidden) - P = Paths.Paths.erase(P); - else - ++P; - } - return true; } @@ -569,18 +557,14 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, // overrider. To do so, we dig down to the original virtual // functions using data recursion and update all of the methods it // overrides. - typedef std::pair<CXXMethodDecl::method_iterator, - CXXMethodDecl::method_iterator> OverriddenMethods; + typedef llvm::iterator_range<CXXMethodDecl::method_iterator> + OverriddenMethods; SmallVector<OverriddenMethods, 4> Stack; - Stack.push_back(std::make_pair(CanonM->begin_overridden_methods(), - CanonM->end_overridden_methods())); + Stack.push_back(llvm::make_range(CanonM->begin_overridden_methods(), + CanonM->end_overridden_methods())); while (!Stack.empty()) { - OverriddenMethods OverMethods = Stack.back(); - Stack.pop_back(); - - for (; OverMethods.first != OverMethods.second; ++OverMethods.first) { - const CXXMethodDecl *CanonOM - = cast<CXXMethodDecl>((*OverMethods.first)->getCanonicalDecl()); + for (const CXXMethodDecl *OM : Stack.pop_back_val()) { + const CXXMethodDecl *CanonOM = OM->getCanonicalDecl(); // C++ [class.virtual]p2: // A virtual member function C::vf of a class object S is @@ -601,8 +585,8 @@ void FinalOverriderCollector::Collect(const CXXRecordDecl *RD, // Continue recursion to the methods that this virtual method // overrides. - Stack.push_back(std::make_pair(CanonOM->begin_overridden_methods(), - CanonOM->end_overridden_methods())); + Stack.push_back(llvm::make_range(CanonOM->begin_overridden_methods(), + CanonOM->end_overridden_methods())); } } @@ -630,54 +614,32 @@ CXXRecordDecl::getFinalOverriders(CXXFinalOverriderMap &FinalOverriders) const { // Weed out any final overriders that come from virtual base class // subobjects that were hidden by other subobjects along any path. // This is the final-overrider variant of C++ [class.member.lookup]p10. - for (CXXFinalOverriderMap::iterator OM = FinalOverriders.begin(), - OMEnd = FinalOverriders.end(); - OM != OMEnd; - ++OM) { - for (OverridingMethods::iterator SO = OM->second.begin(), - SOEnd = OM->second.end(); - SO != SOEnd; - ++SO) { - SmallVectorImpl<UniqueVirtualMethod> &Overriding = SO->second; + for (auto &OM : FinalOverriders) { + for (auto &SO : OM.second) { + SmallVectorImpl<UniqueVirtualMethod> &Overriding = SO.second; if (Overriding.size() < 2) continue; - for (SmallVectorImpl<UniqueVirtualMethod>::iterator - Pos = Overriding.begin(), PosEnd = Overriding.end(); - Pos != PosEnd; - /* increment in loop */) { - if (!Pos->InVirtualSubobject) { - ++Pos; - continue; - } + auto IsHidden = [&Overriding](const UniqueVirtualMethod &M) { + if (!M.InVirtualSubobject) + return false; // We have an overriding method in a virtual base class // subobject (or non-virtual base class subobject thereof); // determine whether there exists an other overriding method // in a base class subobject that hides the virtual base class // subobject. - bool Hidden = false; - for (SmallVectorImpl<UniqueVirtualMethod>::iterator - OP = Overriding.begin(), OPEnd = Overriding.end(); - OP != OPEnd && !Hidden; - ++OP) { - if (Pos == OP) - continue; - - if (OP->Method->getParent()->isVirtuallyDerivedFrom( - const_cast<CXXRecordDecl *>(Pos->InVirtualSubobject))) - Hidden = true; - } - - if (Hidden) { - // The current overriding function is hidden by another - // overriding function; remove this one. - Pos = Overriding.erase(Pos); - PosEnd = Overriding.end(); - } else { - ++Pos; - } - } + for (const UniqueVirtualMethod &OP : Overriding) + if (&M != &OP && + OP.Method->getParent()->isVirtuallyDerivedFrom( + M.InVirtualSubobject)) + return true; + return false; + }; + + Overriding.erase( + std::remove_if(Overriding.begin(), Overriding.end(), IsHidden), + Overriding.end()); } } } diff --git a/lib/AST/CommentLexer.cpp b/lib/AST/CommentLexer.cpp index 06a08bdad45f..98b7e367950c 100644 --- a/lib/AST/CommentLexer.cpp +++ b/lib/AST/CommentLexer.cpp @@ -514,6 +514,12 @@ void Lexer::lexVerbatimBlockBody(Token &T) { if (CommentState == LCS_InsideCComment) skipLineStartingDecorations(); + if (BufferPtr == CommentEnd) { + formTokenWithChars(T, BufferPtr, tok::verbatim_block_line); + T.setVerbatimBlockText(""); + return; + } + lexVerbatimBlockFirstLine(T); } diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index dc08d23a24b5..8eff4c4427b3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -44,6 +44,12 @@ bool Decl::isOutOfLine() const { return !getLexicalDeclContext()->Equals(getDeclContext()); } +TranslationUnitDecl::TranslationUnitDecl(ASTContext &ctx) + : Decl(TranslationUnit, nullptr, SourceLocation()), + DeclContext(TranslationUnit), Ctx(ctx), AnonymousNamespace(nullptr) { + Hidden = Ctx.getLangOpts().ModulesLocalVisibility; +} + //===----------------------------------------------------------------------===// // NamedDecl Implementation //===----------------------------------------------------------------------===// @@ -894,13 +900,13 @@ static LinkageInfo getLVForClassMember(const NamedDecl *D, if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { // If the type of the function uses a type with unique-external // linkage, it's not legally usable from outside this translation unit. - // But only look at the type-as-written. If this function has an auto-deduced - // return type, we can't compute the linkage of that type because it could - // require looking at the linkage of this function, and we don't need this - // for correctness because the type is not part of the function's - // signature. - // FIXME: This is a hack. We should be able to solve this circularity and the - // one in getLVForNamespaceScopeDecl for Functions some other way. + // But only look at the type-as-written. If this function has an + // auto-deduced return type, we can't compute the linkage of that type + // because it could require looking at the linkage of this function, and we + // don't need this for correctness because the type is not part of the + // function's signature. + // FIXME: This is a hack. We should be able to solve this circularity and + // the one in getLVForNamespaceScopeDecl for Functions some other way. { QualType TypeAsWritten = MD->getType(); if (TypeSourceInfo *TSI = MD->getTypeSourceInfo()) @@ -1445,74 +1451,127 @@ void NamedDecl::getNameForDiagnostic(raw_ostream &OS, printName(OS); } -bool NamedDecl::declarationReplaces(NamedDecl *OldD) const { - assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch"); +static bool isKindReplaceableBy(Decl::Kind OldK, Decl::Kind NewK) { + // For method declarations, we never replace. + if (ObjCMethodDecl::classofKind(NewK)) + return false; - // UsingDirectiveDecl's are not really NamedDecl's, and all have same name. - // We want to keep it, unless it nominates same namespace. - if (getKind() == Decl::UsingDirective) { - return cast<UsingDirectiveDecl>(this)->getNominatedNamespace() - ->getOriginalNamespace() == - cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace() - ->getOriginalNamespace(); + if (OldK == NewK) + return true; + + // A compatibility alias for a class can be replaced by an interface. + if (ObjCCompatibleAliasDecl::classofKind(OldK) && + ObjCInterfaceDecl::classofKind(NewK)) + return true; + + // A typedef-declaration, alias-declaration, or Objective-C class declaration + // can replace another declaration of the same type. Semantic analysis checks + // that we have matching types. + if ((TypedefNameDecl::classofKind(OldK) || + ObjCInterfaceDecl::classofKind(OldK)) && + (TypedefNameDecl::classofKind(NewK) || + ObjCInterfaceDecl::classofKind(NewK))) + return true; + + // Otherwise, a kind mismatch implies that the declaration is not replaced. + return false; +} + +template<typename T> static bool isRedeclarableImpl(Redeclarable<T> *) { + return true; +} +static bool isRedeclarableImpl(...) { return false; } +static bool isRedeclarable(Decl::Kind K) { + switch (K) { +#define DECL(Type, Base) \ + case Decl::Type: \ + return isRedeclarableImpl((Type##Decl *)nullptr); +#define ABSTRACT_DECL(DECL) +#include "clang/AST/DeclNodes.inc" } + llvm_unreachable("unknown decl kind"); +} - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) - // For function declarations, we keep track of redeclarations. - return FD->getPreviousDecl() == OldD; +bool NamedDecl::declarationReplaces(NamedDecl *OldD, bool IsKnownNewer) const { + assert(getDeclName() == OldD->getDeclName() && "Declaration name mismatch"); - // For function templates, the underlying function declarations are linked. - if (const FunctionTemplateDecl *FunctionTemplate - = dyn_cast<FunctionTemplateDecl>(this)) - if (const FunctionTemplateDecl *OldFunctionTemplate - = dyn_cast<FunctionTemplateDecl>(OldD)) - return FunctionTemplate->getTemplatedDecl() - ->declarationReplaces(OldFunctionTemplate->getTemplatedDecl()); - - // For method declarations, we keep track of redeclarations. - if (isa<ObjCMethodDecl>(this)) + // Never replace one imported declaration with another; we need both results + // when re-exporting. + if (OldD->isFromASTFile() && isFromASTFile()) return false; - // FIXME: Is this correct if one of the decls comes from an inline namespace? - if (isa<ObjCInterfaceDecl>(this) && isa<ObjCCompatibleAliasDecl>(OldD)) - return true; + if (!isKindReplaceableBy(OldD->getKind(), getKind())) + return false; - if (isa<UsingShadowDecl>(this) && isa<UsingShadowDecl>(OldD)) - return cast<UsingShadowDecl>(this)->getTargetDecl() == - cast<UsingShadowDecl>(OldD)->getTargetDecl(); + // Inline namespaces can give us two declarations with the same + // name and kind in the same scope but different contexts; we should + // keep both declarations in this case. + if (!this->getDeclContext()->getRedeclContext()->Equals( + OldD->getDeclContext()->getRedeclContext())) + return false; - if (isa<UsingDecl>(this) && isa<UsingDecl>(OldD)) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) + // For function declarations, we keep track of redeclarations. + // FIXME: This returns false for functions that should in fact be replaced. + // Instead, perform some kind of type check? + if (FD->getPreviousDecl() != OldD) + return false; + + // For function templates, the underlying function declarations are linked. + if (const FunctionTemplateDecl *FunctionTemplate = + dyn_cast<FunctionTemplateDecl>(this)) + return FunctionTemplate->getTemplatedDecl()->declarationReplaces( + cast<FunctionTemplateDecl>(OldD)->getTemplatedDecl()); + + // Using shadow declarations can be overloaded on their target declarations + // if they introduce functions. + // FIXME: If our target replaces the old target, can we replace the old + // shadow declaration? + if (auto *USD = dyn_cast<UsingShadowDecl>(this)) + if (USD->getTargetDecl() != cast<UsingShadowDecl>(OldD)->getTargetDecl()) + return false; + + // Using declarations can be overloaded if they introduce functions. + if (auto *UD = dyn_cast<UsingDecl>(this)) { ASTContext &Context = getASTContext(); - return Context.getCanonicalNestedNameSpecifier( - cast<UsingDecl>(this)->getQualifier()) == + return Context.getCanonicalNestedNameSpecifier(UD->getQualifier()) == Context.getCanonicalNestedNameSpecifier( - cast<UsingDecl>(OldD)->getQualifier()); + cast<UsingDecl>(OldD)->getQualifier()); } - - if (isa<UnresolvedUsingValueDecl>(this) && - isa<UnresolvedUsingValueDecl>(OldD)) { + if (auto *UUVD = dyn_cast<UnresolvedUsingValueDecl>(this)) { ASTContext &Context = getASTContext(); - return Context.getCanonicalNestedNameSpecifier( - cast<UnresolvedUsingValueDecl>(this)->getQualifier()) == + return Context.getCanonicalNestedNameSpecifier(UUVD->getQualifier()) == Context.getCanonicalNestedNameSpecifier( cast<UnresolvedUsingValueDecl>(OldD)->getQualifier()); } - // A typedef of an Objective-C class type can replace an Objective-C class - // declaration or definition, and vice versa. - // FIXME: Is this correct if one of the decls comes from an inline namespace? - if ((isa<TypedefNameDecl>(this) && isa<ObjCInterfaceDecl>(OldD)) || - (isa<ObjCInterfaceDecl>(this) && isa<TypedefNameDecl>(OldD))) - return true; + // UsingDirectiveDecl's are not really NamedDecl's, and all have same name. + // We want to keep it, unless it nominates same namespace. + if (auto *UD = dyn_cast<UsingDirectiveDecl>(this)) + return UD->getNominatedNamespace()->getOriginalNamespace() == + cast<UsingDirectiveDecl>(OldD)->getNominatedNamespace() + ->getOriginalNamespace(); + + if (!IsKnownNewer && isRedeclarable(getKind())) { + // Check whether this is actually newer than OldD. We want to keep the + // newer declaration. This loop will usually only iterate once, because + // OldD is usually the previous declaration. + for (auto D : redecls()) { + if (D == OldD) + break; - // For non-function declarations, if the declarations are of the - // same kind and have the same parent then this must be a redeclaration, - // or semantic analysis would not have given us the new declaration. - // Note that inline namespaces can give us two declarations with the same - // name and kind in the same scope but different contexts. - return this->getKind() == OldD->getKind() && - this->getDeclContext()->getRedeclContext()->Equals( - OldD->getDeclContext()->getRedeclContext()); + // If we reach the canonical declaration, then OldD is not actually older + // than this one. + // + // FIXME: In this case, we should not add this decl to the lookup table. + if (D->isCanonicalDecl()) + return false; + } + } + + // It's a newer declaration of the same kind of declaration in the same scope, + // and not an overload: we want this decl instead of the existing one. + return true; } bool NamedDecl::hasLinkage() const { @@ -1684,8 +1743,7 @@ QualifierInfo::setTemplateParameterListsInfo(ASTContext &Context, if (NumTPLists > 0) { TemplParamLists = new (Context) TemplateParameterList*[NumTPLists]; NumTemplParamLists = NumTPLists; - for (unsigned i = NumTPLists; i-- > 0; ) - TemplParamLists[i] = TPLists[i]; + std::copy(TPLists, TPLists + NumTPLists, TemplParamLists); } } @@ -1717,6 +1775,8 @@ VarDecl::VarDecl(Kind DK, ASTContext &C, DeclContext *DC, "VarDeclBitfields too large!"); static_assert(sizeof(ParmVarDeclBitfields) <= sizeof(unsigned), "ParmVarDeclBitfields too large!"); + static_assert(sizeof(NonParmVarDeclBitfields) <= sizeof(unsigned), + "NonParmVarDeclBitfields too large!"); AllBits = 0; VarDeclBits.SClass = SC; // Everything else is implicitly initialized to false. @@ -1743,9 +1803,12 @@ void VarDecl::setStorageClass(StorageClass SC) { VarDecl::TLSKind VarDecl::getTLSKind() const { switch (VarDeclBits.TSCSpec) { case TSCS_unspecified: - if (hasAttr<ThreadAttr>()) - return TLS_Static; - return TLS_None; + if (!hasAttr<ThreadAttr>()) + return TLS_None; + return getASTContext().getLangOpts().isCompatibleWithMSVC( + LangOptions::MSVC2015) + ? TLS_Dynamic + : TLS_Static; case TSCS___thread: // Fall through. case TSCS__Thread_local: return TLS_Static; @@ -1825,9 +1888,8 @@ bool VarDecl::isInExternCXXContext() const { VarDecl *VarDecl::getCanonicalDecl() { return getFirstDecl(); } -VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( - ASTContext &C) const -{ +VarDecl::DefinitionKind +VarDecl::isThisDeclarationADefinition(ASTContext &C) const { // C++ [basic.def]p2: // A declaration is a definition unless [...] it contains the 'extern' // specifier or a linkage-specification and neither an initializer [...], @@ -1867,6 +1929,10 @@ VarDecl::DefinitionKind VarDecl::isThisDeclarationADefinition( if (hasAttr<AliasAttr>()) return Definition; + if (const auto *SAA = getAttr<SelectAnyAttr>()) + if (!SAA->isInherited()) + return Definition; + // A variable template specialization (other than a static data member // template or an explicit specialization) is a declaration until we // instantiate its initializer. @@ -2460,39 +2526,6 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction() const { return RD && isNamed(RD, "nothrow_t") && RD->isInStdNamespace(); } -FunctionDecl * -FunctionDecl::getCorrespondingUnsizedGlobalDeallocationFunction() const { - ASTContext &Ctx = getASTContext(); - if (!Ctx.getLangOpts().SizedDeallocation) - return nullptr; - - if (getDeclName().getNameKind() != DeclarationName::CXXOperatorName) - return nullptr; - if (getDeclName().getCXXOverloadedOperator() != OO_Delete && - getDeclName().getCXXOverloadedOperator() != OO_Array_Delete) - return nullptr; - if (isa<CXXRecordDecl>(getDeclContext())) - return nullptr; - - if (!getDeclContext()->getRedeclContext()->isTranslationUnit()) - return nullptr; - - if (getNumParams() != 2 || isVariadic() || - !Ctx.hasSameType(getType()->castAs<FunctionProtoType>()->getParamType(1), - Ctx.getSizeType())) - return nullptr; - - // This is a sized deallocation function. Find the corresponding unsized - // deallocation function. - lookup_const_result R = getDeclContext()->lookup(getDeclName()); - for (lookup_const_result::iterator RI = R.begin(), RE = R.end(); RI != RE; - ++RI) - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(*RI)) - if (FD->getNumParams() == 1 && !FD->isVariadic()) - return FD; - return nullptr; -} - LanguageLinkage FunctionDecl::getLanguageLinkage() const { return getDeclLanguageLinkage(*this); } @@ -2550,10 +2583,6 @@ FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { IsInline = true; } -const FunctionDecl *FunctionDecl::getCanonicalDecl() const { - return getFirstDecl(); -} - FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); } /// \brief Returns a value indicating whether this function @@ -2581,7 +2610,14 @@ unsigned FunctionDecl::getBuiltinID() const { // extern "C". // FIXME: A recognised library function may not be directly in an extern "C" // declaration, for instance "extern "C" { namespace std { decl } }". - if (!LinkageDecl || LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c) + if (!LinkageDecl) { + if (BuiltinID == Builtin::BI__GetExceptionInfo && + Context.getTargetInfo().getCXXABI().isMicrosoft() && + isInStdNamespace()) + return Builtin::BI__GetExceptionInfo; + return 0; + } + if (LinkageDecl->getLanguage() != LinkageSpecDecl::lang_c) return 0; } @@ -2796,6 +2832,18 @@ SourceRange FunctionDecl::getReturnTypeSourceRange() const { return RTRange; } +bool FunctionDecl::hasUnusedResultAttr() const { + QualType RetType = getReturnType(); + if (RetType->isRecordType()) { + const CXXRecordDecl *Ret = RetType->getAsCXXRecordDecl(); + const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(this); + if (Ret && Ret->hasAttr<WarnUnusedResultAttr>() && + !(MD && MD->getCorrespondingMethodInClass(Ret, true))) + return true; + } + return hasAttr<WarnUnusedResultAttr>(); +} + /// \brief For an inline function definition in C, or for a gnu_inline function /// in C++, determine whether the definition will be externally visible. /// @@ -3077,6 +3125,8 @@ DependentFunctionTemplateSpecializationInfo:: DependentFunctionTemplateSpecializationInfo(const UnresolvedSetImpl &Ts, const TemplateArgumentListInfo &TArgs) : AngleLocs(TArgs.getLAngleLoc(), TArgs.getRAngleLoc()) { + static_assert(sizeof(*this) % llvm::AlignOf<void *>::Alignment == 0, + "Trailing data is unaligned!"); d.NumTemplates = Ts.size(); d.NumArgs = TArgs.size(); @@ -3590,7 +3640,7 @@ void RecordDecl::completeDefinition() { /// This which can be turned on with an attribute, pragma, or the /// -mms-bitfields command-line option. bool RecordDecl::isMsStruct(const ASTContext &C) const { - return hasAttr<MsStructAttr>() || C.getLangOpts().MSBitfields == 1; + return hasAttr<MSStructAttr>() || C.getLangOpts().MSBitfields == 1; } static bool isFieldOrIndirectField(Decl::Kind K) { @@ -3747,6 +3797,13 @@ TranslationUnitDecl *TranslationUnitDecl::Create(ASTContext &C) { return new (C, (DeclContext *)nullptr) TranslationUnitDecl(C); } +void ExternCContextDecl::anchor() { } + +ExternCContextDecl *ExternCContextDecl::Create(const ASTContext &C, + TranslationUnitDecl *DC) { + return new (C, DC) ExternCContextDecl(DC); +} + void LabelDecl::anchor() { } LabelDecl *LabelDecl::Create(ASTContext &C, DeclContext *DC, @@ -3885,6 +3942,21 @@ TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, void TypedefNameDecl::anchor() { } +TagDecl *TypedefNameDecl::getAnonDeclWithTypedefName(bool AnyRedecl) const { + if (auto *TT = getTypeSourceInfo()->getType()->getAs<TagType>()) { + auto *OwningTypedef = TT->getDecl()->getTypedefNameForAnonDecl(); + auto *ThisTypedef = this; + if (AnyRedecl && OwningTypedef) { + OwningTypedef = OwningTypedef->getCanonicalDecl(); + ThisTypedef = ThisTypedef->getCanonicalDecl(); + } + if (OwningTypedef == ThisTypedef) + return TT->getDecl(); + } + + return nullptr; +} + TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) TypedefDecl(C, nullptr, SourceLocation(), SourceLocation(), nullptr, nullptr); diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index a46787fb0e8f..79cadcfcb167 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -66,6 +66,12 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Context, void *Decl::operator new(std::size_t Size, const ASTContext &Ctx, DeclContext *Parent, std::size_t Extra) { assert(!Parent || &Parent->getParentASTContext() == &Ctx); + // With local visibility enabled, we track the owning module even for local + // declarations. + if (Ctx.getLangOpts().ModulesLocalVisibility) { + void *Buffer = ::operator new(sizeof(Module *) + Size + Extra, Ctx); + return new (Buffer) Module*(nullptr) + 1; + } return ::operator new(Size + Extra, Ctx); } @@ -336,20 +342,34 @@ bool Decl::isReferenced() const { static AvailabilityResult CheckAvailability(ASTContext &Context, const AvailabilityAttr *A, std::string *Message) { - StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); - StringRef PrettyPlatformName - = AvailabilityAttr::getPrettyPlatformName(TargetPlatform); - if (PrettyPlatformName.empty()) - PrettyPlatformName = TargetPlatform; + VersionTuple TargetMinVersion = + Context.getTargetInfo().getPlatformMinVersion(); - VersionTuple TargetMinVersion = Context.getTargetInfo().getPlatformMinVersion(); if (TargetMinVersion.empty()) return AR_Available; + // Check if this is an App Extension "platform", and if so chop off + // the suffix for matching with the actual platform. + StringRef ActualPlatform = A->getPlatform()->getName(); + StringRef RealizedPlatform = ActualPlatform; + if (Context.getLangOpts().AppExt) { + size_t suffix = RealizedPlatform.rfind("_app_extension"); + if (suffix != StringRef::npos) + RealizedPlatform = RealizedPlatform.slice(0, suffix); + } + + StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); + // Match the platform name. - if (A->getPlatform()->getName() != TargetPlatform) + if (RealizedPlatform != TargetPlatform) return AR_Available; - + + StringRef PrettyPlatformName + = AvailabilityAttr::getPrettyPlatformName(ActualPlatform); + + if (PrettyPlatformName.empty()) + PrettyPlatformName = ActualPlatform; + std::string HintMessage; if (!A->getMessage().empty()) { HintMessage = " - "; @@ -583,6 +603,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Block: case Captured: case TranslationUnit: + case ExternCContext: case UsingDirective: case ClassTemplateSpecialization: @@ -846,6 +867,10 @@ bool DeclContext::isDependentContext() const { return getLexicalParent()->isDependentContext(); } + // FIXME: A variable template is a dependent context, but is not a + // DeclContext. A context within it (such as a lambda-expression) + // should be considered dependent. + return getParent() && getParent()->isDependentContext(); } @@ -889,6 +914,7 @@ bool DeclContext::Encloses(const DeclContext *DC) const { DeclContext *DeclContext::getPrimaryContext() { switch (DeclKind) { case Decl::TranslationUnit: + case Decl::ExternCContext: case Decl::LinkageSpec: case Decl::Block: case Decl::Captured: @@ -991,23 +1017,24 @@ DeclContext::BuildDeclChain(ArrayRef<Decl*> Decls, /// built a lookup map. For every name in the map, pull in the new names from /// the external storage. void DeclContext::reconcileExternalVisibleStorage() const { - assert(NeedToReconcileExternalVisibleStorage && LookupPtr.getPointer()); + assert(NeedToReconcileExternalVisibleStorage && LookupPtr); NeedToReconcileExternalVisibleStorage = false; - for (auto &Lookup : *LookupPtr.getPointer()) + for (auto &Lookup : *LookupPtr) Lookup.second.setHasExternalDecls(); } /// \brief Load the declarations within this lexical storage from an /// external source. -void +/// \return \c true if any declarations were added. +bool DeclContext::LoadLexicalDeclsFromExternalStorage() const { ExternalASTSource *Source = getParentASTContext().getExternalSource(); assert(hasExternalLexicalStorage() && Source && "No external storage?"); // Notify that we have a DeclContext that is initializing. ExternalASTSource::Deserializing ADeclContext(Source); - + // Load the external declarations, if any. SmallVector<Decl*, 64> Decls; ExternalLexicalStorage = false; @@ -1017,11 +1044,11 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { case ELR_Failure: case ELR_AlreadyLoaded: - return; + return false; } if (Decls.empty()) - return; + return false; // We may have already loaded just the fields of this record, in which case // we need to ignore them. @@ -1038,6 +1065,7 @@ DeclContext::LoadLexicalDeclsFromExternalStorage() const { FirstDecl = ExternalFirst; if (!LastDecl) LastDecl = ExternalLast; + return true; } DeclContext::lookup_result @@ -1045,7 +1073,7 @@ ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC, DeclarationName Name) { ASTContext &Context = DC->getParentASTContext(); StoredDeclsMap *Map; - if (!(Map = DC->LookupPtr.getPointer())) + if (!(Map = DC->LookupPtr)) Map = DC->CreateStoredDeclsMap(Context); if (DC->NeedToReconcileExternalVisibleStorage) DC->reconcileExternalVisibleStorage(); @@ -1061,7 +1089,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, ArrayRef<NamedDecl*> Decls) { ASTContext &Context = DC->getParentASTContext(); StoredDeclsMap *Map; - if (!(Map = DC->LookupPtr.getPointer())) + if (!(Map = DC->LookupPtr)) Map = DC->CreateStoredDeclsMap(Context); if (DC->NeedToReconcileExternalVisibleStorage) DC->reconcileExternalVisibleStorage(); @@ -1078,7 +1106,7 @@ ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, // first. llvm::SmallVector<unsigned, 8> Skip; for (unsigned I = 0, N = Decls.size(); I != N; ++I) - if (List.HandleRedeclaration(Decls[I])) + if (List.HandleRedeclaration(Decls[I], /*IsKnownNewer*/false)) Skip.push_back(I); Skip.push_back(Decls.size()); @@ -1155,7 +1183,7 @@ void DeclContext::removeDecl(Decl *D) { // Remove only decls that have a name if (!ND->getDeclName()) return; - StoredDeclsMap *Map = getPrimaryContext()->LookupPtr.getPointer(); + StoredDeclsMap *Map = getPrimaryContext()->LookupPtr; if (!Map) return; StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); @@ -1243,32 +1271,38 @@ static bool shouldBeHidden(NamedDecl *D) { StoredDeclsMap *DeclContext::buildLookup() { assert(this == getPrimaryContext() && "buildLookup called on non-primary DC"); - // FIXME: Should we keep going if hasExternalVisibleStorage? - if (!LookupPtr.getInt()) - return LookupPtr.getPointer(); + if (!HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups) + return LookupPtr; SmallVector<DeclContext *, 2> Contexts; collectAllContexts(Contexts); - for (unsigned I = 0, N = Contexts.size(); I != N; ++I) - buildLookupImpl<&DeclContext::decls_begin, - &DeclContext::decls_end>(Contexts[I]); + + if (HasLazyExternalLexicalLookups) { + HasLazyExternalLexicalLookups = false; + for (auto *DC : Contexts) { + if (DC->hasExternalLexicalStorage()) + HasLazyLocalLexicalLookups |= + DC->LoadLexicalDeclsFromExternalStorage(); + } + + if (!HasLazyLocalLexicalLookups) + return LookupPtr; + } + + for (auto *DC : Contexts) + buildLookupImpl(DC, hasExternalVisibleStorage()); // We no longer have any lazy decls. - LookupPtr.setInt(false); - return LookupPtr.getPointer(); + HasLazyLocalLexicalLookups = false; + return LookupPtr; } /// buildLookupImpl - Build part of the lookup data structure for the /// declarations contained within DCtx, which will either be this /// DeclContext, a DeclContext linked to it, or a transparent context /// nested within it. -template<DeclContext::decl_iterator (DeclContext::*Begin)() const, - DeclContext::decl_iterator (DeclContext::*End)() const> -void DeclContext::buildLookupImpl(DeclContext *DCtx) { - for (decl_iterator I = (DCtx->*Begin)(), E = (DCtx->*End)(); - I != E; ++I) { - Decl *D = *I; - +void DeclContext::buildLookupImpl(DeclContext *DCtx, bool Internal) { + for (Decl *D : DCtx->noload_decls()) { // Insert this declaration into the lookup structure, but only if // it's semantically within its decl context. Any other decls which // should be found in this context are added eagerly. @@ -1282,39 +1316,46 @@ void DeclContext::buildLookupImpl(DeclContext *DCtx) { (!ND->isFromASTFile() || (isTranslationUnit() && !getParentASTContext().getLangOpts().CPlusPlus))) - makeDeclVisibleInContextImpl(ND, false); + makeDeclVisibleInContextImpl(ND, Internal); // If this declaration is itself a transparent declaration context // or inline namespace, add the members of this declaration of that // context (recursively). if (DeclContext *InnerCtx = dyn_cast<DeclContext>(D)) if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) - buildLookupImpl<Begin, End>(InnerCtx); + buildLookupImpl(InnerCtx, Internal); } } +NamedDecl *const DeclContextLookupResult::SingleElementDummyList = nullptr; + DeclContext::lookup_result -DeclContext::lookup(DeclarationName Name) { +DeclContext::lookup(DeclarationName Name) const { assert(DeclKind != Decl::LinkageSpec && "Should not perform lookups into linkage specs!"); - DeclContext *PrimaryContext = getPrimaryContext(); + const DeclContext *PrimaryContext = getPrimaryContext(); 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 we have an external source, ensure that any later redeclarations of this + // context have been loaded, since they may add names to the result of this + // lookup (or add external visible storage). + ExternalASTSource *Source = getParentASTContext().getExternalSource(); + if (Source) + (void)cast<Decl>(this)->getMostRecentDecl(); if (hasExternalVisibleStorage()) { + assert(Source && "external visible storage but no external source?"); + if (NeedToReconcileExternalVisibleStorage) reconcileExternalVisibleStorage(); - StoredDeclsMap *Map = LookupPtr.getPointer(); + StoredDeclsMap *Map = LookupPtr; - if (LookupPtr.getInt()) - Map = buildLookup(); + if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups) + // FIXME: Make buildLookup const? + Map = const_cast<DeclContext*>(this)->buildLookup(); if (!Map) Map = CreateStoredDeclsMap(getParentASTContext()); @@ -1325,28 +1366,27 @@ DeclContext::lookup(DeclarationName Name) { if (!R.second && !R.first->second.hasExternalDecls()) return R.first->second.getLookupResult(); - ExternalASTSource *Source = getParentASTContext().getExternalSource(); if (Source->FindExternalVisibleDeclsByName(this, Name) || !R.second) { - if (StoredDeclsMap *Map = LookupPtr.getPointer()) { + if (StoredDeclsMap *Map = LookupPtr) { StoredDeclsMap::iterator I = Map->find(Name); if (I != Map->end()) return I->second.getLookupResult(); } } - return lookup_result(lookup_iterator(nullptr), lookup_iterator(nullptr)); + return lookup_result(); } - StoredDeclsMap *Map = LookupPtr.getPointer(); - if (LookupPtr.getInt()) - Map = buildLookup(); + StoredDeclsMap *Map = LookupPtr; + if (HasLazyLocalLexicalLookups || HasLazyExternalLexicalLookups) + Map = const_cast<DeclContext*>(this)->buildLookup(); if (!Map) - return lookup_result(lookup_iterator(nullptr), lookup_iterator(nullptr)); + return lookup_result(); StoredDeclsMap::iterator I = Map->find(Name); if (I == Map->end()) - return lookup_result(lookup_iterator(nullptr), lookup_iterator(nullptr)); + return lookup_result(); return I->second.getLookupResult(); } @@ -1355,40 +1395,29 @@ DeclContext::lookup_result DeclContext::noload_lookup(DeclarationName Name) { assert(DeclKind != Decl::LinkageSpec && "Should not perform lookups into linkage specs!"); - if (!hasExternalVisibleStorage()) - return lookup(Name); DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) return PrimaryContext->noload_lookup(Name); - StoredDeclsMap *Map = LookupPtr.getPointer(); - if (LookupPtr.getInt()) { - // Carefully build the lookup map, without deserializing anything. + // If we have any lazy lexical declarations not in our lookup map, add them + // now. Don't import any external declarations, not even if we know we have + // some missing from the external visible lookups. + if (HasLazyLocalLexicalLookups) { SmallVector<DeclContext *, 2> Contexts; collectAllContexts(Contexts); for (unsigned I = 0, N = Contexts.size(); I != N; ++I) - buildLookupImpl<&DeclContext::noload_decls_begin, - &DeclContext::noload_decls_end>(Contexts[I]); - - // We no longer have any lazy decls. - LookupPtr.setInt(false); - - // There may now be names for which we have local decls but are - // missing the external decls. FIXME: Just set the hasExternalDecls - // flag on those names that have external decls. - NeedToReconcileExternalVisibleStorage = true; - - Map = LookupPtr.getPointer(); + buildLookupImpl(Contexts[I], hasExternalVisibleStorage()); + HasLazyLocalLexicalLookups = false; } + StoredDeclsMap *Map = LookupPtr; if (!Map) - return lookup_result(lookup_iterator(nullptr), lookup_iterator(nullptr)); + return lookup_result(); StoredDeclsMap::iterator I = Map->find(Name); return I != Map->end() ? I->second.getLookupResult() - : lookup_result(lookup_iterator(nullptr), - lookup_iterator(nullptr)); + : lookup_result(); } void DeclContext::localUncachedLookup(DeclarationName Name, @@ -1404,8 +1433,9 @@ void DeclContext::localUncachedLookup(DeclarationName Name, } // If we have a lookup table, check there first. Maybe we'll get lucky. - if (Name && !LookupPtr.getInt()) { - if (StoredDeclsMap *Map = LookupPtr.getPointer()) { + // FIXME: Should we be checking these flags on the primary context? + if (Name && !HasLazyLocalLexicalLookups && !HasLazyExternalLexicalLookups) { + if (StoredDeclsMap *Map = LookupPtr) { StoredDeclsMap::iterator Pos = Map->find(Name); if (Pos != Map->end()) { Results.insert(Results.end(), @@ -1418,6 +1448,8 @@ void DeclContext::localUncachedLookup(DeclarationName Name, // Slow case: grovel through the declarations in our chain looking for // matches. + // FIXME: If we have lazy external declarations, this will not find them! + // FIXME: Should we CollectAllContexts and walk them all here? for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) { if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) if (ND->getDeclName() == Name) @@ -1498,7 +1530,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, // FIXME: As a performance hack, don't add such decls into the translation // unit unless we're in C++, since qualified lookup into the TU is never // performed. - if (LookupPtr.getPointer() || hasExternalVisibleStorage() || + if (LookupPtr || hasExternalVisibleStorage() || ((!Recoverable || D->getDeclContext() != D->getLexicalDeclContext()) && (getParentASTContext().getLangOpts().CPlusPlus || !isTranslationUnit()))) { @@ -1508,7 +1540,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, buildLookup(); makeDeclVisibleInContextImpl(D, Internal); } else { - LookupPtr.setInt(true); + HasLazyLocalLexicalLookups = true; } // If we are a transparent context or inline namespace, insert into our @@ -1526,7 +1558,7 @@ void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) { // Find or create the stored declaration map. - StoredDeclsMap *Map = LookupPtr.getPointer(); + StoredDeclsMap *Map = LookupPtr; if (!Map) { ASTContext *C = &getParentASTContext(); Map = CreateStoredDeclsMap(*C); @@ -1555,12 +1587,12 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) { return; } - else if (DeclNameEntries.isNull()) { + if (DeclNameEntries.isNull()) { DeclNameEntries.setOnlyValue(D); return; } - if (DeclNameEntries.HandleRedeclaration(D)) { + if (DeclNameEntries.HandleRedeclaration(D, /*IsKnownNewer*/!Internal)) { // This declaration has replaced an existing one for which // declarationReplaces returns true. return; @@ -1570,15 +1602,17 @@ void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) { DeclNameEntries.AddSubsequentDecl(D); } +UsingDirectiveDecl *DeclContext::udir_iterator::operator*() const { + return cast<UsingDirectiveDecl>(*I); +} + /// Returns iterator range [First, Last) of UsingDirectiveDecls stored within /// this context. DeclContext::udir_range DeclContext::using_directives() const { // FIXME: Use something more efficient than normal lookup for using // directives. In C++, using directives are looked up more than anything else. - lookup_const_result Result = lookup(UsingDirectiveDecl::getName()); - return udir_range( - reinterpret_cast<UsingDirectiveDecl *const *>(Result.begin()), - reinterpret_cast<UsingDirectiveDecl *const *>(Result.end())); + lookup_result Result = lookup(UsingDirectiveDecl::getName()); + return udir_range(Result.begin(), Result.end()); } //===----------------------------------------------------------------------===// @@ -1586,7 +1620,7 @@ DeclContext::udir_range DeclContext::using_directives() const { //===----------------------------------------------------------------------===// StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const { - assert(!LookupPtr.getPointer() && "context already has a decls map"); + assert(!LookupPtr && "context already has a decls map"); assert(getPrimaryContext() == this && "creating decls map on non-primary context"); @@ -1598,7 +1632,7 @@ StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const { M = new StoredDeclsMap(); M->Previous = C.LastSDM; C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent); - LookupPtr.setPointer(M); + LookupPtr = M; return M; } @@ -1630,11 +1664,11 @@ DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C, assert(Parent->isDependentContext() && "cannot iterate dependent diagnostics of non-dependent context"); Parent = Parent->getPrimaryContext(); - if (!Parent->LookupPtr.getPointer()) + if (!Parent->LookupPtr) Parent->CreateStoredDeclsMap(C); - DependentStoredDeclsMap *Map - = static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr.getPointer()); + DependentStoredDeclsMap *Map = + static_cast<DependentStoredDeclsMap *>(Parent->LookupPtr); // Allocate the copy of the PartialDiagnostic via the ASTContext's // BumpPtrAllocator, rather than the ASTContext itself. diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 9af8c4b242a6..8dc62dd07f2c 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -991,7 +991,7 @@ CXXMethodDecl* CXXRecordDecl::getLambdaCallOperator() const { if (!isLambda()) return nullptr; DeclarationName Name = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); - DeclContext::lookup_const_result Calls = lookup(Name); + DeclContext::lookup_result Calls = lookup(Name); assert(!Calls.empty() && "Missing lambda call operator!"); assert(Calls.size() == 1 && "More than one lambda call operator!"); @@ -1008,7 +1008,7 @@ CXXMethodDecl* CXXRecordDecl::getLambdaStaticInvoker() const { if (!isLambda()) return nullptr; DeclarationName Name = &getASTContext().Idents.get(getLambdaStaticInvokerName()); - DeclContext::lookup_const_result Invoker = lookup(Name); + DeclContext::lookup_result Invoker = lookup(Name); if (Invoker.empty()) return nullptr; assert(Invoker.size() == 1 && "More than one static invoker operator!"); NamedDecl *InvokerFun = Invoker.front(); @@ -1173,7 +1173,7 @@ static void CollectVisibleConversions(ASTContext &Context, /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. -std::pair<CXXRecordDecl::conversion_iterator,CXXRecordDecl::conversion_iterator> +llvm::iterator_range<CXXRecordDecl::conversion_iterator> CXXRecordDecl::getVisibleConversionFunctions() { ASTContext &Ctx = getASTContext(); @@ -1189,7 +1189,7 @@ CXXRecordDecl::getVisibleConversionFunctions() { data().ComputedVisibleConversions = true; } } - return std::make_pair(Set->begin(), Set->end()); + return llvm::make_range(Set->begin(), Set->end()); } void CXXRecordDecl::removeConversion(const NamedDecl *ConvDecl) { @@ -1307,7 +1307,7 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const { = Context.DeclarationNames.getCXXDestructorName( Context.getCanonicalType(ClassType)); - DeclContext::lookup_const_result R = lookup(Name); + DeclContext::lookup_result R = lookup(Name); if (R.empty()) return nullptr; @@ -1418,9 +1418,8 @@ CXXMethodDecl::getCorrespondingMethodInClass(const CXXRecordDecl *RD, return nullptr; } - lookup_const_result Candidates = RD->lookup(getDeclName()); - for (NamedDecl * const * I = Candidates.begin(); I != Candidates.end(); ++I) { - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(*I); + for (auto *ND : RD->lookup(getDeclName())) { + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(ND); if (!MD) continue; if (recursivelyOverrides(MD, this)) @@ -1491,8 +1490,8 @@ bool CXXMethodDecl::isUsualDeallocationFunction() const { // This function is a usual deallocation function if there are no // single-parameter deallocation functions of the same kind. - DeclContext::lookup_const_result R = getDeclContext()->lookup(getDeclName()); - for (DeclContext::lookup_const_result::iterator I = R.begin(), E = R.end(); + DeclContext::lookup_result R = getDeclContext()->lookup(getDeclName()); + for (DeclContext::lookup_result::iterator I = R.begin(), E = R.end(); I != E; ++I) { if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) if (FD->getNumParams() == 1) @@ -1740,6 +1739,10 @@ CXXConstructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, isImplicitlyDeclared, isConstexpr); } +CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const { + return CtorInitializers.get(getASTContext().getExternalSource()); +} + CXXConstructorDecl *CXXConstructorDecl::getTargetConstructor() const { assert(isDelegatingConstructor() && "Not a delegating constructor!"); Expr *E = (*init_begin())->getInit()->IgnoreImplicit(); @@ -1887,6 +1890,15 @@ CXXDestructorDecl::Create(ASTContext &C, CXXRecordDecl *RD, isInline, isImplicitlyDeclared); } +void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD) { + auto *First = cast<CXXDestructorDecl>(getFirstDecl()); + if (OD && !First->OperatorDelete) { + First->OperatorDelete = OD; + if (auto *L = getASTMutationListener()) + L->ResolvedOperatorDelete(First, OD); + } +} + void CXXConversionDecl::anchor() { } CXXConversionDecl * diff --git a/lib/AST/DeclGroup.cpp b/lib/AST/DeclGroup.cpp index 9861f2278f9a..512837fdf3f4 100644 --- a/lib/AST/DeclGroup.cpp +++ b/lib/AST/DeclGroup.cpp @@ -18,6 +18,8 @@ using namespace clang; DeclGroup* DeclGroup::Create(ASTContext &C, Decl **Decls, unsigned NumDecls) { + static_assert(sizeof(DeclGroup) % llvm::AlignOf<void *>::Alignment == 0, + "Trailing data is unaligned!"); assert(NumDecls > 1 && "Invalid DeclGroup"); unsigned Size = sizeof(DeclGroup) + sizeof(Decl*) * NumDecls; void* Mem = C.Allocate(Size, llvm::AlignOf<DeclGroup>::Alignment); diff --git a/lib/AST/DeclObjC.cpp b/lib/AST/DeclObjC.cpp index ed5367514c30..a63ba7e698a8 100644 --- a/lib/AST/DeclObjC.cpp +++ b/lib/AST/DeclObjC.cpp @@ -54,8 +54,8 @@ void ObjCContainerDecl::anchor() { } /// ObjCIvarDecl * ObjCContainerDecl::getIvarDecl(IdentifierInfo *Id) const { - lookup_const_result R = lookup(Id); - for (lookup_const_iterator Ivar = R.begin(), IvarEnd = R.end(); + lookup_result R = lookup(Id); + for (lookup_iterator Ivar = R.begin(), IvarEnd = R.end(); Ivar != IvarEnd; ++Ivar) { if (ObjCIvarDecl *ivar = dyn_cast<ObjCIvarDecl>(*Ivar)) return ivar; @@ -83,8 +83,8 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance, // + (float) class_method; // @end // - lookup_const_result R = lookup(Sel); - for (lookup_const_iterator Meth = R.begin(), MethEnd = R.end(); + lookup_result R = lookup(Sel); + for (lookup_iterator Meth = R.begin(), MethEnd = R.end(); Meth != MethEnd; ++Meth) { ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); if (MD && MD->isInstanceMethod() == isInstance) @@ -101,8 +101,8 @@ ObjCContainerDecl::getMethod(Selector Sel, bool isInstance, 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(); + lookup_result R = lookup(Sel); + for (lookup_iterator Meth = R.begin(), MethEnd = R.end(); Meth != MethEnd; ++Meth) { ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(*Meth); if (MD && MD->isInstanceMethod() && !MD->isImplicit()) @@ -161,8 +161,8 @@ ObjCPropertyDecl::findPropertyDecl(const DeclContext *DC, return nullptr; } - DeclContext::lookup_const_result R = DC->lookup(propertyID); - for (DeclContext::lookup_const_iterator I = R.begin(), E = R.end(); I != E; + DeclContext::lookup_result R = DC->lookup(propertyID); + for (DeclContext::lookup_iterator I = R.begin(), E = R.end(); I != E; ++I) if (ObjCPropertyDecl *PD = dyn_cast<ObjCPropertyDecl>(*I)) return PD; @@ -334,9 +334,8 @@ void ObjCInterfaceDecl::mergeClassExtensionProtocolList( return; // Merge ProtocolRefs into class's protocol list; - for (auto *P : all_referenced_protocols()) { - ProtocolRefs.push_back(P); - } + ProtocolRefs.append(all_referenced_protocol_begin(), + all_referenced_protocol_end()); data().AllReferencedProtocols.set(ProtocolRefs.data(), ProtocolRefs.size(),C); } @@ -617,8 +616,7 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod( // Look through local category implementations associated with the class. if (!Method) - Method = Instance ? getCategoryInstanceMethod(Sel) - : getCategoryClassMethod(Sel); + Method = getCategoryMethod(Sel, Instance); // Before we give up, check if the selector is an instance method. // But only in the root. This matches gcc's behavior and what the @@ -1101,7 +1099,7 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { if (NumArgs > 1) return nullptr; - if (!isInstanceMethod() || getMethodFamily() != OMF_None) + if (!isInstanceMethod()) return nullptr; if (isPropertyAccessor()) { @@ -1822,6 +1820,11 @@ void ObjCImplementationDecl::setIvarInitializers(ASTContext &C, } } +ObjCImplementationDecl::init_const_iterator +ObjCImplementationDecl::init_begin() const { + return IvarInitializers.get(getASTContext().getExternalSource()); +} + raw_ostream &clang::operator<<(raw_ostream &OS, const ObjCImplementationDecl &ID) { OS << ID.getName(); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 0d1d2a4613dc..6374a92621a4 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -160,17 +160,43 @@ RedeclarableTemplateDecl::CommonBase *RedeclarableTemplateDecl::getCommonPtr() c return Common; } -template <class EntryType> -typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType* +template<class EntryType> +typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType * RedeclarableTemplateDecl::findSpecializationImpl( - llvm::FoldingSetVector<EntryType> &Specs, - ArrayRef<TemplateArgument> Args, - void *&InsertPos) { + llvm::FoldingSetVector<EntryType> &Specs, ArrayRef<TemplateArgument> Args, + void *&InsertPos) { typedef SpecEntryTraits<EntryType> SETraits; llvm::FoldingSetNodeID ID; EntryType::Profile(ID,Args, getASTContext()); EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos); - return Entry ? SETraits::getMostRecentDecl(Entry) : nullptr; + return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr; +} + +template<class Derived, class EntryType> +void RedeclarableTemplateDecl::addSpecializationImpl( + llvm::FoldingSetVector<EntryType> &Specializations, EntryType *Entry, + void *InsertPos) { + typedef SpecEntryTraits<EntryType> SETraits; + if (InsertPos) { +#ifndef NDEBUG + void *CorrectInsertPos; + assert(!findSpecializationImpl(Specializations, + SETraits::getTemplateArgs(Entry), + CorrectInsertPos) && + InsertPos == CorrectInsertPos && + "given incorrect InsertPos for specialization"); +#endif + Specializations.InsertNode(Entry, InsertPos); + } else { + EntryType *Existing = Specializations.GetOrInsertNode(Entry); + (void)Existing; + assert(SETraits::getDecl(Existing)->isCanonicalDecl() && + "non-canonical specialization?"); + } + + if (ASTMutationListener *L = getASTMutationListener()) + L->AddedCXXTemplateSpecialization(cast<Derived>(this), + SETraits::getDecl(Entry)); } /// \brief Generate the injected template arguments for the given template @@ -246,7 +272,11 @@ FunctionTemplateDecl::newCommon(ASTContext &C) const { } void FunctionTemplateDecl::LoadLazySpecializations() const { - Common *CommonPtr = getCommonPtr(); + // Grab the most recent declaration to ensure we've loaded any lazy + // redeclarations of this template. + // + // FIXME: Avoid walking the entire redeclaration chain here. + Common *CommonPtr = getMostRecentDecl()->getCommonPtr(); if (CommonPtr->LazySpecializations) { ASTContext &Context = getASTContext(); uint32_t *Specs = CommonPtr->LazySpecializations; @@ -270,12 +300,8 @@ FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void FunctionTemplateDecl::addSpecialization( FunctionTemplateSpecializationInfo *Info, void *InsertPos) { - if (InsertPos) - getSpecializations().InsertNode(Info, InsertPos); - else - getSpecializations().GetOrInsertNode(Info); - if (ASTMutationListener *L = getASTMutationListener()) - L->AddedCXXTemplateSpecialization(this, Info->Function); + addSpecializationImpl<FunctionTemplateDecl>(getSpecializations(), Info, + InsertPos); } ArrayRef<TemplateArgument> FunctionTemplateDecl::getInjectedTemplateArgs() { @@ -320,7 +346,11 @@ ClassTemplateDecl *ClassTemplateDecl::CreateDeserialized(ASTContext &C, } void ClassTemplateDecl::LoadLazySpecializations() const { - Common *CommonPtr = getCommonPtr(); + // Grab the most recent declaration to ensure we've loaded any lazy + // redeclarations of this template. + // + // FIXME: Avoid walking the entire redeclaration chain here. + Common *CommonPtr = getMostRecentDecl()->getCommonPtr(); if (CommonPtr->LazySpecializations) { ASTContext &Context = getASTContext(); uint32_t *Specs = CommonPtr->LazySpecializations; @@ -357,16 +387,7 @@ ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, void *InsertPos) { - if (InsertPos) - getSpecializations().InsertNode(D, InsertPos); - else { - ClassTemplateSpecializationDecl *Existing - = getSpecializations().GetOrInsertNode(D); - (void)Existing; - assert(Existing->isCanonicalDecl() && "Non-canonical specialization?"); - } - if (ASTMutationListener *L = getASTMutationListener()) - L->AddedCXXTemplateSpecialization(this, D); + addSpecializationImpl<ClassTemplateDecl>(getSpecializations(), D, InsertPos); } ClassTemplatePartialSpecializationDecl * @@ -953,7 +974,11 @@ VarTemplateDecl *VarTemplateDecl::CreateDeserialized(ASTContext &C, // TODO: Unify across class, function and variable templates? // May require moving this and Common to RedeclarableTemplateDecl. void VarTemplateDecl::LoadLazySpecializations() const { - Common *CommonPtr = getCommonPtr(); + // Grab the most recent declaration to ensure we've loaded any lazy + // redeclarations of this template. + // + // FIXME: Avoid walking the entire redeclaration chain here. + Common *CommonPtr = getMostRecentDecl()->getCommonPtr(); if (CommonPtr->LazySpecializations) { ASTContext &Context = getASTContext(); uint32_t *Specs = CommonPtr->LazySpecializations; @@ -990,16 +1015,7 @@ VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, void *InsertPos) { - if (InsertPos) - getSpecializations().InsertNode(D, InsertPos); - else { - VarTemplateSpecializationDecl *Existing = - getSpecializations().GetOrInsertNode(D); - (void)Existing; - assert(Existing->isCanonicalDecl() && "Non-canonical specialization?"); - } - if (ASTMutationListener *L = getASTMutationListener()) - L->AddedCXXTemplateSpecialization(this, D); + addSpecializationImpl<VarTemplateDecl>(getSpecializations(), D, InsertPos); } VarTemplatePartialSpecializationDecl * diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 712de5056e8d..76a4da2371b5 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1141,40 +1141,13 @@ CallExpr::CallExpr(const ASTContext& C, StmtClass SC, Expr *fn, RParenLoc = rparenloc; } -CallExpr::CallExpr(const ASTContext& C, Expr *fn, ArrayRef<Expr*> args, +CallExpr::CallExpr(const ASTContext &C, Expr *fn, ArrayRef<Expr *> args, QualType t, ExprValueKind VK, SourceLocation rparenloc) - : Expr(CallExprClass, t, VK, OK_Ordinary, - fn->isTypeDependent(), - fn->isValueDependent(), - fn->isInstantiationDependent(), - fn->containsUnexpandedParameterPack()), - NumArgs(args.size()) { - - SubExprs = new (C) Stmt*[args.size()+PREARGS_START]; - SubExprs[FN] = fn; - for (unsigned i = 0; i != args.size(); ++i) { - if (args[i]->isTypeDependent()) - ExprBits.TypeDependent = true; - if (args[i]->isValueDependent()) - ExprBits.ValueDependent = true; - if (args[i]->isInstantiationDependent()) - ExprBits.InstantiationDependent = true; - if (args[i]->containsUnexpandedParameterPack()) - ExprBits.ContainsUnexpandedParameterPack = true; - - SubExprs[i+PREARGS_START] = args[i]; - } - - CallExprBits.NumPreArgs = 0; - RParenLoc = rparenloc; + : CallExpr(C, CallExprClass, fn, /*NumPreArgs=*/0, args, t, VK, rparenloc) { } CallExpr::CallExpr(const ASTContext &C, StmtClass SC, EmptyShell Empty) - : Expr(SC, Empty), SubExprs(nullptr), NumArgs(0) { - // FIXME: Why do we allocate this? - SubExprs = new (C) Stmt*[PREARGS_START]; - CallExprBits.NumPreArgs = 0; -} + : CallExpr(C, SC, /*NumPreArgs=*/0, Empty) {} CallExpr::CallExpr(const ASTContext &C, StmtClass SC, unsigned NumPreArgs, EmptyShell Empty) @@ -1271,16 +1244,21 @@ bool CallExpr::isUnevaluatedBuiltinCall(ASTContext &Ctx) const { return false; } -QualType CallExpr::getCallReturnType() const { - QualType CalleeType = getCallee()->getType(); - if (const PointerType *FnTypePtr = CalleeType->getAs<PointerType>()) +QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const { + const Expr *Callee = getCallee(); + QualType CalleeType = Callee->getType(); + if (const auto *FnTypePtr = CalleeType->getAs<PointerType>()) { CalleeType = FnTypePtr->getPointeeType(); - else if (const BlockPointerType *BPT = CalleeType->getAs<BlockPointerType>()) + } else if (const auto *BPT = CalleeType->getAs<BlockPointerType>()) { CalleeType = BPT->getPointeeType(); - else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember)) + } else if (CalleeType->isSpecificPlaceholderType(BuiltinType::BoundMember)) { + if (isa<CXXPseudoDestructorExpr>(Callee->IgnoreParens())) + return Ctx.VoidTy; + // This should never be overloaded and so should never return null. - CalleeType = Expr::findBoundMemberType(getCallee()); - + CalleeType = Expr::findBoundMemberType(Callee); + } + const FunctionType *FnType = CalleeType->castAs<FunctionType>(); return FnType->getReturnType(); } @@ -1360,16 +1338,50 @@ IdentifierInfo *OffsetOfExpr::OffsetOfNode::getFieldName() const { return reinterpret_cast<IdentifierInfo *> (Data & ~(uintptr_t)Mask); } -MemberExpr *MemberExpr::Create(const ASTContext &C, Expr *base, bool isarrow, - NestedNameSpecifierLoc QualifierLoc, - SourceLocation TemplateKWLoc, - ValueDecl *memberdecl, - DeclAccessPair founddecl, - DeclarationNameInfo nameinfo, - const TemplateArgumentListInfo *targs, - QualType ty, - ExprValueKind vk, - ExprObjectKind ok) { +UnaryExprOrTypeTraitExpr::UnaryExprOrTypeTraitExpr( + UnaryExprOrTypeTrait ExprKind, Expr *E, QualType resultType, + SourceLocation op, SourceLocation rp) + : Expr(UnaryExprOrTypeTraitExprClass, resultType, VK_RValue, OK_Ordinary, + false, // Never type-dependent (C++ [temp.dep.expr]p3). + // Value-dependent if the argument is type-dependent. + E->isTypeDependent(), E->isInstantiationDependent(), + E->containsUnexpandedParameterPack()), + OpLoc(op), RParenLoc(rp) { + UnaryExprOrTypeTraitExprBits.Kind = ExprKind; + UnaryExprOrTypeTraitExprBits.IsType = false; + Argument.Ex = E; + + // Check to see if we are in the situation where alignof(decl) should be + // dependent because decl's alignment is dependent. + if (ExprKind == UETT_AlignOf) { + if (!isValueDependent() || !isInstantiationDependent()) { + E = E->IgnoreParens(); + + const ValueDecl *D = nullptr; + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) + D = DRE->getDecl(); + else if (const auto *ME = dyn_cast<MemberExpr>(E)) + D = ME->getMemberDecl(); + + if (D) { + for (const auto *I : D->specific_attrs<AlignedAttr>()) { + if (I->isAlignmentDependent()) { + setValueDependent(true); + setInstantiationDependent(true); + break; + } + } + } + } + } +} + +MemberExpr *MemberExpr::Create( + const ASTContext &C, Expr *base, bool isarrow, SourceLocation OperatorLoc, + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, + ValueDecl *memberdecl, DeclAccessPair founddecl, + DeclarationNameInfo nameinfo, const TemplateArgumentListInfo *targs, + QualType ty, ExprValueKind vk, ExprObjectKind ok) { std::size_t Size = sizeof(MemberExpr); bool hasQualOrFound = (QualifierLoc || @@ -1384,8 +1396,8 @@ MemberExpr *MemberExpr::Create(const ASTContext &C, Expr *base, bool isarrow, Size += ASTTemplateKWAndArgsInfo::sizeFor(0); void *Mem = C.Allocate(Size, llvm::alignOf<MemberExpr>()); - MemberExpr *E = new (Mem) MemberExpr(base, isarrow, memberdecl, nameinfo, - ty, vk, ok); + MemberExpr *E = new (Mem) + MemberExpr(base, isarrow, OperatorLoc, memberdecl, nameinfo, ty, vk, ok); if (hasQualOrFound) { // FIXME: Wrong. We should be looking at the member declaration we found. @@ -2132,8 +2144,8 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case OO_Greater: case OO_GreaterEqual: case OO_LessEqual: - if (Op->getCallReturnType()->isReferenceType() || - Op->getCallReturnType()->isVoidType()) + if (Op->getCallReturnType(Ctx)->isReferenceType() || + Op->getCallReturnType(Ctx)->isVoidType()) break; WarnE = this; Loc = Op->getOperatorLoc(); @@ -2149,12 +2161,16 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, // If this is a direct call, get the callee. const CallExpr *CE = cast<CallExpr>(this); if (const Decl *FD = CE->getCalleeDecl()) { + const FunctionDecl *Func = dyn_cast<FunctionDecl>(FD); + bool HasWarnUnusedResultAttr = Func ? Func->hasUnusedResultAttr() + : FD->hasAttr<WarnUnusedResultAttr>(); + // If the callee has attribute pure, const, or warn_unused_result, warn // about it. void foo() { strlen("bar"); } should warn. // // Note: If new cases are added here, DiagnoseUnusedExprResult should be // updated to match for QoI. - if (FD->hasAttr<WarnUnusedResultAttr>() || + if (HasWarnUnusedResultAttr || FD->hasAttr<PureAttr>() || FD->hasAttr<ConstAttr>()) { WarnE = this; Loc = CE->getCallee()->getLocStart(); @@ -2200,9 +2216,7 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, } if (const ObjCMethodDecl *MD = ME->getMethodDecl()) - if (MD->hasAttr<WarnUnusedResultAttr>() || - (MD->isPropertyAccessor() && !MD->getReturnType()->isVoidType() && - !ME->getReceiverType()->isObjCIdType())) { + if (MD->hasAttr<WarnUnusedResultAttr>()) { WarnE = this; Loc = getExprLoc(); return true; @@ -2387,7 +2401,7 @@ QualType Expr::findBoundMemberType(const Expr *expr) { return type; } - assert(isa<UnresolvedMemberExpr>(expr)); + assert(isa<UnresolvedMemberExpr>(expr) || isa<CXXPseudoDestructorExpr>(expr)); return QualType(); } @@ -2932,11 +2946,19 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case CXXOperatorCallExprClass: case CXXMemberCallExprClass: case CUDAKernelCallExprClass: + case UserDefinedLiteralClass: { + // We don't know a call definitely has side effects, except for calls + // to pure/const functions that definitely don't. + // If the call itself is considered side-effect free, check the operands. + const Decl *FD = cast<CallExpr>(this)->getCalleeDecl(); + bool IsPure = FD && (FD->hasAttr<ConstAttr>() || FD->hasAttr<PureAttr>()); + if (IsPure || !IncludePossibleEffects) + break; + return true; + } + 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; diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 93361666183b..d6f2ce63a0a5 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -208,8 +208,9 @@ void CXXNewExpr::AllocateArgsArray(const ASTContext &C, bool isArray, } bool CXXNewExpr::shouldNullCheckAllocation(const ASTContext &Ctx) const { - return getOperatorNew()->getType()-> - castAs<FunctionProtoType>()->isNothrow(Ctx); + return getOperatorNew()->getType()->castAs<FunctionProtoType>()->isNothrow( + Ctx) && + !getOperatorNew()->isReservedGlobalPlacementOperator(); } // CXXDeleteExpr @@ -237,10 +238,7 @@ CXXPseudoDestructorExpr::CXXPseudoDestructorExpr(const ASTContext &Context, SourceLocation ColonColonLoc, SourceLocation TildeLoc, PseudoDestructorTypeStorage DestroyedType) : Expr(CXXPseudoDestructorExprClass, - Context.getPointerType(Context.getFunctionType( - Context.VoidTy, None, - FunctionProtoType::ExtProtoInfo( - Context.getDefaultCallingConvention(false, true)))), + Context.BoundMemberTy, VK_RValue, OK_Ordinary, /*isTypeDependent=*/(Base->isTypeDependent() || (DestroyedType.getTypeSourceInfo() && @@ -359,8 +357,7 @@ OverloadExpr::OverloadExpr(StmtClass K, const ASTContext &C, Results = static_cast<DeclAccessPair *>( C.Allocate(sizeof(DeclAccessPair) * NumResults, llvm::alignOf<DeclAccessPair>())); - memcpy(Results, &*Begin.getIterator(), - NumResults * sizeof(DeclAccessPair)); + memcpy(Results, Begin.I, NumResults * sizeof(DeclAccessPair)); } // If we have explicit template arguments, check for dependent @@ -401,8 +398,7 @@ void OverloadExpr::initializeResults(const ASTContext &C, C.Allocate(sizeof(DeclAccessPair) * NumResults, llvm::alignOf<DeclAccessPair>())); - memcpy(Results, &*Begin.getIterator(), - NumResults * sizeof(DeclAccessPair)); + memcpy(Results, Begin.I, NumResults * sizeof(DeclAccessPair)); } } @@ -1031,6 +1027,11 @@ LambdaExpr *LambdaExpr::CreateDeserialized(const ASTContext &C, return new (Mem) LambdaExpr(EmptyShell(), NumCaptures, NumArrayIndexVars > 0); } +bool LambdaExpr::isInitCapture(const LambdaCapture *C) const { + return (C->capturesVariable() && C->getCapturedVar()->isInitCapture() && + (getCallOperator() == C->getCapturedVar()->getDeclContext())); +} + LambdaExpr::capture_iterator LambdaExpr::capture_begin() const { return getLambdaClass()->getLambdaData().Captures; } diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 933ea97fa2ba..5b320c2694ab 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -283,7 +283,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::CXXMemberCallExprClass: case Expr::UserDefinedLiteralClass: case Expr::CUDAKernelCallExprClass: - return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType()); + return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType(Ctx)); // __builtin_choose_expr is equivalent to the chosen expression. case Expr::ChooseExprClass: @@ -418,9 +418,10 @@ static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) { islvalue = NTTParm->getType()->isReferenceType(); else islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) || - isa<IndirectFieldDecl>(D) || - (Ctx.getLangOpts().CPlusPlus && - (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D))); + isa<IndirectFieldDecl>(D) || + (Ctx.getLangOpts().CPlusPlus && + (isa<FunctionDecl>(D) || isa<MSPropertyDecl>(D) || + isa<FunctionTemplateDecl>(D))); return islvalue ? Cl::CL_LValue : Cl::CL_PRValue; } @@ -605,7 +606,7 @@ static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, if (CT.isConstQualified()) return Cl::CM_ConstQualified; if (CT.getQualifiers().getAddressSpace() == LangAS::opencl_constant) - return Cl::CM_ConstQualified; + return Cl::CM_ConstAddrSpace; // Arrays are not modifiable, only their elements are. if (CT->isArrayType()) @@ -671,6 +672,7 @@ Expr::isModifiableLvalue(ASTContext &Ctx, SourceLocation *Loc) const { llvm_unreachable("CM_LValueCast and CL_LValue don't match"); case Cl::CM_NoSetterProperty: return MLV_NoSetterProperty; case Cl::CM_ConstQualified: return MLV_ConstQualified; + case Cl::CM_ConstAddrSpace: return MLV_ConstAddrSpace; case Cl::CM_ArrayType: return MLV_ArrayType; case Cl::CM_IncompleteType: return MLV_IncompleteType; } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 3d7f2dca7a2f..d1ec7aea1d2a 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1406,7 +1406,7 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, return true; } -const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { +static const ValueDecl *GetLValueBaseDecl(const LValue &LVal) { return LVal.Base.dyn_cast<const ValueDecl*>(); } @@ -2173,7 +2173,7 @@ struct CompleteObject { assert(Value && "missing value for complete object"); } - LLVM_EXPLICIT operator bool() const { return Value; } + explicit operator bool() const { return Value; } }; /// Find the designated sub-object of an rvalue. @@ -2502,8 +2502,9 @@ static bool AreElementsOfSameArray(QualType ObjType, } /// Find the complete object to which an LValue refers. -CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, AccessKinds AK, - const LValue &LVal, QualType LValType) { +static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, + AccessKinds AK, const LValue &LVal, + QualType LValType) { if (!LVal.Base) { Info.Diag(E, diag::note_constexpr_access_null) << AK; return CompleteObject(); @@ -3726,8 +3727,9 @@ static bool HandleFunctionCall(SourceLocation CallLoc, // 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() && - (MD->getParent()->isUnion() || hasFields(MD->getParent()))) { + if (MD && MD->isDefaulted() && + (MD->getParent()->isUnion() || + (MD->isTrivial() && hasFields(MD->getParent())))) { assert(This && (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())); LValue RHS; @@ -3791,11 +3793,9 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This, // 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())) && + if (Definition->isDefaulted() && Definition->isCopyOrMoveConstructor() && (Definition->getParent()->isUnion() || - hasFields(Definition->getParent()))) { + (Definition->isTrivial() && hasFields(Definition->getParent())))) { LValue RHS; RHS.setFrom(Info.Ctx, ArgValues[0]); return handleLValueToRValueConversion(Info, Args[0], Args[0]->getType(), @@ -6834,7 +6834,7 @@ void DataRecursiveIntBinOpEvaluator::process(EvalResult &Result) { } bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { - if (E->isAssignmentOp()) + if (!Info.keepEvaluatingAfterFailure() && E->isAssignmentOp()) return Error(E); if (DataRecursiveIntBinOpEvaluator::shouldEnqueue(E)) @@ -6846,7 +6846,11 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) { ComplexValue LHS, RHS; bool LHSOK; - if (E->getLHS()->getType()->isRealFloatingType()) { + if (E->isAssignmentOp()) { + LValue LV; + EvaluateLValue(E->getLHS(), LV, Info); + LHSOK = false; + } else if (LHSTy->isRealFloatingType()) { LHSOK = EvaluateFloat(E->getLHS(), LHS.FloatReal, Info); if (LHSOK) { LHS.makeComplexFloat(); @@ -7586,10 +7590,23 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context, else if (S->getString().getAsInteger(0, fill)) return false; - if (SNaN) - Result = llvm::APFloat::getSNaN(Sem, false, &fill); - else - Result = llvm::APFloat::getQNaN(Sem, false, &fill); + if (Context.getTargetInfo().isNan2008()) { + if (SNaN) + Result = llvm::APFloat::getSNaN(Sem, false, &fill); + else + Result = llvm::APFloat::getQNaN(Sem, false, &fill); + } else { + // Prior to IEEE 754-2008, architectures were allowed to choose whether + // the first bit of their significand was set for qNaN or sNaN. MIPS chose + // a different encoding to what became a standard in 2008, and for pre- + // 2008 revisions, MIPS interpreted sNaN-2008 as qNan and qNaN-2008 as + // sNaN. This is now known as "legacy NaN" encoding. + if (SNaN) + Result = llvm::APFloat::getQNaN(Sem, false, &fill); + else + Result = llvm::APFloat::getSNaN(Sem, false, &fill); + } + return true; } diff --git a/lib/AST/ExternalASTSource.cpp b/lib/AST/ExternalASTSource.cpp index 88941075dd06..730842a28f6a 100644 --- a/lib/AST/ExternalASTSource.cpp +++ b/lib/AST/ExternalASTSource.cpp @@ -66,6 +66,11 @@ Stmt *ExternalASTSource::GetExternalDeclStmt(uint64_t Offset) { return nullptr; } +CXXCtorInitializer ** +ExternalASTSource::GetExternalCXXCtorInitializers(uint64_t Offset) { + return nullptr; +} + CXXBaseSpecifier * ExternalASTSource::GetExternalCXXBaseSpecifiers(uint64_t Offset) { return nullptr; diff --git a/lib/AST/InheritViz.cpp b/lib/AST/InheritViz.cpp index eb3020c5f518..0b82da133fa7 100644 --- a/lib/AST/InheritViz.cpp +++ b/lib/AST/InheritViz.cpp @@ -22,11 +22,9 @@ #include "llvm/Support/raw_ostream.h" #include <map> #include <set> +using namespace clang; -using namespace llvm; - -namespace clang { - +namespace { /// InheritanceHierarchyWriter - Helper class that writes out a /// GraphViz file that diagrams the inheritance hierarchy starting at /// a given C++ class type. Note that we do not use LLVM's @@ -44,7 +42,8 @@ public: : Context(Context), Out(Out) { } void WriteGraph(QualType Type) { - Out << "digraph \"" << DOT::EscapeString(Type.getAsString()) << "\" {\n"; + Out << "digraph \"" << llvm::DOT::EscapeString(Type.getAsString()) + << "\" {\n"; WriteNode(Type, false); Out << "}\n"; } @@ -59,6 +58,7 @@ protected: /// (only) virtual base. raw_ostream& WriteNodeReference(QualType Type, bool FromVirtual); }; +} // namespace void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { QualType CanonType = Context.getCanonicalType(Type); @@ -78,7 +78,7 @@ void InheritanceHierarchyWriter::WriteNode(QualType Type, bool FromVirtual) { // Give the node a label based on the name of the class. std::string TypeName = Type.getAsString(); - Out << " [ shape=\"box\", label=\"" << DOT::EscapeString(TypeName); + Out << " [ shape=\"box\", label=\"" << llvm::DOT::EscapeString(TypeName); // If the name of the class was a typedef or something different // from the "real" class name, show the real class name in @@ -139,9 +139,8 @@ void CXXRecordDecl::viewInheritance(ASTContext& Context) const { int FD; SmallString<128> Filename; - std::error_code EC = - sys::fs::createTemporaryFile(Self.getAsString(), "dot", FD, Filename); - if (EC) { + if (std::error_code EC = llvm::sys::fs::createTemporaryFile( + Self.getAsString(), "dot", FD, Filename)) { llvm::errs() << "Error: " << EC.message() << "\n"; return; } @@ -159,5 +158,3 @@ void CXXRecordDecl::viewInheritance(ASTContext& Context) const { // Display the graph DisplayGraph(Filename); } - -} diff --git a/lib/AST/ItaniumCXXABI.cpp b/lib/AST/ItaniumCXXABI.cpp index 378121c8e5b9..7503cbfc9805 100644 --- a/lib/AST/ItaniumCXXABI.cpp +++ b/lib/AST/ItaniumCXXABI.cpp @@ -106,7 +106,7 @@ public: TargetInfo::IntType PtrDiff = Target.getPtrDiffType(0); uint64_t Width = Target.getTypeWidth(PtrDiff); unsigned Align = Target.getTypeAlign(PtrDiff); - if (MPT->getPointeeType()->isFunctionType()) + if (MPT->isMemberFunctionPointer()) Width = 2 * Width; return std::make_pair(Width, Align); } @@ -133,6 +133,22 @@ public: return Layout.getNonVirtualSize() == PointerSize; } + const CXXConstructorDecl * + getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override { + return nullptr; + } + + void addCopyConstructorForExceptionObject(CXXRecordDecl *RD, + CXXConstructorDecl *CD) override {} + + void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx, Expr *DAE) override {} + + Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx) override { + return nullptr; + } + MangleNumberingContext *createMangleNumberingContext() const override { return new ItaniumNumberingContext(); } diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 156ad646fa6d..d07efaee7bba 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -42,8 +42,8 @@ using namespace clang; namespace { -/// \brief Retrieve the declaration context that should be used when mangling -/// the given declaration. +/// Retrieve the declaration context that should be used when mangling the given +/// declaration. static const DeclContext *getEffectiveDeclContext(const Decl *D) { // The ABI assumes that lambda closure types that occur within // default arguments live in the context of the function. However, due to @@ -69,6 +69,14 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) { if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC)) return getEffectiveDeclContext(CD); + if (const auto *VD = dyn_cast<VarDecl>(D)) + if (VD->isExternC()) + return VD->getASTContext().getTranslationUnitDecl(); + + if (const auto *FD = dyn_cast<FunctionDecl>(D)) + if (FD->isExternC()) + return FD->getASTContext().getTranslationUnitDecl(); + return DC; } @@ -156,12 +164,18 @@ public: void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override; void mangleDynamicAtExitDestructor(const VarDecl *D, raw_ostream &Out) override; + void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl, + raw_ostream &Out) override; + void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl, + raw_ostream &Out) override; void mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &) override; void mangleItaniumThreadLocalWrapper(const VarDecl *D, raw_ostream &) override; void mangleStringLiteral(const StringLiteral *, raw_ostream &) override; + void mangleCXXVTableBitSet(const CXXRecordDecl *RD, raw_ostream &) override; + bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { // Lambda closure types are already numbered. if (isLambda(ND)) @@ -196,7 +210,7 @@ public: /// @} }; -/// CXXNameMangler - Manage the mangling of a single name. +/// Manage the mangling of a single name. class CXXNameMangler { ItaniumMangleContextImpl &Context; raw_ostream &Out; @@ -207,7 +221,7 @@ class CXXNameMangler { const NamedDecl *Structor; unsigned StructorType; - /// SeqID - The next subsitution sequence number. + /// The next substitution sequence number. unsigned SeqID; class FunctionTypeDepthState { @@ -284,7 +298,7 @@ public: #endif raw_ostream &getStream() { return Out; } - void mangle(const NamedDecl *D, StringRef Prefix = "_Z"); + void mangle(const NamedDecl *D); void mangleCallOffset(int64_t NonVirtual, int64_t Virtual); void mangleNumber(const llvm::APSInt &I); void mangleNumber(int64_t Number); @@ -317,10 +331,8 @@ private: void addSubstitution(uintptr_t Ptr); void mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, bool recursive = false); void mangleUnresolvedName(NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, DeclarationName name, unsigned KnownArity = UnknownArity); @@ -350,6 +362,9 @@ private: void manglePrefix(QualType type); void mangleTemplatePrefix(const TemplateDecl *ND, bool NoFunction=false); void mangleTemplatePrefix(TemplateName Template); + bool mangleUnresolvedTypeOrSimpleId(QualType DestroyedType, + StringRef Prefix = ""); + void mangleOperatorName(DeclarationName Name, unsigned Arity); void mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity); void mangleQualifiers(Qualifiers Quals); void mangleRefQualifier(RefQualifierKind RefQualifier); @@ -370,12 +385,14 @@ private: void mangleAArch64NeonVectorType(const VectorType *T); void mangleIntegerLiteral(QualType T, const llvm::APSInt &Value); + void mangleMemberExprBase(const Expr *base, bool isArrow); void mangleMemberExpr(const Expr *base, bool isArrow, NestedNameSpecifier *qualifier, NamedDecl *firstQualifierLookup, DeclarationName name, unsigned knownArity); void mangleCastExpression(const Expr *E, StringRef CastEncoding); + void mangleInitListElements(const InitListExpr *InitList); void mangleExpression(const Expr *E, unsigned Arity = UnknownArity); void mangleCXXCtorType(CXXCtorType T); void mangleCXXDtorType(CXXDtorType T); @@ -439,11 +456,11 @@ bool ItaniumMangleContextImpl::shouldMangleCXXName(const NamedDecl *D) { return true; } -void CXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) { +void CXXNameMangler::mangle(const NamedDecl *D) { // <mangled-name> ::= _Z <encoding> // ::= <data name> // ::= <special-name> - Out << Prefix; + Out << "_Z"; if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) mangleFunctionEncoding(FD); else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) @@ -519,7 +536,7 @@ static const DeclContext *IgnoreLinkageSpecDecls(const DeclContext *DC) { return DC; } -/// isStd - Return whether a given namespace is the 'std' namespace. +/// Return whether a given namespace is the 'std' namespace. static bool isStd(const NamespaceDecl *NS) { if (!IgnoreLinkageSpecDecls(getEffectiveParentContext(NS)) ->isTranslationUnit()) @@ -748,8 +765,7 @@ void CXXNameMangler::mangleCallOffset(int64_t NonVirtual, int64_t Virtual) { } void CXXNameMangler::manglePrefix(QualType type) { - if (const TemplateSpecializationType *TST = - type->getAs<TemplateSpecializationType>()) { + if (const auto *TST = type->getAs<TemplateSpecializationType>()) { if (!mangleSubstitution(QualType(TST, 0))) { mangleTemplatePrefix(TST->getTemplateName()); @@ -759,17 +775,19 @@ void CXXNameMangler::manglePrefix(QualType type) { mangleTemplateArgs(TST->getArgs(), TST->getNumArgs()); addSubstitution(QualType(TST, 0)); } - } else if (const DependentTemplateSpecializationType *DTST - = type->getAs<DependentTemplateSpecializationType>()) { - TemplateName Template - = getASTContext().getDependentTemplateName(DTST->getQualifier(), - DTST->getIdentifier()); - mangleTemplatePrefix(Template); + } else if (const auto *DTST = + type->getAs<DependentTemplateSpecializationType>()) { + if (!mangleSubstitution(QualType(DTST, 0))) { + TemplateName Template = getASTContext().getDependentTemplateName( + DTST->getQualifier(), DTST->getIdentifier()); + mangleTemplatePrefix(Template); - // FIXME: GCC does not appear to mangle the template arguments when - // the template in question is a dependent template name. Should we - // emulate that badness? - mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs()); + // FIXME: GCC does not appear to mangle the template arguments when + // the template in question is a dependent template name. Should we + // emulate that badness? + mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs()); + addSubstitution(QualType(DTST, 0)); + } } else { // We use the QualType mangle type variant here because it handles // substitutions. @@ -779,12 +797,9 @@ void CXXNameMangler::manglePrefix(QualType type) { /// Mangle everything prior to the base-unresolved-name in an unresolved-name. /// -/// \param firstQualifierLookup - the entity found by unqualified lookup -/// for the first name in the qualifier, if this is for a member expression /// \param recursive - true if this is being called recursively, /// i.e. if there is more prefix "to the right". void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, bool recursive) { // x, ::x @@ -817,7 +832,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, case NestedNameSpecifier::Namespace: if (qualifier->getPrefix()) - mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + mangleUnresolvedPrefix(qualifier->getPrefix(), /*recursive*/ true); else Out << "sr"; @@ -825,7 +840,7 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, break; case NestedNameSpecifier::NamespaceAlias: if (qualifier->getPrefix()) - mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + mangleUnresolvedPrefix(qualifier->getPrefix(), /*recursive*/ true); else Out << "sr"; @@ -842,193 +857,26 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, // - a template template parameter with arguments // In all of these cases, we should have no prefix. if (qualifier->getPrefix()) { - mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + mangleUnresolvedPrefix(qualifier->getPrefix(), /*recursive*/ true); } else { // Otherwise, all the cases want this. Out << "sr"; } - // Only certain other types are valid as prefixes; enumerate them. - switch (type->getTypeClass()) { - case Type::Builtin: - case Type::Complex: - case Type::Adjusted: - case Type::Decayed: - case Type::Pointer: - case Type::BlockPointer: - case Type::LValueReference: - case Type::RValueReference: - case Type::MemberPointer: - case Type::ConstantArray: - case Type::IncompleteArray: - case Type::VariableArray: - case Type::DependentSizedArray: - case Type::DependentSizedExtVector: - case Type::Vector: - case Type::ExtVector: - case Type::FunctionProto: - case Type::FunctionNoProto: - case Type::Enum: - case Type::Paren: - case Type::Elaborated: - case Type::Attributed: - case Type::Auto: - case Type::PackExpansion: - case Type::ObjCObject: - case Type::ObjCInterface: - case Type::ObjCObjectPointer: - case Type::Atomic: - llvm_unreachable("type is illegal as a nested name specifier"); - - case Type::SubstTemplateTypeParmPack: - // FIXME: not clear how to mangle this! - // template <class T...> class A { - // template <class U...> void foo(decltype(T::foo(U())) x...); - // }; - Out << "_SUBSTPACK_"; - break; - - // <unresolved-type> ::= <template-param> - // ::= <decltype> - // ::= <template-template-param> <template-args> - // (this last is not official yet) - case Type::TypeOfExpr: - case Type::TypeOf: - case Type::Decltype: - case Type::TemplateTypeParm: - case Type::UnaryTransform: - case Type::SubstTemplateTypeParm: - unresolvedType: - assert(!qualifier->getPrefix()); - - // We only get here recursively if we're followed by identifiers. - if (recursive) Out << 'N'; - - // This seems to do everything we want. It's not really - // sanctioned for a substituted template parameter, though. - mangleType(QualType(type, 0)); - - // We never want to print 'E' directly after an unresolved-type, - // so we return directly. + if (mangleUnresolvedTypeOrSimpleId(QualType(type, 0), recursive ? "N" : "")) return; - case Type::Typedef: - mangleSourceName(cast<TypedefType>(type)->getDecl()->getIdentifier()); - break; - - case Type::UnresolvedUsing: - mangleSourceName(cast<UnresolvedUsingType>(type)->getDecl() - ->getIdentifier()); - break; - - case Type::Record: - mangleSourceName(cast<RecordType>(type)->getDecl()->getIdentifier()); - break; - - case Type::TemplateSpecialization: { - const TemplateSpecializationType *tst - = cast<TemplateSpecializationType>(type); - TemplateName name = tst->getTemplateName(); - switch (name.getKind()) { - case TemplateName::Template: - case TemplateName::QualifiedTemplate: { - TemplateDecl *temp = name.getAsTemplateDecl(); - - // If the base is a template template parameter, this is an - // unresolved type. - assert(temp && "no template for template specialization type"); - if (isa<TemplateTemplateParmDecl>(temp)) goto unresolvedType; - - mangleSourceName(temp->getIdentifier()); - break; - } - - case TemplateName::OverloadedTemplate: - case TemplateName::DependentTemplate: - llvm_unreachable("invalid base for a template specialization type"); - - case TemplateName::SubstTemplateTemplateParm: { - SubstTemplateTemplateParmStorage *subst - = name.getAsSubstTemplateTemplateParm(); - mangleExistingSubstitution(subst->getReplacement()); - break; - } - - case TemplateName::SubstTemplateTemplateParmPack: { - // FIXME: not clear how to mangle this! - // template <template <class U> class T...> class A { - // template <class U...> void foo(decltype(T<U>::foo) x...); - // }; - Out << "_SUBSTPACK_"; - break; - } - } - - mangleTemplateArgs(tst->getArgs(), tst->getNumArgs()); - break; - } - - case Type::InjectedClassName: - mangleSourceName(cast<InjectedClassNameType>(type)->getDecl() - ->getIdentifier()); - break; - - case Type::DependentName: - mangleSourceName(cast<DependentNameType>(type)->getIdentifier()); - break; - - case Type::DependentTemplateSpecialization: { - const DependentTemplateSpecializationType *tst - = cast<DependentTemplateSpecializationType>(type); - mangleSourceName(tst->getIdentifier()); - mangleTemplateArgs(tst->getArgs(), tst->getNumArgs()); - break; - } - } break; } case NestedNameSpecifier::Identifier: // Member expressions can have these without prefixes. - if (qualifier->getPrefix()) { - mangleUnresolvedPrefix(qualifier->getPrefix(), firstQualifierLookup, + if (qualifier->getPrefix()) + mangleUnresolvedPrefix(qualifier->getPrefix(), /*recursive*/ true); - } else if (firstQualifierLookup) { - - // Try to make a proper qualifier out of the lookup result, and - // then just recurse on that. - NestedNameSpecifier *newQualifier; - if (TypeDecl *typeDecl = dyn_cast<TypeDecl>(firstQualifierLookup)) { - QualType type = getASTContext().getTypeDeclType(typeDecl); - - // Pretend we had a different nested name specifier. - newQualifier = NestedNameSpecifier::Create(getASTContext(), - /*prefix*/ nullptr, - /*template*/ false, - type.getTypePtr()); - } else if (NamespaceDecl *nspace = - dyn_cast<NamespaceDecl>(firstQualifierLookup)) { - newQualifier = NestedNameSpecifier::Create(getASTContext(), - /*prefix*/ nullptr, - nspace); - } else if (NamespaceAliasDecl *alias = - dyn_cast<NamespaceAliasDecl>(firstQualifierLookup)) { - newQualifier = NestedNameSpecifier::Create(getASTContext(), - /*prefix*/ nullptr, - alias); - } else { - // No sensible mangling to do here. - newQualifier = nullptr; - } - - if (newQualifier) - return mangleUnresolvedPrefix(newQualifier, /*lookup*/ nullptr, - recursive); - - } else { + else Out << "sr"; - } mangleSourceName(qualifier->getAsIdentifier()); break; @@ -1043,16 +891,41 @@ void CXXNameMangler::mangleUnresolvedPrefix(NestedNameSpecifier *qualifier, /// Mangle an unresolved-name, which is generally used for names which /// weren't resolved to specific entities. void CXXNameMangler::mangleUnresolvedName(NestedNameSpecifier *qualifier, - NamedDecl *firstQualifierLookup, DeclarationName name, unsigned knownArity) { - if (qualifier) mangleUnresolvedPrefix(qualifier, firstQualifierLookup); - mangleUnqualifiedName(nullptr, name, knownArity); + if (qualifier) mangleUnresolvedPrefix(qualifier); + switch (name.getNameKind()) { + // <base-unresolved-name> ::= <simple-id> + case DeclarationName::Identifier: + mangleSourceName(name.getAsIdentifierInfo()); + break; + // <base-unresolved-name> ::= dn <destructor-name> + case DeclarationName::CXXDestructorName: + Out << "dn"; + mangleUnresolvedTypeOrSimpleId(name.getCXXNameType()); + break; + // <base-unresolved-name> ::= on <operator-name> + case DeclarationName::CXXConversionFunctionName: + case DeclarationName::CXXLiteralOperatorName: + case DeclarationName::CXXOperatorName: + Out << "on"; + mangleOperatorName(name, knownArity); + break; + case DeclarationName::CXXConstructorName: + llvm_unreachable("Can't mangle a constructor name!"); + case DeclarationName::CXXUsingDirective: + llvm_unreachable("Can't mangle a using directive name!"); + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCZeroArgSelector: + llvm_unreachable("Can't mangle Objective-C selector names here!"); + } } void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, DeclarationName Name, unsigned KnownArity) { + unsigned Arity = KnownArity; // <unqualified-name> ::= <operator-name> // ::= <ctor-dtor-name> // ::= <source-name> @@ -1163,7 +1036,7 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, Str += llvm::utostr(AnonStructId); Out << Str.size(); - Out << Str.str(); + Out << Str; break; } @@ -1194,33 +1067,19 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, mangleCXXDtorType(Dtor_Complete); break; - case DeclarationName::CXXConversionFunctionName: - // <operator-name> ::= cv <type> # (cast) - Out << "cv"; - mangleType(Name.getCXXNameType()); - break; - - case DeclarationName::CXXOperatorName: { - unsigned Arity; - if (ND) { + case DeclarationName::CXXOperatorName: + if (ND && Arity == UnknownArity) { Arity = cast<FunctionDecl>(ND)->getNumParams(); - // If we have a C++ member function, we need to include the 'this' pointer. - // FIXME: This does not make sense for operators that are static, but their - // names stay the same regardless of the arity (operator new for instance). - if (isa<CXXMethodDecl>(ND)) - Arity++; - } else - Arity = KnownArity; - - mangleOperatorName(Name.getCXXOverloadedOperator(), Arity); - break; - } - + // If we have a member function, we need to include the 'this' pointer. + if (const auto *MD = dyn_cast<CXXMethodDecl>(ND)) + if (!MD->isStatic()) + Arity++; + } + // FALLTHROUGH + case DeclarationName::CXXConversionFunctionName: case DeclarationName::CXXLiteralOperatorName: - // FIXME: This mangling is not yet official. - Out << "li"; - mangleSourceName(Name.getCXXLiteralIdentifier()); + mangleOperatorName(Name, Arity); break; case DeclarationName::CXXUsingDirective: @@ -1529,7 +1388,8 @@ void CXXNameMangler::mangleTemplatePrefix(TemplateName Template) { DependentTemplateName *Dependent = Template.getAsDependentTemplateName(); assert(Dependent && "Unknown template name kind?"); - manglePrefix(Dependent->getQualifier()); + if (NestedNameSpecifier *Qualifier = Dependent->getQualifier()) + manglePrefix(Qualifier); mangleUnscopedTemplateName(Template); } @@ -1591,7 +1451,7 @@ void CXXNameMangler::mangleType(TemplateName TN) { // <class-enum-type> ::= <name> // <name> ::= <nested-name> - mangleUnresolvedPrefix(Dependent->getQualifier(), nullptr); + mangleUnresolvedPrefix(Dependent->getQualifier()); mangleSourceName(Dependent->getIdentifier()); break; } @@ -1620,6 +1480,181 @@ void CXXNameMangler::mangleType(TemplateName TN) { addSubstitution(TN); } +bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, + StringRef Prefix) { + // Only certain other types are valid as prefixes; enumerate them. + switch (Ty->getTypeClass()) { + case Type::Builtin: + case Type::Complex: + case Type::Adjusted: + case Type::Decayed: + case Type::Pointer: + case Type::BlockPointer: + case Type::LValueReference: + case Type::RValueReference: + case Type::MemberPointer: + case Type::ConstantArray: + case Type::IncompleteArray: + case Type::VariableArray: + case Type::DependentSizedArray: + case Type::DependentSizedExtVector: + case Type::Vector: + case Type::ExtVector: + case Type::FunctionProto: + case Type::FunctionNoProto: + case Type::Paren: + case Type::Attributed: + case Type::Auto: + case Type::PackExpansion: + case Type::ObjCObject: + case Type::ObjCInterface: + case Type::ObjCObjectPointer: + case Type::Atomic: + llvm_unreachable("type is illegal as a nested name specifier"); + + case Type::SubstTemplateTypeParmPack: + // FIXME: not clear how to mangle this! + // template <class T...> class A { + // template <class U...> void foo(decltype(T::foo(U())) x...); + // }; + Out << "_SUBSTPACK_"; + break; + + // <unresolved-type> ::= <template-param> + // ::= <decltype> + // ::= <template-template-param> <template-args> + // (this last is not official yet) + case Type::TypeOfExpr: + case Type::TypeOf: + case Type::Decltype: + case Type::TemplateTypeParm: + case Type::UnaryTransform: + case Type::SubstTemplateTypeParm: + unresolvedType: + // Some callers want a prefix before the mangled type. + Out << Prefix; + + // This seems to do everything we want. It's not really + // sanctioned for a substituted template parameter, though. + mangleType(Ty); + + // We never want to print 'E' directly after an unresolved-type, + // so we return directly. + return true; + + case Type::Typedef: + mangleSourceName(cast<TypedefType>(Ty)->getDecl()->getIdentifier()); + break; + + case Type::UnresolvedUsing: + mangleSourceName( + cast<UnresolvedUsingType>(Ty)->getDecl()->getIdentifier()); + break; + + case Type::Enum: + case Type::Record: + mangleSourceName(cast<TagType>(Ty)->getDecl()->getIdentifier()); + break; + + case Type::TemplateSpecialization: { + const TemplateSpecializationType *TST = + cast<TemplateSpecializationType>(Ty); + TemplateName TN = TST->getTemplateName(); + switch (TN.getKind()) { + case TemplateName::Template: + case TemplateName::QualifiedTemplate: { + TemplateDecl *TD = TN.getAsTemplateDecl(); + + // If the base is a template template parameter, this is an + // unresolved type. + assert(TD && "no template for template specialization type"); + if (isa<TemplateTemplateParmDecl>(TD)) + goto unresolvedType; + + mangleSourceName(TD->getIdentifier()); + break; + } + + case TemplateName::OverloadedTemplate: + case TemplateName::DependentTemplate: + llvm_unreachable("invalid base for a template specialization type"); + + case TemplateName::SubstTemplateTemplateParm: { + SubstTemplateTemplateParmStorage *subst = + TN.getAsSubstTemplateTemplateParm(); + mangleExistingSubstitution(subst->getReplacement()); + break; + } + + case TemplateName::SubstTemplateTemplateParmPack: { + // FIXME: not clear how to mangle this! + // template <template <class U> class T...> class A { + // template <class U...> void foo(decltype(T<U>::foo) x...); + // }; + Out << "_SUBSTPACK_"; + break; + } + } + + mangleTemplateArgs(TST->getArgs(), TST->getNumArgs()); + break; + } + + case Type::InjectedClassName: + mangleSourceName( + cast<InjectedClassNameType>(Ty)->getDecl()->getIdentifier()); + break; + + case Type::DependentName: + mangleSourceName(cast<DependentNameType>(Ty)->getIdentifier()); + break; + + case Type::DependentTemplateSpecialization: { + const DependentTemplateSpecializationType *DTST = + cast<DependentTemplateSpecializationType>(Ty); + mangleSourceName(DTST->getIdentifier()); + mangleTemplateArgs(DTST->getArgs(), DTST->getNumArgs()); + break; + } + + case Type::Elaborated: + return mangleUnresolvedTypeOrSimpleId( + cast<ElaboratedType>(Ty)->getNamedType(), Prefix); + } + + return false; +} + +void CXXNameMangler::mangleOperatorName(DeclarationName Name, unsigned Arity) { + switch (Name.getNameKind()) { + case DeclarationName::CXXConstructorName: + case DeclarationName::CXXDestructorName: + case DeclarationName::CXXUsingDirective: + case DeclarationName::Identifier: + case DeclarationName::ObjCMultiArgSelector: + case DeclarationName::ObjCOneArgSelector: + case DeclarationName::ObjCZeroArgSelector: + llvm_unreachable("Not an operator name"); + + case DeclarationName::CXXConversionFunctionName: + // <operator-name> ::= cv <type> # (cast) + Out << "cv"; + mangleType(Name.getCXXNameType()); + break; + + case DeclarationName::CXXLiteralOperatorName: + Out << "li"; + mangleSourceName(Name.getCXXLiteralIdentifier()); + return; + + case DeclarationName::CXXOperatorName: + mangleOperatorName(Name.getCXXOverloadedOperator(), Arity); + break; + } +} + + + void CXXNameMangler::mangleOperatorName(OverloadedOperatorKind OO, unsigned Arity) { switch (OO) { @@ -2276,6 +2311,7 @@ void CXXNameMangler::mangleAArch64NeonVectorType(const VectorType *T) { EltName = "Poly16"; break; case BuiltinType::ULong: + case BuiltinType::ULongLong: EltName = "Poly64"; break; default: @@ -2519,6 +2555,29 @@ void CXXNameMangler::mangleIntegerLiteral(QualType T, } +void CXXNameMangler::mangleMemberExprBase(const Expr *Base, bool IsArrow) { + // 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 + // does not specify anything here, so we follow GCC. + Out << "dtdefpT"; + } else { + Out << (IsArrow ? "pt" : "dt"); + mangleExpression(Base); + } +} + /// Mangles a member expression. void CXXNameMangler::mangleMemberExpr(const Expr *base, bool isArrow, @@ -2528,30 +2587,9 @@ void CXXNameMangler::mangleMemberExpr(const Expr *base, unsigned arity) { // <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 - // does not specify anything here, so we follow GCC. - Out << "dtdefpT"; - } else { - Out << (isArrow ? "pt" : "dt"); - mangleExpression(base); - } - } - mangleUnresolvedName(qualifier, firstQualifierLookup, member, arity); + if (base) + mangleMemberExprBase(base, isArrow); + mangleUnresolvedName(qualifier, member, arity); } /// Look at the callee of the given call expression and determine if @@ -2592,6 +2630,13 @@ void CXXNameMangler::mangleCastExpression(const Expr *E, StringRef CastEncoding) mangleExpression(ECE->getSubExpr()); } +void CXXNameMangler::mangleInitListElements(const InitListExpr *InitList) { + if (auto *Syntactic = InitList->getSyntacticForm()) + InitList = Syntactic; + for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i) + mangleExpression(InitList->getInit(i)); +} + void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { // <expression> ::= <unary operator-name> <expression> // ::= <binary operator-name> <expression> <expression> @@ -2631,7 +2676,6 @@ recurse: // These all can only appear in local or variable-initialization // contexts and so should never appear in a mangling. case Expr::AddrLabelExprClass: - case Expr::DesignatedInitExprClass: case Expr::ImplicitValueInitExprClass: case Expr::ParenListExprClass: case Expr::LambdaExprClass: @@ -2641,9 +2685,9 @@ recurse: // FIXME: invent manglings for all these. case Expr::BlockExprClass: - case Expr::CXXPseudoDestructorExprClass: case Expr::ChooseExprClass: case Expr::CompoundLiteralExprClass: + case Expr::DesignatedInitExprClass: case Expr::ExtVectorElementExprClass: case Expr::GenericSelectionExprClass: case Expr::ObjCEncodeExprClass: @@ -2713,9 +2757,7 @@ recurse: case Expr::InitListExprClass: { Out << "il"; - const InitListExpr *InitList = cast<InitListExpr>(E); - for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i) - mangleExpression(InitList->getInit(i)); + mangleInitListElements(cast<InitListExpr>(E)); Out << "E"; break; } @@ -2759,9 +2801,14 @@ recurse: Out << "cl"; } - mangleExpression(CE->getCallee(), CE->getNumArgs()); - for (unsigned I = 0, N = CE->getNumArgs(); I != N; ++I) - mangleExpression(CE->getArg(I)); + unsigned CallArity = CE->getNumArgs(); + for (const Expr *Arg : CE->arguments()) + if (isa<PackExpansionExpr>(Arg)) + CallArity = UnknownArity; + + mangleExpression(CE->getCallee(), CallArity); + for (const Expr *Arg : CE->arguments()) + mangleExpression(Arg); Out << 'E'; break; } @@ -2793,9 +2840,7 @@ recurse: } else if (New->getInitializationStyle() == CXXNewExpr::ListInit && isa<InitListExpr>(Init)) { // Only take InitListExprs apart for list-initialization. - const InitListExpr *InitList = cast<InitListExpr>(Init); - for (unsigned i = 0, e = InitList->getNumInits(); i != e; ++i) - mangleExpression(InitList->getInit(i)); + mangleInitListElements(cast<InitListExpr>(Init)); } else mangleExpression(Init); } @@ -2803,6 +2848,33 @@ recurse: break; } + case Expr::CXXPseudoDestructorExprClass: { + const auto *PDE = cast<CXXPseudoDestructorExpr>(E); + if (const Expr *Base = PDE->getBase()) + mangleMemberExprBase(Base, PDE->isArrow()); + NestedNameSpecifier *Qualifier = PDE->getQualifier(); + QualType ScopeType; + if (TypeSourceInfo *ScopeInfo = PDE->getScopeTypeInfo()) { + if (Qualifier) { + mangleUnresolvedPrefix(Qualifier, + /*Recursive=*/true); + mangleUnresolvedTypeOrSimpleId(ScopeInfo->getType()); + Out << 'E'; + } else { + Out << "sr"; + if (!mangleUnresolvedTypeOrSimpleId(ScopeInfo->getType())) + Out << 'E'; + } + } else if (Qualifier) { + mangleUnresolvedPrefix(Qualifier); + } + // <base-unresolved-name> ::= dn <destructor-name> + Out << "dn"; + QualType DestroyedType = PDE->getDestroyedType(); + mangleUnresolvedTypeOrSimpleId(DestroyedType); + break; + } + case Expr::MemberExprClass: { const MemberExpr *ME = cast<MemberExpr>(E); mangleMemberExpr(ME->getBase(), ME->isArrow(), @@ -2813,9 +2885,9 @@ recurse: case Expr::UnresolvedMemberExprClass: { const UnresolvedMemberExpr *ME = cast<UnresolvedMemberExpr>(E); - mangleMemberExpr(ME->getBase(), ME->isArrow(), - ME->getQualifier(), nullptr, ME->getMemberName(), - Arity); + mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(), + ME->isArrow(), ME->getQualifier(), nullptr, + ME->getMemberName(), Arity); if (ME->hasExplicitTemplateArgs()) mangleTemplateArgs(ME->getExplicitTemplateArgs()); break; @@ -2824,8 +2896,9 @@ recurse: case Expr::CXXDependentScopeMemberExprClass: { const CXXDependentScopeMemberExpr *ME = cast<CXXDependentScopeMemberExpr>(E); - mangleMemberExpr(ME->getBase(), ME->isArrow(), - ME->getQualifier(), ME->getFirstQualifierFoundInScope(), + mangleMemberExpr(ME->isImplicitAccess() ? nullptr : ME->getBase(), + ME->isArrow(), ME->getQualifier(), + ME->getFirstQualifierFoundInScope(), ME->getMember(), Arity); if (ME->hasExplicitTemplateArgs()) mangleTemplateArgs(ME->getExplicitTemplateArgs()); @@ -2834,7 +2907,7 @@ recurse: case Expr::UnresolvedLookupExprClass: { const UnresolvedLookupExpr *ULE = cast<UnresolvedLookupExpr>(E); - mangleUnresolvedName(ULE->getQualifier(), nullptr, ULE->getName(), Arity); + mangleUnresolvedName(ULE->getQualifier(), ULE->getName(), Arity); // All the <unresolved-name> productions end in a // base-unresolved-name, where <template-args> are just tacked @@ -2856,26 +2929,55 @@ recurse: break; } - case Expr::CXXTemporaryObjectExprClass: case Expr::CXXConstructExprClass: { - const CXXConstructExpr *CE = cast<CXXConstructExpr>(E); + const auto *CE = cast<CXXConstructExpr>(E); + if (!CE->isListInitialization() || CE->isStdInitListInitialization()) { + assert( + CE->getNumArgs() >= 1 && + (CE->getNumArgs() == 1 || isa<CXXDefaultArgExpr>(CE->getArg(1))) && + "implicit CXXConstructExpr must have one argument"); + return mangleExpression(cast<CXXConstructExpr>(E)->getArg(0)); + } + Out << "il"; + for (auto *E : CE->arguments()) + mangleExpression(E); + Out << "E"; + break; + } + + case Expr::CXXTemporaryObjectExprClass: { + const auto *CE = cast<CXXTemporaryObjectExpr>(E); unsigned N = CE->getNumArgs(); + bool List = CE->isListInitialization(); - if (CE->isListInitialization()) + if (List) Out << "tl"; else Out << "cv"; mangleType(CE->getType()); - if (N != 1) Out << '_'; - for (unsigned I = 0; I != N; ++I) mangleExpression(CE->getArg(I)); - if (N != 1) Out << 'E'; + if (!List && N != 1) + Out << '_'; + if (CE->isStdInitListInitialization()) { + // We implicitly created a std::initializer_list<T> for the first argument + // of a constructor of type U in an expression of the form U{a, b, c}. + // Strip all the semantic gunk off the initializer list. + auto *SILE = + cast<CXXStdInitializerListExpr>(CE->getArg(0)->IgnoreImplicit()); + auto *ILE = cast<InitListExpr>(SILE->getSubExpr()->IgnoreImplicit()); + mangleInitListElements(ILE); + } else { + for (auto *E : CE->arguments()) + mangleExpression(E); + } + if (List || N != 1) + Out << 'E'; break; } case Expr::CXXScalarValueInitExprClass: - Out <<"cv"; + Out << "cv"; mangleType(E->getType()); - Out <<"_E"; + Out << "_E"; break; case Expr::CXXNoexceptExprClass: @@ -3020,10 +3122,28 @@ recurse: // Fall through to mangle the cast itself. case Expr::CStyleCastExprClass: - case Expr::CXXFunctionalCastExprClass: mangleCastExpression(E, "cv"); break; + case Expr::CXXFunctionalCastExprClass: { + auto *Sub = cast<ExplicitCastExpr>(E)->getSubExpr()->IgnoreImplicit(); + // FIXME: Add isImplicit to CXXConstructExpr. + if (auto *CCE = dyn_cast<CXXConstructExpr>(Sub)) + if (CCE->getParenOrBraceRange().isInvalid()) + Sub = CCE->getArg(0)->IgnoreImplicit(); + if (auto *StdInitList = dyn_cast<CXXStdInitializerListExpr>(Sub)) + Sub = StdInitList->getSubExpr()->IgnoreImplicit(); + if (auto *IL = dyn_cast<InitListExpr>(Sub)) { + Out << "tl"; + mangleType(E->getType()); + mangleInitListElements(IL); + Out << "E"; + } else { + mangleCastExpression(E, "cv"); + } + break; + } + case Expr::CXXStaticCastExprClass: mangleCastExpression(E, "sc"); break; @@ -3058,7 +3178,7 @@ recurse: default: // <expr-primary> ::= L <mangled-name> E # external name Out << 'L'; - mangle(D, "_Z"); + mangle(D); Out << 'E'; break; @@ -3101,8 +3221,7 @@ recurse: case Expr::DependentScopeDeclRefExprClass: { const DependentScopeDeclRefExpr *DRE = cast<DependentScopeDeclRefExpr>(E); - mangleUnresolvedName(DRE->getQualifier(), nullptr, DRE->getDeclName(), - Arity); + mangleUnresolvedName(DRE->getQualifier(), DRE->getDeclName(), Arity); // All the <unresolved-name> productions end in a // base-unresolved-name, where <template-args> are just tacked @@ -3327,6 +3446,9 @@ void CXXNameMangler::mangleCXXCtorType(CXXCtorType T) { case Ctor_Comdat: Out << "C5"; break; + case Ctor_DefaultClosure: + case Ctor_CopyingClosure: + llvm_unreachable("closure constructors don't exist for the Itanium ABI!"); } } @@ -3410,8 +3532,8 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { const ValueDecl *D = DRE->getDecl(); if (isa<VarDecl>(D) || isa<FunctionDecl>(D)) { - Out << "L"; - mangle(D, "_Z"); + Out << 'L'; + mangle(D); Out << 'E'; break; } @@ -3440,13 +3562,7 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) { Out << 'L'; // References to external entities use the mangled name; if the name would // not normally be manged then mangle it as unqualified. - // - // FIXME: The ABI specifies that external names here should have _Z, but - // gcc leaves this off. - if (compensateMangling) - mangle(D, "_Z"); - else - mangle(D, "Z"); + mangle(D); Out << 'E'; if (compensateMangling) @@ -3524,8 +3640,8 @@ bool CXXNameMangler::mangleSubstitution(const NamedDecl *ND) { return mangleSubstitution(reinterpret_cast<uintptr_t>(ND)); } -/// \brief Determine whether the given type has any qualifiers that are -/// relevant for substitutions. +/// Determine whether the given type has any qualifiers that are relevant for +/// substitutions. static bool hasMangledSubstitutionQualifiers(QualType T) { Qualifiers Qs = T.getQualifiers(); return Qs.getCVRQualifiers() || Qs.hasAddressSpace(); @@ -3571,8 +3687,8 @@ static bool isCharType(QualType T) { T->isSpecificBuiltinType(BuiltinType::Char_U); } -/// isCharSpecialization - Returns whether a given type is a template -/// specialization of a given name with a single argument of type char. +/// Returns whether a given type is a template specialization of a given name +/// with a single argument of type char. static bool isCharSpecialization(QualType T, const char *Name) { if (T.isNull()) return false; @@ -3722,8 +3838,8 @@ void CXXNameMangler::addSubstitution(uintptr_t Ptr) { // -/// \brief Mangles the name of the declaration D and emits that name to the -/// given output stream. +/// Mangles the name of the declaration D and emits that name to the given +/// output stream. /// /// If the declaration D requires a mangled name, this routine will emit that /// mangled name to \p os and return true. Otherwise, \p os will be unchanged @@ -3815,8 +3931,7 @@ void ItaniumMangleContextImpl::mangleCXXDtorThunk( Mangler.mangleFunctionEncoding(DD); } -/// mangleGuardVariable - Returns the mangled name for a guard variable -/// for the passed in VarDecl. +/// Returns the mangled name for a guard variable for the passed in VarDecl. void ItaniumMangleContextImpl::mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out) { // <special-name> ::= GV <object name> # Guard variable for one-time @@ -3845,6 +3960,26 @@ void ItaniumMangleContextImpl::mangleDynamicAtExitDestructor(const VarDecl *D, Mangler.getStream() << D->getName(); } +void ItaniumMangleContextImpl::mangleSEHFilterExpression( + const NamedDecl *EnclosingDecl, raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "__filt_"; + if (shouldMangleDeclName(EnclosingDecl)) + Mangler.mangle(EnclosingDecl); + else + Mangler.getStream() << EnclosingDecl->getName(); +} + +void ItaniumMangleContextImpl::mangleSEHFinallyBlock( + const NamedDecl *EnclosingDecl, raw_ostream &Out) { + CXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "__fin_"; + if (shouldMangleDeclName(EnclosingDecl)) + Mangler.mangle(EnclosingDecl); + else + Mangler.getStream() << EnclosingDecl->getName(); +} + void ItaniumMangleContextImpl::mangleItaniumThreadLocalInit(const VarDecl *D, raw_ostream &Out) { // <special-name> ::= TH <object name> @@ -3923,6 +4058,22 @@ void ItaniumMangleContextImpl::mangleTypeName(QualType Ty, raw_ostream &Out) { mangleCXXRTTIName(Ty, Out); } +void ItaniumMangleContextImpl::mangleCXXVTableBitSet(const CXXRecordDecl *RD, + raw_ostream &Out) { + Linkage L = RD->getLinkageInternal(); + if (L == InternalLinkage || L == UniqueExternalLinkage) { + // This part of the identifier needs to be unique across all translation + // units in the linked program. The scheme fails if multiple translation + // units are compiled using the same relative source file path, or if + // multiple translation units are built from the same source file. + SourceManager &SM = getASTContext().getSourceManager(); + Out << "[" << SM.getFileEntryForID(SM.getMainFileID())->getName() << "]"; + } + + CXXNameMangler Mangler(*this, Out); + Mangler.mangleType(QualType(RD->getTypeForDecl(), 0)); +} + void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_ostream &) { llvm_unreachable("Can't mangle string literals"); } diff --git a/lib/AST/MicrosoftCXXABI.cpp b/lib/AST/MicrosoftCXXABI.cpp index 0603d3b7b9b5..93ff77a2e964 100644 --- a/lib/AST/MicrosoftCXXABI.cpp +++ b/lib/AST/MicrosoftCXXABI.cpp @@ -31,11 +31,12 @@ class MicrosoftNumberingContext : public MangleNumberingContext { llvm::DenseMap<const Type *, unsigned> ManglingNumbers; unsigned LambdaManglingNumber; unsigned StaticLocalNumber; + unsigned StaticThreadlocalNumber; public: MicrosoftNumberingContext() : MangleNumberingContext(), LambdaManglingNumber(0), - StaticLocalNumber(0) {} + StaticLocalNumber(0), StaticThreadlocalNumber(0) {} unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override { return ++LambdaManglingNumber; @@ -47,6 +48,8 @@ public: } unsigned getStaticLocalNumber(const VarDecl *VD) override { + if (VD->getTLSKind()) + return ++StaticThreadlocalNumber; return ++StaticLocalNumber; } @@ -63,6 +66,10 @@ public: class MicrosoftCXXABI : public CXXABI { ASTContext &Context; + llvm::SmallDenseMap<CXXRecordDecl *, CXXConstructorDecl *> RecordToCopyCtor; + llvm::SmallDenseMap<std::pair<const CXXConstructorDecl *, unsigned>, Expr *> + CtorToDefaultArgExpr; + public: MicrosoftCXXABI(ASTContext &Ctx) : Context(Ctx) { } @@ -82,13 +89,36 @@ public: return false; const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - + // In the Microsoft ABI, classes can have one or two vtable pointers. - CharUnits PointerSize = - Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); + CharUnits PointerSize = + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); return Layout.getNonVirtualSize() == PointerSize || Layout.getNonVirtualSize() == PointerSize * 2; - } + } + + void addDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx, Expr *DAE) override { + CtorToDefaultArgExpr[std::make_pair(CD, ParmIdx)] = DAE; + } + + Expr *getDefaultArgExprForConstructor(const CXXConstructorDecl *CD, + unsigned ParmIdx) override { + return CtorToDefaultArgExpr[std::make_pair(CD, ParmIdx)]; + } + + const CXXConstructorDecl * + getCopyConstructorForExceptionObject(CXXRecordDecl *RD) override { + return RecordToCopyCtor[RD]; + } + + void + addCopyConstructorForExceptionObject(CXXRecordDecl *RD, + CXXConstructorDecl *CD) override { + assert(CD != nullptr); + assert(RecordToCopyCtor[RD] == nullptr || RecordToCopyCtor[RD] == CD); + RecordToCopyCtor[RD] = CD; + } MangleNumberingContext *createMangleNumberingContext() const override { return new MicrosoftNumberingContext(); @@ -186,29 +216,28 @@ getMSMemberPointerSlots(const MemberPointerType *MPT) { std::pair<uint64_t, unsigned> MicrosoftCXXABI::getMemberPointerWidthAndAlign( const MemberPointerType *MPT) const { - const TargetInfo &Target = Context.getTargetInfo(); - assert(Target.getTriple().getArch() == llvm::Triple::x86 || - Target.getTriple().getArch() == llvm::Triple::x86_64); - unsigned Ptrs, Ints; - std::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT); // The nominal struct is laid out with pointers followed by ints and aligned // to a pointer width if any are present and an int width otherwise. + const TargetInfo &Target = Context.getTargetInfo(); unsigned PtrSize = Target.getPointerWidth(0); unsigned IntSize = Target.getIntWidth(); + + unsigned Ptrs, Ints; + std::tie(Ptrs, Ints) = getMSMemberPointerSlots(MPT); uint64_t Width = Ptrs * PtrSize + Ints * IntSize; unsigned Align; // When MSVC does x86_32 record layout, it aligns aggregate member pointers to // 8 bytes. However, __alignof usually returns 4 for data memptrs and 8 for // function memptrs. - if (Ptrs + Ints > 1 && Target.getTriple().getArch() == llvm::Triple::x86) - Align = 8 * 8; + if (Ptrs + Ints > 1 && Target.getTriple().isArch32Bit()) + Align = 64; else if (Ptrs) Align = Target.getPointerAlign(0); else Align = Target.getIntAlign(); - if (Target.getTriple().getArch() == llvm::Triple::x86_64) + if (Target.getTriple().isArch64Bit()) Width = llvm::RoundUpToAlignment(Width, Align); return std::make_pair(Width, Align); } diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index 72f90f67cbdf..77522c1f9c5d 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -67,11 +67,15 @@ static const DeclContext *getEffectiveParentContext(const DeclContext *DC) { return getEffectiveDeclContext(cast<Decl>(DC)); } -static const FunctionDecl *getStructor(const FunctionDecl *fn) { - if (const FunctionTemplateDecl *ftd = fn->getPrimaryTemplate()) - return ftd->getTemplatedDecl(); +static const FunctionDecl *getStructor(const NamedDecl *ND) { + if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(ND)) + return FTD->getTemplatedDecl(); - return fn; + const auto *FD = cast<FunctionDecl>(ND); + if (const auto *FTD = FD->getPrimaryTemplate()) + return FTD->getTemplatedDecl(); + + return FD; } static bool isLambda(const NamedDecl *ND) { @@ -89,6 +93,8 @@ class MicrosoftMangleContextImpl : public MicrosoftMangleContext { llvm::DenseMap<DiscriminatorKeyTy, unsigned> Discriminator; llvm::DenseMap<const NamedDecl *, unsigned> Uniquifier; llvm::DenseMap<const CXXRecordDecl *, unsigned> LambdaIds; + llvm::DenseMap<const NamedDecl *, unsigned> SEHFilterIds; + llvm::DenseMap<const NamedDecl *, unsigned> SEHFinallyIds; public: MicrosoftMangleContextImpl(ASTContext &Context, DiagnosticsEngine &Diags) @@ -109,6 +115,16 @@ public: void mangleCXXVBTable(const CXXRecordDecl *Derived, ArrayRef<const CXXRecordDecl *> BasePath, raw_ostream &Out) override; + void mangleCXXThrowInfo(QualType T, bool IsConst, bool IsVolatile, + uint32_t NumEntries, raw_ostream &Out) override; + void mangleCXXCatchableTypeArray(QualType T, uint32_t NumEntries, + raw_ostream &Out) override; + void mangleCXXCatchableType(QualType T, const CXXConstructorDecl *CD, + CXXCtorType CT, uint32_t Size, uint32_t NVOffset, + int32_t VBPtrOffset, uint32_t VBIndex, + raw_ostream &Out) override; + void mangleCXXCatchHandlerType(QualType T, uint32_t Flags, + raw_ostream &Out) override; void mangleCXXRTTI(QualType T, raw_ostream &Out) override; void mangleCXXRTTIName(QualType T, raw_ostream &Out) override; void mangleCXXRTTIBaseClassDescriptor(const CXXRecordDecl *Derived, @@ -131,10 +147,18 @@ public: void mangleReferenceTemporary(const VarDecl *, unsigned ManglingNumber, raw_ostream &) override; void mangleStaticGuardVariable(const VarDecl *D, raw_ostream &Out) override; + void mangleThreadSafeStaticGuardVariable(const VarDecl *D, unsigned GuardNum, + raw_ostream &Out) override; void mangleDynamicInitializer(const VarDecl *D, raw_ostream &Out) override; void mangleDynamicAtExitDestructor(const VarDecl *D, raw_ostream &Out) override; + void mangleSEHFilterExpression(const NamedDecl *EnclosingDecl, + raw_ostream &Out) override; + void mangleSEHFinallyBlock(const NamedDecl *EnclosingDecl, + raw_ostream &Out) override; void mangleStringLiteral(const StringLiteral *SL, raw_ostream &Out) override; + void mangleCXXVTableBitSet(const CXXRecordDecl *RD, + raw_ostream &Out) override; bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { // Lambda closure types are already numbered. if (isLambda(ND)) @@ -211,6 +235,12 @@ public: 64) {} MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_, + const CXXConstructorDecl *D, CXXCtorType Type) + : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), + PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == + 64) {} + + MicrosoftCXXNameMangler(MicrosoftMangleContextImpl &C, raw_ostream &Out_, const CXXDestructorDecl *D, CXXDtorType Type) : Context(C), Out(Out_), Structor(getStructor(D)), StructorType(Type), PointersAre64Bit(C.getASTContext().getTargetInfo().getPointerWidth(0) == @@ -220,7 +250,7 @@ public: void mangle(const NamedDecl *D, StringRef Prefix = "\01?"); void mangleName(const NamedDecl *ND); - void mangleFunctionEncoding(const FunctionDecl *FD); + void mangleFunctionEncoding(const FunctionDecl *FD, bool ShouldMangle); void mangleVariableEncoding(const VarDecl *VD); void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD); void mangleMemberFunctionPointer(const CXXRecordDecl *RD, @@ -247,7 +277,7 @@ private: void mangleQualifiers(Qualifiers Quals, bool IsMember); void mangleRefQualifier(RefQualifierKind RefQualifier); void manglePointerCVQualifiers(Qualifiers Quals); - void manglePointerExtQualifiers(Qualifiers Quals, const Type *PointeeType); + void manglePointerExtQualifiers(Qualifiers Quals, QualType PointeeType); void mangleUnscopedTemplateName(const TemplateDecl *ND); void @@ -261,6 +291,7 @@ private: #define ABSTRACT_TYPE(CLASS, PARENT) #define NON_CANONICAL_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) void mangleType(const CLASS##Type *T, \ + Qualifiers Quals, \ SourceRange Range); #include "clang/AST/TypeNodes.def" #undef ABSTRACT_TYPE @@ -271,6 +302,7 @@ private: void mangleDecayedArrayType(const ArrayType *T); void mangleArrayType(const ArrayType *T); void mangleFunctionClass(const FunctionDecl *FD); + void mangleCallingConvention(CallingConv CC); void mangleCallingConvention(const FunctionType *T); void mangleIntegerLiteral(const llvm::APSInt &Number, bool IsBoolean); void mangleExpression(const Expr *E); @@ -352,7 +384,7 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) { Out << Prefix; mangleName(D); if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - mangleFunctionEncoding(FD); + mangleFunctionEncoding(FD, Context.shouldMangleDeclName(FD)); else if (const VarDecl *VD = dyn_cast<VarDecl>(D)) mangleVariableEncoding(VD); else { @@ -365,7 +397,8 @@ void MicrosoftCXXNameMangler::mangle(const NamedDecl *D, StringRef Prefix) { } } -void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { +void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD, + bool ShouldMangle) { // <type-encoding> ::= <function-class> <function-type> // Since MSVC operates on the type as written and not the canonical type, it @@ -380,13 +413,20 @@ void MicrosoftCXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { // extern "C" functions can hold entities that must be mangled. // As it stands, these functions still need to get expressed in the full // external name. They have their class and type omitted, replaced with '9'. - if (Context.shouldMangleDeclName(FD)) { - // First, the function class. + if (ShouldMangle) { + // We would like to mangle all extern "C" functions using this additional + // component but this would break compatibility with MSVC's behavior. + // Instead, do this when we know that compatibility isn't important (in + // other words, when it is an overloaded extern "C" funciton). + if (FD->isExternC() && FD->hasAttr<OverloadableAttr>()) + Out << "$$J0"; + mangleFunctionClass(FD); mangleFunctionType(FT, FD); - } else + } else { Out << '9'; + } } void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { @@ -422,7 +462,7 @@ void MicrosoftCXXNameMangler::mangleVariableEncoding(const VarDecl *VD) { Ty->isMemberPointerType()) { mangleType(Ty, SR, QMM_Drop); manglePointerExtQualifiers( - Ty.getDesugaredType(getASTContext()).getLocalQualifiers(), nullptr); + Ty.getDesugaredType(getASTContext()).getLocalQualifiers(), QualType()); if (const MemberPointerType *MPT = Ty->getAs<MemberPointerType>()) { mangleQualifiers(MPT->getPointeeType().getQualifiers(), true); // Member pointers are suffixed with a back reference to the member @@ -525,7 +565,7 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD, } } else { mangleName(MD); - mangleFunctionEncoding(MD); + mangleFunctionEncoding(MD, /*ShouldMangle=*/true); } } else { // Null single inheritance member functions are encoded as a simple nullptr. @@ -559,7 +599,7 @@ void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk( Out << "$B"; mangleNumber(OffsetInVFTable); Out << 'A'; - Out << (PointersAre64Bit ? 'A' : 'E'); + mangleCallingConvention(MD->getType()->getAs<FunctionProtoType>()); } void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { @@ -757,12 +797,18 @@ void MicrosoftCXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, llvm_unreachable("Can't mangle Objective-C selector names here!"); case DeclarationName::CXXConstructorName: - if (ND == Structor) { - assert(StructorType == Ctor_Complete && - "Should never be asked to mangle a ctor other than complete"); + if (Structor == getStructor(ND)) { + if (StructorType == Ctor_CopyingClosure) { + Out << "?_O"; + return; + } + if (StructorType == Ctor_DefaultClosure) { + Out << "?_F"; + return; + } } Out << "?0"; - break; + return; case DeclarationName::CXXDestructorName: if (ND == Structor) @@ -1134,10 +1180,13 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, cast<ValueDecl>(ND)); } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD); - if (MD && MD->isInstance()) + if (MD && MD->isInstance()) { mangleMemberFunctionPointer(MD->getParent()->getMostRecentDecl(), MD); - else - mangle(FD, "$1?"); + } else { + Out << "$1?"; + mangleName(FD); + mangleFunctionEncoding(FD, /*ShouldMangle=*/true); + } } else { mangle(ND, TA.getParamTypeForDecl()->isReferenceType() ? "$E?" : "$1?"); } @@ -1171,7 +1220,12 @@ void MicrosoftCXXNameMangler::mangleTemplateArg(const TemplateDecl *TD, if (TemplateArgs.empty()) { if (isa<TemplateTypeParmDecl>(Parm) || isa<TemplateTemplateParmDecl>(Parm)) - Out << "$$V"; + // MSVC 2015 changed the mangling for empty expanded template packs, + // use the old mangling for link compatibility for old versions. + Out << (Context.getASTContext().getLangOpts().isCompatibleWithMSVC( + LangOptions::MSVC2015) + ? "$$V" + : "$$$V"); else if (isa<NonTypeTemplateParmDecl>(Parm)) Out << "$S"; else @@ -1298,11 +1352,11 @@ MicrosoftCXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) { } } -void -MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals, - const Type *PointeeType) { +void MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals, + QualType PointeeType) { bool HasRestrict = Quals.hasRestrict(); - if (PointersAre64Bit && (!PointeeType || !PointeeType->isFunctionType())) + if (PointersAre64Bit && + (PointeeType.isNull() || !PointeeType->isFunctionType())) Out << 'E'; if (HasRestrict) @@ -1338,29 +1392,38 @@ void MicrosoftCXXNameMangler::mangleArgumentType(QualType T, // e.g. // void (*x)(void) will not form a backreference with void x(void) void *TypePtr; - if (const DecayedType *DT = T->getAs<DecayedType>()) { - TypePtr = DT->getOriginalType().getCanonicalType().getAsOpaquePtr(); + if (const auto *DT = T->getAs<DecayedType>()) { + QualType OriginalType = DT->getOriginalType(); + // All decayed ArrayTypes should be treated identically; as-if they were + // a decayed IncompleteArrayType. + if (const auto *AT = getASTContext().getAsArrayType(OriginalType)) + OriginalType = getASTContext().getIncompleteArrayType( + AT->getElementType(), AT->getSizeModifier(), + AT->getIndexTypeCVRQualifiers()); + + TypePtr = OriginalType.getCanonicalType().getAsOpaquePtr(); // If the original parameter was textually written as an array, // instead treat the decayed parameter like it's const. // // e.g. // int [] -> int * const - if (DT->getOriginalType()->isArrayType()) + if (OriginalType->isArrayType()) T = T.withConst(); - } else + } else { TypePtr = T.getCanonicalType().getAsOpaquePtr(); + } ArgBackRefMap::iterator Found = TypeBackReferences.find(TypePtr); if (Found == TypeBackReferences.end()) { - size_t OutSizeBefore = Out.GetNumBytesInBuffer(); + size_t OutSizeBefore = Out.tell(); mangleType(T, Range, QMM_Drop); // See if it's worth creating a back reference. // Only types longer than 1 character are considered // and only 10 back references slots are available: - bool LongerThanOneChar = (Out.GetNumBytesInBuffer() - OutSizeBefore > 1); + bool LongerThanOneChar = (Out.tell() - OutSizeBefore > 1); if (LongerThanOneChar && TypeBackReferences.size() < 10) { size_t Size = TypeBackReferences.size(); TypeBackReferences[TypePtr] = Size; @@ -1388,7 +1451,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, } bool IsPointer = T->isAnyPointerType() || T->isMemberPointerType() || - T->isBlockPointerType(); + T->isReferenceType() || T->isBlockPointerType(); switch (QMM) { case QMM_Drop: @@ -1415,11 +1478,6 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, break; } - // We have to mangle these now, while we still have enough information. - if (IsPointer) { - manglePointerCVQualifiers(Quals); - manglePointerExtQualifiers(Quals, T->getPointeeType().getTypePtr()); - } const Type *ty = T.getTypePtr(); switch (ty->getTypeClass()) { @@ -1430,7 +1488,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, return; #define TYPE(CLASS, PARENT) \ case Type::CLASS: \ - mangleType(cast<CLASS##Type>(ty), Range); \ + mangleType(cast<CLASS##Type>(ty), Quals, Range); \ break; #include "clang/AST/TypeNodes.def" #undef ABSTRACT_TYPE @@ -1439,7 +1497,7 @@ void MicrosoftCXXNameMangler::mangleType(QualType T, SourceRange Range, } } -void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, +void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, Qualifiers, SourceRange Range) { // <type> ::= <builtin-type> // <builtin-type> ::= X # void @@ -1525,7 +1583,7 @@ void MicrosoftCXXNameMangler::mangleType(const BuiltinType *T, } // <type> ::= <function-type> -void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, +void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, Qualifiers, SourceRange) { // Structors only appear in decls, so at this point we know it's not a // structor type. @@ -1539,7 +1597,7 @@ void MicrosoftCXXNameMangler::mangleType(const FunctionProtoType *T, } } void MicrosoftCXXNameMangler::mangleType(const FunctionNoProtoType *T, - SourceRange) { + Qualifiers, SourceRange) { llvm_unreachable("Can't mangle K&R function prototypes"); } @@ -1553,24 +1611,34 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, SourceRange Range; if (D) Range = D->getSourceRange(); - bool IsStructor = false, HasThisQuals = ForceThisQuals; + bool IsStructor = false, HasThisQuals = ForceThisQuals, IsCtorClosure = false; + CallingConv CC = T->getCallConv(); if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(D)) { if (MD->isInstance()) HasThisQuals = true; - if (isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD)) + if (isa<CXXDestructorDecl>(MD)) { + IsStructor = true; + } else if (isa<CXXConstructorDecl>(MD)) { IsStructor = true; + IsCtorClosure = (StructorType == Ctor_CopyingClosure || + StructorType == Ctor_DefaultClosure) && + getStructor(MD) == Structor; + if (IsCtorClosure) + CC = getASTContext().getDefaultCallingConvention( + /*IsVariadic=*/false, /*IsCXXMethod=*/true); + } } // If this is a C++ instance method, mangle the CVR qualifiers for the // this pointer. if (HasThisQuals) { Qualifiers Quals = Qualifiers::fromCVRMask(Proto->getTypeQuals()); - manglePointerExtQualifiers(Quals, /*PointeeType=*/nullptr); + manglePointerExtQualifiers(Quals, /*PointeeType=*/QualType()); mangleRefQualifier(Proto->getRefQualifier()); mangleQualifiers(Quals, /*IsMember=*/false); } - mangleCallingConvention(T); + mangleCallingConvention(CC); // <return-type> ::= <type> // ::= @ # structors (they have no declared return type) @@ -1584,6 +1652,29 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, Out << (PointersAre64Bit ? "PEAXI@Z" : "PAXI@Z"); return; } + if (IsCtorClosure) { + // Default constructor closure and copy constructor closure both return + // void. + Out << 'X'; + + if (StructorType == Ctor_DefaultClosure) { + // Default constructor closure always has no arguments. + Out << 'X'; + } else if (StructorType == Ctor_CopyingClosure) { + // Copy constructor closure always takes an unqualified reference. + mangleArgumentType(getASTContext().getLValueReferenceType( + Proto->getParamType(0) + ->getAs<LValueReferenceType>() + ->getPointeeType(), + /*SpelledAsLValue=*/true), + Range); + Out << '@'; + } else { + llvm_unreachable("unexpected constructor closure!"); + } + Out << 'Z'; + return; + } Out << '@'; } else { QualType ResultType = Proto->getReturnType(); @@ -1608,7 +1699,7 @@ void MicrosoftCXXNameMangler::mangleFunctionType(const FunctionType *T, Out << 'X'; } else { // Happens for function pointer type arguments for example. - for (const QualType Arg : Proto->param_types()) + for (const QualType &Arg : Proto->param_types()) mangleArgumentType(Arg, Range); // <builtin-type> ::= Z # ellipsis if (Proto->isVariadic()) @@ -1673,10 +1764,11 @@ void MicrosoftCXXNameMangler::mangleFunctionClass(const FunctionDecl *FD) { else Out << 'Q'; } - } else + } else { Out << 'Y'; + } } -void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { +void MicrosoftCXXNameMangler::mangleCallingConvention(CallingConv CC) { // <calling-convention> ::= A # __cdecl // ::= B # __export __cdecl // ::= C # __pascal @@ -1693,7 +1785,7 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { // that keyword. (It didn't actually export them, it just made them so // that they could be in a DLL and somebody from another module could call // them.) - CallingConv CC = T->getCallConv(); + switch (CC) { default: llvm_unreachable("Unsupported CC for mangling"); @@ -1707,6 +1799,9 @@ void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { case CC_X86VectorCall: Out << 'Q'; break; } } +void MicrosoftCXXNameMangler::mangleCallingConvention(const FunctionType *T) { + mangleCallingConvention(T->getCallConv()); +} void MicrosoftCXXNameMangler::mangleThrowSpecification( const FunctionProtoType *FT) { // <throw-spec> ::= Z # throw(...) (default) @@ -1719,7 +1814,7 @@ void MicrosoftCXXNameMangler::mangleThrowSpecification( } void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T, - SourceRange Range) { + Qualifiers, SourceRange Range) { // Probably should be mangled as a template instantiation; need to see what // VC does first. DiagnosticsEngine &Diags = Context.getDiags(); @@ -1734,10 +1829,12 @@ void MicrosoftCXXNameMangler::mangleType(const UnresolvedUsingType *T, // <struct-type> ::= U <name> // <class-type> ::= V <name> // <enum-type> ::= W4 <name> -void MicrosoftCXXNameMangler::mangleType(const EnumType *T, SourceRange) { +void MicrosoftCXXNameMangler::mangleType(const EnumType *T, Qualifiers, + SourceRange) { mangleType(cast<TagType>(T)->getDecl()); } -void MicrosoftCXXNameMangler::mangleType(const RecordType *T, SourceRange) { +void MicrosoftCXXNameMangler::mangleType(const RecordType *T, Qualifiers, + SourceRange) { mangleType(cast<TagType>(T)->getDecl()); } void MicrosoftCXXNameMangler::mangleType(const TagDecl *TD) { @@ -1772,39 +1869,41 @@ void MicrosoftCXXNameMangler::mangleDecayedArrayType(const ArrayType *T) { manglePointerCVQualifiers(T->getElementType().getQualifiers()); mangleType(T->getElementType(), SourceRange()); } -void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, +void MicrosoftCXXNameMangler::mangleType(const ConstantArrayType *T, Qualifiers, SourceRange) { llvm_unreachable("Should have been special cased"); } -void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, +void MicrosoftCXXNameMangler::mangleType(const VariableArrayType *T, Qualifiers, SourceRange) { llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const DependentSizedArrayType *T, - SourceRange) { + Qualifiers, SourceRange) { llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleType(const IncompleteArrayType *T, - SourceRange) { + Qualifiers, SourceRange) { llvm_unreachable("Should have been special cased"); } void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) { QualType ElementTy(T, 0); SmallVector<llvm::APInt, 3> Dimensions; for (;;) { - if (const ConstantArrayType *CAT = - getASTContext().getAsConstantArrayType(ElementTy)) { + if (ElementTy->isConstantArrayType()) { + const ConstantArrayType *CAT = + getASTContext().getAsConstantArrayType(ElementTy); Dimensions.push_back(CAT->getSize()); ElementTy = CAT->getElementType(); + } else if (ElementTy->isIncompleteArrayType()) { + const IncompleteArrayType *IAT = + getASTContext().getAsIncompleteArrayType(ElementTy); + Dimensions.push_back(llvm::APInt(32, 0)); + ElementTy = IAT->getElementType(); } else if (ElementTy->isVariableArrayType()) { const VariableArrayType *VAT = getASTContext().getAsVariableArrayType(ElementTy); - DiagnosticsEngine &Diags = Context.getDiags(); - unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, - "cannot mangle this variable-length array yet"); - Diags.Report(VAT->getSizeExpr()->getExprLoc(), DiagID) - << VAT->getBracketsRange(); - return; + Dimensions.push_back(llvm::APInt(32, 0)); + ElementTy = VAT->getElementType(); } else if (ElementTy->isDependentSizedArrayType()) { // The dependent expression has to be folded into a constant (TODO). const DependentSizedArrayType *DSAT = @@ -1815,12 +1914,9 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) { Diags.Report(DSAT->getSizeExpr()->getExprLoc(), DiagID) << DSAT->getBracketsRange(); return; - } else if (const IncompleteArrayType *IAT = - getASTContext().getAsIncompleteArrayType(ElementTy)) { - Dimensions.push_back(llvm::APInt(32, 0)); - ElementTy = IAT->getElementType(); + } else { + break; } - else break; } Out << 'Y'; // <dimension-count> ::= <number> # number of extra dimensions @@ -1833,9 +1929,11 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) { // <type> ::= <pointer-to-member-type> // <pointer-to-member-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> // <class name> <type> -void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, +void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, Qualifiers Quals, SourceRange Range) { QualType PointeeType = T->getPointeeType(); + manglePointerCVQualifiers(Quals); + manglePointerExtQualifiers(Quals, PointeeType); if (const FunctionProtoType *FPT = PointeeType->getAs<FunctionProtoType>()) { Out << '8'; mangleName(T->getClass()->castAs<RecordType>()->getDecl()); @@ -1848,7 +1946,7 @@ void MicrosoftCXXNameMangler::mangleType(const MemberPointerType *T, } void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T, - SourceRange Range) { + Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this template type parameter type yet"); @@ -1856,9 +1954,8 @@ void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T, << Range; } -void MicrosoftCXXNameMangler::mangleType( - const SubstTemplateTypeParmPackType *T, - SourceRange Range) { +void MicrosoftCXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T, + Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this substituted parameter pack yet"); @@ -1869,40 +1966,46 @@ void MicrosoftCXXNameMangler::mangleType( // <type> ::= <pointer-type> // <pointer-type> ::= E? <pointer-cvr-qualifiers> <cvr-qualifiers> <type> // # the E is required for 64-bit non-static pointers -void MicrosoftCXXNameMangler::mangleType(const PointerType *T, +void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Qualifiers Quals, SourceRange Range) { - QualType PointeeTy = T->getPointeeType(); - mangleType(PointeeTy, Range); + QualType PointeeType = T->getPointeeType(); + manglePointerCVQualifiers(Quals); + manglePointerExtQualifiers(Quals, PointeeType); + mangleType(PointeeType, Range); } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, - SourceRange Range) { + Qualifiers Quals, SourceRange Range) { + QualType PointeeType = T->getPointeeType(); + manglePointerCVQualifiers(Quals); + manglePointerExtQualifiers(Quals, PointeeType); // Object pointers never have qualifiers. Out << 'A'; - manglePointerExtQualifiers(Qualifiers(), T->getPointeeType().getTypePtr()); - mangleType(T->getPointeeType(), Range); + mangleType(PointeeType, Range); } // <type> ::= <reference-type> // <reference-type> ::= A E? <cvr-qualifiers> <type> // # the E is required for 64-bit non-static lvalue references void MicrosoftCXXNameMangler::mangleType(const LValueReferenceType *T, - SourceRange Range) { - Out << 'A'; - manglePointerExtQualifiers(Qualifiers(), T->getPointeeType().getTypePtr()); - mangleType(T->getPointeeType(), Range); + Qualifiers Quals, SourceRange Range) { + QualType PointeeType = T->getPointeeType(); + Out << (Quals.hasVolatile() ? 'B' : 'A'); + manglePointerExtQualifiers(Quals, PointeeType); + mangleType(PointeeType, Range); } // <type> ::= <r-value-reference-type> // <r-value-reference-type> ::= $$Q E? <cvr-qualifiers> <type> // # the E is required for 64-bit non-static rvalue references void MicrosoftCXXNameMangler::mangleType(const RValueReferenceType *T, - SourceRange Range) { - Out << "$$Q"; - manglePointerExtQualifiers(Qualifiers(), T->getPointeeType().getTypePtr()); - mangleType(T->getPointeeType(), Range); + Qualifiers Quals, SourceRange Range) { + QualType PointeeType = T->getPointeeType(); + Out << (Quals.hasVolatile() ? "$$R" : "$$Q"); + manglePointerExtQualifiers(Quals, PointeeType); + mangleType(PointeeType, Range); } -void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, +void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -1911,7 +2014,7 @@ void MicrosoftCXXNameMangler::mangleType(const ComplexType *T, << Range; } -void MicrosoftCXXNameMangler::mangleType(const VectorType *T, +void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals, SourceRange Range) { const BuiltinType *ET = T->getElementType()->getAs<BuiltinType>(); assert(ET && "vectors with non-builtin elements are unsupported"); @@ -1939,13 +2042,13 @@ void MicrosoftCXXNameMangler::mangleType(const VectorType *T, // our own mangling to handle uses of __vector_size__ on user-specified // types, and for extensions like __v4sf. Out << "T__clang_vec" << T->getNumElements() << '_'; - mangleType(ET, Range); + mangleType(ET, Quals, Range); } Out << "@@"; } -void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T, +void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -1954,7 +2057,7 @@ void MicrosoftCXXNameMangler::mangleType(const ExtVectorType *T, << Range; } void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T, - SourceRange Range) { + Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this dependent-sized extended vector type yet"); @@ -1962,14 +2065,14 @@ void MicrosoftCXXNameMangler::mangleType(const DependentSizedExtVectorType *T, << Range; } -void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, +void MicrosoftCXXNameMangler::mangleType(const ObjCInterfaceType *T, Qualifiers, SourceRange) { // ObjC interfaces have structs underlying them. Out << 'U'; mangleName(T->getDecl()); } -void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, +void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, Qualifiers, SourceRange Range) { // We don't allow overloading by different protocol qualification, // so mangling them isn't necessary. @@ -1977,20 +2080,23 @@ void MicrosoftCXXNameMangler::mangleType(const ObjCObjectType *T, } void MicrosoftCXXNameMangler::mangleType(const BlockPointerType *T, - SourceRange Range) { + Qualifiers Quals, SourceRange Range) { + QualType PointeeType = T->getPointeeType(); + manglePointerCVQualifiers(Quals); + manglePointerExtQualifiers(Quals, PointeeType); + Out << "_E"; - QualType pointee = T->getPointeeType(); - mangleFunctionType(pointee->castAs<FunctionProtoType>()); + mangleFunctionType(PointeeType->castAs<FunctionProtoType>()); } void MicrosoftCXXNameMangler::mangleType(const InjectedClassNameType *, - SourceRange) { + Qualifiers, SourceRange) { llvm_unreachable("Cannot mangle injected class name type."); } void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T, - SourceRange Range) { + Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this template specialization type yet"); @@ -1998,7 +2104,7 @@ void MicrosoftCXXNameMangler::mangleType(const TemplateSpecializationType *T, << Range; } -void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T, +void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -2008,8 +2114,8 @@ void MicrosoftCXXNameMangler::mangleType(const DependentNameType *T, } void MicrosoftCXXNameMangler::mangleType( - const DependentTemplateSpecializationType *T, - SourceRange Range) { + const DependentTemplateSpecializationType *T, Qualifiers, + SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this dependent template specialization type yet"); @@ -2017,7 +2123,7 @@ void MicrosoftCXXNameMangler::mangleType( << Range; } -void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T, +void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -2026,7 +2132,7 @@ void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T, << Range; } -void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T, +void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -2035,7 +2141,7 @@ void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T, << Range; } -void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T, +void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -2044,7 +2150,7 @@ void MicrosoftCXXNameMangler::mangleType(const TypeOfExprType *T, << Range; } -void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T, +void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -2054,7 +2160,7 @@ void MicrosoftCXXNameMangler::mangleType(const DecltypeType *T, } void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T, - SourceRange Range) { + Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot mangle this unary transform type yet"); @@ -2062,7 +2168,8 @@ void MicrosoftCXXNameMangler::mangleType(const UnaryTransformType *T, << Range; } -void MicrosoftCXXNameMangler::mangleType(const AutoType *T, SourceRange Range) { +void MicrosoftCXXNameMangler::mangleType(const AutoType *T, Qualifiers, + SourceRange Range) { assert(T->getDeducedType().isNull() && "expecting a dependent type!"); DiagnosticsEngine &Diags = Context.getDiags(); @@ -2072,7 +2179,7 @@ void MicrosoftCXXNameMangler::mangleType(const AutoType *T, SourceRange Range) { << Range; } -void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, +void MicrosoftCXXNameMangler::mangleType(const AtomicType *T, Qualifiers, SourceRange Range) { DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -2273,6 +2380,74 @@ void MicrosoftMangleContextImpl::mangleCXXRTTIName(QualType T, Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); } +void MicrosoftMangleContextImpl::mangleCXXCatchHandlerType(QualType T, + uint32_t Flags, + raw_ostream &Out) { + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "llvm.eh.handlertype."; + Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); + Mangler.getStream() << '.' << Flags; +} + +void MicrosoftMangleContextImpl::mangleCXXThrowInfo(QualType T, + bool IsConst, + bool IsVolatile, + uint32_t NumEntries, + raw_ostream &Out) { + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_TI"; + if (IsConst) + Mangler.getStream() << 'C'; + if (IsVolatile) + Mangler.getStream() << 'V'; + Mangler.getStream() << NumEntries; + Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); +} + +void MicrosoftMangleContextImpl::mangleCXXCatchableTypeArray( + QualType T, uint32_t NumEntries, raw_ostream &Out) { + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_CTA"; + Mangler.getStream() << NumEntries; + Mangler.mangleType(T, SourceRange(), MicrosoftCXXNameMangler::QMM_Result); +} + +void MicrosoftMangleContextImpl::mangleCXXCatchableType( + QualType T, const CXXConstructorDecl *CD, CXXCtorType CT, uint32_t Size, + uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBIndex, + raw_ostream &Out) { + MicrosoftCXXNameMangler Mangler(*this, Out); + Mangler.getStream() << "_CT"; + + llvm::SmallString<64> RTTIMangling; + { + llvm::raw_svector_ostream Stream(RTTIMangling); + mangleCXXRTTI(T, Stream); + } + Mangler.getStream() << RTTIMangling.substr(1); + + // VS2015 CTP6 omits the copy-constructor in the mangled name. This name is, + // in fact, superfluous but I'm not sure the change was made consciously. + // TODO: Revisit this when VS2015 gets released. + llvm::SmallString<64> CopyCtorMangling; + if (CD) { + llvm::raw_svector_ostream Stream(CopyCtorMangling); + mangleCXXCtor(CD, CT, Stream); + } + Mangler.getStream() << CopyCtorMangling.substr(1); + + Mangler.getStream() << Size; + if (VBPtrOffset == -1) { + if (NVOffset) { + Mangler.getStream() << NVOffset; + } + } else { + Mangler.getStream() << NVOffset; + Mangler.getStream() << VBPtrOffset; + Mangler.getStream() << VBIndex; + } +} + void MicrosoftMangleContextImpl::mangleCXXRTTIBaseClassDescriptor( const CXXRecordDecl *Derived, uint32_t NVOffset, int32_t VBPtrOffset, uint32_t VBTableOffset, uint32_t Flags, raw_ostream &Out) { @@ -2318,6 +2493,28 @@ void MicrosoftMangleContextImpl::mangleCXXRTTICompleteObjectLocator( Mangler.getStream() << '@'; } +void MicrosoftMangleContextImpl::mangleSEHFilterExpression( + const NamedDecl *EnclosingDecl, raw_ostream &Out) { + MicrosoftCXXNameMangler Mangler(*this, Out); + // The function body is in the same comdat as the function with the handler, + // so the numbering here doesn't have to be the same across TUs. + // + // <mangled-name> ::= ?filt$ <filter-number> @0 + Mangler.getStream() << "\01?filt$" << SEHFilterIds[EnclosingDecl]++ << "@0@"; + Mangler.mangleName(EnclosingDecl); +} + +void MicrosoftMangleContextImpl::mangleSEHFinallyBlock( + const NamedDecl *EnclosingDecl, raw_ostream &Out) { + MicrosoftCXXNameMangler Mangler(*this, Out); + // The function body is in the same comdat as the function with the handler, + // so the numbering here doesn't have to be the same across TUs. + // + // <mangled-name> ::= ?fin$ <filter-number> @0 + Mangler.getStream() << "\01?fin$" << SEHFinallyIds[EnclosingDecl]++ << "@0@"; + Mangler.mangleName(EnclosingDecl); +} + void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) { // This is just a made up unique string for the purposes of tbaa. undname // does *not* know how to demangle it. @@ -2329,7 +2526,7 @@ void MicrosoftMangleContextImpl::mangleTypeName(QualType T, raw_ostream &Out) { void MicrosoftMangleContextImpl::mangleCXXCtor(const CXXConstructorDecl *D, CXXCtorType Type, raw_ostream &Out) { - MicrosoftCXXNameMangler mangler(*this, Out); + MicrosoftCXXNameMangler mangler(*this, Out, D, Type); mangler.mangle(D); } @@ -2348,18 +2545,18 @@ void MicrosoftMangleContextImpl::mangleReferenceTemporary(const VarDecl *VD, getDiags().Report(VD->getLocation(), DiagID); } +void MicrosoftMangleContextImpl::mangleThreadSafeStaticGuardVariable( + const VarDecl *VD, unsigned GuardNum, raw_ostream &Out) { + MicrosoftCXXNameMangler Mangler(*this, Out); + + Mangler.getStream() << "\01?$TSS" << GuardNum << '@'; + Mangler.mangleNestedName(VD); +} + void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD, raw_ostream &Out) { - // 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 - // mangling, they all get $TSS <number>. - // - // N.B. This means that they can get more than 32 static variable guards in a - // scope. It also means that they broke compatibility with their own ABI. - // <guard-name> ::= ?_B <postfix> @5 <scope-depth> + // ::= ?__J <postfix> @5 <scope-depth> // ::= ?$S <guard-num> @ <postfix> @4IA // The first mangling is what MSVC uses to guard static locals in inline @@ -2371,8 +2568,11 @@ void MicrosoftMangleContextImpl::mangleStaticGuardVariable(const VarDecl *VD, MicrosoftCXXNameMangler Mangler(*this, Out); bool Visible = VD->isExternallyVisible(); - // <operator-name> ::= ?_B # local static guard - Mangler.getStream() << (Visible ? "\01??_B" : "\01?$S1@"); + if (Visible) { + Mangler.getStream() << (VD->getTLSKind() ? "\01??__J" : "\01??_B"); + } else { + Mangler.getStream() << "\01?$S1@"; + } unsigned ScopeDepth = 0; if (Visible && !getNextDiscriminator(VD, ScopeDepth)) // If we do not have a discriminator and are emitting a guard variable for @@ -2553,6 +2753,11 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, Mangler.getStream() << '@'; } +void MicrosoftMangleContextImpl::mangleCXXVTableBitSet(const CXXRecordDecl *RD, + raw_ostream &Out) { + llvm::report_fatal_error("Cannot mangle bitsets yet"); +} + MicrosoftMangleContext * MicrosoftMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) { return new MicrosoftMangleContextImpl(Context, Diags); diff --git a/lib/AST/NSAPI.cpp b/lib/AST/NSAPI.cpp index 3dc750a81787..2749100e14a2 100644 --- a/lib/AST/NSAPI.cpp +++ b/lib/AST/NSAPI.cpp @@ -27,7 +27,10 @@ IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const { "NSMutableArray", "NSDictionary", "NSMutableDictionary", - "NSNumber" + "NSNumber", + "NSMutableSet", + "NSCountedSet", + "NSMutableOrderedSet" }; if (!ClassIds[K]) @@ -124,6 +127,25 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const { Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } + case NSMutableArr_addObject: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); + break; + case NSMutableArr_insertObjectAtIndex: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("insertObject"), + &Ctx.Idents.get("atIndex") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + case NSMutableArr_setObjectAtIndexedSubscript: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setObject"), + &Ctx.Idents.get("atIndexedSubscript") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } } return (NSArraySelectors[MK] = Sel); } @@ -209,6 +231,22 @@ Selector NSAPI::getNSDictionarySelector( Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } + case NSMutableDict_setObjectForKeyedSubscript: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setObject"), + &Ctx.Idents.get("forKeyedSubscript") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + case NSMutableDict_setValueForKey: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setValue"), + &Ctx.Idents.get("forKey") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } } return (NSDictionarySelectors[MK] = Sel); } @@ -227,6 +265,63 @@ NSAPI::getNSDictionaryMethodKind(Selector Sel) { return None; } +Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const { + if (NSSetSelectors[MK].isNull()) { + Selector Sel; + switch (MK) { + case NSMutableSet_addObject: + Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); + break; + case NSOrderedSet_insertObjectAtIndex: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("insertObject"), + &Ctx.Idents.get("atIndex") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + case NSOrderedSet_setObjectAtIndex: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setObject"), + &Ctx.Idents.get("atIndex") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + case NSOrderedSet_setObjectAtIndexedSubscript: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setObject"), + &Ctx.Idents.get("atIndexedSubscript") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + case NSOrderedSet_replaceObjectAtIndexWithObject: { + IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("replaceObjectAtIndex"), + &Ctx.Idents.get("withObject") + }; + Sel = Ctx.Selectors.getSelector(2, KeyIdents); + break; + } + } + return (NSSetSelectors[MK] = Sel); + } + + return NSSetSelectors[MK]; +} + +Optional<NSAPI::NSSetMethodKind> +NSAPI::getNSSetMethodKind(Selector Sel) { + for (unsigned i = 0; i != NumNSSetMethods; ++i) { + NSSetMethodKind MK = NSSetMethodKind(i); + if (Sel == getNSSetSelector(MK)) + return MK; + } + + return None; +} + Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK, bool Instance) const { static const char *ClassSelectorName[NumNSNumberLiteralMethods] = { @@ -410,6 +505,11 @@ StringRef NSAPI::GetNSIntegralKind(QualType T) const { return StringRef(); } +bool NSAPI::isMacroDefined(StringRef Id) const { + // FIXME: Check whether the relevant module macros are visible. + return Ctx.Idents.get(Id).hasMacroDefinition(); +} + bool NSAPI::isObjCTypedef(QualType T, StringRef name, IdentifierInfo *&II) const { if (!Ctx.getLangOpts().ObjC1) diff --git a/lib/AST/RecordLayoutBuilder.cpp b/lib/AST/RecordLayoutBuilder.cpp index 0d070a4bfbfc..2101a5534a6b 100644 --- a/lib/AST/RecordLayoutBuilder.cpp +++ b/lib/AST/RecordLayoutBuilder.cpp @@ -55,6 +55,52 @@ struct BaseSubobjectInfo { const BaseSubobjectInfo *Derived; }; +/// \brief Externally provided layout. Typically used when the AST source, such +/// as DWARF, lacks all the information that was available at compile time, such +/// as alignment attributes on fields and pragmas in effect. +struct ExternalLayout { + ExternalLayout() : Size(0), Align(0) {} + + /// \brief Overall record size in bits. + uint64_t Size; + + /// \brief Overall record alignment in bits. + uint64_t Align; + + /// \brief Record field offsets in bits. + llvm::DenseMap<const FieldDecl *, uint64_t> FieldOffsets; + + /// \brief Direct, non-virtual base offsets. + llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsets; + + /// \brief Virtual base offsets. + llvm::DenseMap<const CXXRecordDecl *, CharUnits> VirtualBaseOffsets; + + /// Get the offset of the given field. The external source must provide + /// entries for all fields in the record. + uint64_t getExternalFieldOffset(const FieldDecl *FD) { + assert(FieldOffsets.count(FD) && + "Field does not have an external offset"); + return FieldOffsets[FD]; + } + + bool getExternalNVBaseOffset(const CXXRecordDecl *RD, CharUnits &BaseOffset) { + auto Known = BaseOffsets.find(RD); + if (Known == BaseOffsets.end()) + return false; + BaseOffset = Known->second; + return true; + } + + bool getExternalVBaseOffset(const CXXRecordDecl *RD, CharUnits &BaseOffset) { + auto Known = VirtualBaseOffsets.find(RD); + if (Known == VirtualBaseOffsets.end()) + return false; + BaseOffset = Known->second; + return true; + } +}; + /// EmptySubobjectMap - Keeps track of which empty subobjects exist at different /// offsets while laying out a C++ class. class EmptySubobjectMap { @@ -541,7 +587,7 @@ protected: /// \brief Whether the external AST source has provided a layout for this /// record. - unsigned ExternalLayout : 1; + unsigned UseExternalLayout : 1; /// \brief Whether we need to infer alignment, even when we have an /// externally-provided layout. @@ -607,26 +653,14 @@ protected: /// avoid visiting virtual bases more than once. llvm::SmallPtrSet<const CXXRecordDecl *, 4> VisitedVirtualBases; - /// \brief Externally-provided size. - uint64_t ExternalSize; - - /// \brief Externally-provided alignment. - uint64_t ExternalAlign; - - /// \brief Externally-provided field offsets. - llvm::DenseMap<const FieldDecl *, uint64_t> ExternalFieldOffsets; - - /// \brief Externally-provided direct, non-virtual base offsets. - llvm::DenseMap<const CXXRecordDecl *, CharUnits> ExternalBaseOffsets; - - /// \brief Externally-provided virtual base offsets. - llvm::DenseMap<const CXXRecordDecl *, CharUnits> ExternalVirtualBaseOffsets; + /// Valid if UseExternalLayout is true. + ExternalLayout External; RecordLayoutBuilder(const ASTContext &Context, EmptySubobjectMap *EmptySubobjects) : Context(Context), EmptySubobjects(EmptySubobjects), Size(0), Alignment(CharUnits::One()), UnpackedAlignment(CharUnits::One()), - ExternalLayout(false), InferAlignment(false), + UseExternalLayout(false), InferAlignment(false), Packed(false), IsUnion(false), IsMac68kAlign(false), IsMsStruct(false), UnfilledBitsInLastUnit(0), LastBitfieldTypeSize(0), MaxFieldAlignment(CharUnits::Zero()), @@ -748,8 +782,8 @@ protected: void setDataSize(CharUnits NewSize) { DataSize = Context.toBits(NewSize); } void setDataSize(uint64_t NewSize) { DataSize = NewSize; } - RecordLayoutBuilder(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION; - void operator=(const RecordLayoutBuilder &) LLVM_DELETED_FUNCTION; + RecordLayoutBuilder(const RecordLayoutBuilder &) = delete; + void operator=(const RecordLayoutBuilder &) = delete; }; } // end anonymous namespace @@ -1134,21 +1168,12 @@ CharUnits RecordLayoutBuilder::LayoutBase(const BaseSubobjectInfo *Base) { // Query the external layout to see if it provides an offset. bool HasExternalLayout = false; - if (ExternalLayout) { + if (UseExternalLayout) { llvm::DenseMap<const CXXRecordDecl *, CharUnits>::iterator Known; - if (Base->IsVirtual) { - Known = ExternalVirtualBaseOffsets.find(Base->Class); - if (Known != ExternalVirtualBaseOffsets.end()) { - Offset = Known->second; - HasExternalLayout = true; - } - } else { - Known = ExternalBaseOffsets.find(Base->Class); - if (Known != ExternalBaseOffsets.end()) { - Offset = Known->second; - HasExternalLayout = true; - } - } + if (Base->IsVirtual) + HasExternalLayout = External.getExternalNVBaseOffset(Base->Class, Offset); + else + HasExternalLayout = External.getExternalVBaseOffset(Base->Class, Offset); } CharUnits UnpackedBaseAlign = Layout.getNonVirtualAlignment(); @@ -1235,18 +1260,15 @@ void RecordLayoutBuilder::InitializeLayout(const Decl *D) { // If there is an external AST source, ask it for the various offsets. if (const RecordDecl *RD = dyn_cast<RecordDecl>(D)) - if (ExternalASTSource *External = Context.getExternalSource()) { - ExternalLayout = External->layoutRecordType(RD, - ExternalSize, - ExternalAlign, - ExternalFieldOffsets, - ExternalBaseOffsets, - ExternalVirtualBaseOffsets); - + if (ExternalASTSource *Source = Context.getExternalSource()) { + UseExternalLayout = Source->layoutRecordType( + RD, External.Size, External.Align, External.FieldOffsets, + External.BaseOffsets, External.VirtualBaseOffsets); + // Update based on external alignment. - if (ExternalLayout) { - if (ExternalAlign > 0) { - Alignment = Context.toCharUnitsFromBits(ExternalAlign); + if (UseExternalLayout) { + if (External.Align > 0) { + Alignment = Context.toCharUnitsFromBits(External.Align); } else { // The external source didn't have alignment information; infer it. InferAlignment = true; @@ -1588,7 +1610,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // If we're using external layout, give the external layout a chance // to override this information. - if (ExternalLayout) + if (UseExternalLayout) FieldOffset = updateExternalFieldOffset(D, FieldOffset); // Okay, place the bitfield at the calculated offset. @@ -1604,7 +1626,7 @@ void RecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { FieldAlign = UnpackedFieldAlign = 1; // Diagnose differences in layout due to padding or packing. - if (!ExternalLayout) + if (!UseExternalLayout) CheckFieldPadding(FieldOffset, UnpaddedFieldOffset, UnpackedFieldOffset, UnpackedFieldAlign, FieldPacked, D); @@ -1727,7 +1749,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D, UnpackedFieldOffset = UnpackedFieldOffset.RoundUpToAlignment(UnpackedFieldAlign); - if (ExternalLayout) { + if (UseExternalLayout) { FieldOffset = Context.toCharUnitsFromBits( updateExternalFieldOffset(D, Context.toBits(FieldOffset))); @@ -1750,7 +1772,7 @@ void RecordLayoutBuilder::LayoutField(const FieldDecl *D, // Place this field at the current location. FieldOffsets.push_back(Context.toBits(FieldOffset)); - if (!ExternalLayout) + if (!UseExternalLayout) CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffset, Context.toBits(UnpackedFieldOffset), Context.toBits(UnpackedFieldAlign), FieldPacked, D); @@ -1802,15 +1824,15 @@ void RecordLayoutBuilder::FinishLayout(const NamedDecl *D) { uint64_t RoundedSize = llvm::RoundUpToAlignment(getSizeInBits(), Context.toBits(Alignment)); - if (ExternalLayout) { + if (UseExternalLayout) { // If we're inferring alignment, and the external size is smaller than // our size after we've rounded up to alignment, conservatively set the // alignment to 1. - if (InferAlignment && ExternalSize < RoundedSize) { + if (InferAlignment && External.Size < RoundedSize) { Alignment = CharUnits::One(); InferAlignment = false; } - setSize(ExternalSize); + setSize(External.Size); return; } @@ -1846,18 +1868,18 @@ void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment, CharUnits UnpackedNewAlignment) { // The alignment is not modified when using 'mac68k' alignment or when // we have an externally-supplied layout that also provides overall alignment. - if (IsMac68kAlign || (ExternalLayout && !InferAlignment)) + if (IsMac68kAlign || (UseExternalLayout && !InferAlignment)) return; if (NewAlignment > Alignment) { - assert(llvm::isPowerOf2_32(NewAlignment.getQuantity() && - "Alignment not a power of 2")); + assert(llvm::isPowerOf2_64(NewAlignment.getQuantity()) && + "Alignment not a power of 2"); Alignment = NewAlignment; } if (UnpackedNewAlignment > UnpackedAlignment) { - assert(llvm::isPowerOf2_32(UnpackedNewAlignment.getQuantity() && - "Alignment not a power of 2")); + assert(llvm::isPowerOf2_64(UnpackedNewAlignment.getQuantity()) && + "Alignment not a power of 2"); UnpackedAlignment = UnpackedNewAlignment; } } @@ -1865,11 +1887,8 @@ void RecordLayoutBuilder::UpdateAlignment(CharUnits NewAlignment, uint64_t RecordLayoutBuilder::updateExternalFieldOffset(const FieldDecl *Field, uint64_t ComputedOffset) { - assert(ExternalFieldOffsets.find(Field) != ExternalFieldOffsets.end() && - "Field does not have an external offset"); - - uint64_t ExternalFieldOffset = ExternalFieldOffsets[Field]; - + uint64_t ExternalFieldOffset = External.getExternalFieldOffset(Field); + if (InferAlignment && ExternalFieldOffset < ComputedOffset) { // The externally-supplied field offset is before the field offset we // computed. Assume that the structure is packed. @@ -2152,9 +2171,8 @@ struct MicrosoftRecordLayoutBuilder { typedef llvm::DenseMap<const CXXRecordDecl *, CharUnits> BaseOffsetsMapTy; MicrosoftRecordLayoutBuilder(const ASTContext &Context) : Context(Context) {} private: - MicrosoftRecordLayoutBuilder(const MicrosoftRecordLayoutBuilder &) - LLVM_DELETED_FUNCTION; - void operator=(const MicrosoftRecordLayoutBuilder &) LLVM_DELETED_FUNCTION; + MicrosoftRecordLayoutBuilder(const MicrosoftRecordLayoutBuilder &) = delete; + void operator=(const MicrosoftRecordLayoutBuilder &) = delete; public: void layout(const RecordDecl *RD); void cxxLayout(const CXXRecordDecl *RD); @@ -2252,6 +2270,13 @@ public: /// \brief True if this class is zero sized or first base is zero sized or /// has this property. Only used for MS-ABI. bool LeadsWithZeroSizedBase : 1; + + /// \brief True if the external AST source provided a layout for this record. + bool UseExternalLayout : 1; + + /// \brief The layout provided by the external AST source. Only active if + /// UseExternalLayout is true. + ExternalLayout External; }; } // namespace @@ -2354,8 +2379,9 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) { // In 64-bit mode we always perform an alignment step after laying out vbases. // In 32-bit mode we do not. The check to see if we need to perform alignment // checks the RequiredAlignment field and performs alignment if it isn't 0. - RequiredAlignment = Context.getTargetInfo().getPointerWidth(0) == 64 ? - CharUnits::One() : CharUnits::Zero(); + RequiredAlignment = Context.getTargetInfo().getTriple().isArch64Bit() + ? CharUnits::One() + : CharUnits::Zero(); // Compute the maximum field alignment. MaxFieldAlignment = CharUnits::Zero(); // Honor the default struct packing maximum alignment flag. @@ -2371,6 +2397,13 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) { // Packed attribute forces max field alignment to be 1. if (RD->hasAttr<PackedAttr>()) MaxFieldAlignment = CharUnits::One(); + + // Try to respect the external layout if present. + UseExternalLayout = false; + if (ExternalASTSource *Source = Context.getExternalSource()) + UseExternalLayout = Source->layoutRecordType( + RD, External.Size, External.Align, External.FieldOffsets, + External.BaseOffsets, External.VirtualBaseOffsets); } void @@ -2385,7 +2418,8 @@ MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) { // injection. PointerInfo.Size = Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); - PointerInfo.Alignment = PointerInfo.Size; + PointerInfo.Alignment = + Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerAlign(0)); // Respect pragma pack. if (!MaxFieldAlignment.isZero()) PointerInfo.Alignment = std::min(PointerInfo.Alignment, MaxFieldAlignment); @@ -2475,7 +2509,18 @@ void MicrosoftRecordLayoutBuilder::layoutNonVirtualBase( BaseLayout.leadsWithZeroSizedBase()) Size++; ElementInfo Info = getAdjustedElementInfo(BaseLayout); - CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment); + CharUnits BaseOffset; + + // Respect the external AST source base offset, if present. + bool FoundBase = false; + if (UseExternalLayout) { + FoundBase = External.getExternalNVBaseOffset(BaseDecl, BaseOffset); + if (FoundBase) + assert(BaseOffset >= Size && "base offset already allocated"); + } + + if (!FoundBase) + BaseOffset = Size.RoundUpToAlignment(Info.Alignment); Bases.insert(std::make_pair(BaseDecl, BaseOffset)); Size = BaseOffset + BaseLayout.getNonVirtualSize(); PreviousBaseLayout = &BaseLayout; @@ -2499,7 +2544,14 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) { placeFieldAtOffset(CharUnits::Zero()); Size = std::max(Size, Info.Size); } else { - CharUnits FieldOffset = Size.RoundUpToAlignment(Info.Alignment); + CharUnits FieldOffset; + if (UseExternalLayout) { + FieldOffset = + Context.toCharUnitsFromBits(External.getExternalFieldOffset(FD)); + assert(FieldOffset >= Size && "field offset already allocated"); + } else { + FieldOffset = Size.RoundUpToAlignment(Info.Alignment); + } placeFieldAtOffset(FieldOffset); Size = FieldOffset + Info.Size; } @@ -2573,14 +2625,16 @@ void MicrosoftRecordLayoutBuilder::injectVBPtr(const CXXRecordDecl *RD) { CharUnits InjectionSite = VBPtrOffset; // But before we do, make sure it's properly aligned. VBPtrOffset = VBPtrOffset.RoundUpToAlignment(PointerInfo.Alignment); + // Shift everything after the vbptr down, unless we're using an external + // layout. + if (UseExternalLayout) + return; // Determine where the first field should be laid out after the vbptr. CharUnits FieldStart = VBPtrOffset + PointerInfo.Size; // Make sure that the amount we push the fields back by is a multiple of the // alignment. CharUnits Offset = (FieldStart - InjectionSite).RoundUpToAlignment( std::max(RequiredAlignment, Alignment)); - // Increase the size of the object and push back all fields by the offset - // amount. Size += Offset; for (uint64_t &FieldOffset : FieldOffsets) FieldOffset += Context.toBits(Offset); @@ -2647,7 +2701,18 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { } // Insert the virtual base. ElementInfo Info = getAdjustedElementInfo(BaseLayout); - CharUnits BaseOffset = Size.RoundUpToAlignment(Info.Alignment); + CharUnits BaseOffset; + + // Respect the external AST source base offset, if present. + bool FoundBase = false; + if (UseExternalLayout) { + FoundBase = External.getExternalVBaseOffset(BaseDecl, BaseOffset); + if (FoundBase) + assert(BaseOffset >= Size && "base offset already allocated"); + } + if (!FoundBase) + BaseOffset = Size.RoundUpToAlignment(Info.Alignment); + VBases.insert(std::make_pair(BaseDecl, ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp))); Size = BaseOffset + BaseLayout.getNonVirtualSize(); @@ -2677,6 +2742,12 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { else Size = MinEmptyStructSize; } + + if (UseExternalLayout) { + Size = Context.toCharUnitsFromBits(External.Size); + if (External.Align) + Alignment = Context.toCharUnitsFromBits(External.Align); + } } // Recursively walks the non-virtual bases of a class and determines if any of @@ -2815,7 +2886,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { const ASTRecordLayout *NewEntry = nullptr; - if (isMsLayout(D) && !D->getASTContext().getExternalSource()) { + if (isMsLayout(D)) { NewEntry = BuildMicrosoftASTRecordLayout(D); } else if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) { EmptySubobjectMap EmptySubobjects(*this, RD); @@ -2905,11 +2976,11 @@ void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) { // Look up the cache entry. Since we're working with the first // declaration, its parent must be the class definition, which is // the correct key for the KeyFunctions hash. - llvm::DenseMap<const CXXRecordDecl*, LazyDeclPtr>::iterator - I = KeyFunctions.find(Method->getParent()); + const auto &Map = KeyFunctions; + auto I = Map.find(Method->getParent()); // If it's not cached, there's nothing to do. - if (I == KeyFunctions.end()) return; + if (I == Map.end()) return; // If it is cached, check whether it's the target method, and if so, // remove it from the cache. Note, the call to 'get' might invalidate diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index 68c7e7278432..6baa99bbc5bf 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -95,10 +95,16 @@ void Stmt::EnableStatistics() { Stmt *Stmt::IgnoreImplicit() { Stmt *s = this; - if (ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(s)) + if (auto *ewc = dyn_cast<ExprWithCleanups>(s)) s = ewc->getSubExpr(); - while (ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(s)) + if (auto *mte = dyn_cast<MaterializeTemporaryExpr>(s)) + s = mte->GetTemporaryExpr(); + + if (auto *bte = dyn_cast<CXXBindTemporaryExpr>(s)) + s = bte->getSubExpr(); + + while (auto *ice = dyn_cast<ImplicitCastExpr>(s)) s = ice->getSubExpr(); return s; @@ -934,8 +940,7 @@ void ForStmt::setConditionVariable(const ASTContext &C, VarDecl *V) { } SwitchStmt::SwitchStmt(const ASTContext &C, VarDecl *Var, Expr *cond) - : Stmt(SwitchStmtClass), FirstCase(nullptr), AllEnumCasesCovered(0) -{ + : Stmt(SwitchStmtClass), FirstCase(nullptr, false) { setConditionVariable(C, Var); SubExprs[COND] = cond; SubExprs[BODY] = nullptr; @@ -1241,17 +1246,47 @@ OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPFirstprivateClause(N); } -OMPLastprivateClause *OMPLastprivateClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef<Expr *> VL) { +void OMPLastprivateClause::setPrivateCopies(ArrayRef<Expr *> PrivateCopies) { + assert(PrivateCopies.size() == varlist_size() && + "Number of private copies is not the same as the preallocated buffer"); + std::copy(PrivateCopies.begin(), PrivateCopies.end(), varlist_end()); +} + +void OMPLastprivateClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) { + assert(SrcExprs.size() == varlist_size() && "Number of source expressions is " + "not the same as the " + "preallocated buffer"); + std::copy(SrcExprs.begin(), SrcExprs.end(), getPrivateCopies().end()); +} + +void OMPLastprivateClause::setDestinationExprs(ArrayRef<Expr *> DstExprs) { + assert(DstExprs.size() == varlist_size() && "Number of destination " + "expressions is not the same as " + "the preallocated buffer"); + std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end()); +} + +void OMPLastprivateClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) { + assert(AssignmentOps.size() == varlist_size() && + "Number of assignment expressions is not the same as the preallocated " + "buffer"); + std::copy(AssignmentOps.begin(), AssignmentOps.end(), + getDestinationExprs().end()); +} + +OMPLastprivateClause *OMPLastprivateClause::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs, + ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * VL.size()); + 5 * sizeof(Expr *) * VL.size()); OMPLastprivateClause *Clause = new (Mem) OMPLastprivateClause(StartLoc, LParenLoc, EndLoc, VL.size()); Clause->setVarRefs(VL); + Clause->setSourceExprs(SrcExprs); + Clause->setDestinationExprs(DstExprs); + Clause->setAssignmentOps(AssignmentOps); return Clause; } @@ -1259,7 +1294,7 @@ OMPLastprivateClause *OMPLastprivateClause::CreateEmpty(const ASTContext &C, unsigned N) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLastprivateClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * N); + 5 * sizeof(Expr *) * N); return new (Mem) OMPLastprivateClause(N); } @@ -1285,27 +1320,56 @@ OMPSharedClause *OMPSharedClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPSharedClause(N); } -OMPLinearClause *OMPLinearClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation ColonLoc, - SourceLocation EndLoc, - ArrayRef<Expr *> VL, Expr *Step) { +void OMPLinearClause::setInits(ArrayRef<Expr *> IL) { + assert(IL.size() == varlist_size() && + "Number of inits is not the same as the preallocated buffer"); + std::copy(IL.begin(), IL.end(), varlist_end()); +} + +void OMPLinearClause::setUpdates(ArrayRef<Expr *> UL) { + assert(UL.size() == varlist_size() && + "Number of updates is not the same as the preallocated buffer"); + std::copy(UL.begin(), UL.end(), getInits().end()); +} + +void OMPLinearClause::setFinals(ArrayRef<Expr *> FL) { + assert(FL.size() == varlist_size() && + "Number of final updates is not the same as the preallocated buffer"); + std::copy(FL.begin(), FL.end(), getUpdates().end()); +} + +OMPLinearClause * +OMPLinearClause::Create(const ASTContext &C, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, + ArrayRef<Expr *> IL, Expr *Step, Expr *CalcStep) { + // Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions + // (Step and CalcStep). void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * (VL.size() + 1)); + (4 * VL.size() + 2) * sizeof(Expr *)); OMPLinearClause *Clause = new (Mem) OMPLinearClause(StartLoc, LParenLoc, ColonLoc, EndLoc, VL.size()); Clause->setVarRefs(VL); + Clause->setInits(IL); + // Fill update and final expressions with zeroes, they are provided later, + // after the directive construction. + std::fill(Clause->getInits().end(), Clause->getInits().end() + VL.size(), + nullptr); + std::fill(Clause->getUpdates().end(), Clause->getUpdates().end() + VL.size(), + nullptr); Clause->setStep(Step); + Clause->setCalcStep(CalcStep); return Clause; } OMPLinearClause *OMPLinearClause::CreateEmpty(const ASTContext &C, unsigned NumVars) { + // Allocate space for 4 lists (Vars, Inits, Updates, Finals) and 2 expressions + // (Step and CalcStep). void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPLinearClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * (NumVars + 1)); + (4 * NumVars + 2) * sizeof(Expr *)); return new (Mem) OMPLinearClause(NumVars); } @@ -1331,17 +1395,41 @@ OMPAlignedClause *OMPAlignedClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPAlignedClause(NumVars); } -OMPCopyinClause *OMPCopyinClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef<Expr *> VL) { +void OMPCopyinClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) { + assert(SrcExprs.size() == varlist_size() && "Number of source expressions is " + "not the same as the " + "preallocated buffer"); + std::copy(SrcExprs.begin(), SrcExprs.end(), varlist_end()); +} + +void OMPCopyinClause::setDestinationExprs(ArrayRef<Expr *> DstExprs) { + assert(DstExprs.size() == varlist_size() && "Number of destination " + "expressions is not the same as " + "the preallocated buffer"); + std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end()); +} + +void OMPCopyinClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) { + assert(AssignmentOps.size() == varlist_size() && + "Number of assignment expressions is not the same as the preallocated " + "buffer"); + std::copy(AssignmentOps.begin(), AssignmentOps.end(), + getDestinationExprs().end()); +} + +OMPCopyinClause *OMPCopyinClause::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs, + ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * VL.size()); + 4 * sizeof(Expr *) * VL.size()); OMPCopyinClause *Clause = new (Mem) OMPCopyinClause(StartLoc, LParenLoc, EndLoc, VL.size()); Clause->setVarRefs(VL); + Clause->setSourceExprs(SrcExprs); + Clause->setDestinationExprs(DstExprs); + Clause->setAssignmentOps(AssignmentOps); return Clause; } @@ -1349,21 +1437,45 @@ OMPCopyinClause *OMPCopyinClause::CreateEmpty(const ASTContext &C, unsigned N) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * N); + 4 * sizeof(Expr *) * N); return new (Mem) OMPCopyinClause(N); } -OMPCopyprivateClause *OMPCopyprivateClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef<Expr *> VL) { +void OMPCopyprivateClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) { + assert(SrcExprs.size() == varlist_size() && "Number of source expressions is " + "not the same as the " + "preallocated buffer"); + std::copy(SrcExprs.begin(), SrcExprs.end(), varlist_end()); +} + +void OMPCopyprivateClause::setDestinationExprs(ArrayRef<Expr *> DstExprs) { + assert(DstExprs.size() == varlist_size() && "Number of destination " + "expressions is not the same as " + "the preallocated buffer"); + std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end()); +} + +void OMPCopyprivateClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) { + assert(AssignmentOps.size() == varlist_size() && + "Number of assignment expressions is not the same as the preallocated " + "buffer"); + std::copy(AssignmentOps.begin(), AssignmentOps.end(), + getDestinationExprs().end()); +} + +OMPCopyprivateClause *OMPCopyprivateClause::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs, + ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * VL.size()); + 4 * sizeof(Expr *) * VL.size()); OMPCopyprivateClause *Clause = new (Mem) OMPCopyprivateClause(StartLoc, LParenLoc, EndLoc, VL.size()); Clause->setVarRefs(VL); + Clause->setSourceExprs(SrcExprs); + Clause->setDestinationExprs(DstExprs); + Clause->setAssignmentOps(AssignmentOps); return Clause; } @@ -1371,7 +1483,7 @@ OMPCopyprivateClause *OMPCopyprivateClause::CreateEmpty(const ASTContext &C, unsigned N) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyprivateClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * N); + 4 * sizeof(Expr *) * N); return new (Mem) OMPCopyprivateClause(N); } @@ -1399,16 +1511,42 @@ void OMPLoopDirective::setFinals(ArrayRef<Expr *> A) { std::copy(A.begin(), A.end(), getFinals().begin()); } +void OMPReductionClause::setLHSExprs(ArrayRef<Expr *> LHSExprs) { + assert( + LHSExprs.size() == varlist_size() && + "Number of LHS expressions is not the same as the preallocated buffer"); + std::copy(LHSExprs.begin(), LHSExprs.end(), varlist_end()); +} + +void OMPReductionClause::setRHSExprs(ArrayRef<Expr *> RHSExprs) { + assert( + RHSExprs.size() == varlist_size() && + "Number of RHS expressions is not the same as the preallocated buffer"); + std::copy(RHSExprs.begin(), RHSExprs.end(), getLHSExprs().end()); +} + +void OMPReductionClause::setReductionOps(ArrayRef<Expr *> ReductionOps) { + assert(ReductionOps.size() == varlist_size() && "Number of reduction " + "expressions is not the same " + "as the preallocated buffer"); + std::copy(ReductionOps.begin(), ReductionOps.end(), getRHSExprs().end()); +} + OMPReductionClause *OMPReductionClause::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VL, - NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo) { + NestedNameSpecifierLoc QualifierLoc, const DeclarationNameInfo &NameInfo, + ArrayRef<Expr *> LHSExprs, ArrayRef<Expr *> RHSExprs, + ArrayRef<Expr *> ReductionOps) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * VL.size()); + 4 * sizeof(Expr *) * VL.size()); OMPReductionClause *Clause = new (Mem) OMPReductionClause( StartLoc, LParenLoc, EndLoc, ColonLoc, VL.size(), QualifierLoc, NameInfo); Clause->setVarRefs(VL); + Clause->setLHSExprs(LHSExprs); + Clause->setRHSExprs(RHSExprs); + Clause->setReductionOps(ReductionOps); return Clause; } @@ -1416,7 +1554,7 @@ OMPReductionClause *OMPReductionClause::CreateEmpty(const ASTContext &C, unsigned N) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPReductionClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * N); + 4 * sizeof(Expr *) * N); return new (Mem) OMPReductionClause(N); } @@ -1443,10 +1581,7 @@ OMPFlushClause *OMPFlushClause::CreateEmpty(const ASTContext &C, unsigned 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); + auto &&I = getClausesOfKind(K); if (I) { auto *Clause = *I; @@ -1948,14 +2083,14 @@ OMPOrderedDirective *OMPOrderedDirective::CreateEmpty(const ASTContext &C, 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) { +OMPAtomicDirective *OMPAtomicDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *X, Expr *V, + Expr *E, Expr *UE, bool IsXLHSInRHSPart, bool IsPostfixUpdate) { unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective), llvm::alignOf<OMPClause *>()); void *Mem = C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + - 4 * sizeof(Stmt *)); + 5 * sizeof(Stmt *)); OMPAtomicDirective *Dir = new (Mem) OMPAtomicDirective(StartLoc, EndLoc, Clauses.size()); Dir->setClauses(Clauses); @@ -1963,6 +2098,9 @@ OMPAtomicDirective::Create(const ASTContext &C, SourceLocation StartLoc, Dir->setX(X); Dir->setV(V); Dir->setExpr(E); + Dir->setUpdateExpr(UE); + Dir->IsXLHSInRHSPart = IsXLHSInRHSPart; + Dir->IsPostfixUpdate = IsPostfixUpdate; return Dir; } @@ -1972,7 +2110,7 @@ OMPAtomicDirective *OMPAtomicDirective::CreateEmpty(const ASTContext &C, unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPAtomicDirective), llvm::alignOf<OMPClause *>()); void *Mem = - C.Allocate(Size + sizeof(OMPClause *) * NumClauses + 4 * sizeof(Stmt *)); + C.Allocate(Size + sizeof(OMPClause *) * NumClauses + 5 * sizeof(Stmt *)); return new (Mem) OMPAtomicDirective(NumClauses); } diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 927a679244b5..dc4f9964c7a6 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1069,7 +1069,8 @@ void StmtPrinter::VisitIntegerLiteral(IntegerLiteral *Node) { // Emit suffixes. Integer literals are always a builtin integer type. switch (Node->getType()->getAs<BuiltinType>()->getKind()) { default: llvm_unreachable("Unexpected type for integer literal!"); - case BuiltinType::SChar: OS << "i8"; break; + case BuiltinType::Char_S: + case BuiltinType::Char_U: OS << "i8"; break; case BuiltinType::UChar: OS << "Ui8"; break; case BuiltinType::Short: OS << "i16"; break; case BuiltinType::UShort: OS << "Ui16"; break; @@ -1373,24 +1374,24 @@ void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { return; } - OS << "{ "; + OS << "{"; for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) { if (i) OS << ", "; if (Node->getInit(i)) PrintExpr(Node->getInit(i)); else - OS << "0"; + OS << "{}"; } - OS << " }"; + OS << "}"; } void StmtPrinter::VisitParenListExpr(ParenListExpr* Node) { - OS << "( "; + OS << "("; for (unsigned i = 0, e = Node->getNumExprs(); i != e; ++i) { if (i) OS << ", "; PrintExpr(Node->getExpr(i)); } - OS << " )"; + OS << ")"; } void StmtPrinter::VisitDesignatedInitExpr(DesignatedInitExpr *Node) { @@ -1621,6 +1622,15 @@ void StmtPrinter::VisitUserDefinedLiteral(UserDefinedLiteral *Node) { const TemplateArgumentList *Args = cast<FunctionDecl>(DRE->getDecl())->getTemplateSpecializationArgs(); assert(Args); + + if (Args->size() != 1) { + OS << "operator \"\" " << Node->getUDSuffix()->getName(); + TemplateSpecializationType::PrintTemplateArgumentList( + OS, Args->data(), Args->size(), Policy); + OS << "()"; + return; + } + const TemplateArgument &Pack = Args->get(0); for (const auto &P : Pack.pack_elements()) { char C = (char)P.getAsIntegral().getZExtValue(); @@ -1679,9 +1689,13 @@ void StmtPrinter::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *Node) { void StmtPrinter::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *Node) { Node->getType().print(OS, Policy); - OS << "("; + // If there are no parens, this is list-initialization, and the braces are + // part of the syntax of the inner construct. + if (Node->getLParenLoc().isValid()) + OS << "("; PrintExpr(Node->getSubExpr()); - OS << ")"; + if (Node->getLParenLoc().isValid()) + OS << ")"; } void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { @@ -1690,7 +1704,12 @@ void StmtPrinter::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *Node) { void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { Node->getType().print(OS, Policy); - OS << "("; + if (Node->isStdInitListInitialization()) + /* Nothing to do; braces are part of creating the std::initializer_list. */; + else if (Node->isListInitialization()) + OS << "{"; + else + OS << "("; for (CXXTemporaryObjectExpr::arg_iterator Arg = Node->arg_begin(), ArgEnd = Node->arg_end(); Arg != ArgEnd; ++Arg) { @@ -1700,7 +1719,12 @@ void StmtPrinter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *Node) { OS << ", "; PrintExpr(*Arg); } - OS << ")"; + if (Node->isStdInitListInitialization()) + /* See above. */; + else if (Node->isListInitialization()) + OS << "}"; + else + OS << ")"; } void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { @@ -1734,7 +1758,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { break; case LCK_ByRef: - if (Node->getCaptureDefault() != LCD_ByRef || C->isInitCapture()) + if (Node->getCaptureDefault() != LCD_ByRef || Node->isInitCapture(C)) OS << '&'; OS << C->getCapturedVar()->getName(); break; @@ -1746,7 +1770,7 @@ void StmtPrinter::VisitLambdaExpr(LambdaExpr *Node) { llvm_unreachable("VLA type in explicit captures."); } - if (C->isInitCapture()) + if (Node->isInitCapture(C)) PrintExpr(C->getCapturedVar()->getInit()); } OS << ']'; @@ -1866,8 +1890,8 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { } void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { - if (E->isListInitialization()) - OS << "{ "; + if (E->isListInitialization() && !E->isStdInitListInitialization()) + OS << "{"; for (unsigned i = 0, e = E->getNumArgs(); i != e; ++i) { if (isa<CXXDefaultArgExpr>(E->getArg(i))) { @@ -1879,8 +1903,8 @@ void StmtPrinter::VisitCXXConstructExpr(CXXConstructExpr *E) { PrintExpr(E->getArg(i)); } - if (E->isListInitialization()) - OS << " }"; + if (E->isListInitialization() && !E->isStdInitListInitialization()) + OS << "}"; } void StmtPrinter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index d1f25d63b3f9..c66b153eadbb 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -298,8 +298,12 @@ void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { } void OMPClauseProfiler::VisitOMPProcBindClause(const OMPProcBindClause *C) { } void OMPClauseProfiler::VisitOMPScheduleClause(const OMPScheduleClause *C) { - if (C->getChunkSize()) + if (C->getChunkSize()) { Profiler->VisitStmt(C->getChunkSize()); + if (C->getHelperChunkSize()) { + Profiler->VisitStmt(C->getChunkSize()); + } + } } void OMPClauseProfiler::VisitOMPOrderedClause(const OMPOrderedClause *) {} @@ -346,6 +350,15 @@ OMPClauseProfiler::VisitOMPFirstprivateClause(const OMPFirstprivateClause *C) { void OMPClauseProfiler::VisitOMPLastprivateClause(const OMPLastprivateClause *C) { VisitOMPClauseList(C); + for (auto *E : C->source_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->destination_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->assignment_ops()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) { VisitOMPClauseList(C); @@ -356,10 +369,29 @@ void OMPClauseProfiler::VisitOMPReductionClause( C->getQualifierLoc().getNestedNameSpecifier()); Profiler->VisitName(C->getNameInfo().getName()); VisitOMPClauseList(C); + for (auto *E : C->lhs_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->rhs_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->reduction_ops()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPLinearClause(const OMPLinearClause *C) { VisitOMPClauseList(C); + for (auto *E : C->inits()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->updates()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->finals()) { + Profiler->VisitStmt(E); + } Profiler->VisitStmt(C->getStep()); + Profiler->VisitStmt(C->getCalcStep()); } void OMPClauseProfiler::VisitOMPAlignedClause(const OMPAlignedClause *C) { VisitOMPClauseList(C); @@ -367,10 +399,28 @@ void OMPClauseProfiler::VisitOMPAlignedClause(const OMPAlignedClause *C) { } void OMPClauseProfiler::VisitOMPCopyinClause(const OMPCopyinClause *C) { VisitOMPClauseList(C); + for (auto *E : C->source_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->destination_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->assignment_ops()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) { VisitOMPClauseList(C); + for (auto *E : C->source_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->destination_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->assignment_ops()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPFlushClause(const OMPFlushClause *C) { VisitOMPClauseList(C); diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index e4f364d04f86..09bb7692596c 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -170,15 +170,7 @@ DependentSizedExtVectorType::Profile(llvm::FoldingSetNodeID &ID, VectorType::VectorType(QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind) - : Type(Vector, canonType, vecType->isDependentType(), - vecType->isInstantiationDependentType(), - vecType->isVariablyModifiedType(), - vecType->containsUnexpandedParameterPack()), - ElementType(vecType) -{ - VectorTypeBits.VecKind = vecKind; - VectorTypeBits.NumElements = nElements; -} + : VectorType(Vector, vecType, nElements, canonType, vecKind) {} VectorType::VectorType(TypeClass tc, QualType vecType, unsigned nElements, QualType canonType, VectorKind vecKind) @@ -640,12 +632,13 @@ bool Type::hasIntegerRepresentation() const { bool Type::isIntegralType(ASTContext &Ctx) const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && - BT->getKind() <= BuiltinType::Int128; - + BT->getKind() <= BuiltinType::Int128; + + // Complete enum types are integral in C. if (!Ctx.getLangOpts().CPlusPlus) if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) - return ET->getDecl()->isComplete(); // Complete enum types are integral in C. - + return ET->getDecl()->isComplete(); + return false; } @@ -736,7 +729,7 @@ bool Type::isSignedIntegerType() const { bool Type::isSignedIntegerOrEnumerationType() const { if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) { return BT->getKind() >= BuiltinType::Char_S && - BT->getKind() <= BuiltinType::Int128; + BT->getKind() <= BuiltinType::Int128; } if (const EnumType *ET = dyn_cast<EnumType>(CanonicalType)) { @@ -1089,7 +1082,7 @@ bool QualType::isTrivialType(ASTContext &Context) const { bool QualType::isTriviallyCopyableType(ASTContext &Context) const { if ((*this)->isArrayType()) - return Context.getBaseElementType(*this).isTrivialType(Context); + return Context.getBaseElementType(*this).isTriviallyCopyableType(Context); if (Context.getLangOpts().ObjCAutoRefCount) { switch (getObjCLifetime()) { @@ -1586,8 +1579,9 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_X86_64SysV: return "sysv_abi"; case CC_AAPCS: return "aapcs"; case CC_AAPCS_VFP: return "aapcs-vfp"; - case CC_PnaclCall: return "pnaclcall"; case CC_IntelOclBicc: return "intel_ocl_bicc"; + case CC_SpirFunction: return "spir_function"; + case CC_SpirKernel: return "spir_kernel"; } llvm_unreachable("Invalid calling convention."); @@ -1720,7 +1714,7 @@ bool FunctionProtoType::isNothrow(const ASTContext &Ctx, if (EST == EST_DynamicNone || EST == EST_BasicNoexcept) return true; - if (EST == EST_Dynamic && ResultIfDependent == true) { + if (EST == EST_Dynamic && ResultIfDependent) { // A dynamic exception specification is throwing unless every exception // type is an (unexpanded) pack expansion type. for (unsigned I = 0, N = NumExceptions; I != N; ++I) @@ -1936,7 +1930,6 @@ bool AttributedType::isCallingConv() const { case attr_pascal: case attr_ms_abi: case attr_sysv_abi: - case attr_pnaclcall: case attr_inteloclbicc: return true; } @@ -2378,6 +2371,11 @@ bool Type::isObjCNSObjectType() const { return typedefType->getDecl()->hasAttr<ObjCNSObjectAttr>(); return false; } +bool Type::isObjCIndependentClassType() const { + if (const TypedefType *typedefType = dyn_cast<TypedefType>(this)) + return typedefType->getDecl()->hasAttr<ObjCIndependentClassAttr>(); + return false; +} bool Type::isObjCRetainableType() const { return isObjCObjectPointerType() || isBlockPointerType() || diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index e36fc175c449..3928fe8f8942 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -110,7 +110,7 @@ namespace { }; } -static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals) { +static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals, bool C99) { bool appendSpace = false; if (TypeQuals & Qualifiers::Const) { OS << "const"; @@ -123,7 +123,11 @@ static void AppendTypeQualList(raw_ostream &OS, unsigned TypeQuals) { } if (TypeQuals & Qualifiers::Restrict) { if (appendSpace) OS << ' '; - OS << "restrict"; + if (C99) { + OS << "restrict"; + } else { + OS << "__restrict"; + } } } @@ -432,7 +436,7 @@ void TypePrinter::printConstantArrayAfter(const ConstantArrayType *T, raw_ostream &OS) { OS << '['; if (T->getIndexTypeQualifiers().hasQualifiers()) { - AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers()); + AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), Policy.LangOpts.C99); OS << ' '; } @@ -465,7 +469,7 @@ void TypePrinter::printVariableArrayAfter(const VariableArrayType *T, raw_ostream &OS) { OS << '['; if (T->getIndexTypeQualifiers().hasQualifiers()) { - AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers()); + AppendTypeQualList(OS, T->getIndexTypeCVRQualifiers(), Policy.LangOpts.C99); OS << ' '; } @@ -685,9 +689,6 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, case CC_AAPCS_VFP: OS << " __attribute__((pcs(\"aapcs-vfp\")))"; break; - case CC_PnaclCall: - OS << " __attribute__((pnaclcall))"; - break; case CC_IntelOclBicc: OS << " __attribute__((intel_ocl_bicc))"; break; @@ -697,6 +698,10 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, case CC_X86_64SysV: OS << " __attribute__((sysv_abi))"; break; + case CC_SpirFunction: + case CC_SpirKernel: + // Do nothing. These CCs are not available as attributes. + break; } } @@ -708,7 +713,7 @@ void TypePrinter::printFunctionProtoAfter(const FunctionProtoType *T, if (unsigned quals = T->getTypeQuals()) { OS << ' '; - AppendTypeQualList(OS, quals); + AppendTypeQualList(OS, quals, Policy.LangOpts.C99); } switch (T->getRefQualifier()) { @@ -1253,7 +1258,6 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, OS << ')'; break; } - case AttributedType::attr_pnaclcall: OS << "pnaclcall"; break; case AttributedType::attr_inteloclbicc: OS << "inteloclbicc"; break; } OS << "))"; @@ -1473,7 +1477,7 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, unsigned quals = getCVRQualifiers(); if (quals) { - AppendTypeQualList(OS, quals); + AppendTypeQualList(OS, quals, Policy.LangOpts.C99); addSpace = true; } if (unsigned addrspace = getAddressSpace()) { diff --git a/lib/AST/VTableBuilder.cpp b/lib/AST/VTableBuilder.cpp index ddb1f057ac8e..ca5f0aad0013 100644 --- a/lib/AST/VTableBuilder.cpp +++ b/lib/AST/VTableBuilder.cpp @@ -13,9 +13,11 @@ #include "clang/AST/VTableBuilder.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" @@ -216,7 +218,7 @@ FinalOverriders::FinalOverriders(const CXXRecordDecl *MostDerivedClass, #endif } -static BaseOffset ComputeBaseOffset(ASTContext &Context, +static BaseOffset ComputeBaseOffset(const ASTContext &Context, const CXXRecordDecl *DerivedRD, const CXXBasePath &Path) { CharUnits NonVirtualOffset = CharUnits::Zero(); @@ -255,7 +257,7 @@ static BaseOffset ComputeBaseOffset(ASTContext &Context, } -static BaseOffset ComputeBaseOffset(ASTContext &Context, +static BaseOffset ComputeBaseOffset(const ASTContext &Context, const CXXRecordDecl *BaseRD, const CXXRecordDecl *DerivedRD) { CXXBasePaths Paths(/*FindAmbiguities=*/false, @@ -411,7 +413,8 @@ void FinalOverriders::dump(raw_ostream &Out, BaseSubobject Base, for (const auto *MD : RD->methods()) { if (!MD->isVirtual()) continue; - + MD = MD->getCanonicalDecl(); + OverriderInfo Overrider = getOverrider(MD, Base.getBaseOffset()); Out << " "; @@ -695,6 +698,7 @@ void VCallAndVBaseOffsetBuilder::AddVCallOffsets(BaseSubobject Base, for (const auto *MD : RD->methods()) { if (!MD->isVirtual()) continue; + MD = MD->getCanonicalDecl(); CharUnits OffsetOffset = getCurrentOffsetOffset(); @@ -1514,6 +1518,7 @@ void ItaniumVTableBuilder::AddMethods( for (const auto *MD : RD->methods()) { if (!MD->isVirtual()) continue; + MD = MD->getCanonicalDecl(); // Get the final overrider. FinalOverriders::OverriderInfo Overrider = @@ -2196,6 +2201,7 @@ void ItaniumVTableBuilder::dumpLayout(raw_ostream &Out) { // We only want virtual member functions. if (!MD->isVirtual()) continue; + MD = MD->getCanonicalDecl(); std::string MethodName = PredefinedExpr::ComputeName(PredefinedExpr::PrettyFunctionNoVirtual, @@ -2585,7 +2591,9 @@ public: // Only include the RTTI component if we know that we will provide a // definition of the vftable. HasRTTIComponent = Context.getLangOpts().RTTIData && - !MostDerivedClass->hasAttr<DLLImportAttr>(); + !MostDerivedClass->hasAttr<DLLImportAttr>() && + MostDerivedClass->getTemplateSpecializationKind() != + TSK_ExplicitInstantiationDeclaration; LayoutVFTable(); @@ -2625,8 +2633,6 @@ public: void dumpLayout(raw_ostream &); }; -} // end namespace - /// InitialOverriddenDefinitionCollector - Finds the set of least derived bases /// that define the given method. struct InitialOverriddenDefinitionCollector { @@ -2641,6 +2647,8 @@ struct InitialOverriddenDefinitionCollector { } }; +} // end namespace + static bool BaseInSet(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, void *BasesSet) { BasesSetVectorTy *Bases = (BasesSetVectorTy *)BasesSet; @@ -2730,8 +2738,9 @@ VFTableBuilder::ComputeThisOffset(FinalOverriders::OverriderInfo Overrider) { CharUnits ThisOffset = Overrider.Offset; CharUnits LastVBaseOffset; - // For each path from the overrider to the parents of the overridden methods, - // traverse the path, calculating the this offset in the most derived class. + // For each path from the overrider to the parents of the overridden + // methods, traverse the path, calculating the this offset in the most + // derived class. for (int J = 0, F = Path.size(); J != F; ++J) { const CXXBasePathElement &Element = Path[J]; QualType CurTy = Element.Base->getType(); @@ -2930,6 +2939,7 @@ static void GroupNewVirtualOverloads( typedef llvm::DenseMap<DeclarationName, unsigned> VisitedGroupIndicesTy; VisitedGroupIndicesTy VisitedGroupIndices; for (const auto *MD : RD->methods()) { + MD = MD->getCanonicalDecl(); VisitedGroupIndicesTy::iterator J; bool Inserted; std::tie(J, Inserted) = VisitedGroupIndices.insert( @@ -2962,7 +2972,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); // See if this class expands a vftable of the base we look at, which is either - // the one defined by the vfptr base path or the primary base of the current class. + // the one defined by the vfptr base path or the primary base of the current + // class. const CXXRecordDecl *NextBase = nullptr, *NextLastVBase = LastVBase; CharUnits NextBaseOffset; if (BaseDepth < WhichVFPtr.PathToBaseWithVPtr.size()) { @@ -3020,7 +3031,8 @@ void VFTableBuilder::AddMethods(BaseSubobject Base, unsigned BaseDepth, ThisAdjustmentOffset); if (OverriddenMD) { - // If MD overrides anything in this vftable, we need to update the entries. + // If MD overrides anything in this vftable, we need to update the + // entries. MethodInfoMapTy::iterator OverriddenMDIterator = MethodInfoMap.find(OverriddenMD); @@ -3435,55 +3447,176 @@ 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; +namespace { +typedef llvm::SetVector<BaseSubobject, std::vector<BaseSubobject>, + llvm::DenseSet<BaseSubobject>> FullPathTy; +} + +// This recursive function finds all paths from a subobject centered at +// (RD, Offset) to the subobject located at BaseWithVPtr. +static void findPathsToSubobject(ASTContext &Context, + const ASTRecordLayout &MostDerivedLayout, + const CXXRecordDecl *RD, CharUnits Offset, + BaseSubobject BaseWithVPtr, + FullPathTy &FullPath, + std::list<FullPathTy> &Paths) { + if (BaseSubobject(RD, Offset) == BaseWithVPtr) { + Paths.push_back(FullPath); + return; } 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; + for (const CXXBaseSpecifier &BS : RD->bases()) { + const CXXRecordDecl *Base = BS.getType()->getAsCXXRecordDecl(); + CharUnits NewOffset = BS.isVirtual() + ? MostDerivedLayout.getVBaseClassOffset(Base) + : Offset + Layout.getBaseClassOffset(Base); + FullPath.insert(BaseSubobject(Base, NewOffset)); + findPathsToSubobject(Context, MostDerivedLayout, Base, NewOffset, + BaseWithVPtr, FullPath, Paths); FullPath.pop_back(); } - return false; +} + +// Return the paths which are not subsets of other paths. +static void removeRedundantPaths(std::list<FullPathTy> &FullPaths) { + FullPaths.remove_if([&](const FullPathTy &SpecificPath) { + for (const FullPathTy &OtherPath : FullPaths) { + if (&SpecificPath == &OtherPath) + continue; + if (std::all_of(SpecificPath.begin(), SpecificPath.end(), + [&](const BaseSubobject &BSO) { + return OtherPath.count(BSO) != 0; + })) { + return true; + } + } + return false; + }); +} + +static CharUnits getOffsetOfFullPath(ASTContext &Context, + const CXXRecordDecl *RD, + const FullPathTy &FullPath) { + const ASTRecordLayout &MostDerivedLayout = + Context.getASTRecordLayout(RD); + CharUnits Offset = CharUnits::fromQuantity(-1); + for (const BaseSubobject &BSO : FullPath) { + const CXXRecordDecl *Base = BSO.getBase(); + // The first entry in the path is always the most derived record, skip it. + if (Base == RD) { + assert(Offset.getQuantity() == -1); + Offset = CharUnits::Zero(); + continue; + } + assert(Offset.getQuantity() != -1); + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + // While we know which base has to be traversed, we don't know if that base + // was a virtual base. + const CXXBaseSpecifier *BaseBS = std::find_if( + RD->bases_begin(), RD->bases_end(), [&](const CXXBaseSpecifier &BS) { + return BS.getType()->getAsCXXRecordDecl() == Base; + }); + Offset = BaseBS->isVirtual() ? MostDerivedLayout.getVBaseClassOffset(Base) + : Offset + Layout.getBaseClassOffset(Base); + RD = Base; + } + return Offset; +} + +// We want to select the path which introduces the most covariant overrides. If +// two paths introduce overrides which the other path doesn't contain, issue a +// diagnostic. +static const FullPathTy *selectBestPath(ASTContext &Context, + const CXXRecordDecl *RD, VPtrInfo *Info, + std::list<FullPathTy> &FullPaths) { + // Handle some easy cases first. + if (FullPaths.empty()) + return nullptr; + if (FullPaths.size() == 1) + return &FullPaths.front(); + + const FullPathTy *BestPath = nullptr; + typedef std::set<const CXXMethodDecl *> OverriderSetTy; + OverriderSetTy LastOverrides; + for (const FullPathTy &SpecificPath : FullPaths) { + assert(!SpecificPath.empty()); + OverriderSetTy CurrentOverrides; + const CXXRecordDecl *TopLevelRD = SpecificPath.begin()->getBase(); + // Find the distance from the start of the path to the subobject with the + // VPtr. + CharUnits BaseOffset = + getOffsetOfFullPath(Context, TopLevelRD, SpecificPath); + FinalOverriders Overriders(TopLevelRD, CharUnits::Zero(), TopLevelRD); + for (const CXXMethodDecl *MD : Info->BaseWithVPtr->methods()) { + if (!MD->isVirtual()) + continue; + FinalOverriders::OverriderInfo OI = + Overriders.getOverrider(MD->getCanonicalDecl(), BaseOffset); + const CXXMethodDecl *OverridingMethod = OI.Method; + // Only overriders which have a return adjustment introduce problematic + // thunks. + if (ComputeReturnAdjustmentBaseOffset(Context, OverridingMethod, MD) + .isEmpty()) + continue; + // It's possible that the overrider isn't in this path. If so, skip it + // because this path didn't introduce it. + const CXXRecordDecl *OverridingParent = OverridingMethod->getParent(); + if (std::none_of(SpecificPath.begin(), SpecificPath.end(), + [&](const BaseSubobject &BSO) { + return BSO.getBase() == OverridingParent; + })) + continue; + CurrentOverrides.insert(OverridingMethod); + } + OverriderSetTy NewOverrides = + llvm::set_difference(CurrentOverrides, LastOverrides); + if (NewOverrides.empty()) + continue; + OverriderSetTy MissingOverrides = + llvm::set_difference(LastOverrides, CurrentOverrides); + if (MissingOverrides.empty()) { + // This path is a strict improvement over the last path, let's use it. + BestPath = &SpecificPath; + std::swap(CurrentOverrides, LastOverrides); + } else { + // This path introduces an overrider with a conflicting covariant thunk. + DiagnosticsEngine &Diags = Context.getDiagnostics(); + const CXXMethodDecl *CovariantMD = *NewOverrides.begin(); + const CXXMethodDecl *ConflictMD = *MissingOverrides.begin(); + Diags.Report(RD->getLocation(), diag::err_vftable_ambiguous_component) + << RD; + Diags.Report(CovariantMD->getLocation(), diag::note_covariant_thunk) + << CovariantMD; + Diags.Report(ConflictMD->getLocation(), diag::note_covariant_thunk) + << ConflictMD; + } + } + // Go with the path that introduced the most covariant overrides. If there is + // no such path, pick the first path. + return BestPath ? BestPath : &FullPaths.front(); } 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; + FullPathTy FullPath; + std::list<FullPathTy> FullPaths; for (VPtrInfo *Info : Paths) { - findPathForVPtr(Context, MostDerivedLayout, RD, CharUnits::Zero(), - VBasesSeen, FullPath, Info); - VBasesSeen.clear(); + findPathsToSubobject( + Context, MostDerivedLayout, RD, CharUnits::Zero(), + BaseSubobject(Info->BaseWithVPtr, Info->FullOffsetInMDC), FullPath, + FullPaths); FullPath.clear(); + removeRedundantPaths(FullPaths); + Info->PathToBaseWithVPtr.clear(); + if (const FullPathTy *BestPath = + selectBestPath(Context, RD, Info, FullPaths)) + for (const BaseSubobject &BSO : *BestPath) + Info->PathToBaseWithVPtr.push_back(BSO.getBase()); + FullPaths.clear(); } } diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp index fa7968a805c4..c5f3063fb4f3 100644 --- a/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/lib/ASTMatchers/ASTMatchFinder.cpp @@ -300,7 +300,7 @@ public: const MatchFinder::MatchFinderOptions &Options) : Matchers(Matchers), Options(Options), ActiveASTContext(nullptr) {} - ~MatchASTVisitor() { + ~MatchASTVisitor() override { if (Options.CheckProfiling) { Options.CheckProfiling->Records = std::move(TimeByBucket); } diff --git a/lib/ASTMatchers/CMakeLists.txt b/lib/ASTMatchers/CMakeLists.txt index 8a8e8c36569f..b49528ede227 100644 --- a/lib/ASTMatchers/CMakeLists.txt +++ b/lib/ASTMatchers/CMakeLists.txt @@ -8,4 +8,5 @@ add_clang_library(clangASTMatchers LINK_LIBS clangAST + clangBasic ) diff --git a/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/lib/ASTMatchers/Dynamic/Diagnostics.cpp index b0abdc7cf810..f6d34494dec5 100644 --- a/lib/ASTMatchers/Dynamic/Diagnostics.cpp +++ b/lib/ASTMatchers/Dynamic/Diagnostics.cpp @@ -12,7 +12,6 @@ namespace clang { namespace ast_matchers { namespace dynamic { - Diagnostics::ArgStream Diagnostics::pushContextFrame(ContextType Type, SourceRange Range) { ContextStack.push_back(ContextFrame()); @@ -75,7 +74,7 @@ Diagnostics::ArgStream Diagnostics::addError(const SourceRange &Range, return ArgStream(&Last.Messages.back().Args); } -StringRef contextTypeToFormatString(Diagnostics::ContextType Type) { +static StringRef contextTypeToFormatString(Diagnostics::ContextType Type) { switch (Type) { case Diagnostics::CT_MatcherConstruct: return "Error building matcher $0."; @@ -85,7 +84,7 @@ StringRef contextTypeToFormatString(Diagnostics::ContextType Type) { llvm_unreachable("Unknown ContextType value."); } -StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) { +static StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) { switch (Type) { case Diagnostics::ET_RegistryMatcherNotFound: return "Matcher not found: $0"; @@ -130,8 +129,9 @@ StringRef errorTypeToFormatString(Diagnostics::ErrorType Type) { llvm_unreachable("Unknown ErrorType value."); } -void formatErrorString(StringRef FormatString, ArrayRef<std::string> Args, - llvm::raw_ostream &OS) { +static void formatErrorString(StringRef FormatString, + ArrayRef<std::string> Args, + llvm::raw_ostream &OS) { while (!FormatString.empty()) { std::pair<StringRef, StringRef> Pieces = FormatString.split("$"); OS << Pieces.first.str(); diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h index b78bc0381990..36a6415ae82c 100644 --- a/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/lib/ASTMatchers/Dynamic/Marshallers.h @@ -181,18 +181,20 @@ public: ArgKinds(ArgKinds.begin(), ArgKinds.end()) {} VariantMatcher create(const SourceRange &NameRange, - ArrayRef<ParserValue> Args, Diagnostics *Error) const { + ArrayRef<ParserValue> Args, + Diagnostics *Error) const override { return Marshaller(Func, MatcherName, NameRange, Args, Error); } - bool isVariadic() const { return false; } - unsigned getNumArgs() const { return ArgKinds.size(); } + bool isVariadic() const override { return false; } + unsigned getNumArgs() const override { return ArgKinds.size(); } void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, - std::vector<ArgKind> &Kinds) const { + std::vector<ArgKind> &Kinds) const override { Kinds.push_back(ArgKinds[ArgNo]); } - bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, - ast_type_traits::ASTNodeKind *LeastDerivedKind) const { + bool isConvertibleTo( + ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, + ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { return isRetKindConvertibleTo(RetKinds, Kind, Specificity, LeastDerivedKind); } @@ -333,18 +335,20 @@ public: } VariantMatcher create(const SourceRange &NameRange, - ArrayRef<ParserValue> Args, Diagnostics *Error) const { + ArrayRef<ParserValue> Args, + Diagnostics *Error) const override { return Func(MatcherName, NameRange, Args, Error); } - 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(ArgsKind); } - bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, - ast_type_traits::ASTNodeKind *LeastDerivedKind) const { + bool isConvertibleTo( + ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, + ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { return isRetKindConvertibleTo(RetKinds, Kind, Specificity, LeastDerivedKind); } @@ -487,11 +491,11 @@ public: OverloadedMatcherDescriptor(ArrayRef<MatcherDescriptor *> Callbacks) : Overloads(Callbacks.begin(), Callbacks.end()) {} - virtual ~OverloadedMatcherDescriptor() {} + ~OverloadedMatcherDescriptor() override {} - virtual VariantMatcher create(const SourceRange &NameRange, - ArrayRef<ParserValue> Args, - Diagnostics *Error) const { + VariantMatcher create(const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const override { std::vector<VariantMatcher> Constructed; Diagnostics::OverloadContext Ctx(Error); for (const auto &O : Overloads) { @@ -512,7 +516,7 @@ public: return Constructed[0]; } - bool isVariadic() const { + bool isVariadic() const override { bool Overload0Variadic = Overloads[0]->isVariadic(); #ifndef NDEBUG for (const auto &O : Overloads) { @@ -522,7 +526,7 @@ public: return Overload0Variadic; } - unsigned getNumArgs() const { + unsigned getNumArgs() const override { unsigned Overload0NumArgs = Overloads[0]->getNumArgs(); #ifndef NDEBUG for (const auto &O : Overloads) { @@ -533,15 +537,16 @@ public: } void getArgKinds(ast_type_traits::ASTNodeKind ThisKind, unsigned ArgNo, - std::vector<ArgKind> &Kinds) const { + std::vector<ArgKind> &Kinds) const override { for (const auto &O : Overloads) { if (O->isConvertibleTo(ThisKind)) O->getArgKinds(ThisKind, ArgNo, Kinds); } } - bool isConvertibleTo(ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, - ast_type_traits::ASTNodeKind *LeastDerivedKind) const { + bool isConvertibleTo( + ast_type_traits::ASTNodeKind Kind, unsigned *Specificity, + ast_type_traits::ASTNodeKind *LeastDerivedKind) const override { for (const auto &O : Overloads) { if (O->isConvertibleTo(Kind, Specificity, LeastDerivedKind)) return true; @@ -562,9 +567,9 @@ public: : MinCount(MinCount), MaxCount(MaxCount), Op(Op), MatcherName(MatcherName) {} - virtual VariantMatcher create(const SourceRange &NameRange, - ArrayRef<ParserValue> Args, - Diagnostics *Error) const override { + VariantMatcher create(const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) const override { if (Args.size() < MinCount || MaxCount < Args.size()) { const std::string MaxStr = (MaxCount == UINT_MAX ? "" : Twine(MaxCount)).str(); diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index d550a89cad49..04d3a3256313 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -128,6 +128,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(constructorDecl); REGISTER_MATCHER(containsDeclaration); REGISTER_MATCHER(continueStmt); + REGISTER_MATCHER(conversionDecl); REGISTER_MATCHER(cStyleCastExpr); REGISTER_MATCHER(ctorInitializer); REGISTER_MATCHER(CUDAKernelCallExpr); @@ -198,6 +199,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasIncrement); REGISTER_MATCHER(hasIndex); REGISTER_MATCHER(hasInitializer); + REGISTER_MATCHER(hasKeywordSelector); REGISTER_MATCHER(hasLHS); REGISTER_MATCHER(hasLocalQualifiers); REGISTER_MATCHER(hasLocalStorage); @@ -205,6 +207,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasLoopVariable); REGISTER_MATCHER(hasMethod); REGISTER_MATCHER(hasName); + REGISTER_MATCHER(hasNullSelector); REGISTER_MATCHER(hasObjectExpression); REGISTER_MATCHER(hasOperatorName); REGISTER_MATCHER(hasOverloadedOperatorName); @@ -212,7 +215,9 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasParent); REGISTER_MATCHER(hasQualifier); REGISTER_MATCHER(hasRangeInit); + REGISTER_MATCHER(hasReceiverType); REGISTER_MATCHER(hasRHS); + REGISTER_MATCHER(hasSelector); REGISTER_MATCHER(hasSingleDecl); REGISTER_MATCHER(hasSize); REGISTER_MATCHER(hasSizeExpr); @@ -223,6 +228,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasTrueExpression); REGISTER_MATCHER(hasTypeLoc); REGISTER_MATCHER(hasUnaryOperand); + REGISTER_MATCHER(hasUnarySelector); REGISTER_MATCHER(hasValueType); REGISTER_MATCHER(ifStmt); REGISTER_MATCHER(ignoringImpCasts); @@ -262,6 +268,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(lambdaExpr); REGISTER_MATCHER(lValueReferenceType); REGISTER_MATCHER(matchesName); + REGISTER_MATCHER(matchesSelector); REGISTER_MATCHER(materializeTemporaryExpr); REGISTER_MATCHER(member); REGISTER_MATCHER(memberCallExpr); @@ -276,7 +283,9 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(newExpr); REGISTER_MATCHER(nullPtrLiteralExpr); REGISTER_MATCHER(nullStmt); + REGISTER_MATCHER(numSelectorArgs); REGISTER_MATCHER(ofClass); + REGISTER_MATCHER(objcMessageExpr); REGISTER_MATCHER(on); REGISTER_MATCHER(onImplicitObjectArgument); REGISTER_MATCHER(operatorCallExpr); @@ -315,6 +324,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(throughUsingDecl); REGISTER_MATCHER(throwExpr); REGISTER_MATCHER(to); + REGISTER_MATCHER(translationUnitDecl); REGISTER_MATCHER(tryStmt); REGISTER_MATCHER(type); REGISTER_MATCHER(typedefDecl); diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index be66f32e77be..4e623c8d6c39 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -530,14 +530,14 @@ static DeclVec* LazyInitializeReferencedDecls(const BlockDecl *BD, return BV; } -std::pair<AnalysisDeclContext::referenced_decls_iterator, - AnalysisDeclContext::referenced_decls_iterator> +llvm::iterator_range<AnalysisDeclContext::referenced_decls_iterator> AnalysisDeclContext::getReferencedBlockVars(const BlockDecl *BD) { if (!ReferencedBlockVars) ReferencedBlockVars = new llvm::DenseMap<const BlockDecl*,void*>(); - DeclVec *V = LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A); - return std::make_pair(V->begin(), V->end()); + const DeclVec *V = + LazyInitializeReferencedDecls(BD, (*ReferencedBlockVars)[BD], A); + return llvm::make_range(V->begin(), V->end()); } ManagedAnalysis *&AnalysisDeclContext::getAnalysisImpl(const void *tag) { diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index d9073aa63b16..2744c5fbe72d 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -156,7 +156,7 @@ public: return !(*this == rhs); } - LLVM_EXPLICIT operator bool() const { + explicit operator bool() const { return *this != const_iterator(); } @@ -203,9 +203,9 @@ int LocalScope::const_iterator::distance(LocalScope::const_iterator L) { return D; } -/// BlockScopePosPair - Structure for specifying position in CFG during its -/// build process. It consists of CFGBlock that specifies position in CFG graph -/// and LocalScope::const_iterator that specifies position in LocalScope graph. +/// Structure for specifying position in CFG during its build process. It +/// consists of CFGBlock that specifies position in CFG and +/// LocalScope::const_iterator that specifies position in LocalScope graph. struct BlockScopePosPair { BlockScopePosPair() : block(nullptr) {} BlockScopePosPair(CFGBlock *b, LocalScope::const_iterator scopePos) @@ -841,12 +841,12 @@ private: // must be false. llvm::APSInt IntVal; if (Bop->getLHS()->EvaluateAsInt(IntVal, *Context)) { - if (IntVal.getBoolValue() == false) { + if (!IntVal.getBoolValue()) { return TryResult(false); } } if (Bop->getRHS()->EvaluateAsInt(IntVal, *Context)) { - if (IntVal.getBoolValue() == false) { + if (!IntVal.getBoolValue()) { return TryResult(false); } } @@ -3950,9 +3950,8 @@ public: } } } - - virtual ~StmtPrinterHelper() {} + ~StmtPrinterHelper() override {} const LangOptions &getLangOpts() const { return LangOpts; } void setBlockID(signed i) { currentBlock = i; } diff --git a/lib/Analysis/Consumed.cpp b/lib/Analysis/Consumed.cpp index 2b2da2c69a41..fa985ee02e59 100644 --- a/lib/Analysis/Consumed.cpp +++ b/lib/Analysis/Consumed.cpp @@ -946,10 +946,9 @@ void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) { namespace clang { namespace consumed { -void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test, - ConsumedStateMap *ThenStates, - ConsumedStateMap *ElseStates) { - +static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test, + ConsumedStateMap *ThenStates, + ConsumedStateMap *ElseStates) { ConsumedState VarState = ThenStates->getState(Test.Var); if (VarState == CS_Unknown) { @@ -964,9 +963,9 @@ void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test, } } -void splitVarStateForIfBinOp(const PropagationInfo &PInfo, - ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) { - +static void splitVarStateForIfBinOp(const PropagationInfo &PInfo, + ConsumedStateMap *ThenStates, + ConsumedStateMap *ElseStates) { const VarTestResult <est = PInfo.getLTest(), &RTest = PInfo.getRTest(); @@ -1443,7 +1442,7 @@ void ConsumedAnalyzer::run(AnalysisDeclContext &AC) { CurrStates, WarningsHandler); - if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock)) + if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI)) BlockInfo.discardInfo(*SI); } else { BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken); diff --git a/lib/Analysis/FormatString.cpp b/lib/Analysis/FormatString.cpp index 8c663d856f6a..0948bc0b08a8 100644 --- a/lib/Analysis/FormatString.cpp +++ b/lib/Analysis/FormatString.cpp @@ -256,16 +256,17 @@ clang::analyze_format_string::ParseLengthModifier(FormatSpecifier &FS, // Methods on ArgType. //===----------------------------------------------------------------------===// -bool ArgType::matchesType(ASTContext &C, QualType argTy) const { +clang::analyze_format_string::ArgType::MatchKind +ArgType::matchesType(ASTContext &C, QualType argTy) const { if (Ptr) { // It has to be a pointer. const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) - return false; + return NoMatch; // We cannot write through a const qualified pointer. if (PT->getPointeeType().isConstQualified()) - return false; + return NoMatch; argTy = PT->getPointeeType(); } @@ -275,8 +276,8 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { llvm_unreachable("ArgType must be valid"); case UnknownTy: - return true; - + return Match; + case AnyCharTy: { if (const EnumType *ETy = argTy->getAs<EnumType>()) argTy = ETy->getDecl()->getIntegerType(); @@ -289,18 +290,18 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::SChar: case BuiltinType::UChar: case BuiltinType::Char_U: - return true; + return Match; } - return false; + return NoMatch; } - + case SpecificTy: { if (const EnumType *ETy = argTy->getAs<EnumType>()) argTy = ETy->getDecl()->getIntegerType(); argTy = C.getCanonicalType(argTy).getUnqualifiedType(); if (T == argTy) - return true; + return Match; // Check for "compatible types". if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) switch (BT->getKind()) { @@ -309,32 +310,33 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::Char_S: case BuiltinType::SChar: case BuiltinType::Char_U: - case BuiltinType::UChar: - return T == C.UnsignedCharTy || T == C.SignedCharTy; + case BuiltinType::UChar: + return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match + : NoMatch; case BuiltinType::Short: - return T == C.UnsignedShortTy; + return T == C.UnsignedShortTy ? Match : NoMatch; case BuiltinType::UShort: - return T == C.ShortTy; + return T == C.ShortTy ? Match : NoMatch; case BuiltinType::Int: - return T == C.UnsignedIntTy; + return T == C.UnsignedIntTy ? Match : NoMatch; case BuiltinType::UInt: - return T == C.IntTy; + return T == C.IntTy ? Match : NoMatch; case BuiltinType::Long: - return T == C.UnsignedLongTy; + return T == C.UnsignedLongTy ? Match : NoMatch; case BuiltinType::ULong: - return T == C.LongTy; + return T == C.LongTy ? Match : NoMatch; case BuiltinType::LongLong: - return T == C.UnsignedLongLongTy; + return T == C.UnsignedLongLongTy ? Match : NoMatch; case BuiltinType::ULongLong: - return T == C.LongLongTy; + return T == C.LongLongTy ? Match : NoMatch; } - return false; + return NoMatch; } case CStrTy: { const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) - return false; + return NoMatch; QualType pointeeTy = PT->getPointeeType(); if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>()) switch (BT->getKind()) { @@ -343,50 +345,56 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { case BuiltinType::UChar: case BuiltinType::Char_S: case BuiltinType::SChar: - return true; + return Match; default: break; } - return false; + return NoMatch; } case WCStrTy: { const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) - return false; + return NoMatch; QualType pointeeTy = C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); - return pointeeTy == C.getWideCharType(); + return pointeeTy == C.getWideCharType() ? Match : NoMatch; } - + case WIntTy: { - + QualType PromoArg = argTy->isPromotableIntegerType() ? C.getPromotedIntegerType(argTy) : argTy; - + QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType(); PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType(); - + // If the promoted argument is the corresponding signed type of the // wint_t type, then it should match. if (PromoArg->hasSignedIntegerRepresentation() && C.getCorrespondingUnsignedType(PromoArg) == WInt) - return true; + return Match; - return WInt == PromoArg; + return WInt == PromoArg ? Match : NoMatch; } case CPointerTy: - return argTy->isPointerType() || argTy->isObjCObjectPointerType() || - argTy->isBlockPointerType() || argTy->isNullPtrType(); + if (argTy->isVoidPointerType()) { + return Match; + } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() || + argTy->isBlockPointerType() || argTy->isNullPtrType()) { + return NoMatchPedantic; + } else { + return NoMatch; + } case ObjCPointerTy: { if (argTy->getAs<ObjCObjectPointerType>() || argTy->getAs<BlockPointerType>()) - return true; - + return Match; + // Handle implicit toll-free bridging. if (const PointerType *PT = argTy->getAs<PointerType>()) { // Things such as CFTypeRef are really just opaque pointers @@ -395,9 +403,9 @@ bool ArgType::matchesType(ASTContext &C, QualType argTy) const { // structs can be toll-free bridged, we just accept them all. QualType pointee = PT->getPointeeType(); if (pointee->getAsStructureType() || pointee->isVoidType()) - return true; + return Match; } - return false; + return NoMatch; } } @@ -552,6 +560,12 @@ const char *ConversionSpecifier::toString() const { // Objective-C specific specifiers. case ObjCObjArg: return "@"; + // FreeBSD kernel specific specifiers. + case FreeBSDbArg: return "b"; + case FreeBSDDArg: return "D"; + case FreeBSDrArg: return "r"; + case FreeBSDyArg: return "y"; + // GlibC specific specifiers. case PrintErrno: return "m"; @@ -647,6 +661,9 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { case ConversionSpecifier::XArg: case ConversionSpecifier::nArg: return true; + case ConversionSpecifier::FreeBSDrArg: + case ConversionSpecifier::FreeBSDyArg: + return Target.getTriple().isOSFreeBSD(); default: return false; } @@ -677,6 +694,9 @@ bool FormatSpecifier::hasValidLengthModifier(const TargetInfo &Target) const { case ConversionSpecifier::ScanListArg: case ConversionSpecifier::ZArg: return true; + case ConversionSpecifier::FreeBSDrArg: + case ConversionSpecifier::FreeBSDyArg: + return Target.getTriple().isOSFreeBSD(); default: return false; } @@ -779,7 +799,8 @@ bool FormatSpecifier::hasStandardLengthModifier() const { llvm_unreachable("Invalid LengthModifier Kind!"); } -bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt) const { +bool FormatSpecifier::hasStandardConversionSpecifier( + const LangOptions &LangOpt) const { switch (CS.getKind()) { case ConversionSpecifier::cArg: case ConversionSpecifier::dArg: @@ -807,6 +828,10 @@ bool FormatSpecifier::hasStandardConversionSpecifier(const LangOptions &LangOpt) case ConversionSpecifier::SArg: return LangOpt.ObjC1 || LangOpt.ObjC2; case ConversionSpecifier::InvalidSpecifier: + case ConversionSpecifier::FreeBSDbArg: + case ConversionSpecifier::FreeBSDDArg: + case ConversionSpecifier::FreeBSDrArg: + case ConversionSpecifier::FreeBSDyArg: case ConversionSpecifier::PrintErrno: case ConversionSpecifier::DArg: case ConversionSpecifier::OArg: diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp index 86b679cb155b..0ab158036d84 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -356,11 +356,8 @@ void TransferFunctions::VisitBinaryOperator(BinaryOperator *B) { } void TransferFunctions::VisitBlockExpr(BlockExpr *BE) { - AnalysisDeclContext::referenced_decls_iterator I, E; - std::tie(I, E) = - LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl()); - for ( ; I != E ; ++I) { - const VarDecl *VD = *I; + for (const VarDecl *VD : + LV.analysisContext.getReferencedBlockVars(BE->getBlockDecl())) { if (isAlwaysAlive(VD)) continue; val.liveDecls = LV.DSetFact.add(val.liveDecls, VD); diff --git a/lib/Analysis/PrintfFormatString.cpp b/lib/Analysis/PrintfFormatString.cpp index 146635b88702..b8d3ec18016a 100644 --- a/lib/Analysis/PrintfFormatString.cpp +++ b/lib/Analysis/PrintfFormatString.cpp @@ -55,7 +55,8 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, unsigned &argIndex, const LangOptions &LO, const TargetInfo &Target, - bool Warn) { + bool Warn, + bool isFreeBSDKPrintf) { using namespace clang::analyze_format_string; using namespace clang::analyze_printf; @@ -206,9 +207,24 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, case '@': k = ConversionSpecifier::ObjCObjArg; break; // Glibc specific. case 'm': k = ConversionSpecifier::PrintErrno; break; + // FreeBSD kernel specific. + case 'b': + if (isFreeBSDKPrintf) + k = ConversionSpecifier::FreeBSDbArg; // int followed by char * + break; + case 'r': + if (isFreeBSDKPrintf) + k = ConversionSpecifier::FreeBSDrArg; // int + break; + case 'y': + if (isFreeBSDKPrintf) + k = ConversionSpecifier::FreeBSDyArg; // int + break; // Apple-specific. case 'D': - if (Target.getTriple().isOSDarwin()) + if (isFreeBSDKPrintf) + k = ConversionSpecifier::FreeBSDDArg; // void * followed by char * + else if (Target.getTriple().isOSDarwin()) k = ConversionSpecifier::DArg; break; case 'O': @@ -228,6 +244,10 @@ static PrintfSpecifierResult ParsePrintfSpecifier(FormatStringHandler &H, FS.setConversionSpecifier(CS); if (CS.consumesDataArgument() && !FS.usesPositionalArg()) FS.setArgIndex(argIndex++); + // FreeBSD kernel specific. + if (k == ConversionSpecifier::FreeBSDbArg || + k == ConversionSpecifier::FreeBSDDArg) + argIndex++; if (k == ConversionSpecifier::InvalidSpecifier) { // Assume the conversion takes one argument. @@ -240,14 +260,16 @@ bool clang::analyze_format_string::ParsePrintfString(FormatStringHandler &H, const char *I, const char *E, const LangOptions &LO, - const TargetInfo &Target) { + const TargetInfo &Target, + bool isFreeBSDKPrintf) { unsigned argIndex = 0; // Keep looking for a format specifier until we have exhausted the string. while (I != E) { const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, - LO, Target, true); + LO, Target, true, + isFreeBSDKPrintf); // Did a fail-stop error of any kind occur when parsing the specifier? // If so, don't do any more processing. if (FSR.shouldStop()) @@ -276,7 +298,8 @@ bool clang::analyze_format_string::ParseFormatStringHasSArg(const char *I, FormatStringHandler H; while (I != E) { const PrintfSpecifierResult &FSR = ParsePrintfSpecifier(H, I, E, argIndex, - LO, Target, false); + LO, Target, false, + 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()) @@ -674,6 +697,8 @@ bool PrintfSpecifier::hasValidPlusPrefix() const { case ConversionSpecifier::GArg: case ConversionSpecifier::aArg: case ConversionSpecifier::AArg: + case ConversionSpecifier::FreeBSDrArg: + case ConversionSpecifier::FreeBSDyArg: return true; default: @@ -699,6 +724,8 @@ bool PrintfSpecifier::hasValidAlternativeForm() const { case ConversionSpecifier::FArg: case ConversionSpecifier::gArg: case ConversionSpecifier::GArg: + case ConversionSpecifier::FreeBSDrArg: + case ConversionSpecifier::FreeBSDyArg: return true; default: @@ -729,6 +756,8 @@ bool PrintfSpecifier::hasValidLeadingZeros() const { case ConversionSpecifier::FArg: case ConversionSpecifier::gArg: case ConversionSpecifier::GArg: + case ConversionSpecifier::FreeBSDrArg: + case ConversionSpecifier::FreeBSDyArg: return true; default: @@ -753,6 +782,8 @@ bool PrintfSpecifier::hasValidSpacePrefix() const { case ConversionSpecifier::GArg: case ConversionSpecifier::aArg: case ConversionSpecifier::AArg: + case ConversionSpecifier::FreeBSDrArg: + case ConversionSpecifier::FreeBSDyArg: return true; default: @@ -818,6 +849,8 @@ bool PrintfSpecifier::hasValidPrecision() const { case ConversionSpecifier::gArg: case ConversionSpecifier::GArg: case ConversionSpecifier::sArg: + case ConversionSpecifier::FreeBSDrArg: + case ConversionSpecifier::FreeBSDyArg: return true; default: diff --git a/lib/Analysis/ThreadSafety.cpp b/lib/Analysis/ThreadSafety.cpp index f45d6e7ef139..e2c6ab5d9485 100644 --- a/lib/Analysis/ThreadSafety.cpp +++ b/lib/Analysis/ThreadSafety.cpp @@ -44,14 +44,13 @@ #include <sstream> #include <utility> #include <vector> - - -namespace clang { -namespace threadSafety { +using namespace clang; +using namespace threadSafety; // Key method definition ThreadSafetyHandler::~ThreadSafetyHandler() {} +namespace { class TILPrinter : public til::PrettyPrinter<TILPrinter, llvm::raw_ostream> {}; @@ -69,7 +68,6 @@ static void warnInvalidLock(ThreadSafetyHandler &Handler, Handler.handleInvalidLockExp(Kind, Loc); } - /// \brief A set of CapabilityInfo objects, which are compiled from the /// requires attributes on a function. class CapExprSet : public SmallVector<CapabilityExpr, 4> { @@ -101,17 +99,22 @@ private: LockKind LKind; ///< exclusive or shared SourceLocation AcquireLoc; ///< where it was acquired. bool Asserted; ///< true if the lock was asserted + bool Declared; ///< true if the lock was declared public: FactEntry(const CapabilityExpr &CE, LockKind LK, SourceLocation Loc, - bool Asrt) - : CapabilityExpr(CE), LKind(LK), AcquireLoc(Loc), Asserted(Asrt) {} + bool Asrt, bool Declrd = false) + : CapabilityExpr(CE), LKind(LK), AcquireLoc(Loc), Asserted(Asrt), + Declared(Declrd) {} virtual ~FactEntry() {} - LockKind kind() const { return LKind; } + LockKind kind() const { return LKind; } SourceLocation loc() const { return AcquireLoc; } bool asserted() const { return Asserted; } + bool declared() const { return Declared; } + + void setDeclared(bool D) { Declared = D; } virtual void handleRemovalFromIntersection(const FactSet &FSet, FactManager &FactMan, @@ -231,14 +234,61 @@ public: FactEntry *findPartialMatch(FactManager &FM, const CapabilityExpr &CapE) const { - auto I = std::find_if(begin(), end(), [&](FactID ID) { + auto I = std::find_if(begin(), end(), [&](FactID ID) -> bool { return FM[ID].partiallyMatches(CapE); }); return I != end() ? &FM[*I] : nullptr; } + + bool containsMutexDecl(FactManager &FM, const ValueDecl* Vd) const { + auto I = std::find_if(begin(), end(), [&](FactID ID) -> bool { + return FM[ID].valueDecl() == Vd; + }); + return I != end(); + } }; +class ThreadSafetyAnalyzer; +} // namespace + +namespace clang { +namespace threadSafety { +class BeforeSet { +private: + typedef SmallVector<const ValueDecl*, 4> BeforeVect; + + struct BeforeInfo { + BeforeInfo() : Vect(nullptr), Visited(false) { } + BeforeInfo(BeforeInfo &&O) + : Vect(std::move(O.Vect)), Visited(O.Visited) + {} + + std::unique_ptr<BeforeVect> Vect; + int Visited; + }; + + typedef llvm::DenseMap<const ValueDecl*, BeforeInfo> BeforeMap; + typedef llvm::DenseMap<const ValueDecl*, bool> CycleMap; + +public: + BeforeSet() { } + + BeforeInfo* insertAttrExprs(const ValueDecl* Vd, + ThreadSafetyAnalyzer& Analyzer); + + void checkBeforeAfter(const ValueDecl* Vd, + const FactSet& FSet, + ThreadSafetyAnalyzer& Analyzer, + SourceLocation Loc, StringRef CapKind); + +private: + BeforeMap BMap; + CycleMap CycMap; +}; +} // end namespace threadSafety +} // end namespace clang +namespace { typedef llvm::ImmutableMap<const NamedDecl*, unsigned> LocalVarContext; class LocalVariableMap; @@ -853,6 +903,7 @@ public: /// \brief Class which implements the core thread safety analysis routines. class ThreadSafetyAnalyzer { friend class BuildLockset; + friend class threadSafety::BeforeSet; llvm::BumpPtrAllocator Bpa; threadSafety::til::MemRegionRef Arena; @@ -864,9 +915,11 @@ class ThreadSafetyAnalyzer { FactManager FactMan; std::vector<CFGBlockInfo> BlockInfo; + BeforeSet* GlobalBeforeSet; + public: - ThreadSafetyAnalyzer(ThreadSafetyHandler &H) - : Arena(&Bpa), SxBuilder(Arena), Handler(H) {} + ThreadSafetyAnalyzer(ThreadSafetyHandler &H, BeforeSet* Bset) + : Arena(&Bpa), SxBuilder(Arena), Handler(H), GlobalBeforeSet(Bset) {} bool inCurrentScope(const CapabilityExpr &CapE); @@ -906,6 +959,134 @@ public: void runAnalysis(AnalysisDeclContext &AC); }; +} // namespace + +/// Process acquired_before and acquired_after attributes on Vd. +BeforeSet::BeforeInfo* BeforeSet::insertAttrExprs(const ValueDecl* Vd, + ThreadSafetyAnalyzer& Analyzer) { + // Create a new entry for Vd. + auto& Entry = BMap.FindAndConstruct(Vd); + BeforeInfo* Info = &Entry.second; + BeforeVect* Bv = nullptr; + + for (Attr* At : Vd->attrs()) { + switch (At->getKind()) { + case attr::AcquiredBefore: { + auto *A = cast<AcquiredBeforeAttr>(At); + + // Create a new BeforeVect for Vd if necessary. + if (!Bv) { + Bv = new BeforeVect; + Info->Vect.reset(Bv); + } + // Read exprs from the attribute, and add them to BeforeVect. + for (const auto *Arg : A->args()) { + CapabilityExpr Cp = + Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr); + if (const ValueDecl *Cpvd = Cp.valueDecl()) { + Bv->push_back(Cpvd); + auto It = BMap.find(Cpvd); + if (It == BMap.end()) + insertAttrExprs(Cpvd, Analyzer); + } + } + break; + } + case attr::AcquiredAfter: { + auto *A = cast<AcquiredAfterAttr>(At); + + // Read exprs from the attribute, and add them to BeforeVect. + for (const auto *Arg : A->args()) { + CapabilityExpr Cp = + Analyzer.SxBuilder.translateAttrExpr(Arg, nullptr); + if (const ValueDecl *ArgVd = Cp.valueDecl()) { + // Get entry for mutex listed in attribute + BeforeInfo* ArgInfo; + auto It = BMap.find(ArgVd); + if (It == BMap.end()) + ArgInfo = insertAttrExprs(ArgVd, Analyzer); + else + ArgInfo = &It->second; + + // Create a new BeforeVect if necessary. + BeforeVect* ArgBv = ArgInfo->Vect.get(); + if (!ArgBv) { + ArgBv = new BeforeVect; + ArgInfo->Vect.reset(ArgBv); + } + ArgBv->push_back(Vd); + } + } + break; + } + default: + break; + } + } + + return Info; +} + + +/// Return true if any mutexes in FSet are in the acquired_before set of Vd. +void BeforeSet::checkBeforeAfter(const ValueDecl* StartVd, + const FactSet& FSet, + ThreadSafetyAnalyzer& Analyzer, + SourceLocation Loc, StringRef CapKind) { + SmallVector<BeforeInfo*, 8> InfoVect; + + // Do a depth-first traversal of Vd. + // Return true if there are cycles. + std::function<bool (const ValueDecl*)> traverse = [&](const ValueDecl* Vd) { + if (!Vd) + return false; + + BeforeSet::BeforeInfo* Info; + auto It = BMap.find(Vd); + if (It == BMap.end()) + Info = insertAttrExprs(Vd, Analyzer); + else + Info = &It->second; + + if (Info->Visited == 1) + return true; + + if (Info->Visited == 2) + return false; + + BeforeVect* Bv = Info->Vect.get(); + if (!Bv) + return false; + + InfoVect.push_back(Info); + Info->Visited = 1; + for (auto *Vdb : *Bv) { + // Exclude mutexes in our immediate before set. + if (FSet.containsMutexDecl(Analyzer.FactMan, Vdb)) { + StringRef L1 = StartVd->getName(); + StringRef L2 = Vdb->getName(); + Analyzer.Handler.handleLockAcquiredBefore(CapKind, L1, L2, Loc); + } + // Transitively search other before sets, and warn on cycles. + if (traverse(Vdb)) { + if (CycMap.find(Vd) == CycMap.end()) { + CycMap.insert(std::make_pair(Vd, true)); + StringRef L1 = Vd->getName(); + Analyzer.Handler.handleBeforeAfterCycle(L1, Vd->getLocation()); + } + } + } + Info->Visited = 2; + return false; + }; + + traverse(StartVd); + + for (auto* Info : InfoVect) + Info->Visited = 0; +} + + /// \brief Gets the value decl pointer from DeclRefExprs or MemberExprs. static const ValueDecl *getValueDecl(const Expr *Exp) { @@ -921,6 +1102,7 @@ static const ValueDecl *getValueDecl(const Expr *Exp) { return nullptr; } +namespace { template <typename Ty> class has_arg_iterator_range { typedef char yes[1]; @@ -935,6 +1117,7 @@ class has_arg_iterator_range { public: static const bool value = sizeof(test<Ty>(nullptr)) == sizeof(yes); }; +} // namespace static StringRef ClassifyDiagnostic(const CapabilityAttr *A) { return A->getName(); @@ -1020,7 +1203,13 @@ void ThreadSafetyAnalyzer::addLock(FactSet &FSet, } } - // FIXME: deal with acquired before/after annotations. + // Check before/after constraints + if (Handler.issueBetaWarnings() && + !Entry->asserted() && !Entry->declared()) { + GlobalBeforeSet->checkBeforeAfter(Entry->valueDecl(), FSet, *this, + Entry->loc(), DiagKind); + } + // FIXME: Don't always warn when we have support for reentrant locks. if (FSet.findLock(FactMan, *Entry)) { if (!Entry->asserted()) @@ -1119,8 +1308,7 @@ void ThreadSafetyAnalyzer::getMutexIDs(CapExprSet &Mtxs, AttrType *Attr, } } - -bool getStaticBooleanValue(Expr* E, bool& TCond) { +static bool getStaticBooleanValue(Expr *E, bool &TCond) { if (isa<CXXNullPtrLiteralExpr>(E) || isa<GNUNullExpr>(E)) { TCond = false; return true; @@ -1230,7 +1418,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result, CapExprSet SharedLocksToAdd; // If the condition is a call to a Trylock function, then grab the attributes - for (auto *Attr : FunDecl->getAttrs()) { + for (auto *Attr : FunDecl->attrs()) { switch (Attr->getKind()) { case attr::ExclusiveTrylockFunction: { ExclusiveTrylockFunctionAttr *A = @@ -1265,6 +1453,7 @@ void ThreadSafetyAnalyzer::getEdgeLockset(FactSet& Result, CapDiagKind); } +namespace { /// \brief We use this class to visit different types of expressions in /// CFGBlocks, and build up the lockset. /// An expression may cause us to add or remove locks from the lockset, or else @@ -1308,7 +1497,7 @@ public: void VisitCXXConstructExpr(CXXConstructExpr *Exp); void VisitDeclStmt(DeclStmt *S); }; - +} // namespace /// \brief Warn if the LSet does not contain a lock sufficient to protect access /// of at least the passed in AccessKind. @@ -1500,13 +1689,23 @@ void BuildLockset::checkPtAccess(const Expr *Exp, AccessKind AK, /// void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { SourceLocation Loc = Exp->getExprLoc(); - const AttrVec &ArgAttrs = D->getAttrs(); CapExprSet ExclusiveLocksToAdd, SharedLocksToAdd; CapExprSet ExclusiveLocksToRemove, SharedLocksToRemove, GenericLocksToRemove; + CapExprSet ScopedExclusiveReqs, ScopedSharedReqs; StringRef CapDiagKind = "mutex"; - for(unsigned i = 0; i < ArgAttrs.size(); ++i) { - Attr *At = const_cast<Attr*>(ArgAttrs[i]); + // Figure out if we're calling the constructor of scoped lockable class + bool isScopedVar = false; + if (VD) { + if (const CXXConstructorDecl *CD = dyn_cast<const CXXConstructorDecl>(D)) { + const CXXRecordDecl* PD = CD->getParent(); + if (PD && PD->hasAttr<ScopedLockableAttr>()) + isScopedVar = true; + } + } + + for(Attr *Atconst : D->attrs()) { + Attr* At = const_cast<Attr*>(Atconst); switch (At->getKind()) { // When we encounter a lock function, we need to add the lock to our // lockset. @@ -1564,10 +1763,17 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { case attr::RequiresCapability: { RequiresCapabilityAttr *A = cast<RequiresCapabilityAttr>(At); - for (auto *Arg : A->args()) + for (auto *Arg : A->args()) { warnIfMutexNotHeld(D, Exp, A->isShared() ? AK_Read : AK_Written, Arg, POK_FunctionCall, ClassifyDiagnostic(A), Exp->getExprLoc()); + // use for adopting a lock + if (isScopedVar) { + Analyzer->getMutexIDs(A->isShared() ? ScopedSharedReqs + : ScopedExclusiveReqs, + A, Exp, D, VD); + } + } break; } @@ -1584,16 +1790,6 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { } } - // Figure out if we're calling the constructor of scoped lockable class - bool isScopedVar = false; - if (VD) { - if (const CXXConstructorDecl *CD = dyn_cast<const CXXConstructorDecl>(D)) { - const CXXRecordDecl* PD = CD->getParent(); - if (PD && PD->hasAttr<ScopedLockableAttr>()) - isScopedVar = true; - } - } - // Add locks. for (const auto &M : ExclusiveLocksToAdd) Analyzer->addLock(FSet, llvm::make_unique<LockableFactEntry>( @@ -1611,9 +1807,10 @@ void BuildLockset::handleCall(Expr *Exp, const NamedDecl *D, VarDecl *VD) { // FIXME: does this store a pointer to DRE? CapabilityExpr Scp = Analyzer->SxBuilder.translateAttrExpr(&DRE, nullptr); - CapExprSet UnderlyingMutexes(ExclusiveLocksToAdd); - std::copy(SharedLocksToAdd.begin(), SharedLocksToAdd.end(), - std::back_inserter(UnderlyingMutexes)); + std::copy(ScopedExclusiveReqs.begin(), ScopedExclusiveReqs.end(), + std::back_inserter(ExclusiveLocksToAdd)); + std::copy(ScopedSharedReqs.begin(), ScopedSharedReqs.end(), + std::back_inserter(SharedLocksToAdd)); Analyzer->addLock(FSet, llvm::make_unique<ScopedLockableFactEntry>( Scp, MLoc, ExclusiveLocksToAdd, SharedLocksToAdd), @@ -1863,7 +2060,7 @@ void ThreadSafetyAnalyzer::intersectAndWarn(FactSet &FSet1, // Return true if block B never continues to its successors. -inline bool neverReturns(const CFGBlock* B) { +static bool neverReturns(const CFGBlock *B) { if (B->hasNoReturnElement()) return true; if (B->empty()) @@ -1940,14 +2137,13 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { if (!SortedGraph->empty() && D->hasAttrs()) { const CFGBlock *FirstBlock = *SortedGraph->begin(); FactSet &InitialLockset = BlockInfo[FirstBlock->getBlockID()].EntrySet; - const AttrVec &ArgAttrs = D->getAttrs(); CapExprSet ExclusiveLocksToAdd; CapExprSet SharedLocksToAdd; StringRef CapDiagKind = "mutex"; SourceLocation Loc = D->getLocation(); - for (const auto *Attr : ArgAttrs) { + for (const auto *Attr : D->attrs()) { Loc = Attr->getLocation(); if (const auto *A = dyn_cast<RequiresCapabilityAttr>(Attr)) { getMutexIDs(A->isShared() ? SharedLocksToAdd : ExclusiveLocksToAdd, A, @@ -1979,14 +2175,16 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { } // FIXME -- Loc can be wrong here. - for (const auto &Mu : ExclusiveLocksToAdd) - addLock(InitialLockset, - llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc), - CapDiagKind, true); - for (const auto &Mu : SharedLocksToAdd) - addLock(InitialLockset, - llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc), - CapDiagKind, true); + for (const auto &Mu : ExclusiveLocksToAdd) { + auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Exclusive, Loc); + Entry->setDeclared(true); + addLock(InitialLockset, std::move(Entry), CapDiagKind, true); + } + for (const auto &Mu : SharedLocksToAdd) { + auto Entry = llvm::make_unique<LockableFactEntry>(Mu, LK_Shared, Loc); + Entry->setDeclared(true); + addLock(InitialLockset, std::move(Entry), CapDiagKind, true); + } } for (const auto *CurrBlock : *SortedGraph) { @@ -2179,15 +2377,20 @@ void ThreadSafetyAnalyzer::runAnalysis(AnalysisDeclContext &AC) { /// We traverse the blocks in the CFG, compute the set of mutexes that are held /// at the end of each block, and issue warnings for thread safety violations. /// Each block in the CFG is traversed exactly once. -void runThreadSafetyAnalysis(AnalysisDeclContext &AC, - ThreadSafetyHandler &Handler) { - ThreadSafetyAnalyzer Analyzer(Handler); +void threadSafety::runThreadSafetyAnalysis(AnalysisDeclContext &AC, + ThreadSafetyHandler &Handler, + BeforeSet **BSet) { + if (!*BSet) + *BSet = new BeforeSet; + ThreadSafetyAnalyzer Analyzer(Handler, *BSet); Analyzer.runAnalysis(AC); } +void threadSafety::threadSafetyCleanup(BeforeSet *Cache) { delete Cache; } + /// \brief Helper function that returns a LockKind required for the given level /// of access. -LockKind getLockKindFromAccessKind(AccessKind AK) { +LockKind threadSafety::getLockKindFromAccessKind(AccessKind AK) { switch (AK) { case AK_Read : return LK_Shared; @@ -2196,5 +2399,3 @@ LockKind getLockKindFromAccessKind(AccessKind AK) { } llvm_unreachable("Unknown AccessKind"); } - -}} // end namespace clang::threadSafety diff --git a/lib/Analysis/ThreadSafetyCommon.cpp b/lib/Analysis/ThreadSafetyCommon.cpp index 563e0590aacb..d4b1ce26d4b3 100644 --- a/lib/Analysis/ThreadSafetyCommon.cpp +++ b/lib/Analysis/ThreadSafetyCommon.cpp @@ -31,13 +31,11 @@ #include <algorithm> #include <climits> #include <vector> - - -namespace clang { -namespace threadSafety { +using namespace clang; +using namespace threadSafety; // From ThreadSafetyUtil.h -std::string getSourceLiteralString(const clang::Expr *CE) { +std::string threadSafety::getSourceLiteralString(const clang::Expr *CE) { switch (CE->getStmtClass()) { case Stmt::IntegerLiteralClass: return cast<IntegerLiteral>(CE)->getValue().toString(10, true); @@ -59,18 +57,13 @@ std::string getSourceLiteralString(const clang::Expr *CE) { } } -namespace til { - // Return true if E is a variable that points to an incomplete Phi node. -static bool isIncompletePhi(const SExpr *E) { - if (const auto *Ph = dyn_cast<Phi>(E)) - return Ph->status() == Phi::PH_Incomplete; +static bool isIncompletePhi(const til::SExpr *E) { + if (const auto *Ph = dyn_cast<til::Phi>(E)) + return Ph->status() == til::Phi::PH_Incomplete; return false; } -} // end namespace til - - typedef SExprBuilder::CallingContext CallingContext; @@ -87,9 +80,7 @@ til::SCFG *SExprBuilder::buildCFG(CFGWalker &Walker) { return Scfg; } - - -inline bool isCalleeArrow(const Expr *E) { +static bool isCalleeArrow(const Expr *E) { const MemberExpr *ME = dyn_cast<MemberExpr>(E->IgnoreParenCasts()); return ME ? ME->isArrow() : false; } @@ -313,8 +304,7 @@ til::SExpr *SExprBuilder::translateCXXThisExpr(const CXXThisExpr *TE, return SelfVar; } - -const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) { +static const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) { if (auto *V = dyn_cast<til::Variable>(E)) return V->clangDecl(); if (auto *Ph = dyn_cast<til::Phi>(E)) @@ -326,7 +316,7 @@ const ValueDecl *getValueDeclFromSExpr(const til::SExpr *E) { return 0; } -bool hasCppPointerType(const til::SExpr *E) { +static bool hasCppPointerType(const til::SExpr *E) { auto *VD = getValueDeclFromSExpr(E); if (VD && VD->getType()->isPointerType()) return true; @@ -336,9 +326,8 @@ bool hasCppPointerType(const til::SExpr *E) { return false; } - // Grab the very first declaration of virtual method D -const CXXMethodDecl* getFirstVirtualDecl(const CXXMethodDecl *D) { +static const CXXMethodDecl *getFirstVirtualDecl(const CXXMethodDecl *D) { while (true) { D = D->getCanonicalDecl(); CXXMethodDecl::method_iterator I = D->begin_overridden_methods(), @@ -663,7 +652,7 @@ til::SExpr *SExprBuilder::lookupVarDecl(const ValueDecl *VD) { // if E is a til::Variable, update its clangDecl. -inline void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) { +static void maybeUpdateVD(til::SExpr *E, const ValueDecl *VD) { if (!E) return; if (til::Variable *V = dyn_cast<til::Variable>(E)) { @@ -986,8 +975,3 @@ void printSCFG(CFGWalker &Walker) { TILPrinter::print(Scfg, llvm::errs()); } */ - - -} // end namespace threadSafety - -} // end namespace clang diff --git a/lib/Analysis/ThreadSafetyTIL.cpp b/lib/Analysis/ThreadSafetyTIL.cpp index ebe374ea609d..2923f7e66a61 100644 --- a/lib/Analysis/ThreadSafetyTIL.cpp +++ b/lib/Analysis/ThreadSafetyTIL.cpp @@ -9,13 +9,11 @@ #include "clang/Analysis/Analyses/ThreadSafetyTIL.h" #include "clang/Analysis/Analyses/ThreadSafetyTraverse.h" +using namespace clang; +using namespace threadSafety; +using namespace til; -namespace clang { -namespace threadSafety { -namespace til { - - -StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op) { +StringRef til::getUnaryOpcodeString(TIL_UnaryOpcode Op) { switch (Op) { case UOP_Minus: return "-"; case UOP_BitNot: return "~"; @@ -24,8 +22,7 @@ StringRef getUnaryOpcodeString(TIL_UnaryOpcode Op) { return ""; } - -StringRef getBinaryOpcodeString(TIL_BinaryOpcode Op) { +StringRef til::getBinaryOpcodeString(TIL_BinaryOpcode Op) { switch (Op) { case BOP_Mul: return "*"; case BOP_Div: return "/"; @@ -82,7 +79,7 @@ void BasicBlock::reservePredecessors(unsigned NumPreds) { // If E is a variable, then trace back through any aliases or redundant // Phi nodes to find the canonical definition. -const SExpr *getCanonicalVal(const SExpr *E) { +const SExpr *til::getCanonicalVal(const SExpr *E) { while (true) { if (auto *V = dyn_cast<Variable>(E)) { if (V->kind() == Variable::VK_Let) { @@ -105,7 +102,7 @@ const SExpr *getCanonicalVal(const SExpr *E) { // If E is a variable, then trace back through any aliases or redundant // Phi nodes to find the canonical definition. // The non-const version will simplify incomplete Phi nodes. -SExpr *simplifyToCanonicalVal(SExpr *E) { +SExpr *til::simplifyToCanonicalVal(SExpr *E) { while (true) { if (auto *V = dyn_cast<Variable>(E)) { if (V->kind() != Variable::VK_Let) @@ -135,7 +132,7 @@ SExpr *simplifyToCanonicalVal(SExpr *E) { // Trace the arguments of an incomplete Phi node to see if they have the same // canonical definition. If so, mark the Phi node as redundant. // getCanonicalVal() will recursively call simplifyIncompletePhi(). -void simplifyIncompleteArg(til::Phi *Ph) { +void til::simplifyIncompleteArg(til::Phi *Ph) { assert(Ph && Ph->status() == Phi::PH_Incomplete); // eliminate infinite recursion -- assume that this node is not redundant. @@ -337,7 +334,3 @@ void SCFG::computeNormalForm() { computeNodeID(Block, &BasicBlock::PostDominatorNode); } } - -} // end namespace til -} // end namespace threadSafety -} // end namespace clang diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index 61a259217d7d..f2f791957aa3 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -14,6 +14,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/Analyses/UninitializedValues.h" @@ -35,9 +36,9 @@ using namespace clang; static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) { if (vd->isLocalVarDecl() && !vd->hasGlobalStorage() && !vd->isExceptionVariable() && !vd->isInitCapture() && - vd->getDeclContext() == dc) { + !vd->isImplicit() && vd->getDeclContext() == dc) { QualType ty = vd->getType(); - return ty->isScalarType() || ty->isVectorType(); + return ty->isScalarType() || ty->isVectorType() || ty->isRecordType(); } return false; } @@ -347,6 +348,7 @@ public: } static const DeclRefExpr *getSelfInitExpr(VarDecl *VD) { + if (VD->getType()->isRecordType()) return nullptr; if (Expr *Init = VD->getInit()) { const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(stripCasts(VD->getASTContext(), Init)); @@ -376,10 +378,26 @@ void ClassifyRefs::classify(const Expr *E, Class C) { return; } + if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + if (VarDecl *VD = dyn_cast<VarDecl>(ME->getMemberDecl())) { + if (!VD->isStaticDataMember()) + classify(ME->getBase(), C); + } + return; + } + if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { - if (BO->getOpcode() == BO_Comma) + switch (BO->getOpcode()) { + case BO_PtrMemD: + case BO_PtrMemI: + classify(BO->getLHS(), C); + return; + case BO_Comma: classify(BO->getRHS(), C); - return; + return; + default: + return; + } } FindVarResult Var = findVar(E, DC); @@ -404,7 +422,7 @@ void ClassifyRefs::VisitBinaryOperator(BinaryOperator *BO) { // use. if (BO->isCompoundAssignmentOp()) classify(BO->getLHS(), Use); - else if (BO->getOpcode() == BO_Assign) + else if (BO->getOpcode() == BO_Assign || BO->getOpcode() == BO_Comma) classify(BO->getLHS(), Ignore); } @@ -415,25 +433,40 @@ void ClassifyRefs::VisitUnaryOperator(UnaryOperator *UO) { classify(UO->getSubExpr(), Use); } +static bool isPointerToConst(const QualType &QT) { + return QT->isAnyPointerType() && QT->getPointeeType().isConstQualified(); +} + void ClassifyRefs::VisitCallExpr(CallExpr *CE) { // Classify arguments to std::move as used. if (CE->getNumArgs() == 1) { if (FunctionDecl *FD = CE->getDirectCallee()) { if (FD->isInStdNamespace() && FD->getIdentifier() && FD->getIdentifier()->isStr("move")) { - classify(CE->getArg(0), Use); + // RecordTypes are handled in SemaDeclCXX.cpp. + if (!CE->getArg(0)->getType()->isRecordType()) + classify(CE->getArg(0), Use); return; } } } - // If a value is passed by const reference to a function, we should not assume - // that it is initialized by the call, and we conservatively do not assume - // that it is used. + // If a value is passed by const pointer or by const reference to a function, + // we should not assume that it is initialized by the call, and we + // conservatively do not assume that it is used. for (CallExpr::arg_iterator I = CE->arg_begin(), E = CE->arg_end(); - I != E; ++I) - if ((*I)->getType().isConstQualified() && (*I)->isGLValue()) - classify(*I, Ignore); + I != E; ++I) { + if ((*I)->isGLValue()) { + if ((*I)->getType().isConstQualified()) + classify((*I), Ignore); + } else if (isPointerToConst((*I)->getType())) { + const Expr *Ex = stripCasts(DC->getParentASTContext(), *I); + const UnaryOperator *UO = dyn_cast<UnaryOperator>(Ex); + if (UO && UO->getOpcode() == UO_AddrOf) + Ex = UO->getSubExpr(); + classify(Ex, Ignore); + } + } } void ClassifyRefs::VisitCastExpr(CastExpr *CE) { @@ -804,7 +837,7 @@ struct PruneBlocksHandler : public UninitVariablesHandler { : hadUse(numBlocks, false), hadAnyUse(false), currentBlock(0) {} - virtual ~PruneBlocksHandler() {} + ~PruneBlocksHandler() override {} /// Records if a CFGBlock had a potential use of an uninitialized variable. llvm::BitVector hadUse; diff --git a/lib/Basic/Diagnostic.cpp b/lib/Basic/Diagnostic.cpp index 83228ad3c55d..631b97899bd5 100644 --- a/lib/Basic/Diagnostic.cpp +++ b/lib/Basic/Diagnostic.cpp @@ -633,7 +633,8 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, // When the diagnostic string is only "%0", the entire string is being given // by an outside source. Remove unprintable characters from this string // and skip all the other string processing. - if (DiagEnd - DiagStr == 2 && DiagStr[0] == '%' && DiagStr[1] == '0' && + if (DiagEnd - DiagStr == 2 && + StringRef(DiagStr, DiagEnd - DiagStr).equals("%0") && getArgKind(0) == DiagnosticsEngine::ak_std_string) { const std::string &S = getArgStdStr(0); for (char c : S) { @@ -948,14 +949,8 @@ StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, SmallString<64> Message; Info.FormatDiagnostic(Message); this->Message.assign(Message.begin(), Message.end()); - - Ranges.reserve(Info.getNumRanges()); - for (unsigned I = 0, N = Info.getNumRanges(); I != N; ++I) - Ranges.push_back(Info.getRange(I)); - - FixIts.reserve(Info.getNumFixItHints()); - for (unsigned I = 0, N = Info.getNumFixItHints(); I != N; ++I) - FixIts.push_back(Info.getFixItHint(I)); + this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end()); + this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end()); } StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID, diff --git a/lib/Basic/DiagnosticIDs.cpp b/lib/Basic/DiagnosticIDs.cpp index 1c68375f3cdd..643503b00b91 100644 --- a/lib/Basic/DiagnosticIDs.cpp +++ b/lib/Basic/DiagnosticIDs.cpp @@ -528,7 +528,7 @@ static bool getDiagnosticsInGroup(diag::Flavor Flavor, // An empty group is considered to be a warning group: we have empty groups // for GCC compatibility, and GCC does not have remarks. if (!Group->Members && !Group->SubGroups) - return Flavor == diag::Flavor::Remark ? true : false; + return Flavor == diag::Flavor::Remark; bool NotFound = true; diff --git a/lib/Basic/FileManager.cpp b/lib/Basic/FileManager.cpp index 214e0f35a52e..c46e2c7db380 100644 --- a/lib/Basic/FileManager.cpp +++ b/lib/Basic/FileManager.cpp @@ -430,7 +430,7 @@ FileManager::getBufferForFile(const FileEntry *Entry, bool isVolatile, SmallString<128> FilePath(Entry->getName()); FixupRelativePath(FilePath); - return FS->getBufferForFile(FilePath.str(), FileSize, + return FS->getBufferForFile(FilePath, FileSize, /*RequiresNullTerminator=*/true, isVolatile); } diff --git a/lib/Basic/IdentifierTable.cpp b/lib/Basic/IdentifierTable.cpp index 613b43fce95f..e830be9603e6 100644 --- a/lib/Basic/IdentifierTable.cpp +++ b/lib/Basic/IdentifierTable.cpp @@ -35,7 +35,7 @@ IdentifierInfo::IdentifierInfo() { HasMacro = false; HadMacro = false; IsExtension = false; - IsCXX11CompatKeyword = false; + IsFutureCompatKeyword = false; IsPoisoned = false; IsCPPOperatorKeyword = false; NeedsHandleIdentifier = false; @@ -105,10 +105,12 @@ namespace { KEYOPENCL = 0x200, KEYC11 = 0x400, KEYARC = 0x800, - KEYNOMS = 0x01000, - WCHARSUPPORT = 0x02000, - HALFSUPPORT = 0x04000, - KEYALL = (0xffff & ~KEYNOMS) // Because KEYNOMS is used to exclude. + KEYNOMS18 = 0x01000, + KEYNOOPENCL = 0x02000, + WCHARSUPPORT = 0x04000, + HALFSUPPORT = 0x08000, + KEYALL = (0xffff & ~KEYNOMS18 & + ~KEYNOOPENCL) // KEYNOMS18 and KEYNOOPENCL are used to exclude. }; /// \brief How a keyword is treated in the selected standard. @@ -154,15 +156,21 @@ static void AddKeyword(StringRef Keyword, KeywordStatus AddResult = getKeywordStatus(LangOpts, Flags); // Don't add this keyword under MSVCCompat. - if (LangOpts.MSVCCompat && (Flags & KEYNOMS)) - return; + if (LangOpts.MSVCCompat && (Flags & KEYNOMS18) && + !LangOpts.isCompatibleWithMSVC(LangOptions::MSVC2015)) + return; + + // Don't add this keyword under OpenCL. + if (LangOpts.OpenCL && (Flags & KEYNOOPENCL)) + return; + // Don't add this keyword if disabled in this language. if (AddResult == KS_Disabled) return; IdentifierInfo &Info = Table.get(Keyword, AddResult == KS_Future ? tok::identifier : TokenCode); Info.setIsExtensionToken(AddResult == KS_Extension); - Info.setIsCXX11CompatKeyword(AddResult == KS_Future); + Info.setIsFutureCompatKeyword(AddResult == KS_Future); } /// AddCXXOperatorKeyword - Register a C++ operator keyword alternative @@ -207,6 +215,12 @@ void IdentifierTable::AddKeywords(const LangOptions &LangOpts) { if (LangOpts.ParseUnknownAnytype) AddKeyword("__unknown_anytype", tok::kw___unknown_anytype, KEYALL, LangOpts, *this); + + // FIXME: __declspec isn't really a CUDA extension, however it is required for + // supporting cuda_builtin_vars.h, which uses __declspec(property). Once that + // has been rewritten in terms of something more generic, remove this code. + if (LangOpts.CUDA) + AddKeyword("__declspec", tok::kw___declspec, KEYALL, LangOpts, *this); } /// \brief Checks if the specified token kind represents a keyword in the diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp index dcbd22817111..2c87845b7b0e 100644 --- a/lib/Basic/LangOptions.cpp +++ b/lib/Basic/LangOptions.cpp @@ -30,7 +30,7 @@ void LangOptions::resetNonModularOptions() { // FIXME: This should not be reset; modules can be different with different // sanitizer options (this affects __has_feature(address_sanitizer) etc). Sanitize.clear(); - SanitizerBlacklistFile.clear(); + SanitizerBlacklistFiles.clear(); CurrentModule.clear(); ImplementationOfModule.clear(); diff --git a/lib/Basic/Module.cpp b/lib/Basic/Module.cpp index 03f9bd3f329c..7308665bd2d8 100644 --- a/lib/Basic/Module.cpp +++ b/lib/Basic/Module.cpp @@ -25,14 +25,14 @@ using namespace clang; Module::Module(StringRef Name, SourceLocation DefinitionLoc, Module *Parent, - bool IsFramework, bool IsExplicit) + bool IsFramework, bool IsExplicit, unsigned VisibilityID) : Name(Name), DefinitionLoc(DefinitionLoc), Parent(Parent), Directory(), - Umbrella(), ASTFile(nullptr), IsMissingRequirement(false), - IsAvailable(true), IsFromModuleFile(false), IsFramework(IsFramework), - IsExplicit(IsExplicit), IsSystem(false), IsExternC(false), - IsInferred(false), InferSubmodules(false), InferExplicitSubmodules(false), - InferExportWildcard(false), ConfigMacrosExhaustive(false), - NameVisibility(Hidden) { + Umbrella(), ASTFile(nullptr), VisibilityID(VisibilityID), + IsMissingRequirement(false), IsAvailable(true), IsFromModuleFile(false), + IsFramework(IsFramework), IsExplicit(IsExplicit), IsSystem(false), + IsExternC(false), IsInferred(false), InferSubmodules(false), + InferExplicitSubmodules(false), InferExportWildcard(false), + ConfigMacrosExhaustive(false), NameVisibility(Hidden) { if (Parent) { if (!Parent->isAvailable()) IsAvailable = false; @@ -58,16 +58,21 @@ Module::~Module() { /// language options has the given feature. static bool hasFeature(StringRef Feature, const LangOptions &LangOpts, const TargetInfo &Target) { - return llvm::StringSwitch<bool>(Feature) - .Case("altivec", LangOpts.AltiVec) - .Case("blocks", LangOpts.Blocks) - .Case("cplusplus", LangOpts.CPlusPlus) - .Case("cplusplus11", LangOpts.CPlusPlus11) - .Case("objc", LangOpts.ObjC1) - .Case("objc_arc", LangOpts.ObjCAutoRefCount) - .Case("opencl", LangOpts.OpenCL) - .Case("tls", Target.isTLSSupported()) - .Default(Target.hasFeature(Feature)); + bool HasFeature = llvm::StringSwitch<bool>(Feature) + .Case("altivec", LangOpts.AltiVec) + .Case("blocks", LangOpts.Blocks) + .Case("cplusplus", LangOpts.CPlusPlus) + .Case("cplusplus11", LangOpts.CPlusPlus11) + .Case("objc", LangOpts.ObjC1) + .Case("objc_arc", LangOpts.ObjCAutoRefCount) + .Case("opencl", LangOpts.OpenCL) + .Case("tls", Target.isTLSSupported()) + .Default(Target.hasFeature(Feature)); + if (!HasFeature) + HasFeature = std::find(LangOpts.ModuleFeatures.begin(), + LangOpts.ModuleFeatures.end(), + Feature) != LangOpts.ModuleFeatures.end(); + return HasFeature; } bool Module::isAvailable(const LangOptions &LangOpts, const TargetInfo &Target, @@ -133,11 +138,11 @@ std::string Module::getFullModuleName() const { return Result; } -const DirectoryEntry *Module::getUmbrellaDir() const { - if (const FileEntry *Header = getUmbrellaHeader()) - return Header->getDir(); +Module::DirectoryName Module::getUmbrellaDir() const { + if (Header U = getUmbrellaHeader()) + return {"", U.Entry->getDir()}; - return Umbrella.dyn_cast<const DirectoryEntry *>(); + return {UmbrellaAsWritten, Umbrella.dyn_cast<const DirectoryEntry *>()}; } ArrayRef<const FileEntry *> Module::getTopHeaders(FileManager &FileMgr) { @@ -153,6 +158,19 @@ ArrayRef<const FileEntry *> Module::getTopHeaders(FileManager &FileMgr) { return llvm::makeArrayRef(TopHeaders.begin(), TopHeaders.end()); } +bool Module::directlyUses(const Module *Requested) const { + auto *Top = getTopLevelModule(); + + // A top-level module implicitly uses itself. + if (Requested->isSubModuleOf(Top)) + return true; + + for (auto *Use : Top->DirectUses) + if (Requested->isSubModuleOf(Use)) + return true; + return false; +} + void Module::addRequirement(StringRef Feature, bool RequiredState, const LangOptions &LangOpts, const TargetInfo &Target) { @@ -316,15 +334,15 @@ void Module::print(raw_ostream &OS, unsigned Indent) const { OS << "\n"; } - if (const FileEntry *UmbrellaHeader = getUmbrellaHeader()) { + if (Header H = getUmbrellaHeader()) { OS.indent(Indent + 2); OS << "umbrella header \""; - OS.write_escaped(UmbrellaHeader->getName()); + OS.write_escaped(H.NameAsWritten); OS << "\"\n"; - } else if (const DirectoryEntry *UmbrellaDir = getUmbrellaDir()) { + } else if (DirectoryName D = getUmbrellaDir()) { OS.indent(Indent + 2); OS << "umbrella \""; - OS.write_escaped(UmbrellaDir->getName()); + OS.write_escaped(D.NameAsWritten); OS << "\"\n"; } @@ -457,4 +475,47 @@ void Module::dump() const { print(llvm::errs()); } +void VisibleModuleSet::setVisible(Module *M, SourceLocation Loc, + VisibleCallback Vis, ConflictCallback Cb) { + if (isVisible(M)) + return; + ++Generation; + + struct Visiting { + Module *M; + Visiting *ExportedBy; + }; + + std::function<void(Visiting)> VisitModule = [&](Visiting V) { + // Modules that aren't available cannot be made visible. + if (!V.M->isAvailable()) + return; + + // Nothing to do for a module that's already visible. + unsigned ID = V.M->getVisibilityID(); + if (ImportLocs.size() <= ID) + ImportLocs.resize(ID + 1); + else if (ImportLocs[ID].isValid()) + return; + + ImportLocs[ID] = Loc; + Vis(M); + + // Make any exported modules visible. + SmallVector<Module *, 16> Exports; + V.M->getExportedModules(Exports); + for (Module *E : Exports) + VisitModule({E, &V}); + + for (auto &C : V.M->Conflicts) { + if (isVisible(C.Other)) { + llvm::SmallVector<Module*, 8> Path; + for (Visiting *I = &V; I; I = I->ExportedBy) + Path.push_back(I->M); + Cb(Path, C.Other, C.Message); + } + } + }; + VisitModule({M, nullptr}); +} diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp index 6e98d48c27d3..b83a0692c132 100644 --- a/lib/Basic/OpenMPKinds.cpp +++ b/lib/Basic/OpenMPKinds.cpp @@ -374,7 +374,6 @@ bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) { } bool clang::isOpenMPThreadPrivate(OpenMPClauseKind Kind) { - return Kind == OMPC_threadprivate || - Kind == OMPC_copyin; // TODO add next clauses like 'copyprivate'. + return Kind == OMPC_threadprivate || Kind == OMPC_copyin; } diff --git a/lib/Basic/SanitizerBlacklist.cpp b/lib/Basic/SanitizerBlacklist.cpp index ea5b8d0da845..095fcd6ccaeb 100644 --- a/lib/Basic/SanitizerBlacklist.cpp +++ b/lib/Basic/SanitizerBlacklist.cpp @@ -15,9 +15,9 @@ using namespace clang; -SanitizerBlacklist::SanitizerBlacklist(StringRef BlacklistPath, - SourceManager &SM) - : SCL(llvm::SpecialCaseList::createOrDie(BlacklistPath)), SM(SM) {} +SanitizerBlacklist::SanitizerBlacklist( + const std::vector<std::string> &BlacklistPaths, SourceManager &SM) + : SCL(llvm::SpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {} bool SanitizerBlacklist::isBlacklistedGlobal(StringRef GlobalName, StringRef Category) const { diff --git a/lib/Basic/Sanitizers.cpp b/lib/Basic/Sanitizers.cpp index e9aaa366e32b..8c4884b8ec36 100644 --- a/lib/Basic/Sanitizers.cpp +++ b/lib/Basic/Sanitizers.cpp @@ -11,25 +11,48 @@ // //===----------------------------------------------------------------------===// #include "clang/Basic/Sanitizers.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/MathExtras.h" using namespace clang; -SanitizerSet::SanitizerSet() : Kinds(0) {} +SanitizerSet::SanitizerSet() : Mask(0) {} -bool SanitizerSet::has(SanitizerKind K) const { - unsigned Bit = static_cast<unsigned>(K); - return Kinds & (1 << Bit); +bool SanitizerSet::has(SanitizerMask K) const { + assert(llvm::countPopulation(K) == 1); + return Mask & K; } -void SanitizerSet::set(SanitizerKind K, bool Value) { - unsigned Bit = static_cast<unsigned>(K); - Kinds = Value ? (Kinds | (1 << Bit)) : (Kinds & ~(1 << Bit)); +void SanitizerSet::set(SanitizerMask K, bool Value) { + assert(llvm::countPopulation(K) == 1); + Mask = Value ? (Mask | K) : (Mask & ~K); } void SanitizerSet::clear() { - Kinds = 0; + Mask = 0; } bool SanitizerSet::empty() const { - return Kinds == 0; + return Mask == 0; +} + +SanitizerMask clang::parseSanitizerValue(StringRef Value, bool AllowGroups) { + SanitizerMask ParsedKind = llvm::StringSwitch<SanitizerMask>(Value) +#define SANITIZER(NAME, ID) .Case(NAME, SanitizerKind::ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + .Case(NAME, AllowGroups ? SanitizerKind::ID##Group : 0) +#include "clang/Basic/Sanitizers.def" + .Default(0); + return ParsedKind; +} + +SanitizerMask clang::expandSanitizerGroups(SanitizerMask Kinds) { +#define SANITIZER(NAME, ID) +#define SANITIZER_GROUP(NAME, ID, ALIAS) \ + if (Kinds & SanitizerKind::ID##Group) \ + Kinds |= SanitizerKind::ID; +#include "clang/Basic/Sanitizers.def" + return Kinds; } diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp index 118e3f32008b..c0b045331dd6 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -110,8 +110,8 @@ llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag, // possible. if (!BufferOrError) { StringRef FillStr("<<<MISSING SOURCE FILE>>>\n"); - Buffer.setPointer(MemoryBuffer::getNewMemBuffer(ContentsEntry->getSize(), - "<invalid>").release()); + Buffer.setPointer(MemoryBuffer::getNewUninitMemBuffer( + ContentsEntry->getSize(), "<invalid>").release()); char *Ptr = const_cast<char*>(Buffer.getPointer()->getBufferStart()); for (unsigned i = 0, e = ContentsEntry->getSize(); i != e; ++i) Ptr[i] = FillStr[i % FillStr.size()]; diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index 871bbd5ef43f..330258b025b5 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -36,6 +36,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) { LongWidth = LongAlign = 32; LongLongWidth = LongLongAlign = 64; SuitableAlign = 64; + DefaultAlignForAttributeAligned = 128; MinGlobalAlign = 0; HalfWidth = 16; HalfAlign = 16; diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index a7a00570d127..a768081e70e0 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -25,9 +25,9 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" -#include "llvm/IR/Type.h" #include "llvm/MC/MCSectionMachO.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetParser.h" #include <algorithm> #include <memory> using namespace clang; @@ -185,6 +185,28 @@ static void getDarwinDefines(MacroBuilder &Builder, const LangOptions &Opts, } namespace { +// CloudABI Target +template <typename Target> +class CloudABITargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("__CloudABI__"); + Builder.defineMacro("__ELF__"); + + // CloudABI uses ISO/IEC 10646:2012 for wchar_t, char16_t and char32_t. + Builder.defineMacro("__STDC_ISO_10646__", "201206L"); + Builder.defineMacro("__STDC_UTF_16__"); + Builder.defineMacro("__STDC_UTF_32__"); + } + +public: + CloudABITargetInfo(const llvm::Triple &Triple) + : OSTargetInfo<Target>(Triple) { + this->UserLabelPrefix = ""; + } +}; + template<typename Target> class DarwinTargetInfo : public OSTargetInfo<Target> { protected: @@ -364,8 +386,13 @@ protected: DefineStd(Builder, "linux", Opts); Builder.defineMacro("__gnu_linux__"); Builder.defineMacro("__ELF__"); - if (Triple.getEnvironment() == llvm::Triple::Android) + if (Triple.getEnvironment() == llvm::Triple::Android) { Builder.defineMacro("__ANDROID__", "1"); + unsigned Maj, Min, Rev; + Triple.getOSVersion(Maj, Min, Rev); + this->PlatformName = "android"; + this->PlatformMinVersion = VersionTuple(Maj, Min, Rev); + } if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); if (Opts.CPlusPlus) @@ -473,6 +500,17 @@ protected: Builder.defineMacro("__ELF__"); if (Opts.POSIXThreads) Builder.defineMacro("_REENTRANT"); + + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + Builder.defineMacro("__ARM_DWARF_EH__"); + break; + } } public: BitrigTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) { @@ -526,6 +564,33 @@ public: } }; +template <typename Target> +class PS4OSTargetInfo : public OSTargetInfo<Target> { +protected: + void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, + MacroBuilder &Builder) const override { + Builder.defineMacro("__FreeBSD__", "9"); + Builder.defineMacro("__FreeBSD_cc_version", "900001"); + Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); + DefineStd(Builder, "unix", Opts); + Builder.defineMacro("__ELF__"); + Builder.defineMacro("__PS4__"); + } +public: + PS4OSTargetInfo(const llvm::Triple &Triple) : OSTargetInfo<Target>(Triple) { + this->WCharType = this->UnsignedShort; + + this->UserLabelPrefix = ""; + + switch (Triple.getArch()) { + default: + case llvm::Triple::x86_64: + this->MCountName = ".mcount"; + break; + } + } +}; + // Solaris target template<typename Target> class SolarisTargetInfo : public OSTargetInfo<Target> { @@ -574,7 +639,7 @@ protected: if (Opts.RTTIData) Builder.defineMacro("_CPPRTTI"); - if (Opts.Exceptions) + if (Opts.CXXExceptions) Builder.defineMacro("_CPPUNWIND"); } @@ -592,6 +657,9 @@ protected: Builder.defineMacro("_MSC_FULL_VER", Twine(Opts.MSCompatibilityVersion)); // FIXME We cannot encode the revision information into 32-bits Builder.defineMacro("_MSC_BUILD", Twine(1)); + + if (Opts.CPlusPlus11 && Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) + Builder.defineMacro("_HAS_CHAR16_T_LANGUAGE_SUPPORT", Twine(1)); } if (Opts.MicrosoftExt) { @@ -647,8 +715,7 @@ public: // RegParmMax is inherited from the underlying architecture this->LongDoubleFormat = &llvm::APFloat::IEEEdouble; if (Triple.getArch() == llvm::Triple::arm) { - this->DescriptionString = - "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128"; + // Handled in ARM's setABI(). } else if (Triple.getArch() == llvm::Triple::x86) { this->DescriptionString = "e-m:e-p:32:32-i64:64-n8:16:32-S128"; } else if (Triple.getArch() == llvm::Triple::x86_64) { @@ -660,19 +727,12 @@ public: this->DescriptionString = "e-p:32:32-i64:64"; } } - typename Target::CallingConvCheckResult checkCallingConvention( - CallingConv CC) const override { - return CC == CC_PnaclCall ? Target::CCCR_OK : - Target::checkCallingConvention(CC); - } }; -} // end anonymous namespace. //===----------------------------------------------------------------------===// // Specific target implementations. //===----------------------------------------------------------------------===// -namespace { // PPC abstract base class class PPCTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; @@ -683,13 +743,21 @@ class PPCTargetInfo : public TargetInfo { // Target cpu features. bool HasVSX; bool HasP8Vector; + bool HasP8Crypto; + bool HasDirectMove; + bool HasQPX; + bool HasHTM; + bool HasBPERMD; + bool HasExtDiv; protected: std::string ABI; public: PPCTargetInfo(const llvm::Triple &Triple) - : TargetInfo(Triple), HasVSX(false), HasP8Vector(false) { + : TargetInfo(Triple), HasVSX(false), HasP8Vector(false), + HasP8Crypto(false), HasDirectMove(false), HasQPX(false), HasHTM(false), + HasBPERMD(false), HasExtDiv(false) { BigEndian = (Triple.getArch() != llvm::Triple::ppc64le); LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble; @@ -949,8 +1017,40 @@ bool PPCTargetInfo::handleTargetFeatures(std::vector<std::string> &Features, continue; } + if (Feature == "bpermd") { + HasBPERMD = true; + continue; + } + + if (Feature == "extdiv") { + HasExtDiv = true; + continue; + } + if (Feature == "power8-vector") { HasP8Vector = true; + HasVSX = true; + continue; + } + + if (Feature == "crypto") { + HasP8Crypto = true; + continue; + } + + if (Feature == "direct-move") { + HasDirectMove = true; + HasVSX = true; + continue; + } + + if (Feature == "qpx") { + HasQPX = true; + continue; + } + + if (Feature == "htm") { + HasHTM = true; continue; } @@ -988,7 +1088,7 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, } // ABI options. - if (ABI == "elfv1") + if (ABI == "elfv1" || ABI == "elfv1-qpx") Builder.defineMacro("_CALL_ELF", "1"); if (ABI == "elfv2") Builder.defineMacro("_CALL_ELF", "2"); @@ -1106,6 +1206,18 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__VSX__"); if (HasP8Vector) Builder.defineMacro("__POWER8_VECTOR__"); + if (HasP8Crypto) + Builder.defineMacro("__CRYPTO__"); + if (HasHTM) + Builder.defineMacro("__HTM__"); + if (getTriple().getArch() == llvm::Triple::ppc64le || + (defs & ArchDefinePwr8) || (CPU == "pwr8")) { + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + if (PointerWidth == 64) + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); + } // FIXME: The following are not yet generated here by Clang, but are // generated by GCC: @@ -1144,9 +1256,28 @@ void PPCTargetInfo::getDefaultFeatures(llvm::StringMap<bool> &Features) const { .Default(false); Features["qpx"] = (CPU == "a2q"); - - if (!ABI.empty()) - Features[ABI] = true; + Features["crypto"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Default(false); + Features["power8-vector"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Default(false); + Features["bpermd"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + Features["extdiv"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Case("pwr7", true) + .Default(false); + Features["direct-move"] = llvm::StringSwitch<bool>(CPU) + .Case("ppc64le", true) + .Case("pwr8", true) + .Default(false); } bool PPCTargetInfo::hasFeature(StringRef Feature) const { @@ -1154,6 +1285,12 @@ bool PPCTargetInfo::hasFeature(StringRef Feature) const { .Case("powerpc", true) .Case("vsx", HasVSX) .Case("power8-vector", HasP8Vector) + .Case("crypto", HasP8Crypto) + .Case("direct-move", HasDirectMove) + .Case("qpx", HasQPX) + .Case("htm", HasHTM) + .Case("bpermd", HasBPERMD) + .Case("extdiv", HasExtDiv) .Default(false); } @@ -1259,9 +1396,7 @@ void PPCTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, Aliases = GCCRegAliases; NumAliases = llvm::array_lengthof(GCCRegAliases); } -} // end anonymous namespace. -namespace { class PPC32TargetInfo : public PPCTargetInfo { public: PPC32TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) { @@ -1293,11 +1428,9 @@ public: return TargetInfo::PowerABIBuiltinVaList; } }; -} // end anonymous namespace. // Note: ABI differences may eventually require us to have a separate // TargetInfo for little endian. -namespace { class PPC64TargetInfo : public PPCTargetInfo { public: PPC64TargetInfo(const llvm::Triple &Triple) : PPCTargetInfo(Triple) { @@ -1334,17 +1467,14 @@ public: } // PPC64 Linux-specifc ABI options. bool setABI(const std::string &Name) override { - if (Name == "elfv1" || Name == "elfv2") { + if (Name == "elfv1" || Name == "elfv1-qpx" || Name == "elfv2") { ABI = Name; return true; } return false; } }; -} // end anonymous namespace. - -namespace { class DarwinPPC32TargetInfo : public DarwinTargetInfo<PPC32TargetInfo> { public: @@ -1372,9 +1502,7 @@ public: DescriptionString = "E-m:o-i64:64-n32:64"; } }; -} // end anonymous namespace. -namespace { static const unsigned NVPTXAddrSpaceMap[] = { 1, // opencl_global 3, // opencl_local @@ -1396,6 +1524,7 @@ namespace { GK_SM21, GK_SM30, GK_SM35, + GK_SM37, } GPU; public: @@ -1431,6 +1560,9 @@ namespace { case GK_SM35: CUDAArchCode = "350"; break; + case GK_SM37: + CUDAArchCode = "370"; + break; default: llvm_unreachable("Unhandled target CPU"); } @@ -1483,6 +1615,7 @@ namespace { .Case("sm_21", GK_SM21) .Case("sm_30", GK_SM30) .Case("sm_35", GK_SM35) + .Case("sm_37", GK_SM37) .Default(GK_NONE); return GPU != GK_NONE; @@ -1510,24 +1643,23 @@ namespace { public: NVPTX32TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) { PointerWidth = PointerAlign = 32; - SizeType = PtrDiffType = TargetInfo::UnsignedInt; + SizeType = TargetInfo::UnsignedInt; + PtrDiffType = TargetInfo::SignedInt; IntPtrType = TargetInfo::SignedInt; DescriptionString = "e-p:32:32-i64:64-v16:16-v32:32-n16:32:64"; - } + } }; class NVPTX64TargetInfo : public NVPTXTargetInfo { public: NVPTX64TargetInfo(const llvm::Triple &Triple) : NVPTXTargetInfo(Triple) { PointerWidth = PointerAlign = 64; - SizeType = PtrDiffType = TargetInfo::UnsignedLongLong; - IntPtrType = TargetInfo::SignedLongLong; + SizeType = TargetInfo::UnsignedLong; + PtrDiffType = TargetInfo::SignedLong; + IntPtrType = TargetInfo::SignedLong; DescriptionString = "e-i64:64-v16:16-v32:32-n16:32:64"; - } + } }; -} - -namespace { static const unsigned R600AddrSpaceMap[] = { 1, // opencl_global @@ -1557,6 +1689,7 @@ static const char *DescriptionStringSI = class R600TargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; + static const char * const GCCRegNames[]; /// \brief The GPU profiles supported by the R600 target. enum GPUKind { @@ -1573,10 +1706,27 @@ class R600TargetInfo : public TargetInfo { GK_SEA_ISLANDS } GPU; + bool hasFP64:1; + bool hasFMAF:1; + bool hasLDEXPF:1; + public: R600TargetInfo(const llvm::Triple &Triple) - : TargetInfo(Triple), GPU(GK_R600) { - DescriptionString = DescriptionStringR600; + : TargetInfo(Triple) { + + if (Triple.getArch() == llvm::Triple::amdgcn) { + DescriptionString = DescriptionStringSI; + GPU = GK_SOUTHERN_ISLANDS; + hasFP64 = true; + hasFMAF = true; + hasLDEXPF = true; + } else { + DescriptionString = DescriptionStringR600; + GPU = GK_R600; + hasFP64 = false; + hasFMAF = false; + hasLDEXPF = false; + } AddrSpaceMap = &R600AddrSpaceMap; UseAddrSpaceMapMangling = true; } @@ -1600,10 +1750,7 @@ public: } void getGCCRegNames(const char * const *&Names, - unsigned &numNames) const override { - Names = nullptr; - numNames = 0; - } + unsigned &NumNames) const override; void getGCCRegAliases(const GCCRegAlias *&Aliases, unsigned &NumAliases) const override { @@ -1625,6 +1772,13 @@ public: void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { Builder.defineMacro("__R600__"); + if (hasFMAF) + Builder.defineMacro("__HAS_FMAF__"); + if (hasLDEXPF) + Builder.defineMacro("__HAS_LDEXPF__"); + if (hasFP64 && Opts.OpenCL) { + Builder.defineMacro("cl_khr_fp64"); + } } BuiltinVaListKind getBuiltinVaListKind() const override { @@ -1682,16 +1836,25 @@ public: case GK_EVERGREEN: case GK_NORTHERN_ISLANDS: DescriptionString = DescriptionStringR600; + hasFP64 = false; + hasFMAF = false; + hasLDEXPF = false; break; case GK_R600_DOUBLE_OPS: case GK_R700_DOUBLE_OPS: case GK_EVERGREEN_DOUBLE_OPS: case GK_CAYMAN: DescriptionString = DescriptionStringR600DoubleOps; + hasFP64 = true; + hasFMAF = true; + hasLDEXPF = false; break; case GK_SOUTHERN_ISLANDS: case GK_SEA_ISLANDS: DescriptionString = DescriptionStringSI; + hasFP64 = true; + hasFMAF = true; + hasLDEXPF = true; break; } @@ -1704,10 +1867,65 @@ const Builtin::Info R600TargetInfo::BuiltinInfo[] = { { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, #include "clang/Basic/BuiltinsR600.def" }; +const char * const R600TargetInfo::GCCRegNames[] = { + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31", + "v32", "v33", "v34", "v35", "v36", "v37", "v38", "v39", + "v40", "v41", "v42", "v43", "v44", "v45", "v46", "v47", + "v48", "v49", "v50", "v51", "v52", "v53", "v54", "v55", + "v56", "v57", "v58", "v59", "v60", "v61", "v62", "v63", + "v64", "v65", "v66", "v67", "v68", "v69", "v70", "v71", + "v72", "v73", "v74", "v75", "v76", "v77", "v78", "v79", + "v80", "v81", "v82", "v83", "v84", "v85", "v86", "v87", + "v88", "v89", "v90", "v91", "v92", "v93", "v94", "v95", + "v96", "v97", "v98", "v99", "v100", "v101", "v102", "v103", + "v104", "v105", "v106", "v107", "v108", "v109", "v110", "v111", + "v112", "v113", "v114", "v115", "v116", "v117", "v118", "v119", + "v120", "v121", "v122", "v123", "v124", "v125", "v126", "v127", + "v128", "v129", "v130", "v131", "v132", "v133", "v134", "v135", + "v136", "v137", "v138", "v139", "v140", "v141", "v142", "v143", + "v144", "v145", "v146", "v147", "v148", "v149", "v150", "v151", + "v152", "v153", "v154", "v155", "v156", "v157", "v158", "v159", + "v160", "v161", "v162", "v163", "v164", "v165", "v166", "v167", + "v168", "v169", "v170", "v171", "v172", "v173", "v174", "v175", + "v176", "v177", "v178", "v179", "v180", "v181", "v182", "v183", + "v184", "v185", "v186", "v187", "v188", "v189", "v190", "v191", + "v192", "v193", "v194", "v195", "v196", "v197", "v198", "v199", + "v200", "v201", "v202", "v203", "v204", "v205", "v206", "v207", + "v208", "v209", "v210", "v211", "v212", "v213", "v214", "v215", + "v216", "v217", "v218", "v219", "v220", "v221", "v222", "v223", + "v224", "v225", "v226", "v227", "v228", "v229", "v230", "v231", + "v232", "v233", "v234", "v235", "v236", "v237", "v238", "v239", + "v240", "v241", "v242", "v243", "v244", "v245", "v246", "v247", + "v248", "v249", "v250", "v251", "v252", "v253", "v254", "v255", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15", + "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23", + "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31", + "s32", "s33", "s34", "s35", "s36", "s37", "s38", "s39", + "s40", "s41", "s42", "s43", "s44", "s45", "s46", "s47", + "s48", "s49", "s50", "s51", "s52", "s53", "s54", "s55", + "s56", "s57", "s58", "s59", "s60", "s61", "s62", "s63", + "s64", "s65", "s66", "s67", "s68", "s69", "s70", "s71", + "s72", "s73", "s74", "s75", "s76", "s77", "s78", "s79", + "s80", "s81", "s82", "s83", "s84", "s85", "s86", "s87", + "s88", "s89", "s90", "s91", "s92", "s93", "s94", "s95", + "s96", "s97", "s98", "s99", "s100", "s101", "s102", "s103", + "s104", "s105", "s106", "s107", "s108", "s109", "s110", "s111", + "s112", "s113", "s114", "s115", "s116", "s117", "s118", "s119", + "s120", "s121", "s122", "s123", "s124", "s125", "s126", "s127" + "exec", "vcc", "scc", "m0", "flat_scr", "exec_lo", "exec_hi", + "vcc_lo", "vcc_hi", "flat_scr_lo", "flat_scr_hi" +}; -} // end anonymous namespace +void R600TargetInfo::getGCCRegNames(const char * const *&Names, + unsigned &NumNames) const { + Names = GCCRegNames; + NumNames = llvm::array_lengthof(GCCRegNames); +} -namespace { // Namespace for x86 abstract base class const Builtin::Info BuiltinInfo[] = { #define BUILTIN(ID, TYPE, ATTRS) { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, @@ -2496,11 +2714,6 @@ void X86TargetInfo::setXOPLevel(llvm::StringMap<bool> &Features, XOPEnum Level, void X86TargetInfo::setFeatureEnabledImpl(llvm::StringMap<bool> &Features, StringRef Name, bool Enabled) { - // FIXME: This *really* should not be here. We need some way of translating - // options into llvm subtarget features. - if (Name == "sse4") - Name = "sse4.2"; - Features[Name] = Enabled; if (Name == "mmx") { @@ -3236,9 +3449,7 @@ X86TargetInfo::convertConstraint(const char *&Constraint) const { return std::string(1, *Constraint); } } -} // end anonymous namespace -namespace { // X86-32 generic target class X86_32TargetInfo : public X86TargetInfo { public: @@ -3293,9 +3504,7 @@ public: return X86TargetInfo::validateOperandSize(Constraint, Size); } }; -} // end anonymous namespace -namespace { class NetBSDI386TargetInfo : public NetBSDTargetInfo<X86_32TargetInfo> { public: NetBSDI386TargetInfo(const llvm::Triple &Triple) @@ -3311,9 +3520,7 @@ public: return 1; } }; -} // end anonymous namespace -namespace { class OpenBSDI386TargetInfo : public OpenBSDTargetInfo<X86_32TargetInfo> { public: OpenBSDI386TargetInfo(const llvm::Triple &Triple) @@ -3323,9 +3530,7 @@ public: PtrDiffType = SignedLong; } }; -} // end anonymous namespace -namespace { class BitrigI386TargetInfo : public BitrigTargetInfo<X86_32TargetInfo> { public: BitrigI386TargetInfo(const llvm::Triple &Triple) @@ -3335,9 +3540,7 @@ public: PtrDiffType = SignedLong; } }; -} // end anonymous namespace -namespace { class DarwinI386TargetInfo : public DarwinTargetInfo<X86_32TargetInfo> { public: DarwinI386TargetInfo(const llvm::Triple &Triple) @@ -3353,9 +3556,7 @@ public: } }; -} // end anonymous namespace -namespace { // x86-32 Windows target class WindowsX86_32TargetInfo : public WindowsTargetInfo<X86_32TargetInfo> { public: @@ -3365,8 +3566,9 @@ public: DoubleAlign = LongLongAlign = 64; bool IsWinCOFF = getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); - DescriptionString = IsWinCOFF ? "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32" - : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-S32"; + DescriptionString = IsWinCOFF + ? "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" + : "e-m:e-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { @@ -3436,9 +3638,7 @@ public: addMinGWDefines(Opts, Builder); } }; -} // end anonymous namespace -namespace { // x86-32 Cygwin target class CygwinX86_32TargetInfo : public X86_32TargetInfo { public: @@ -3447,7 +3647,7 @@ public: TLSSupported = false; WCharType = UnsignedShort; DoubleAlign = LongLongAlign = 64; - DescriptionString = "e-m:w-p:32:32-i64:64-f80:32-n8:16:32-S32"; + DescriptionString = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"; } void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { @@ -3460,9 +3660,7 @@ public: Builder.defineMacro("_GNU_SOURCE"); } }; -} // end anonymous namespace -namespace { // x86-32 Haiku target class HaikuX86_32TargetInfo : public X86_32TargetInfo { public: @@ -3481,7 +3679,6 @@ public: Builder.defineMacro("__HAIKU__"); } }; -} // end anonymous namespace // RTEMS Target template<typename Target> @@ -3518,7 +3715,6 @@ public: } }; -namespace { // x86-32 RTEMS target class RTEMSX86_32TargetInfo : public X86_32TargetInfo { public: @@ -3535,14 +3731,14 @@ public: Builder.defineMacro("__rtems__"); } }; -} // end anonymous namespace -namespace { // x86-64 generic target class X86_64TargetInfo : public X86TargetInfo { public: X86_64TargetInfo(const llvm::Triple &Triple) : X86TargetInfo(Triple) { const bool IsX32 = getTriple().getEnvironment() == llvm::Triple::GNUX32; + bool IsWinCOFF = + getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); LongWidth = LongAlign = PointerWidth = PointerAlign = IsX32 ? 32 : 64; LongDoubleWidth = 128; LongDoubleAlign = 128; @@ -3557,9 +3753,10 @@ public: RegParmMax = 6; // Pointers are 32-bit in x32. - DescriptionString = (IsX32) - ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128" - : "e-m:e-i64:64-f80:128-n8:16:32:64-S128"; + DescriptionString = IsX32 ? "e-m:e-p:32:32-i64:64-f80:128-n8:16:32:64-S128" + : IsWinCOFF + ? "e-m:w-i64:64-f80:128-n8:16:32:64-S128" + : "e-m:e-i64:64-f80:128-n8:16:32:64-S128"; // Use fpret only for long double. RealTypeUsesObjCFPRet = (1 << TargetInfo::LongDouble); @@ -3595,9 +3792,7 @@ public: // for x32 we need it here explicitly bool hasInt128Type() const override { return true; } }; -} // end anonymous namespace -namespace { // x86-64 Windows target class WindowsX86_64TargetInfo : public WindowsTargetInfo<X86_64TargetInfo> { public: @@ -3613,24 +3808,34 @@ public: IntPtrType = SignedLongLong; this->UserLabelPrefix = ""; } + void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override { WindowsTargetInfo<X86_64TargetInfo>::getTargetDefines(Opts, Builder); Builder.defineMacro("_WIN64"); } + BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::CharPtrBuiltinVaList; } + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { - return (CC == CC_C || - CC == CC_X86VectorCall || - CC == CC_IntelOclBicc || - CC == CC_X86_64SysV) ? CCCR_OK : CCCR_Warning; + switch (CC) { + case CC_X86StdCall: + case CC_X86ThisCall: + case CC_X86FastCall: + return CCCR_Ignore; + case CC_C: + case CC_X86VectorCall: + case CC_IntelOclBicc: + case CC_X86_64SysV: + return CCCR_OK; + default: + return CCCR_Warning; + } } }; -} // end anonymous namespace -namespace { // x86-64 Windows Visual Studio target class MicrosoftX86_64TargetInfo : public WindowsX86_64TargetInfo { public: @@ -3647,9 +3852,7 @@ public: Builder.defineMacro("_M_AMD64"); } }; -} // end anonymous namespace -namespace { // x86-64 MinGW target class MinGWX86_64TargetInfo : public WindowsX86_64TargetInfo { public: @@ -3667,9 +3870,7 @@ public: Builder.defineMacro("__SEH__"); } }; -} // end anonymous namespace -namespace { class DarwinX86_64TargetInfo : public DarwinTargetInfo<X86_64TargetInfo> { public: DarwinX86_64TargetInfo(const llvm::Triple &Triple) @@ -3683,9 +3884,7 @@ public: DescriptionString = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"; } }; -} // end anonymous namespace -namespace { class OpenBSDX86_64TargetInfo : public OpenBSDTargetInfo<X86_64TargetInfo> { public: OpenBSDX86_64TargetInfo(const llvm::Triple &Triple) @@ -3694,9 +3893,7 @@ public: Int64Type = SignedLongLong; } }; -} // end anonymous namespace -namespace { class BitrigX86_64TargetInfo : public BitrigTargetInfo<X86_64TargetInfo> { public: BitrigX86_64TargetInfo(const llvm::Triple &Triple) @@ -3705,10 +3902,7 @@ public: Int64Type = SignedLongLong; } }; -} - -namespace { class ARMTargetInfo : public TargetInfo { // Possible FPU choices. enum FPUMode { @@ -3800,8 +3994,9 @@ class ARMTargetInfo : public TargetInfo { DoubleAlign = LongLongAlign = LongDoubleAlign = SuitableAlign = 64; const llvm::Triple &T = getTriple(); - // size_t is unsigned long on MachO-derived environments and NetBSD. - if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD) + // size_t is unsigned long on MachO-derived environments, NetBSD and Bitrig. + if (T.isOSBinFormatMachO() || T.getOS() == llvm::Triple::NetBSD || + T.getOS() == llvm::Triple::Bitrig) SizeType = UnsignedLong; else SizeType = UnsignedInt; @@ -3831,16 +4026,18 @@ class ARMTargetInfo : public TargetInfo { BigEndian ? "E-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" : "e-m:o-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"; } else if (T.isOSWindows()) { - // FIXME: this is invalid for WindowsCE assert(!BigEndian && "Windows on ARM does not support big endian"); DescriptionString = "e" - "-m:e" + "-m:w" "-p:32:32" "-i64:64" "-v128:64:128" "-a:0:32" "-n32" "-S64"; + } else if (T.isOSNaCl()) { + assert(!BigEndian && "NaCl on ARM does not support big endian"); + DescriptionString = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S128"; } else { DescriptionString = BigEndian ? "E-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" @@ -3984,8 +4181,15 @@ public: return false; } + // FIXME: This should be based on Arch attributes, not CPU names. void getDefaultFeatures(llvm::StringMap<bool> &Features) const override { StringRef ArchName = getTriple().getArchName(); + unsigned ArchKind = + llvm::ARMTargetParser::parseArch( + llvm::ARMTargetParser::getCanonicalArchName(ArchName)); + bool IsV8 = (ArchKind == llvm::ARM::AK_ARMV8A || + ArchKind == llvm::ARM::AK_ARMV8_1A); + if (CPU == "arm1136jf-s" || CPU == "arm1176jzf-s" || CPU == "mpcore") Features["vfp2"] = true; else if (CPU == "cortex-a8" || CPU == "cortex-a9") { @@ -4002,28 +4206,19 @@ public: Features["neon"] = true; Features["hwdiv"] = true; Features["hwdiv-arm"] = true; - } else if (CPU == "cyclone") { - Features["v8fp"] = true; - Features["neon"] = true; - Features["hwdiv"] = true; - Features["hwdiv-arm"] = true; - } else if (CPU == "cortex-a53" || CPU == "cortex-a57") { + } else if (CPU == "cyclone" || CPU == "cortex-a53" || CPU == "cortex-a57" || + CPU == "cortex-a72") { Features["fp-armv8"] = true; Features["neon"] = true; Features["hwdiv"] = true; Features["hwdiv-arm"] = true; Features["crc"] = true; Features["crypto"] = true; - } else if (CPU == "cortex-r5" || - // Enable the hwdiv extension for all v8a AArch32 cores by - // default. - ArchName == "armv8a" || ArchName == "armv8" || - ArchName == "armebv8a" || ArchName == "armebv8" || - ArchName == "thumbv8a" || ArchName == "thumbv8" || - ArchName == "thumbebv8a" || ArchName == "thumbebv8") { + } else if (CPU == "cortex-r5" || CPU == "cortex-r7" || IsV8) { Features["hwdiv"] = true; Features["hwdiv-arm"] = true; - } else if (CPU == "cortex-m3" || CPU == "cortex-m4" || CPU == "cortex-m7") { + } else if (CPU == "cortex-m3" || CPU == "cortex-m4" || CPU == "cortex-m7" || + CPU == "sc300" || CPU == "cortex-r4" || CPU == "cortex-r4f") { Features["hwdiv"] = true; } } @@ -4080,12 +4275,10 @@ public: Features.push_back("-neonfp"); // Remove front-end specific options which the backend handles differently. - const StringRef FrontEndFeatures[] = { "+soft-float", "+soft-float-abi" }; - for (const auto &FEFeature : FrontEndFeatures) { - auto Feature = std::find(Features.begin(), Features.end(), FEFeature); - if (Feature != Features.end()) - Features.erase(Feature); - } + auto Feature = + std::find(Features.begin(), Features.end(), "+soft-float-abi"); + if (Feature != Features.end()) + Features.erase(Feature); return true; } @@ -4101,7 +4294,18 @@ public: .Default(false); } // FIXME: Should we actually have some table instead of these switches? - static const char *getCPUDefineSuffix(StringRef Name) { + const char *getCPUDefineSuffix(StringRef Name) const { + // FIXME: Use ARMTargetParser + if(Name == "generic") { + auto subarch = getTriple().getSubArch(); + switch (subarch) { + case llvm::Triple::SubArchType::ARMSubArch_v8_1a: + return "8_1A"; + default: + break; + } + } + return llvm::StringSwitch<const char *>(Name) .Cases("arm8", "arm810", "4") .Cases("strongarm", "strongarm110", "strongarm1100", "strongarm1110", @@ -4115,30 +4319,48 @@ public: .Cases("arm10e", "arm1020e", "arm1022e", "5TE") .Cases("xscale", "iwmmxt", "5TE") .Case("arm1136j-s", "6J") - .Cases("arm1176jz-s", "arm1176jzf-s", "6ZK") - .Cases("arm1136jf-s", "mpcorenovfp", "mpcore", "6K") + .Case("arm1136jf-s", "6") + .Cases("mpcorenovfp", "mpcore", "6K") + .Cases("arm1176jz-s", "arm1176jzf-s", "6K") .Cases("arm1156t2-s", "arm1156t2f-s", "6T2") .Cases("cortex-a5", "cortex-a7", "cortex-a8", "7A") .Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait", "7A") - .Cases("cortex-r4", "cortex-r5", "7R") + .Cases("cortex-r4", "cortex-r4f", "cortex-r5", "cortex-r7", "7R") .Case("swift", "7S") .Case("cyclone", "8A") - .Case("cortex-m3", "7M") + .Cases("sc300", "cortex-m3", "7M") .Cases("cortex-m4", "cortex-m7", "7EM") - .Case("cortex-m0", "6M") - .Cases("cortex-a53", "cortex-a57", "8A") + .Cases("sc000", "cortex-m0", "cortex-m0plus", "cortex-m1", "6M") + .Cases("cortex-a53", "cortex-a57", "cortex-a72", "8A") .Default(nullptr); } - static const char *getCPUProfile(StringRef Name) { - return llvm::StringSwitch<const char *>(Name) - .Cases("cortex-a5", "cortex-a7", "cortex-a8", "A") - .Cases("cortex-a9", "cortex-a12", "cortex-a15", "cortex-a17", "krait", - "A") - .Cases("cortex-a53", "cortex-a57", "A") - .Cases("cortex-m3", "cortex-m4", "cortex-m0", "cortex-m7", "M") - .Cases("cortex-r4", "cortex-r5", "R") - .Default(""); + const char *getCPUProfile(StringRef Name) const { + if(Name == "generic") { + auto subarch = getTriple().getSubArch(); + switch (subarch) { + case llvm::Triple::SubArchType::ARMSubArch_v8_1a: + return "A"; + default: + break; + } + } + + unsigned CPUArch = llvm::ARMTargetParser::parseCPUArch(Name); + if (CPUArch == llvm::ARM::AK_INVALID) + return ""; + + StringRef ArchName = llvm::ARMTargetParser::getArchName(CPUArch); + switch(llvm::ARMTargetParser::parseArchProfile(ArchName)) { + case llvm::ARM::PK_A: + return "A"; + case llvm::ARM::PK_R: + return "R"; + case llvm::ARM::PK_M: + return "M"; + default: + return ""; + } } bool setCPU(const std::string &Name) override { if (!getCPUDefineSuffix(Name)) @@ -4165,6 +4387,7 @@ public: // We check both CPUArchVer and ArchName because when only triple is // specified, the default CPU is arm1136j-s. return ArchName.endswith("v6t2") || ArchName.endswith("v7") || + ArchName.endswith("v8.1a") || ArchName.endswith("v8") || CPUArch == "6T2" || CPUArchVer >= 7; } void getTargetDefines(const LangOptions &Opts, @@ -4499,8 +4722,8 @@ class ARMleTargetInfo : public ARMTargetInfo { public: ARMleTargetInfo(const llvm::Triple &Triple) : ARMTargetInfo(Triple, false) { } - virtual void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { Builder.defineMacro("__ARMEL__"); ARMTargetInfo::getTargetDefines(Opts, Builder); } @@ -4510,16 +4733,14 @@ class ARMbeTargetInfo : public ARMTargetInfo { public: ARMbeTargetInfo(const llvm::Triple &Triple) : ARMTargetInfo(Triple, true) { } - virtual void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const { + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { Builder.defineMacro("__ARMEB__"); Builder.defineMacro("__ARM_BIG_ENDIAN"); ARMTargetInfo::getTargetDefines(Opts, Builder); } }; -} // end anonymous namespace. -namespace { class WindowsARMTargetInfo : public WindowsTargetInfo<ARMleTargetInfo> { const llvm::Triple Triple; public: @@ -4585,10 +4806,7 @@ public: WindowsARMTargetInfo::getVisualStudioDefines(Opts, Builder); } }; -} - -namespace { class DarwinARMTargetInfo : public DarwinTargetInfo<ARMleTargetInfo> { protected: @@ -4610,10 +4828,7 @@ public: TheCXXABI.set(TargetCXXABI::iOS); } }; -} // end anonymous namespace. - -namespace { class AArch64TargetInfo : public TargetInfo { virtual void setDescriptionString() = 0; static const TargetInfo::GCCRegAlias GCCRegAliases[]; @@ -4655,13 +4870,20 @@ public: MaxAtomicInlineWidth = 128; MaxAtomicPromoteWidth = 128; - LongDoubleWidth = LongDoubleAlign = 128; + LongDoubleWidth = LongDoubleAlign = SuitableAlign = 128; LongDoubleFormat = &llvm::APFloat::IEEEquad; // {} in inline assembly are neon specifiers, not assembly variant // specifiers. NoAsmVariants = true; + // AAPCS gives rules for bitfields. 7.1.7 says: "The container type + // contributes to the alignment of the containing aggregate in the same way + // a plain (non bit-field) member of that type would, without exception for + // zero-sized or anonymous bit-fields." + UseBitFieldTypeAlignment = true; + UseZeroLengthBitfieldAlignment = true; + // AArch64 targets default to using the ARM C++ ABI. TheCXXABI.set(TargetCXXABI::GenericAArch64); } @@ -4678,14 +4900,14 @@ public: bool setCPU(const std::string &Name) override { bool CPUKnown = llvm::StringSwitch<bool>(Name) .Case("generic", true) - .Cases("cortex-a53", "cortex-a57", true) + .Cases("cortex-a53", "cortex-a57", "cortex-a72", true) .Case("cyclone", true) .Default(false); return CPUKnown; } - virtual void getTargetDefines(const LangOptions &Opts, - MacroBuilder &Builder) const override { + void getTargetDefines(const LangOptions &Opts, + MacroBuilder &Builder) const override { // Target identification. Builder.defineMacro("__aarch64__"); @@ -4742,10 +4964,16 @@ public: if (Crypto) Builder.defineMacro("__ARM_FEATURE_CRYPTO"); + + // All of the __sync_(bool|val)_compare_and_swap_(1|2|4|8) builtins work. + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4"); + Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8"); } - virtual void getTargetBuiltins(const Builtin::Info *&Records, - unsigned &NumRecords) const override { + void getTargetBuiltins(const Builtin::Info *&Records, + unsigned &NumRecords) const override { Records = BuiltinInfo; NumRecords = clang::AArch64::LastTSBuiltin - Builtin::FirstTSBuiltin; } @@ -4781,14 +5009,13 @@ public: return TargetInfo::AArch64ABIBuiltinVaList; } - virtual void getGCCRegNames(const char *const *&Names, - unsigned &NumNames) const override; - virtual void getGCCRegAliases(const GCCRegAlias *&Aliases, - unsigned &NumAliases) const override; + void getGCCRegNames(const char *const *&Names, + unsigned &NumNames) const override; + void getGCCRegAliases(const GCCRegAlias *&Aliases, + unsigned &NumAliases) const override; - virtual bool - validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &Info) const override { + bool validateAsmConstraint(const char *&Name, + TargetInfo::ConstraintInfo &Info) const override { switch (*Name) { default: return false; @@ -4963,9 +5190,7 @@ public: AArch64TargetInfo::getTargetDefines(Opts, Builder); } }; -} // end anonymous namespace. -namespace { class DarwinAArch64TargetInfo : public DarwinTargetInfo<AArch64leTargetInfo> { protected: void getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, @@ -4988,7 +5213,7 @@ public: WCharType = SignedInt; UseSignedCharForObjCBool = false; - LongDoubleWidth = LongDoubleAlign = 64; + LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble; TheCXXABI.set(TargetCXXABI::iOS64); @@ -4998,9 +5223,7 @@ public: return TargetInfo::CharPtrBuiltinVaList; } }; -} // end anonymous namespace -namespace { // Hexagon abstract base class class HexagonTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; @@ -5149,24 +5372,25 @@ const Builtin::Info HexagonTargetInfo::BuiltinInfo[] = { ALL_LANGUAGES }, #include "clang/Basic/BuiltinsHexagon.def" }; -} - -namespace { // Shared base class for SPARC v8 (32-bit) and SPARC v9 (64-bit). class SparcTargetInfo : public TargetInfo { static const TargetInfo::GCCRegAlias GCCRegAliases[]; static const char * const GCCRegNames[]; bool SoftFloat; public: - SparcTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) {} + SparcTargetInfo(const llvm::Triple &Triple) + : TargetInfo(Triple), SoftFloat(false) {} bool handleTargetFeatures(std::vector<std::string> &Features, DiagnosticsEngine &Diags) override { - SoftFloat = false; - for (unsigned i = 0, e = Features.size(); i != e; ++i) - if (Features[i] == "+soft-float") - SoftFloat = true; + // The backend doesn't actually handle soft float yet, but in case someone + // is using the support for the front end continue to support it. + auto Feature = std::find(Features.begin(), Features.end(), "+soft-float"); + if (Feature != Features.end()) { + SoftFloat = true; + Features.erase(Feature); + } return true; } void getTargetDefines(const LangOptions &Opts, @@ -5285,6 +5509,15 @@ public: } }; +// SPARCV8el is the 32-bit little-endian mode selected by Triple::sparcel. +class SparcV8elTargetInfo : public SparcV8TargetInfo { + public: + SparcV8elTargetInfo(const llvm::Triple &Triple) : SparcV8TargetInfo(Triple) { + DescriptionString = "e-m:e-p:32:32-i64:64-f128:64-n32-S64"; + BigEndian = false; + } +}; + // SPARC v9 is the 64-bit mode selected by Triple::sparcv9. class SparcV9TargetInfo : public SparcTargetInfo { public: @@ -5339,9 +5572,6 @@ public: } }; -} // end anonymous namespace. - -namespace { class SolarisSparcV8TargetInfo : public SolarisTargetInfo<SparcV8TargetInfo> { public: SolarisSparcV8TargetInfo(const llvm::Triple &Triple) @@ -5350,14 +5580,19 @@ public: PtrDiffType = SignedInt; } }; -} // end anonymous namespace. -namespace { class SystemZTargetInfo : public TargetInfo { + static const Builtin::Info BuiltinInfo[]; static const char *const GCCRegNames[]; + std::string CPU; + bool HasTransactionalExecution; + bool HasVector; public: - SystemZTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { + SystemZTargetInfo(const llvm::Triple &Triple) + : TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false), HasVector(false) { + IntMaxType = SignedLong; + Int64Type = SignedLong; TLSSupported = true; IntWidth = IntAlign = 32; LongWidth = LongLongWidth = LongAlign = LongLongAlign = 64; @@ -5365,6 +5600,7 @@ public: LongDoubleWidth = 128; LongDoubleAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEquad; + DefaultAlignForAttributeAligned = 64; MinGlobalAlign = 16; DescriptionString = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64-a:8:16-n32:64"; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; @@ -5375,12 +5611,13 @@ public: Builder.defineMacro("__s390x__"); Builder.defineMacro("__zarch__"); Builder.defineMacro("__LONG_DOUBLE_128__"); + if (HasTransactionalExecution) + Builder.defineMacro("__HTM__"); } void getTargetBuiltins(const Builtin::Info *&Records, unsigned &NumRecords) const override { - // FIXME: Implement. - Records = nullptr; - NumRecords = 0; + Records = BuiltinInfo; + NumRecords = clang::SystemZ::LastTSBuiltin-Builtin::FirstTSBuiltin; } void getGCCRegNames(const char *const *&Names, @@ -5401,16 +5638,62 @@ public: return TargetInfo::SystemZBuiltinVaList; } bool setCPU(const std::string &Name) override { + CPU = Name; bool CPUKnown = llvm::StringSwitch<bool>(Name) .Case("z10", true) .Case("z196", true) .Case("zEC12", true) + .Case("z13", true) .Default(false); - // No need to store the CPU yet. There aren't any CPU-specific - // macros to define. return CPUKnown; } + void getDefaultFeatures(llvm::StringMap<bool> &Features) const override { + if (CPU == "zEC12") + Features["transactional-execution"] = true; + if (CPU == "z13") { + Features["transactional-execution"] = true; + Features["vector"] = true; + } + } + + bool handleTargetFeatures(std::vector<std::string> &Features, + DiagnosticsEngine &Diags) override { + HasTransactionalExecution = false; + for (unsigned i = 0, e = Features.size(); i != e; ++i) { + if (Features[i] == "+transactional-execution") + HasTransactionalExecution = true; + if (Features[i] == "+vector") + HasVector = true; + } + // If we use the vector ABI, vector types are 64-bit aligned. + if (HasVector) { + MaxVectorAlign = 64; + DescriptionString = "E-m:e-i1:8:16-i8:8:16-i64:64-f128:64" + "-v128:64-a:8:16-n32:64"; + } + return true; + } + + bool hasFeature(StringRef Feature) const override { + return llvm::StringSwitch<bool>(Feature) + .Case("systemz", true) + .Case("htm", HasTransactionalExecution) + .Case("vx", HasVector) + .Default(false); + } + + StringRef getABI() const override { + if (HasVector) + return "vector"; + return ""; + } +}; + +const Builtin::Info SystemZTargetInfo::BuiltinInfo[] = { +#define BUILTIN(ID, TYPE, ATTRS) \ + { #ID, TYPE, ATTRS, 0, ALL_LANGUAGES }, +#include "clang/Basic/BuiltinsSystemZ.def" }; const char *const SystemZTargetInfo::GCCRegNames[] = { @@ -5454,9 +5737,7 @@ validateAsmConstraint(const char *&Name, return true; } } -} -namespace { class MSP430TargetInfo : public TargetInfo { static const char * const GCCRegNames[]; public: @@ -5531,9 +5812,6 @@ namespace { Names = GCCRegNames; NumNames = llvm::array_lengthof(GCCRegNames); } -} - -namespace { // LLVM and Clang cannot be used directly to output native binaries for // target, but is used to compile C code to llvm bitcode with correct @@ -5611,9 +5889,7 @@ namespace { void getGCCRegAliases(const GCCRegAlias *&Aliases, unsigned &NumAliases) const override {} }; -} -namespace { class MipsTargetInfoBase : public TargetInfo { virtual void setDescriptionString() = 0; @@ -5652,6 +5928,10 @@ public: return CPU == "mips32r6" || ABI == "n32" || ABI == "n64" || ABI == "64"; } + bool isNan2008() const override { + return IsNan2008; + } + StringRef getABI() const override { return ABI; } bool setCPU(const std::string &Name) override { bool IsMips32 = getTriple().getArch() == llvm::Triple::mips || @@ -5665,23 +5945,19 @@ public: .Case("mips5", true) .Case("mips32", IsMips32) .Case("mips32r2", IsMips32) + .Case("mips32r3", IsMips32) + .Case("mips32r5", IsMips32) .Case("mips32r6", IsMips32) .Case("mips64", true) .Case("mips64r2", true) + .Case("mips64r3", true) + .Case("mips64r5", true) .Case("mips64r6", true) .Case("octeon", true) .Default(false); } const std::string& getCPU() const { return CPU; } void getDefaultFeatures(llvm::StringMap<bool> &Features) const override { - // The backend enables certain ABI's by default according to the - // architecture. - // Disable both possible defaults so that we don't end up with multiple - // ABI's selected and trigger an assertion. - Features["o32"] = false; - Features["n64"] = false; - - Features[ABI] = true; if (CPU == "octeon") Features["mips64r2"] = Features["cnmips"] = true; else @@ -5818,7 +6094,28 @@ public: case 'R': // An address that can be used in a non-macro load or store Info.setAllowsMemory(); return true; + case 'Z': + if (Name[1] == 'C') { // An address usable by ll, and sc. + Info.setAllowsMemory(); + Name++; // Skip over 'Z'. + return true; + } + return false; + } + } + + std::string convertConstraint(const char *&Constraint) const override { + std::string R; + switch (*Constraint) { + case 'Z': // Two-character constraint; add "^" hint for later parsing. + if (Constraint[1] == 'C') { + R = std::string("^") + std::string(Constraint, 2); + Constraint++; + return R; + } + break; } + return TargetInfo::convertConstraint(Constraint); } const char *getClobbers() const override { @@ -5882,12 +6179,6 @@ public: IsNan2008 = false; } - // Remove front-end specific options. - std::vector<std::string>::iterator it = - std::find(Features.begin(), Features.end(), "+soft-float"); - if (it != Features.end()) - Features.erase(it); - setDescriptionString(); return true; @@ -5938,6 +6229,10 @@ public: Builder.defineMacro("__mips_isa_rev", "1"); else if (CPUStr == "mips32r2") Builder.defineMacro("__mips_isa_rev", "2"); + else if (CPUStr == "mips32r3") + Builder.defineMacro("__mips_isa_rev", "3"); + else if (CPUStr == "mips32r5") + Builder.defineMacro("__mips_isa_rev", "5"); else if (CPUStr == "mips32r6") Builder.defineMacro("__mips_isa_rev", "6"); @@ -6087,6 +6382,10 @@ public: Builder.defineMacro("__mips_isa_rev", "1"); else if (CPUStr == "mips64r2") Builder.defineMacro("__mips_isa_rev", "2"); + else if (CPUStr == "mips64r3") + Builder.defineMacro("__mips_isa_rev", "3"); + else if (CPUStr == "mips64r5") + Builder.defineMacro("__mips_isa_rev", "5"); else if (CPUStr == "mips64r6") Builder.defineMacro("__mips_isa_rev", "6"); @@ -6185,9 +6484,7 @@ public: Mips64TargetInfoBase::getTargetDefines(Opts, Builder); } }; -} // end anonymous namespace. -namespace { class PNaClTargetInfo : public TargetInfo { public: PNaClTargetInfo(const llvm::Triple &Triple) : TargetInfo(Triple) { @@ -6252,9 +6549,7 @@ void PNaClTargetInfo::getGCCRegAliases(const GCCRegAlias *&Aliases, Aliases = nullptr; NumAliases = 0; } -} // end anonymous namespace. -namespace { class Le64TargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; @@ -6359,6 +6654,15 @@ namespace { BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::VoidPtrBuiltinVaList; } + + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { + return (CC == CC_SpirFunction || + CC == CC_SpirKernel) ? CCCR_OK : CCCR_Warning; + } + + CallingConv getDefaultCallingConv(CallingConvMethodType MT) const override { + return CC_SpirFunction; + } }; @@ -6392,9 +6696,7 @@ namespace { DefineStd(Builder, "SPIR64", Opts); } }; -} -namespace { class XCoreTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; public: @@ -6460,6 +6762,30 @@ const Builtin::Info XCoreTargetInfo::BuiltinInfo[] = { }; } // end anonymous namespace. +namespace { +// x86_32 Android target +class AndroidX86_32TargetInfo : public LinuxTargetInfo<X86_32TargetInfo> { +public: + AndroidX86_32TargetInfo(const llvm::Triple &Triple) + : LinuxTargetInfo<X86_32TargetInfo>(Triple) { + SuitableAlign = 32; + LongDoubleWidth = 64; + LongDoubleFormat = &llvm::APFloat::IEEEdouble; + } +}; +} // end anonymous namespace + +namespace { +// x86_64 Android target +class AndroidX86_64TargetInfo : public LinuxTargetInfo<X86_64TargetInfo> { +public: + AndroidX86_64TargetInfo(const llvm::Triple &Triple) + : LinuxTargetInfo<X86_64TargetInfo>(Triple) { + LongDoubleFormat = &llvm::APFloat::IEEEquad; + } +}; +} // end anonymous namespace + //===----------------------------------------------------------------------===// // Driver code @@ -6629,10 +6955,10 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { case llvm::Triple::le32: switch (os) { - case llvm::Triple::NaCl: - return new NaClTargetInfo<PNaClTargetInfo>(Triple); - default: - return nullptr; + case llvm::Triple::NaCl: + return new NaClTargetInfo<PNaClTargetInfo>(Triple); + default: + return nullptr; } case llvm::Triple::le64: @@ -6707,6 +7033,21 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { return new SparcV8TargetInfo(Triple); } + // The 'sparcel' architecture copies all the above cases except for Solaris. + case llvm::Triple::sparcel: + switch (os) { + case llvm::Triple::Linux: + return new LinuxTargetInfo<SparcV8elTargetInfo>(Triple); + case llvm::Triple::NetBSD: + return new NetBSDTargetInfo<SparcV8elTargetInfo>(Triple); + case llvm::Triple::OpenBSD: + return new OpenBSDTargetInfo<SparcV8elTargetInfo>(Triple); + case llvm::Triple::RTEMS: + return new RTEMSTargetInfo<SparcV8elTargetInfo>(Triple); + default: + return new SparcV8elTargetInfo(Triple); + } + case llvm::Triple::sparcv9: switch (os) { case llvm::Triple::Linux: @@ -6739,8 +7080,14 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { return new DarwinI386TargetInfo(Triple); switch (os) { - case llvm::Triple::Linux: - return new LinuxTargetInfo<X86_32TargetInfo>(Triple); + case llvm::Triple::Linux: { + switch (Triple.getEnvironment()) { + default: + return new LinuxTargetInfo<X86_32TargetInfo>(Triple); + case llvm::Triple::Android: + return new AndroidX86_32TargetInfo(Triple); + } + } case llvm::Triple::DragonFly: return new DragonFlyBSDTargetInfo<X86_32TargetInfo>(Triple); case llvm::Triple::NetBSD: @@ -6785,8 +7132,16 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { return new DarwinX86_64TargetInfo(Triple); switch (os) { - case llvm::Triple::Linux: - return new LinuxTargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::CloudABI: + return new CloudABITargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::Linux: { + switch (Triple.getEnvironment()) { + default: + return new LinuxTargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::Android: + return new AndroidX86_64TargetInfo(Triple); + } + } case llvm::Triple::DragonFly: return new DragonFlyBSDTargetInfo<X86_64TargetInfo>(Triple); case llvm::Triple::NetBSD: @@ -6813,22 +7168,24 @@ static TargetInfo *AllocateTarget(const llvm::Triple &Triple) { } case llvm::Triple::NaCl: return new NaClTargetInfo<X86_64TargetInfo>(Triple); + case llvm::Triple::PS4: + return new PS4OSTargetInfo<X86_64TargetInfo>(Triple); default: return new X86_64TargetInfo(Triple); } - case llvm::Triple::spir: { - if (Triple.getOS() != llvm::Triple::UnknownOS || - Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) - return nullptr; - return new SPIR32TargetInfo(Triple); - } - case llvm::Triple::spir64: { - if (Triple.getOS() != llvm::Triple::UnknownOS || - Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) - return nullptr; - return new SPIR64TargetInfo(Triple); - } + case llvm::Triple::spir: { + if (Triple.getOS() != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIR32TargetInfo(Triple); + } + case llvm::Triple::spir64: { + if (Triple.getOS() != llvm::Triple::UnknownOS || + Triple.getEnvironment() != llvm::Triple::UnknownEnvironment) + return nullptr; + return new SPIR64TargetInfo(Triple); + } } } diff --git a/lib/Basic/Version.cpp b/lib/Basic/Version.cpp index b631b3e8a763..a1a67c2bc144 100644 --- a/lib/Basic/Version.cpp +++ b/lib/Basic/Version.cpp @@ -36,7 +36,7 @@ std::string getClangRepositoryPath() { // If the SVN_REPOSITORY is empty, try to use the SVN keyword. This helps us // pick up a tag in an SVN export, for example. - StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/tags/RELEASE_360/final/lib/Basic/Version.cpp $"); + StringRef SVNRepository("$URL: https://llvm.org/svn/llvm-project/cfe/trunk/lib/Basic/Version.cpp $"); if (URL.empty()) { URL = SVNRepository.slice(SVNRepository.find(':'), SVNRepository.find("/lib/Basic")); diff --git a/lib/Basic/VersionTuple.cpp b/lib/Basic/VersionTuple.cpp index aa43ae298e23..9c73fd98a174 100644 --- a/lib/Basic/VersionTuple.cpp +++ b/lib/Basic/VersionTuple.cpp @@ -32,6 +32,8 @@ raw_ostream& clang::operator<<(raw_ostream &Out, Out << (V.usesUnderscores() ? '_' : '.') << *Minor; if (Optional<unsigned> Subminor = V.getSubminor()) Out << (V.usesUnderscores() ? '_' : '.') << *Subminor; + if (Optional<unsigned> Build = V.getBuild()) + Out << (V.usesUnderscores() ? '_' : '.') << *Build; return Out; } @@ -55,7 +57,7 @@ static bool parseInt(StringRef &input, unsigned &value) { } bool VersionTuple::tryParse(StringRef input) { - unsigned major = 0, minor = 0, micro = 0; + unsigned major = 0, minor = 0, micro = 0, build = 0; // Parse the major version, [0-9]+ if (parseInt(input, major)) return true; @@ -80,9 +82,19 @@ bool VersionTuple::tryParse(StringRef input) { input = input.substr(1); if (parseInt(input, micro)) return true; + if (input.empty()) { + *this = VersionTuple(major, minor, micro); + return false; + } + + // If we're not done, parse the micro version, \.[0-9]+ + if (input[0] != '.') return true; + input = input.substr(1); + if (parseInt(input, build)) return true; + // If we have characters left over, it's an error. if (!input.empty()) return true; - *this = VersionTuple(major, minor, micro); + *this = VersionTuple(major, minor, micro, build); return false; } diff --git a/lib/Basic/VirtualFileSystem.cpp b/lib/Basic/VirtualFileSystem.cpp index c89195e9326c..8a882e13f7a5 100644 --- a/lib/Basic/VirtualFileSystem.cpp +++ b/lib/Basic/VirtualFileSystem.cpp @@ -92,7 +92,7 @@ class RealFile : public File { } public: - ~RealFile(); + ~RealFile() override; ErrorOr<Status> status() override; ErrorOr<std::unique_ptr<MemoryBuffer>> getBuffer(const Twine &Name, int64_t FileSize = -1, @@ -362,7 +362,7 @@ class DirectoryEntry : public Entry { Status S; public: - virtual ~DirectoryEntry(); + ~DirectoryEntry() override; DirectoryEntry(StringRef Name, std::vector<Entry *> Contents, Status S) : Entry(EK_Directory, Name), Contents(std::move(Contents)), S(std::move(S)) {} @@ -498,7 +498,7 @@ private: ErrorOr<Status> status(const Twine &Path, Entry *E); public: - ~VFSFromYAML(); + ~VFSFromYAML() override; /// \brief Parses \p Buffer, which is expected to be in YAML format and /// returns a virtual file system representing its contents. @@ -1134,7 +1134,7 @@ VFSFromYamlDirIterImpl::VFSFromYamlDirIterImpl(const Twine &_Path, if (Current != End) { SmallString<128> PathStr(Dir); llvm::sys::path::append(PathStr, (*Current)->getName()); - llvm::ErrorOr<vfs::Status> S = FS.status(PathStr.str()); + llvm::ErrorOr<vfs::Status> S = FS.status(PathStr); if (S) CurrentEntry = *S; else @@ -1147,7 +1147,7 @@ std::error_code VFSFromYamlDirIterImpl::increment() { if (++Current != End) { SmallString<128> PathStr(Dir); llvm::sys::path::append(PathStr, (*Current)->getName()); - llvm::ErrorOr<vfs::Status> S = FS.status(PathStr.str()); + llvm::ErrorOr<vfs::Status> S = FS.status(PathStr); if (!S) return S.getError(); CurrentEntry = *S; diff --git a/lib/CodeGen/ABIInfo.h b/lib/CodeGen/ABIInfo.h index 7e7f7fa20679..cc8652e169d8 100644 --- a/lib/CodeGen/ABIInfo.h +++ b/lib/CodeGen/ABIInfo.h @@ -87,6 +87,8 @@ namespace clang { virtual bool isHomogeneousAggregateSmallEnough(const Type *Base, uint64_t Members) const; + virtual bool shouldSignExtUnsignedType(QualType Ty) const; + bool isHomogeneousAggregate(QualType Ty, const Type *&Base, uint64_t &Members) const; diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 25ecec586244..7f0c7bafc046 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -15,22 +15,22 @@ #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/Utils.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeWriterPass.h" #include "llvm/CodeGen/RegAllocRegistry.h" #include "llvm/CodeGen/SchedulerRegistry.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Module.h" #include "llvm/IR/Verifier.h" #include "llvm/MC/SubtargetFeature.h" -#include "llvm/PassManager.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/FormattedStream.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Target/TargetSubtargetInfo.h" @@ -55,44 +55,48 @@ class EmitAssemblyHelper { Timer CodeGenerationTime; - mutable PassManager *CodeGenPasses; - mutable PassManager *PerModulePasses; - mutable FunctionPassManager *PerFunctionPasses; + mutable legacy::PassManager *CodeGenPasses; + mutable legacy::PassManager *PerModulePasses; + mutable legacy::FunctionPassManager *PerFunctionPasses; private: - PassManager *getCodeGenPasses() const { + TargetIRAnalysis getTargetIRAnalysis() const { + if (TM) + return TM->getTargetIRAnalysis(); + + return TargetIRAnalysis(); + } + + legacy::PassManager *getCodeGenPasses() const { if (!CodeGenPasses) { - CodeGenPasses = new PassManager(); - CodeGenPasses->add(new DataLayoutPass()); - if (TM) - TM->addAnalysisPasses(*CodeGenPasses); + CodeGenPasses = new legacy::PassManager(); + CodeGenPasses->add( + createTargetTransformInfoWrapperPass(getTargetIRAnalysis())); } return CodeGenPasses; } - PassManager *getPerModulePasses() const { + legacy::PassManager *getPerModulePasses() const { if (!PerModulePasses) { - PerModulePasses = new PassManager(); - PerModulePasses->add(new DataLayoutPass()); - if (TM) - TM->addAnalysisPasses(*PerModulePasses); + PerModulePasses = new legacy::PassManager(); + PerModulePasses->add( + createTargetTransformInfoWrapperPass(getTargetIRAnalysis())); } return PerModulePasses; } - FunctionPassManager *getPerFunctionPasses() const { + legacy::FunctionPassManager *getPerFunctionPasses() const { if (!PerFunctionPasses) { - PerFunctionPasses = new FunctionPassManager(TheModule); - PerFunctionPasses->add(new DataLayoutPass()); - if (TM) - TM->addAnalysisPasses(*PerFunctionPasses); + PerFunctionPasses = new legacy::FunctionPassManager(TheModule); + PerFunctionPasses->add( + createTargetTransformInfoWrapperPass(getTargetIRAnalysis())); } return PerFunctionPasses; } void CreatePasses(); - /// CreateTargetMachine - Generates the TargetMachine. + /// Generates the TargetMachine. /// Returns Null if it is unable to create the target machine. /// Some of our clang tests specify triples which are not built /// into clang. This is okay because these tests check the generated @@ -102,10 +106,10 @@ private: /// the requested target. TargetMachine *CreateTargetMachine(bool MustCreateTM); - /// AddEmitPasses - Add passes necessary to emit assembly or LLVM IR. + /// Add passes necessary to emit assembly or LLVM IR. /// /// \return True on success. - bool AddEmitPasses(BackendAction Action, formatted_raw_ostream &OS); + bool AddEmitPasses(BackendAction Action, raw_pwrite_stream &OS); public: EmitAssemblyHelper(DiagnosticsEngine &_Diags, @@ -128,7 +132,7 @@ public: std::unique_ptr<TargetMachine> TM; - void EmitAssembly(BackendAction Action, raw_ostream *OS); + void EmitAssembly(BackendAction Action, raw_pwrite_stream *OS); }; // We need this wrapper to access LangOpts and CGOpts from extension functions @@ -163,7 +167,7 @@ static void addObjCARCOptPass(const PassManagerBuilder &Builder, PassManagerBase } static void addSampleProfileLoaderPass(const PassManagerBuilder &Builder, - PassManagerBase &PM) { + legacy::PassManagerBase &PM) { const PassManagerBuilderWrapper &BuilderWrapper = static_cast<const PassManagerBuilderWrapper &>(Builder); const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); @@ -171,31 +175,38 @@ static void addSampleProfileLoaderPass(const PassManagerBuilder &Builder, } static void addAddDiscriminatorsPass(const PassManagerBuilder &Builder, - PassManagerBase &PM) { + legacy::PassManagerBase &PM) { PM.add(createAddDiscriminatorsPass()); } static void addBoundsCheckingPass(const PassManagerBuilder &Builder, - PassManagerBase &PM) { + legacy::PassManagerBase &PM) { PM.add(createBoundsCheckingPass()); } static void addSanitizerCoveragePass(const PassManagerBuilder &Builder, - PassManagerBase &PM) { + legacy::PassManagerBase &PM) { const PassManagerBuilderWrapper &BuilderWrapper = static_cast<const PassManagerBuilderWrapper&>(Builder); const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); - PM.add(createSanitizerCoverageModulePass(CGOpts.SanitizeCoverage)); + SanitizerCoverageOptions Opts; + Opts.CoverageType = + static_cast<SanitizerCoverageOptions::Type>(CGOpts.SanitizeCoverageType); + Opts.IndirectCalls = CGOpts.SanitizeCoverageIndirectCalls; + Opts.TraceBB = CGOpts.SanitizeCoverageTraceBB; + Opts.TraceCmp = CGOpts.SanitizeCoverageTraceCmp; + Opts.Use8bitCounters = CGOpts.SanitizeCoverage8bitCounters; + PM.add(createSanitizerCoverageModulePass(Opts)); } static void addAddressSanitizerPasses(const PassManagerBuilder &Builder, - PassManagerBase &PM) { + legacy::PassManagerBase &PM) { PM.add(createAddressSanitizerFunctionPass()); PM.add(createAddressSanitizerModulePass()); } static void addMemorySanitizerPass(const PassManagerBuilder &Builder, - PassManagerBase &PM) { + legacy::PassManagerBase &PM) { const PassManagerBuilderWrapper &BuilderWrapper = static_cast<const PassManagerBuilderWrapper&>(Builder); const CodeGenOptions &CGOpts = BuilderWrapper.getCGOpts(); @@ -215,28 +226,36 @@ static void addMemorySanitizerPass(const PassManagerBuilder &Builder, } static void addThreadSanitizerPass(const PassManagerBuilder &Builder, - PassManagerBase &PM) { + legacy::PassManagerBase &PM) { PM.add(createThreadSanitizerPass()); } static void addDataFlowSanitizerPass(const PassManagerBuilder &Builder, - PassManagerBase &PM) { + legacy::PassManagerBase &PM) { const PassManagerBuilderWrapper &BuilderWrapper = static_cast<const PassManagerBuilderWrapper&>(Builder); const LangOptions &LangOpts = BuilderWrapper.getLangOpts(); - PM.add(createDataFlowSanitizerPass(LangOpts.SanitizerBlacklistFile)); + PM.add(createDataFlowSanitizerPass(LangOpts.SanitizerBlacklistFiles)); } -static TargetLibraryInfo *createTLI(llvm::Triple &TargetTriple, - const CodeGenOptions &CodeGenOpts) { - TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple); +static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple, + const CodeGenOptions &CodeGenOpts) { + TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(TargetTriple); if (!CodeGenOpts.SimplifyLibCalls) - TLI->disableAllFunctions(); - return TLI; + TLII->disableAllFunctions(); + + switch (CodeGenOpts.getVecLib()) { + case CodeGenOptions::Accelerate: + TLII->addVectorizableFunctionsFromVecLib(TargetLibraryInfoImpl::Accelerate); + break; + default: + break; + } + return TLII; } static void addSymbolRewriterPass(const CodeGenOptions &Opts, - PassManager *MPM) { + legacy::PassManager *MPM) { llvm::SymbolRewriter::RewriteDescriptorList DL; llvm::SymbolRewriter::RewriteMapParser MapParser; @@ -294,7 +313,9 @@ void EmitAssemblyHelper::CreatePasses() { addBoundsCheckingPass); } - if (CodeGenOpts.SanitizeCoverage) { + if (CodeGenOpts.SanitizeCoverageType || + CodeGenOpts.SanitizeCoverageIndirectCalls || + CodeGenOpts.SanitizeCoverageTraceCmp) { PMBuilder.addExtension(PassManagerBuilder::EP_OptimizerLast, addSanitizerCoveragePass); PMBuilder.addExtension(PassManagerBuilder::EP_EnabledOnOptLevel0, @@ -331,7 +352,7 @@ void EmitAssemblyHelper::CreatePasses() { // Figure out TargetLibraryInfo. Triple TargetTriple(TheModule->getTargetTriple()); - PMBuilder.LibraryInfo = createTLI(TargetTriple, CodeGenOpts); + PMBuilder.LibraryInfo = createTLII(TargetTriple, CodeGenOpts); switch (Inlining) { case CodeGenOptions::NoInlining: break; @@ -351,17 +372,15 @@ void EmitAssemblyHelper::CreatePasses() { } // Set up the per-function pass manager. - FunctionPassManager *FPM = getPerFunctionPasses(); + legacy::FunctionPassManager *FPM = getPerFunctionPasses(); if (CodeGenOpts.VerifyModule) FPM->add(createVerifierPass()); PMBuilder.populateFunctionPassManager(*FPM); // Set up the per-module pass manager. - PassManager *MPM = getPerModulePasses(); + legacy::PassManager *MPM = getPerModulePasses(); if (!CodeGenOpts.RewriteMapFiles.empty()) addSymbolRewriterPass(CodeGenOpts, MPM); - if (CodeGenOpts.VerifyModule) - MPM->add(createDebugInfoVerifierPass()); if (!CodeGenOpts.DisableGCov && (CodeGenOpts.EmitGcovArcs || CodeGenOpts.EmitGcovNotes)) { @@ -375,6 +394,7 @@ void EmitAssemblyHelper::CreatePasses() { Options.NoRedZone = CodeGenOpts.DisableRedZone; Options.FunctionNamesInData = !CodeGenOpts.CoverageNoFunctionNamesInData; + Options.ExitBlockBeforeBody = CodeGenOpts.CoverageExitBlockBeforeBody; MPM->add(createGCOVProfilerPass(Options)); if (CodeGenOpts.getDebugInfo() == CodeGenOptions::NoDebugInfo) MPM->add(createStripSymbolsPass(true)); @@ -383,6 +403,7 @@ void EmitAssemblyHelper::CreatePasses() { if (CodeGenOpts.ProfileInstrGenerate) { InstrProfOptions Options; Options.NoRedZone = CodeGenOpts.DisableRedZone; + Options.InstrProfileOutput = CodeGenOpts.InstrProfileOutput; MPM->add(createInstrProfilingPass(Options)); } @@ -425,14 +446,12 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) { BackendArgs.push_back("-time-passes"); for (unsigned i = 0, e = CodeGenOpts.BackendOptions.size(); i != e; ++i) BackendArgs.push_back(CodeGenOpts.BackendOptions[i].c_str()); - if (CodeGenOpts.NoGlobalMerge) - BackendArgs.push_back("-enable-global-merge=false"); BackendArgs.push_back(nullptr); llvm::cl::ParseCommandLineOptions(BackendArgs.size() - 1, BackendArgs.data()); std::string FeaturesStr; - if (TargetOpts.Features.size()) { + if (!TargetOpts.Features.empty()) { SubtargetFeatures Features; for (std::vector<std::string>::const_iterator it = TargetOpts.Features.begin(), @@ -472,15 +491,6 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) { if (CodeGenOpts.CompressDebugSections) Options.CompressDebugSections = true; - // Set frame pointer elimination mode. - if (!CodeGenOpts.DisableFPElim) { - Options.NoFramePointerElim = false; - } else if (CodeGenOpts.OmitLeafFramePointer) { - Options.NoFramePointerElim = false; - } else { - Options.NoFramePointerElim = true; - } - if (CodeGenOpts.UseInitArray) Options.UseInitArray = true; @@ -512,13 +522,13 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) { Options.NoNaNsFPMath = CodeGenOpts.NoNaNsFPMath; Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; Options.UnsafeFPMath = CodeGenOpts.UnsafeFPMath; - Options.UseSoftFloat = CodeGenOpts.SoftFloat; Options.StackAlignmentOverride = CodeGenOpts.StackAlignment; Options.DisableTailCalls = CodeGenOpts.DisableTailCalls; Options.TrapFuncName = CodeGenOpts.TrapFuncName; Options.PositionIndependentExecutable = LangOpts.PIELevel != 0; Options.FunctionSections = CodeGenOpts.FunctionSections; Options.DataSections = CodeGenOpts.DataSections; + Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames; Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll; Options.MCOptions.MCSaveTempLabels = CodeGenOpts.SaveTempLabels; @@ -536,17 +546,16 @@ TargetMachine *EmitAssemblyHelper::CreateTargetMachine(bool MustCreateTM) { } bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, - formatted_raw_ostream &OS) { + raw_pwrite_stream &OS) { // Create the code generator passes. - PassManager *PM = getCodeGenPasses(); + legacy::PassManager *PM = getCodeGenPasses(); // Add LibraryInfo. llvm::Triple TargetTriple(TheModule->getTargetTriple()); - PM->add(createTLI(TargetTriple, CodeGenOpts)); - - // Add Target specific analysis passes. - TM->addAnalysisPasses(*PM); + std::unique_ptr<TargetLibraryInfoImpl> TLII( + createTLII(TargetTriple, CodeGenOpts)); + PM->add(new TargetLibraryInfoWrapperPass(*TLII)); // Normal mode, emit a .s or .o file by running the code generator. Note, // this also adds codegenerator level optimization passes. @@ -561,8 +570,7 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, // Add ObjC ARC final-cleanup optimizations. This is done as part of the // "codegen" passes so that it isn't run multiple times when there is // inlining happening. - if (LangOpts.ObjCAutoRefCount && - CodeGenOpts.OptimizationLevel > 0) + if (CodeGenOpts.OptimizationLevel > 0) PM->add(createObjCARCContractPass()); if (TM->addPassesToEmitFile(*PM, OS, CGFT, @@ -574,9 +582,9 @@ bool EmitAssemblyHelper::AddEmitPasses(BackendAction Action, return true; } -void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) { +void EmitAssemblyHelper::EmitAssembly(BackendAction Action, + raw_pwrite_stream *OS) { TimeRegion Region(llvm::TimePassesIsEnabled ? &CodeGenerationTime : nullptr); - llvm::formatted_raw_ostream FormattedOS; bool UsesCodeGen = (Action != Backend_EmitNothing && Action != Backend_EmitBC && @@ -592,17 +600,17 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, raw_ostream *OS) { break; case Backend_EmitBC: - getPerModulePasses()->add(createBitcodeWriterPass(*OS)); + getPerModulePasses()->add( + createBitcodeWriterPass(*OS, CodeGenOpts.EmitLLVMUseLists)); break; case Backend_EmitLL: - FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM); - getPerModulePasses()->add(createPrintModulePass(FormattedOS)); + getPerModulePasses()->add( + createPrintModulePass(*OS, "", CodeGenOpts.EmitLLVMUseLists)); break; default: - FormattedOS.setStream(*OS, formatted_raw_ostream::PRESERVE_STREAM); - if (!AddEmitPasses(Action, FormattedOS)) + if (!AddEmitPasses(Action, *OS)) return; } @@ -639,7 +647,7 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags, const clang::TargetOptions &TOpts, const LangOptions &LOpts, StringRef TDesc, Module *M, BackendAction Action, - raw_ostream *OS) { + raw_pwrite_stream *OS) { EmitAssemblyHelper AsmHelper(Diags, CGOpts, TOpts, LOpts, M); AsmHelper.EmitAssembly(Action, OS); @@ -647,9 +655,8 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags, // If an optional clang TargetInfo description string was passed in, use it to // verify the LLVM TargetMachine's DataLayout. if (AsmHelper.TM && !TDesc.empty()) { - std::string DLDesc = AsmHelper.TM->getSubtargetImpl() - ->getDataLayout() - ->getStringRepresentation(); + std::string DLDesc = + AsmHelper.TM->getDataLayout()->getStringRepresentation(); if (DLDesc != TDesc) { unsigned DiagID = Diags.getCustomDiagID( DiagnosticsEngine::Error, "backend data layout '%0' does not match " diff --git a/lib/CodeGen/CGAtomic.cpp b/lib/CodeGen/CGAtomic.cpp index daac174c8e0c..da82249fe114 100644 --- a/lib/CodeGen/CGAtomic.cpp +++ b/lib/CodeGen/CGAtomic.cpp @@ -13,6 +13,7 @@ #include "CodeGenFunction.h" #include "CGCall.h" +#include "CGRecordLayout.h" #include "CodeGenModule.h" #include "clang/AST/ASTContext.h" #include "clang/CodeGen/CGFunctionInfo.h" @@ -36,34 +37,94 @@ namespace { CharUnits LValueAlign; TypeEvaluationKind EvaluationKind; bool UseLibcall; + LValue LVal; + CGBitFieldInfo BFI; public: - AtomicInfo(CodeGenFunction &CGF, LValue &lvalue) : CGF(CGF) { - assert(lvalue.isSimple()); - - AtomicTy = lvalue.getType(); - ValueTy = AtomicTy->castAs<AtomicType>()->getValueType(); - EvaluationKind = CGF.getEvaluationKind(ValueTy); - + AtomicInfo(CodeGenFunction &CGF, LValue &lvalue) + : CGF(CGF), AtomicSizeInBits(0), ValueSizeInBits(0), + EvaluationKind(TEK_Scalar), UseLibcall(true) { + assert(!lvalue.isGlobalReg()); ASTContext &C = CGF.getContext(); - - uint64_t ValueAlignInBits; - uint64_t AtomicAlignInBits; - TypeInfo ValueTI = C.getTypeInfo(ValueTy); - ValueSizeInBits = ValueTI.Width; - ValueAlignInBits = ValueTI.Align; - - TypeInfo AtomicTI = C.getTypeInfo(AtomicTy); - AtomicSizeInBits = AtomicTI.Width; - AtomicAlignInBits = AtomicTI.Align; - - assert(ValueSizeInBits <= AtomicSizeInBits); - assert(ValueAlignInBits <= AtomicAlignInBits); - - AtomicAlign = C.toCharUnitsFromBits(AtomicAlignInBits); - ValueAlign = C.toCharUnitsFromBits(ValueAlignInBits); - if (lvalue.getAlignment().isZero()) - lvalue.setAlignment(AtomicAlign); - + if (lvalue.isSimple()) { + AtomicTy = lvalue.getType(); + if (auto *ATy = AtomicTy->getAs<AtomicType>()) + ValueTy = ATy->getValueType(); + else + ValueTy = AtomicTy; + EvaluationKind = CGF.getEvaluationKind(ValueTy); + + uint64_t ValueAlignInBits; + uint64_t AtomicAlignInBits; + TypeInfo ValueTI = C.getTypeInfo(ValueTy); + ValueSizeInBits = ValueTI.Width; + ValueAlignInBits = ValueTI.Align; + + TypeInfo AtomicTI = C.getTypeInfo(AtomicTy); + AtomicSizeInBits = AtomicTI.Width; + AtomicAlignInBits = AtomicTI.Align; + + assert(ValueSizeInBits <= AtomicSizeInBits); + assert(ValueAlignInBits <= AtomicAlignInBits); + + AtomicAlign = C.toCharUnitsFromBits(AtomicAlignInBits); + ValueAlign = C.toCharUnitsFromBits(ValueAlignInBits); + if (lvalue.getAlignment().isZero()) + lvalue.setAlignment(AtomicAlign); + + LVal = lvalue; + } else if (lvalue.isBitField()) { + ValueTy = lvalue.getType(); + ValueSizeInBits = C.getTypeSize(ValueTy); + auto &OrigBFI = lvalue.getBitFieldInfo(); + auto Offset = OrigBFI.Offset % C.toBits(lvalue.getAlignment()); + AtomicSizeInBits = C.toBits( + C.toCharUnitsFromBits(Offset + OrigBFI.Size + C.getCharWidth() - 1) + .RoundUpToAlignment(lvalue.getAlignment())); + auto VoidPtrAddr = CGF.EmitCastToVoidPtr(lvalue.getBitFieldAddr()); + auto OffsetInChars = + (C.toCharUnitsFromBits(OrigBFI.Offset) / lvalue.getAlignment()) * + lvalue.getAlignment(); + VoidPtrAddr = CGF.Builder.CreateConstGEP1_64( + VoidPtrAddr, OffsetInChars.getQuantity()); + auto Addr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + VoidPtrAddr, + CGF.Builder.getIntNTy(AtomicSizeInBits)->getPointerTo(), + "atomic_bitfield_base"); + BFI = OrigBFI; + BFI.Offset = Offset; + BFI.StorageSize = AtomicSizeInBits; + LVal = LValue::MakeBitfield(Addr, BFI, lvalue.getType(), + lvalue.getAlignment()); + LVal.setTBAAInfo(lvalue.getTBAAInfo()); + AtomicTy = C.getIntTypeForBitwidth(AtomicSizeInBits, OrigBFI.IsSigned); + if (AtomicTy.isNull()) { + llvm::APInt Size( + /*numBits=*/32, + C.toCharUnitsFromBits(AtomicSizeInBits).getQuantity()); + AtomicTy = C.getConstantArrayType(C.CharTy, Size, ArrayType::Normal, + /*IndexTypeQuals=*/0); + } + AtomicAlign = ValueAlign = lvalue.getAlignment(); + } else if (lvalue.isVectorElt()) { + ValueTy = lvalue.getType()->getAs<VectorType>()->getElementType(); + ValueSizeInBits = C.getTypeSize(ValueTy); + AtomicTy = lvalue.getType(); + AtomicSizeInBits = C.getTypeSize(AtomicTy); + AtomicAlign = ValueAlign = lvalue.getAlignment(); + LVal = lvalue; + } else { + assert(lvalue.isExtVectorElt()); + ValueTy = lvalue.getType(); + ValueSizeInBits = C.getTypeSize(ValueTy); + AtomicTy = ValueTy = CGF.getContext().getExtVectorType( + lvalue.getType(), lvalue.getExtVectorAddr() + ->getType() + ->getPointerElementType() + ->getVectorNumElements()); + AtomicSizeInBits = C.getTypeSize(AtomicTy); + AtomicAlign = ValueAlign = lvalue.getAlignment(); + LVal = lvalue; + } UseLibcall = !C.getTargetInfo().hasBuiltinAtomic( AtomicSizeInBits, C.toBits(lvalue.getAlignment())); } @@ -76,6 +137,17 @@ namespace { uint64_t getValueSizeInBits() const { return ValueSizeInBits; } TypeEvaluationKind getEvaluationKind() const { return EvaluationKind; } bool shouldUseLibcall() const { return UseLibcall; } + const LValue &getAtomicLValue() const { return LVal; } + llvm::Value *getAtomicAddress() const { + if (LVal.isSimple()) + return LVal.getAddress(); + else if (LVal.isBitField()) + return LVal.getBitFieldAddr(); + else if (LVal.isVectorElt()) + return LVal.getVectorAddr(); + assert(LVal.isExtVectorElt()); + return LVal.getExtVectorAddr(); + } /// Is the atomic size larger than the underlying value type? /// @@ -87,7 +159,7 @@ namespace { return (ValueSizeInBits != AtomicSizeInBits); } - bool emitMemSetZeroIfNecessary(LValue dest) const; + bool emitMemSetZeroIfNecessary() const; llvm::Value *getAtomicSizeValue() const { CharUnits size = CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits); @@ -99,37 +171,141 @@ namespace { llvm::Value *emitCastToAtomicIntPointer(llvm::Value *addr) const; /// Turn an atomic-layout object into an r-value. - RValue convertTempToRValue(llvm::Value *addr, - AggValueSlot resultSlot, - SourceLocation loc) const; + RValue convertTempToRValue(llvm::Value *addr, AggValueSlot resultSlot, + SourceLocation loc, bool AsValue) const; /// \brief Converts a rvalue to integer value. llvm::Value *convertRValueToInt(RValue RVal) const; - RValue convertIntToValue(llvm::Value *IntVal, AggValueSlot ResultSlot, - SourceLocation Loc) const; + RValue ConvertIntToValueOrAtomic(llvm::Value *IntVal, + AggValueSlot ResultSlot, + SourceLocation Loc, bool AsValue) const; /// Copy an atomic r-value into atomic-layout memory. - void emitCopyIntoMemory(RValue rvalue, LValue lvalue) const; + void emitCopyIntoMemory(RValue rvalue) const; /// Project an l-value down to the value field. - LValue projectValue(LValue lvalue) const { - llvm::Value *addr = lvalue.getAddress(); + LValue projectValue() const { + assert(LVal.isSimple()); + llvm::Value *addr = getAtomicAddress(); if (hasPadding()) - addr = CGF.Builder.CreateStructGEP(addr, 0); + addr = CGF.Builder.CreateStructGEP(nullptr, addr, 0); - return LValue::MakeAddr(addr, getValueType(), lvalue.getAlignment(), - CGF.getContext(), lvalue.getTBAAInfo()); + return LValue::MakeAddr(addr, getValueType(), LVal.getAlignment(), + CGF.getContext(), LVal.getTBAAInfo()); } + /// \brief Emits atomic load. + /// \returns Loaded value. + RValue EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc, + bool AsValue, llvm::AtomicOrdering AO, + bool IsVolatile); + + /// \brief Emits atomic compare-and-exchange sequence. + /// \param Expected Expected value. + /// \param Desired Desired value. + /// \param Success Atomic ordering for success operation. + /// \param Failure Atomic ordering for failed operation. + /// \param IsWeak true if atomic operation is weak, false otherwise. + /// \returns Pair of values: previous value from storage (value type) and + /// boolean flag (i1 type) with true if success and false otherwise. + std::pair<RValue, llvm::Value *> EmitAtomicCompareExchange( + RValue Expected, RValue Desired, + llvm::AtomicOrdering Success = llvm::SequentiallyConsistent, + llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent, + bool IsWeak = false); + + /// \brief Emits atomic update. + /// \param AO Atomic ordering. + /// \param UpdateOp Update operation for the current lvalue. + void EmitAtomicUpdate(llvm::AtomicOrdering AO, + const llvm::function_ref<RValue(RValue)> &UpdateOp, + bool IsVolatile); + /// \brief Emits atomic update. + /// \param AO Atomic ordering. + void EmitAtomicUpdate(llvm::AtomicOrdering AO, RValue UpdateRVal, + bool IsVolatile); + /// Materialize an atomic r-value in atomic-layout memory. llvm::Value *materializeRValue(RValue rvalue) const; + /// \brief Translates LLVM atomic ordering to GNU atomic ordering for + /// libcalls. + static AtomicExpr::AtomicOrderingKind + translateAtomicOrdering(const llvm::AtomicOrdering AO); + private: bool requiresMemSetZero(llvm::Type *type) const; + + /// \brief Creates temp alloca for intermediate operations on atomic value. + llvm::Value *CreateTempAlloca() const; + + /// \brief Emits atomic load as a libcall. + void EmitAtomicLoadLibcall(llvm::Value *AddForLoaded, + llvm::AtomicOrdering AO, bool IsVolatile); + /// \brief Emits atomic load as LLVM instruction. + llvm::Value *EmitAtomicLoadOp(llvm::AtomicOrdering AO, bool IsVolatile); + /// \brief Emits atomic compare-and-exchange op as a libcall. + llvm::Value *EmitAtomicCompareExchangeLibcall( + llvm::Value *ExpectedAddr, llvm::Value *DesiredAddr, + llvm::AtomicOrdering Success = llvm::SequentiallyConsistent, + llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent); + /// \brief Emits atomic compare-and-exchange op as LLVM instruction. + std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeOp( + llvm::Value *ExpectedVal, llvm::Value *DesiredVal, + llvm::AtomicOrdering Success = llvm::SequentiallyConsistent, + llvm::AtomicOrdering Failure = llvm::SequentiallyConsistent, + bool IsWeak = false); + /// \brief Emit atomic update as libcalls. + void + EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO, + const llvm::function_ref<RValue(RValue)> &UpdateOp, + bool IsVolatile); + /// \brief Emit atomic update as LLVM instructions. + void EmitAtomicUpdateOp(llvm::AtomicOrdering AO, + const llvm::function_ref<RValue(RValue)> &UpdateOp, + bool IsVolatile); + /// \brief Emit atomic update as libcalls. + void EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO, RValue UpdateRVal, + bool IsVolatile); + /// \brief Emit atomic update as LLVM instructions. + void EmitAtomicUpdateOp(llvm::AtomicOrdering AO, RValue UpdateRal, + bool IsVolatile); }; } +AtomicExpr::AtomicOrderingKind +AtomicInfo::translateAtomicOrdering(const llvm::AtomicOrdering AO) { + switch (AO) { + case llvm::Unordered: + case llvm::NotAtomic: + case llvm::Monotonic: + return AtomicExpr::AO_ABI_memory_order_relaxed; + case llvm::Acquire: + return AtomicExpr::AO_ABI_memory_order_acquire; + case llvm::Release: + return AtomicExpr::AO_ABI_memory_order_release; + case llvm::AcquireRelease: + return AtomicExpr::AO_ABI_memory_order_acq_rel; + case llvm::SequentiallyConsistent: + return AtomicExpr::AO_ABI_memory_order_seq_cst; + } + llvm_unreachable("Unhandled AtomicOrdering"); +} + +llvm::Value *AtomicInfo::CreateTempAlloca() const { + auto *TempAlloca = CGF.CreateMemTemp( + (LVal.isBitField() && ValueSizeInBits > AtomicSizeInBits) ? ValueTy + : AtomicTy, + "atomic-temp"); + TempAlloca->setAlignment(getAtomicAlignment().getQuantity()); + // Cast to pointer to value type for bitfields. + if (LVal.isBitField()) + return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + TempAlloca, getAtomicAddress()->getType()); + return TempAlloca; +} + static RValue emitAtomicLibcall(CodeGenFunction &CGF, StringRef fnName, QualType resultType, @@ -172,14 +348,16 @@ bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const { llvm_unreachable("bad evaluation kind"); } -bool AtomicInfo::emitMemSetZeroIfNecessary(LValue dest) const { - llvm::Value *addr = dest.getAddress(); +bool AtomicInfo::emitMemSetZeroIfNecessary() const { + assert(LVal.isSimple()); + llvm::Value *addr = LVal.getAddress(); if (!requiresMemSetZero(addr->getType()->getPointerElementType())) return false; - CGF.Builder.CreateMemSet(addr, llvm::ConstantInt::get(CGF.Int8Ty, 0), - AtomicSizeInBits / 8, - dest.getAlignment().getQuantity()); + CGF.Builder.CreateMemSet( + addr, llvm::ConstantInt::get(CGF.Int8Ty, 0), + CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(), + LVal.getAlignment().getQuantity()); return true; } @@ -901,29 +1079,53 @@ llvm::Value *AtomicInfo::emitCastToAtomicIntPointer(llvm::Value *addr) const { RValue AtomicInfo::convertTempToRValue(llvm::Value *addr, AggValueSlot resultSlot, - SourceLocation loc) const { - if (EvaluationKind == TEK_Aggregate) - return resultSlot.asRValue(); - - // Drill into the padding structure if we have one. - if (hasPadding()) - addr = CGF.Builder.CreateStructGEP(addr, 0); - - // Otherwise, just convert the temporary to an r-value using the - // normal conversion routine. - return CGF.convertTempToRValue(addr, getValueType(), loc); + SourceLocation loc, bool AsValue) const { + if (LVal.isSimple()) { + if (EvaluationKind == TEK_Aggregate) + return resultSlot.asRValue(); + + // Drill into the padding structure if we have one. + if (hasPadding()) + addr = CGF.Builder.CreateStructGEP(nullptr, addr, 0); + + // Otherwise, just convert the temporary to an r-value using the + // normal conversion routine. + return CGF.convertTempToRValue(addr, getValueType(), loc); + } + if (!AsValue) + // Get RValue from temp memory as atomic for non-simple lvalues + return RValue::get( + CGF.Builder.CreateAlignedLoad(addr, AtomicAlign.getQuantity())); + if (LVal.isBitField()) + return CGF.EmitLoadOfBitfieldLValue(LValue::MakeBitfield( + addr, LVal.getBitFieldInfo(), LVal.getType(), LVal.getAlignment())); + if (LVal.isVectorElt()) + return CGF.EmitLoadOfLValue(LValue::MakeVectorElt(addr, LVal.getVectorIdx(), + LVal.getType(), + LVal.getAlignment()), + loc); + assert(LVal.isExtVectorElt()); + return CGF.EmitLoadOfExtVectorElementLValue(LValue::MakeExtVectorElt( + addr, LVal.getExtVectorElts(), LVal.getType(), LVal.getAlignment())); } -RValue AtomicInfo::convertIntToValue(llvm::Value *IntVal, - AggValueSlot ResultSlot, - SourceLocation Loc) const { +RValue AtomicInfo::ConvertIntToValueOrAtomic(llvm::Value *IntVal, + AggValueSlot ResultSlot, + SourceLocation Loc, + bool AsValue) const { // Try not to in some easy cases. assert(IntVal->getType()->isIntegerTy() && "Expected integer value"); - if (getEvaluationKind() == TEK_Scalar && !hasPadding()) { - auto *ValTy = CGF.ConvertTypeForMem(ValueTy); + if (getEvaluationKind() == TEK_Scalar && + (((!LVal.isBitField() || + LVal.getBitFieldInfo().Size == ValueSizeInBits) && + !hasPadding()) || + !AsValue)) { + auto *ValTy = AsValue + ? CGF.ConvertTypeForMem(ValueTy) + : getAtomicAddress()->getType()->getPointerElementType(); if (ValTy->isIntegerTy()) { assert(IntVal->getType() == ValTy && "Different integer types."); - return RValue::get(IntVal); + return RValue::get(CGF.EmitFromMemory(IntVal, ValueTy)); } else if (ValTy->isPointerTy()) return RValue::get(CGF.Builder.CreateIntToPtr(IntVal, ValTy)); else if (llvm::CastInst::isBitCastable(IntVal->getType(), ValTy)) @@ -935,13 +1137,13 @@ RValue AtomicInfo::convertIntToValue(llvm::Value *IntVal, llvm::Value *Temp; bool TempIsVolatile = false; CharUnits TempAlignment; - if (getEvaluationKind() == TEK_Aggregate) { + if (AsValue && getEvaluationKind() == TEK_Aggregate) { assert(!ResultSlot.isIgnored()); Temp = ResultSlot.getAddr(); TempAlignment = getValueAlignment(); TempIsVolatile = ResultSlot.isVolatile(); } else { - Temp = CGF.CreateMemTemp(getAtomicType(), "atomic-temp"); + Temp = CreateTempAlloca(); TempAlignment = getAtomicAlignment(); } @@ -950,93 +1152,146 @@ RValue AtomicInfo::convertIntToValue(llvm::Value *IntVal, CGF.Builder.CreateAlignedStore(IntVal, CastTemp, TempAlignment.getQuantity()) ->setVolatile(TempIsVolatile); - return convertTempToRValue(Temp, ResultSlot, Loc); + return convertTempToRValue(Temp, ResultSlot, Loc, AsValue); } -/// Emit a load from an l-value of atomic type. Note that the r-value -/// we produce is an r-value of the atomic *value* type. -RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc, - AggValueSlot resultSlot) { - AtomicInfo atomics(*this, src); +void AtomicInfo::EmitAtomicLoadLibcall(llvm::Value *AddForLoaded, + llvm::AtomicOrdering AO, bool) { + // void __atomic_load(size_t size, void *mem, void *return, int order); + CallArgList Args; + Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType()); + Args.add(RValue::get(CGF.EmitCastToVoidPtr(getAtomicAddress())), + CGF.getContext().VoidPtrTy); + Args.add(RValue::get(CGF.EmitCastToVoidPtr(AddForLoaded)), + CGF.getContext().VoidPtrTy); + Args.add(RValue::get( + llvm::ConstantInt::get(CGF.IntTy, translateAtomicOrdering(AO))), + CGF.getContext().IntTy); + emitAtomicLibcall(CGF, "__atomic_load", CGF.getContext().VoidTy, Args); +} - // Check whether we should use a library call. - if (atomics.shouldUseLibcall()) { - llvm::Value *tempAddr; - if (!resultSlot.isIgnored()) { - assert(atomics.getEvaluationKind() == TEK_Aggregate); - tempAddr = resultSlot.getAddr(); - } else { - tempAddr = CreateMemTemp(atomics.getAtomicType(), "atomic-load-temp"); - } +llvm::Value *AtomicInfo::EmitAtomicLoadOp(llvm::AtomicOrdering AO, + bool IsVolatile) { + // Okay, we're doing this natively. + llvm::Value *Addr = emitCastToAtomicIntPointer(getAtomicAddress()); + llvm::LoadInst *Load = CGF.Builder.CreateLoad(Addr, "atomic-load"); + Load->setAtomic(AO); - // void __atomic_load(size_t size, void *mem, void *return, int order); - CallArgList args; - args.add(RValue::get(atomics.getAtomicSizeValue()), - getContext().getSizeType()); - args.add(RValue::get(EmitCastToVoidPtr(src.getAddress())), - getContext().VoidPtrTy); - args.add(RValue::get(EmitCastToVoidPtr(tempAddr)), - getContext().VoidPtrTy); - args.add(RValue::get(llvm::ConstantInt::get( - IntTy, AtomicExpr::AO_ABI_memory_order_seq_cst)), - getContext().IntTy); - emitAtomicLibcall(*this, "__atomic_load", getContext().VoidTy, args); + // Other decoration. + Load->setAlignment(getAtomicAlignment().getQuantity()); + if (IsVolatile) + Load->setVolatile(true); + if (LVal.getTBAAInfo()) + CGF.CGM.DecorateInstruction(Load, LVal.getTBAAInfo()); + return Load; +} + +/// An LValue is a candidate for having its loads and stores be made atomic if +/// we are operating under /volatile:ms *and* the LValue itself is volatile and +/// performing such an operation can be performed without a libcall. +bool CodeGenFunction::LValueIsSuitableForInlineAtomic(LValue LV) { + AtomicInfo AI(*this, LV); + bool IsVolatile = LV.isVolatile() || hasVolatileMember(LV.getType()); + // An atomic is inline if we don't need to use a libcall. + bool AtomicIsInline = !AI.shouldUseLibcall(); + return CGM.getCodeGenOpts().MSVolatile && IsVolatile && AtomicIsInline; +} - // Produce the r-value. - return atomics.convertTempToRValue(tempAddr, resultSlot, loc); +/// An type is a candidate for having its loads and stores be made atomic if +/// we are operating under /volatile:ms *and* we know the access is volatile and +/// performing such an operation can be performed without a libcall. +bool CodeGenFunction::typeIsSuitableForInlineAtomic(QualType Ty, + bool IsVolatile) const { + // An atomic is inline if we don't need to use a libcall (e.g. it is builtin). + bool AtomicIsInline = getContext().getTargetInfo().hasBuiltinAtomic( + getContext().getTypeSize(Ty), getContext().getTypeAlign(Ty)); + return CGM.getCodeGenOpts().MSVolatile && IsVolatile && AtomicIsInline; +} + +RValue CodeGenFunction::EmitAtomicLoad(LValue LV, SourceLocation SL, + AggValueSlot Slot) { + llvm::AtomicOrdering AO; + bool IsVolatile = LV.isVolatileQualified(); + if (LV.getType()->isAtomicType()) { + AO = llvm::SequentiallyConsistent; + } else { + AO = llvm::Acquire; + IsVolatile = true; } + return EmitAtomicLoad(LV, SL, AO, IsVolatile, Slot); +} - // Okay, we're doing this natively. - llvm::Value *addr = atomics.emitCastToAtomicIntPointer(src.getAddress()); - llvm::LoadInst *load = Builder.CreateLoad(addr, "atomic-load"); - load->setAtomic(llvm::SequentiallyConsistent); +RValue AtomicInfo::EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc, + bool AsValue, llvm::AtomicOrdering AO, + bool IsVolatile) { + // Check whether we should use a library call. + if (shouldUseLibcall()) { + llvm::Value *TempAddr; + if (LVal.isSimple() && !ResultSlot.isIgnored()) { + assert(getEvaluationKind() == TEK_Aggregate); + TempAddr = ResultSlot.getAddr(); + } else + TempAddr = CreateTempAlloca(); + + EmitAtomicLoadLibcall(TempAddr, AO, IsVolatile); + + // Okay, turn that back into the original value or whole atomic (for + // non-simple lvalues) type. + return convertTempToRValue(TempAddr, ResultSlot, Loc, AsValue); + } - // Other decoration. - load->setAlignment(src.getAlignment().getQuantity()); - if (src.isVolatileQualified()) - load->setVolatile(true); - if (src.getTBAAInfo()) - CGM.DecorateInstruction(load, src.getTBAAInfo()); + // Okay, we're doing this natively. + auto *Load = EmitAtomicLoadOp(AO, IsVolatile); // If we're ignoring an aggregate return, don't do anything. - if (atomics.getEvaluationKind() == TEK_Aggregate && resultSlot.isIgnored()) + if (getEvaluationKind() == TEK_Aggregate && ResultSlot.isIgnored()) return RValue::getAggregate(nullptr, false); - // Okay, turn that back into the original value type. - return atomics.convertIntToValue(load, resultSlot, loc); + // Okay, turn that back into the original value or atomic (for non-simple + // lvalues) type. + return ConvertIntToValueOrAtomic(Load, ResultSlot, Loc, AsValue); } - +/// Emit a load from an l-value of atomic type. Note that the r-value +/// we produce is an r-value of the atomic *value* type. +RValue CodeGenFunction::EmitAtomicLoad(LValue src, SourceLocation loc, + llvm::AtomicOrdering AO, bool IsVolatile, + AggValueSlot resultSlot) { + AtomicInfo Atomics(*this, src); + return Atomics.EmitAtomicLoad(resultSlot, loc, /*AsValue=*/true, AO, + IsVolatile); +} /// Copy an r-value into memory as part of storing to an atomic type. /// This needs to create a bit-pattern suitable for atomic operations. -void AtomicInfo::emitCopyIntoMemory(RValue rvalue, LValue dest) const { +void AtomicInfo::emitCopyIntoMemory(RValue rvalue) const { + assert(LVal.isSimple()); // If we have an r-value, the rvalue should be of the atomic type, // which means that the caller is responsible for having zeroed // any padding. Just do an aggregate copy of that type. if (rvalue.isAggregate()) { - CGF.EmitAggregateCopy(dest.getAddress(), + CGF.EmitAggregateCopy(getAtomicAddress(), rvalue.getAggregateAddr(), getAtomicType(), (rvalue.isVolatileQualified() - || dest.isVolatileQualified()), - dest.getAlignment()); + || LVal.isVolatileQualified()), + LVal.getAlignment()); return; } // Okay, otherwise we're copying stuff. // Zero out the buffer if necessary. - emitMemSetZeroIfNecessary(dest); + emitMemSetZeroIfNecessary(); // Drill past the padding if present. - dest = projectValue(dest); + LValue TempLVal = projectValue(); // Okay, store the rvalue in. if (rvalue.isScalar()) { - CGF.EmitStoreOfScalar(rvalue.getScalarVal(), dest, /*init*/ true); + CGF.EmitStoreOfScalar(rvalue.getScalarVal(), TempLVal, /*init*/ true); } else { - CGF.EmitStoreOfComplex(rvalue.getComplexVal(), dest, /*init*/ true); + CGF.EmitStoreOfComplex(rvalue.getComplexVal(), TempLVal, /*init*/ true); } } @@ -1050,22 +1305,24 @@ llvm::Value *AtomicInfo::materializeRValue(RValue rvalue) const { return rvalue.getAggregateAddr(); // Otherwise, make a temporary and materialize into it. - llvm::Value *temp = CGF.CreateMemTemp(getAtomicType(), "atomic-store-temp"); - LValue tempLV = CGF.MakeAddrLValue(temp, getAtomicType(), getAtomicAlignment()); - emitCopyIntoMemory(rvalue, tempLV); - return temp; + LValue TempLV = CGF.MakeAddrLValue(CreateTempAlloca(), getAtomicType(), + getAtomicAlignment()); + AtomicInfo Atomics(CGF, TempLV); + Atomics.emitCopyIntoMemory(rvalue); + return TempLV.getAddress(); } llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const { // If we've got a scalar value of the right size, try to avoid going // through memory. - if (RVal.isScalar() && !hasPadding()) { + if (RVal.isScalar() && (!hasPadding() || !LVal.isSimple())) { llvm::Value *Value = RVal.getScalarVal(); if (isa<llvm::IntegerType>(Value->getType())) - return Value; + return CGF.EmitToMemory(Value, ValueTy); else { - llvm::IntegerType *InputIntTy = - llvm::IntegerType::get(CGF.getLLVMContext(), getValueSizeInBits()); + llvm::IntegerType *InputIntTy = llvm::IntegerType::get( + CGF.getLLVMContext(), + LVal.isSimple() ? getValueSizeInBits() : getAtomicSizeInBits()); if (isa<llvm::PointerType>(Value->getType())) return CGF.Builder.CreatePtrToInt(Value, InputIntTy); else if (llvm::BitCastInst::isBitCastable(Value->getType(), InputIntTy)) @@ -1082,12 +1339,324 @@ llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const { getAtomicAlignment().getQuantity()); } +std::pair<llvm::Value *, llvm::Value *> AtomicInfo::EmitAtomicCompareExchangeOp( + llvm::Value *ExpectedVal, llvm::Value *DesiredVal, + llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak) { + // Do the atomic store. + auto *Addr = emitCastToAtomicIntPointer(getAtomicAddress()); + auto *Inst = CGF.Builder.CreateAtomicCmpXchg(Addr, ExpectedVal, DesiredVal, + Success, Failure); + // Other decoration. + Inst->setVolatile(LVal.isVolatileQualified()); + Inst->setWeak(IsWeak); + + // Okay, turn that back into the original value type. + auto *PreviousVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/0); + auto *SuccessFailureVal = CGF.Builder.CreateExtractValue(Inst, /*Idxs=*/1); + return std::make_pair(PreviousVal, SuccessFailureVal); +} + +llvm::Value * +AtomicInfo::EmitAtomicCompareExchangeLibcall(llvm::Value *ExpectedAddr, + llvm::Value *DesiredAddr, + llvm::AtomicOrdering Success, + llvm::AtomicOrdering Failure) { + // bool __atomic_compare_exchange(size_t size, void *obj, void *expected, + // void *desired, int success, int failure); + CallArgList Args; + Args.add(RValue::get(getAtomicSizeValue()), CGF.getContext().getSizeType()); + Args.add(RValue::get(CGF.EmitCastToVoidPtr(getAtomicAddress())), + CGF.getContext().VoidPtrTy); + Args.add(RValue::get(CGF.EmitCastToVoidPtr(ExpectedAddr)), + CGF.getContext().VoidPtrTy); + Args.add(RValue::get(CGF.EmitCastToVoidPtr(DesiredAddr)), + CGF.getContext().VoidPtrTy); + Args.add(RValue::get(llvm::ConstantInt::get( + CGF.IntTy, translateAtomicOrdering(Success))), + CGF.getContext().IntTy); + Args.add(RValue::get(llvm::ConstantInt::get( + CGF.IntTy, translateAtomicOrdering(Failure))), + CGF.getContext().IntTy); + auto SuccessFailureRVal = emitAtomicLibcall(CGF, "__atomic_compare_exchange", + CGF.getContext().BoolTy, Args); + + return SuccessFailureRVal.getScalarVal(); +} + +std::pair<RValue, llvm::Value *> AtomicInfo::EmitAtomicCompareExchange( + RValue Expected, RValue Desired, llvm::AtomicOrdering Success, + llvm::AtomicOrdering Failure, bool IsWeak) { + if (Failure >= Success) + // Don't assert on undefined behavior. + Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(Success); + + // Check whether we should use a library call. + if (shouldUseLibcall()) { + // Produce a source address. + auto *ExpectedAddr = materializeRValue(Expected); + auto *DesiredAddr = materializeRValue(Desired); + auto *Res = EmitAtomicCompareExchangeLibcall(ExpectedAddr, DesiredAddr, + Success, Failure); + return std::make_pair( + convertTempToRValue(ExpectedAddr, AggValueSlot::ignored(), + SourceLocation(), /*AsValue=*/false), + Res); + } + + // If we've got a scalar value of the right size, try to avoid going + // through memory. + auto *ExpectedVal = convertRValueToInt(Expected); + auto *DesiredVal = convertRValueToInt(Desired); + auto Res = EmitAtomicCompareExchangeOp(ExpectedVal, DesiredVal, Success, + Failure, IsWeak); + return std::make_pair( + ConvertIntToValueOrAtomic(Res.first, AggValueSlot::ignored(), + SourceLocation(), /*AsValue=*/false), + Res.second); +} + +static void +EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics, RValue OldRVal, + const llvm::function_ref<RValue(RValue)> &UpdateOp, + llvm::Value *DesiredAddr) { + llvm::Value *Ptr = nullptr; + LValue UpdateLVal; + RValue UpRVal; + LValue AtomicLVal = Atomics.getAtomicLValue(); + LValue DesiredLVal; + if (AtomicLVal.isSimple()) { + UpRVal = OldRVal; + DesiredLVal = + LValue::MakeAddr(DesiredAddr, AtomicLVal.getType(), + AtomicLVal.getAlignment(), CGF.CGM.getContext()); + } else { + // Build new lvalue for temp address + Ptr = Atomics.materializeRValue(OldRVal); + if (AtomicLVal.isBitField()) { + UpdateLVal = + LValue::MakeBitfield(Ptr, AtomicLVal.getBitFieldInfo(), + AtomicLVal.getType(), AtomicLVal.getAlignment()); + DesiredLVal = + LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(), + AtomicLVal.getType(), AtomicLVal.getAlignment()); + } else if (AtomicLVal.isVectorElt()) { + UpdateLVal = LValue::MakeVectorElt(Ptr, AtomicLVal.getVectorIdx(), + AtomicLVal.getType(), + AtomicLVal.getAlignment()); + DesiredLVal = LValue::MakeVectorElt( + DesiredAddr, AtomicLVal.getVectorIdx(), AtomicLVal.getType(), + AtomicLVal.getAlignment()); + } else { + assert(AtomicLVal.isExtVectorElt()); + UpdateLVal = LValue::MakeExtVectorElt(Ptr, AtomicLVal.getExtVectorElts(), + AtomicLVal.getType(), + AtomicLVal.getAlignment()); + DesiredLVal = LValue::MakeExtVectorElt( + DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(), + AtomicLVal.getAlignment()); + } + UpdateLVal.setTBAAInfo(AtomicLVal.getTBAAInfo()); + DesiredLVal.setTBAAInfo(AtomicLVal.getTBAAInfo()); + UpRVal = CGF.EmitLoadOfLValue(UpdateLVal, SourceLocation()); + } + // Store new value in the corresponding memory area + RValue NewRVal = UpdateOp(UpRVal); + if (NewRVal.isScalar()) { + CGF.EmitStoreThroughLValue(NewRVal, DesiredLVal); + } else { + assert(NewRVal.isComplex()); + CGF.EmitStoreOfComplex(NewRVal.getComplexVal(), DesiredLVal, + /*isInit=*/false); + } +} + +void AtomicInfo::EmitAtomicUpdateLibcall( + llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp, + bool IsVolatile) { + auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO); + + llvm::Value *ExpectedAddr = CreateTempAlloca(); + + EmitAtomicLoadLibcall(ExpectedAddr, AO, IsVolatile); + auto *ContBB = CGF.createBasicBlock("atomic_cont"); + auto *ExitBB = CGF.createBasicBlock("atomic_exit"); + CGF.EmitBlock(ContBB); + auto *DesiredAddr = CreateTempAlloca(); + if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) || + requiresMemSetZero( + getAtomicAddress()->getType()->getPointerElementType())) { + auto *OldVal = CGF.Builder.CreateAlignedLoad( + ExpectedAddr, getAtomicAlignment().getQuantity()); + CGF.Builder.CreateAlignedStore(OldVal, DesiredAddr, + getAtomicAlignment().getQuantity()); + } + auto OldRVal = convertTempToRValue(ExpectedAddr, AggValueSlot::ignored(), + SourceLocation(), /*AsValue=*/false); + EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, DesiredAddr); + auto *Res = + EmitAtomicCompareExchangeLibcall(ExpectedAddr, DesiredAddr, AO, Failure); + CGF.Builder.CreateCondBr(Res, ExitBB, ContBB); + CGF.EmitBlock(ExitBB, /*IsFinished=*/true); +} + +void AtomicInfo::EmitAtomicUpdateOp( + llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp, + bool IsVolatile) { + auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO); + + // Do the atomic load. + auto *OldVal = EmitAtomicLoadOp(AO, IsVolatile); + // For non-simple lvalues perform compare-and-swap procedure. + auto *ContBB = CGF.createBasicBlock("atomic_cont"); + auto *ExitBB = CGF.createBasicBlock("atomic_exit"); + auto *CurBB = CGF.Builder.GetInsertBlock(); + CGF.EmitBlock(ContBB); + llvm::PHINode *PHI = CGF.Builder.CreatePHI(OldVal->getType(), + /*NumReservedValues=*/2); + PHI->addIncoming(OldVal, CurBB); + auto *NewAtomicAddr = CreateTempAlloca(); + auto *NewAtomicIntAddr = emitCastToAtomicIntPointer(NewAtomicAddr); + if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) || + requiresMemSetZero( + getAtomicAddress()->getType()->getPointerElementType())) { + CGF.Builder.CreateAlignedStore(PHI, NewAtomicIntAddr, + getAtomicAlignment().getQuantity()); + } + auto OldRVal = ConvertIntToValueOrAtomic(PHI, AggValueSlot::ignored(), + SourceLocation(), /*AsValue=*/false); + EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, NewAtomicAddr); + auto *DesiredVal = CGF.Builder.CreateAlignedLoad( + NewAtomicIntAddr, getAtomicAlignment().getQuantity()); + // Try to write new value using cmpxchg operation + auto Res = EmitAtomicCompareExchangeOp(PHI, DesiredVal, AO, Failure); + PHI->addIncoming(Res.first, CGF.Builder.GetInsertBlock()); + CGF.Builder.CreateCondBr(Res.second, ExitBB, ContBB); + CGF.EmitBlock(ExitBB, /*IsFinished=*/true); +} + +static void EmitAtomicUpdateValue(CodeGenFunction &CGF, AtomicInfo &Atomics, + RValue UpdateRVal, llvm::Value *DesiredAddr) { + LValue AtomicLVal = Atomics.getAtomicLValue(); + LValue DesiredLVal; + // Build new lvalue for temp address + if (AtomicLVal.isBitField()) { + DesiredLVal = + LValue::MakeBitfield(DesiredAddr, AtomicLVal.getBitFieldInfo(), + AtomicLVal.getType(), AtomicLVal.getAlignment()); + } else if (AtomicLVal.isVectorElt()) { + DesiredLVal = + LValue::MakeVectorElt(DesiredAddr, AtomicLVal.getVectorIdx(), + AtomicLVal.getType(), AtomicLVal.getAlignment()); + } else { + assert(AtomicLVal.isExtVectorElt()); + DesiredLVal = LValue::MakeExtVectorElt( + DesiredAddr, AtomicLVal.getExtVectorElts(), AtomicLVal.getType(), + AtomicLVal.getAlignment()); + } + DesiredLVal.setTBAAInfo(AtomicLVal.getTBAAInfo()); + // Store new value in the corresponding memory area + assert(UpdateRVal.isScalar()); + CGF.EmitStoreThroughLValue(UpdateRVal, DesiredLVal); +} + +void AtomicInfo::EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO, + RValue UpdateRVal, bool IsVolatile) { + auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO); + + llvm::Value *ExpectedAddr = CreateTempAlloca(); + + EmitAtomicLoadLibcall(ExpectedAddr, AO, IsVolatile); + auto *ContBB = CGF.createBasicBlock("atomic_cont"); + auto *ExitBB = CGF.createBasicBlock("atomic_exit"); + CGF.EmitBlock(ContBB); + auto *DesiredAddr = CreateTempAlloca(); + if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) || + requiresMemSetZero( + getAtomicAddress()->getType()->getPointerElementType())) { + auto *OldVal = CGF.Builder.CreateAlignedLoad( + ExpectedAddr, getAtomicAlignment().getQuantity()); + CGF.Builder.CreateAlignedStore(OldVal, DesiredAddr, + getAtomicAlignment().getQuantity()); + } + EmitAtomicUpdateValue(CGF, *this, UpdateRVal, DesiredAddr); + auto *Res = + EmitAtomicCompareExchangeLibcall(ExpectedAddr, DesiredAddr, AO, Failure); + CGF.Builder.CreateCondBr(Res, ExitBB, ContBB); + CGF.EmitBlock(ExitBB, /*IsFinished=*/true); +} + +void AtomicInfo::EmitAtomicUpdateOp(llvm::AtomicOrdering AO, RValue UpdateRVal, + bool IsVolatile) { + auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO); + + // Do the atomic load. + auto *OldVal = EmitAtomicLoadOp(AO, IsVolatile); + // For non-simple lvalues perform compare-and-swap procedure. + auto *ContBB = CGF.createBasicBlock("atomic_cont"); + auto *ExitBB = CGF.createBasicBlock("atomic_exit"); + auto *CurBB = CGF.Builder.GetInsertBlock(); + CGF.EmitBlock(ContBB); + llvm::PHINode *PHI = CGF.Builder.CreatePHI(OldVal->getType(), + /*NumReservedValues=*/2); + PHI->addIncoming(OldVal, CurBB); + auto *NewAtomicAddr = CreateTempAlloca(); + auto *NewAtomicIntAddr = emitCastToAtomicIntPointer(NewAtomicAddr); + if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) || + requiresMemSetZero( + getAtomicAddress()->getType()->getPointerElementType())) { + CGF.Builder.CreateAlignedStore(PHI, NewAtomicIntAddr, + getAtomicAlignment().getQuantity()); + } + EmitAtomicUpdateValue(CGF, *this, UpdateRVal, NewAtomicAddr); + auto *DesiredVal = CGF.Builder.CreateAlignedLoad( + NewAtomicIntAddr, getAtomicAlignment().getQuantity()); + // Try to write new value using cmpxchg operation + auto Res = EmitAtomicCompareExchangeOp(PHI, DesiredVal, AO, Failure); + PHI->addIncoming(Res.first, CGF.Builder.GetInsertBlock()); + CGF.Builder.CreateCondBr(Res.second, ExitBB, ContBB); + CGF.EmitBlock(ExitBB, /*IsFinished=*/true); +} + +void AtomicInfo::EmitAtomicUpdate( + llvm::AtomicOrdering AO, const llvm::function_ref<RValue(RValue)> &UpdateOp, + bool IsVolatile) { + if (shouldUseLibcall()) { + EmitAtomicUpdateLibcall(AO, UpdateOp, IsVolatile); + } else { + EmitAtomicUpdateOp(AO, UpdateOp, IsVolatile); + } +} + +void AtomicInfo::EmitAtomicUpdate(llvm::AtomicOrdering AO, RValue UpdateRVal, + bool IsVolatile) { + if (shouldUseLibcall()) { + EmitAtomicUpdateLibcall(AO, UpdateRVal, IsVolatile); + } else { + EmitAtomicUpdateOp(AO, UpdateRVal, IsVolatile); + } +} + +void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue lvalue, + bool isInit) { + bool IsVolatile = lvalue.isVolatileQualified(); + llvm::AtomicOrdering AO; + if (lvalue.getType()->isAtomicType()) { + AO = llvm::SequentiallyConsistent; + } else { + AO = llvm::Release; + IsVolatile = true; + } + return EmitAtomicStore(rvalue, lvalue, AO, IsVolatile, isInit); +} + /// Emit a store to an l-value of atomic type. /// /// Note that the r-value is expected to be an r-value *of the atomic /// type*; this means that for aggregate r-values, it should include /// storage for any padding that was necessary. -void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, bool isInit) { +void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, + llvm::AtomicOrdering AO, bool IsVolatile, + bool isInit) { // If this is an aggregate r-value, it should agree in type except // maybe for address-space qualification. assert(!rvalue.isAggregate() || @@ -1095,54 +1664,64 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, bool isInit) { == dest.getAddress()->getType()->getPointerElementType()); AtomicInfo atomics(*this, dest); + LValue LVal = atomics.getAtomicLValue(); // If this is an initialization, just put the value there normally. - if (isInit) { - atomics.emitCopyIntoMemory(rvalue, dest); - return; - } + if (LVal.isSimple()) { + if (isInit) { + atomics.emitCopyIntoMemory(rvalue); + return; + } - // Check whether we should use a library call. - if (atomics.shouldUseLibcall()) { - // Produce a source address. - llvm::Value *srcAddr = atomics.materializeRValue(rvalue); + // Check whether we should use a library call. + if (atomics.shouldUseLibcall()) { + // Produce a source address. + llvm::Value *srcAddr = atomics.materializeRValue(rvalue); - // void __atomic_store(size_t size, void *mem, void *val, int order) - CallArgList args; - args.add(RValue::get(atomics.getAtomicSizeValue()), - getContext().getSizeType()); - args.add(RValue::get(EmitCastToVoidPtr(dest.getAddress())), - getContext().VoidPtrTy); - args.add(RValue::get(EmitCastToVoidPtr(srcAddr)), - getContext().VoidPtrTy); - args.add(RValue::get(llvm::ConstantInt::get( - IntTy, AtomicExpr::AO_ABI_memory_order_seq_cst)), - getContext().IntTy); - emitAtomicLibcall(*this, "__atomic_store", getContext().VoidTy, args); + // void __atomic_store(size_t size, void *mem, void *val, int order) + CallArgList args; + args.add(RValue::get(atomics.getAtomicSizeValue()), + getContext().getSizeType()); + args.add(RValue::get(EmitCastToVoidPtr(atomics.getAtomicAddress())), + getContext().VoidPtrTy); + args.add(RValue::get(EmitCastToVoidPtr(srcAddr)), getContext().VoidPtrTy); + args.add(RValue::get(llvm::ConstantInt::get( + IntTy, AtomicInfo::translateAtomicOrdering(AO))), + getContext().IntTy); + emitAtomicLibcall(*this, "__atomic_store", getContext().VoidTy, args); + return; + } + + // Okay, we're doing this natively. + llvm::Value *intValue = atomics.convertRValueToInt(rvalue); + + // Do the atomic store. + llvm::Value *addr = + atomics.emitCastToAtomicIntPointer(atomics.getAtomicAddress()); + intValue = Builder.CreateIntCast( + intValue, addr->getType()->getPointerElementType(), /*isSigned=*/false); + llvm::StoreInst *store = Builder.CreateStore(intValue, addr); + + // Initializations don't need to be atomic. + if (!isInit) + store->setAtomic(AO); + + // Other decoration. + store->setAlignment(dest.getAlignment().getQuantity()); + if (IsVolatile) + store->setVolatile(true); + if (dest.getTBAAInfo()) + CGM.DecorateInstruction(store, dest.getTBAAInfo()); return; } - // Okay, we're doing this natively. - llvm::Value *intValue = atomics.convertRValueToInt(rvalue); - - // Do the atomic store. - llvm::Value *addr = atomics.emitCastToAtomicIntPointer(dest.getAddress()); - llvm::StoreInst *store = Builder.CreateStore(intValue, addr); - - // Initializations don't need to be atomic. - if (!isInit) store->setAtomic(llvm::SequentiallyConsistent); - - // Other decoration. - store->setAlignment(dest.getAlignment().getQuantity()); - if (dest.isVolatileQualified()) - store->setVolatile(true); - if (dest.getTBAAInfo()) - CGM.DecorateInstruction(store, dest.getTBAAInfo()); + // Emit simple atomic update operation. + atomics.EmitAtomicUpdate(AO, rvalue, IsVolatile); } /// Emit a compare-and-exchange op for atomic type. /// -std::pair<RValue, RValue> CodeGenFunction::EmitAtomicCompareExchange( +std::pair<RValue, llvm::Value *> CodeGenFunction::EmitAtomicCompareExchange( LValue Obj, RValue Expected, RValue Desired, SourceLocation Loc, llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure, bool IsWeak, AggValueSlot Slot) { @@ -1156,56 +1735,15 @@ std::pair<RValue, RValue> CodeGenFunction::EmitAtomicCompareExchange( Obj.getAddress()->getType()->getPointerElementType()); AtomicInfo Atomics(*this, Obj); - if (Failure >= Success) - // Don't assert on undefined behavior. - Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(Success); - - auto Alignment = Atomics.getValueAlignment(); - // Check whether we should use a library call. - if (Atomics.shouldUseLibcall()) { - auto *ExpectedAddr = Atomics.materializeRValue(Expected); - // Produce a source address. - auto *DesiredAddr = Atomics.materializeRValue(Desired); - // bool __atomic_compare_exchange(size_t size, void *obj, void *expected, - // void *desired, int success, int failure); - CallArgList Args; - Args.add(RValue::get(Atomics.getAtomicSizeValue()), - getContext().getSizeType()); - Args.add(RValue::get(EmitCastToVoidPtr(Obj.getAddress())), - getContext().VoidPtrTy); - Args.add(RValue::get(EmitCastToVoidPtr(ExpectedAddr)), - getContext().VoidPtrTy); - Args.add(RValue::get(EmitCastToVoidPtr(DesiredAddr)), - getContext().VoidPtrTy); - Args.add(RValue::get(llvm::ConstantInt::get(IntTy, Success)), - getContext().IntTy); - Args.add(RValue::get(llvm::ConstantInt::get(IntTy, Failure)), - getContext().IntTy); - auto SuccessFailureRVal = emitAtomicLibcall( - *this, "__atomic_compare_exchange", getContext().BoolTy, Args); - auto *PreviousVal = - Builder.CreateAlignedLoad(ExpectedAddr, Alignment.getQuantity()); - return std::make_pair(RValue::get(PreviousVal), SuccessFailureRVal); - } - - // If we've got a scalar value of the right size, try to avoid going - // through memory. - auto *ExpectedIntVal = Atomics.convertRValueToInt(Expected); - auto *DesiredIntVal = Atomics.convertRValueToInt(Desired); - - // Do the atomic store. - auto *Addr = Atomics.emitCastToAtomicIntPointer(Obj.getAddress()); - auto *Inst = Builder.CreateAtomicCmpXchg(Addr, ExpectedIntVal, DesiredIntVal, - Success, Failure); - // Other decoration. - Inst->setVolatile(Obj.isVolatileQualified()); - Inst->setWeak(IsWeak); + return Atomics.EmitAtomicCompareExchange(Expected, Desired, Success, Failure, + IsWeak); +} - // Okay, turn that back into the original value type. - auto *PreviousVal = Builder.CreateExtractValue(Inst, /*Idxs=*/0); - auto *SuccessFailureVal = Builder.CreateExtractValue(Inst, /*Idxs=*/1); - return std::make_pair(Atomics.convertIntToValue(PreviousVal, Slot, Loc), - RValue::get(SuccessFailureVal)); +void CodeGenFunction::EmitAtomicUpdate( + LValue LVal, llvm::AtomicOrdering AO, + const llvm::function_ref<RValue(RValue)> &UpdateOp, bool IsVolatile) { + AtomicInfo Atomics(*this, LVal); + Atomics.EmitAtomicUpdate(AO, UpdateOp, IsVolatile); } void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) { @@ -1214,13 +1752,13 @@ void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) { switch (atomics.getEvaluationKind()) { case TEK_Scalar: { llvm::Value *value = EmitScalarExpr(init); - atomics.emitCopyIntoMemory(RValue::get(value), dest); + atomics.emitCopyIntoMemory(RValue::get(value)); return; } case TEK_Complex: { ComplexPairTy value = EmitComplexExpr(init); - atomics.emitCopyIntoMemory(RValue::getComplex(value), dest); + atomics.emitCopyIntoMemory(RValue::getComplex(value)); return; } @@ -1229,8 +1767,8 @@ void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) { // of atomic type. bool Zeroed = false; if (!init->getType()->isAtomicType()) { - Zeroed = atomics.emitMemSetZeroIfNecessary(dest); - dest = atomics.projectValue(dest); + Zeroed = atomics.emitMemSetZeroIfNecessary(); + dest = atomics.projectValue(); } // Evaluate the expression directly into the destination. diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index b98460a9ddd8..3fd344c389a5 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -621,8 +621,8 @@ static void enterBlockScope(CodeGenFunction &CGF, BlockDecl *block) { } // GEP down to the address. - llvm::Value *addr = CGF.Builder.CreateStructGEP(blockInfo.Address, - capture.getIndex()); + llvm::Value *addr = CGF.Builder.CreateStructGEP( + blockInfo.StructureType, blockInfo.Address, capture.getIndex()); // We can use that GEP as the dominating IP. if (!blockInfo.DominatingIP) @@ -721,6 +721,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // Build the block descriptor. llvm::Constant *descriptor = buildBlockDescriptor(CGM, blockInfo); + llvm::Type *blockTy = blockInfo.StructureType; llvm::AllocaInst *blockAddr = blockInfo.Address; assert(blockAddr && "block has no address!"); @@ -732,14 +733,17 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { if (blockInfo.UsesStret) flags |= BLOCK_USE_STRET; // Initialize the block literal. - Builder.CreateStore(isa, Builder.CreateStructGEP(blockAddr, 0, "block.isa")); - Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()), - Builder.CreateStructGEP(blockAddr, 1, "block.flags")); - Builder.CreateStore(llvm::ConstantInt::get(IntTy, 0), - Builder.CreateStructGEP(blockAddr, 2, "block.reserved")); - Builder.CreateStore(blockFn, Builder.CreateStructGEP(blockAddr, 3, - "block.invoke")); - Builder.CreateStore(descriptor, Builder.CreateStructGEP(blockAddr, 4, + Builder.CreateStore( + isa, Builder.CreateStructGEP(blockTy, blockAddr, 0, "block.isa")); + Builder.CreateStore( + llvm::ConstantInt::get(IntTy, flags.getBitMask()), + Builder.CreateStructGEP(blockTy, blockAddr, 1, "block.flags")); + Builder.CreateStore( + llvm::ConstantInt::get(IntTy, 0), + Builder.CreateStructGEP(blockTy, blockAddr, 2, "block.reserved")); + Builder.CreateStore( + blockFn, Builder.CreateStructGEP(blockTy, blockAddr, 3, "block.invoke")); + Builder.CreateStore(descriptor, Builder.CreateStructGEP(blockTy, blockAddr, 4, "block.descriptor")); // Finally, capture all the values into the block. @@ -747,9 +751,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // First, 'this'. if (blockDecl->capturesCXXThis()) { - llvm::Value *addr = Builder.CreateStructGEP(blockAddr, - blockInfo.CXXThisIndex, - "block.captured-this.addr"); + llvm::Value *addr = Builder.CreateStructGEP( + blockTy, blockAddr, blockInfo.CXXThisIndex, "block.captured-this.addr"); Builder.CreateStore(LoadCXXThis(), addr); } @@ -766,9 +769,8 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // This will be a [[type]]*, except that a byref entry will just be // an i8**. - llvm::Value *blockField = - Builder.CreateStructGEP(blockAddr, capture.getIndex(), - "block.captured"); + llvm::Value *blockField = Builder.CreateStructGEP( + blockTy, blockAddr, capture.getIndex(), "block.captured"); // Compute the address of the thing we're going to move into the // block literal. @@ -779,7 +781,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { BlockInfo->getCapture(variable); // This is a [[type]]*, except that a byref entry wil just be an i8**. - src = Builder.CreateStructGEP(LoadBlockStruct(), + src = Builder.CreateStructGEP(BlockInfo->StructureType, LoadBlockStruct(), enclosingCapture.getIndex(), "block.capture.addr"); } else if (blockDecl->isConversionFromLambda()) { @@ -964,7 +966,8 @@ RValue CodeGenFunction::EmitBlockCallExpr(const CallExpr *E, Builder.CreateBitCast(Callee, BlockLiteralTy, "block.literal"); // Get the function pointer from the literal. - llvm::Value *FuncPtr = Builder.CreateStructGEP(BlockLiteral, 3); + llvm::Value *FuncPtr = Builder.CreateStructGEP( + CGM.getGenericBlockLiteralType(), BlockLiteral, 3); BlockLiteral = Builder.CreateBitCast(BlockLiteral, VoidPtrTy); @@ -1004,26 +1007,27 @@ llvm::Value *CodeGenFunction::GetAddrOfBlockDecl(const VarDecl *variable, if (capture.isConstant()) return LocalDeclMap[variable]; llvm::Value *addr = - Builder.CreateStructGEP(LoadBlockStruct(), capture.getIndex(), - "block.capture.addr"); + Builder.CreateStructGEP(BlockInfo->StructureType, LoadBlockStruct(), + capture.getIndex(), "block.capture.addr"); if (isByRef) { // addr should be a void** right now. Load, then cast the result // to byref*. addr = Builder.CreateLoad(addr); - llvm::PointerType *byrefPointerType - = llvm::PointerType::get(BuildByRefType(variable), 0); + auto *byrefType = BuildByRefType(variable); + llvm::PointerType *byrefPointerType = llvm::PointerType::get(byrefType, 0); addr = Builder.CreateBitCast(addr, byrefPointerType, "byref.addr"); // Follow the forwarding pointer. - addr = Builder.CreateStructGEP(addr, 1, "byref.forwarding"); + addr = Builder.CreateStructGEP(byrefType, addr, 1, "byref.forwarding"); addr = Builder.CreateLoad(addr, "byref.addr.forwarded"); // Cast back to byref* and GEP over to the actual object. addr = Builder.CreateBitCast(addr, byrefPointerType); - addr = Builder.CreateStructGEP(addr, getByRefValueLLVMField(variable), + addr = Builder.CreateStructGEP(byrefType, addr, + getByRefValueLLVMField(variable).second, variable->getNameAsString()); } @@ -1136,8 +1140,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, args.push_back(&selfDecl); // Now add the rest of the parameters. - for (auto i : blockDecl->params()) - args.push_back(i); + args.append(blockDecl->param_begin(), blockDecl->param_end()); // Create the function declaration. const FunctionProtoType *fnType = blockInfo.getBlockExpr()->getFunctionType(); @@ -1178,7 +1181,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, Alloca->setAlignment(Align); // Set the DebugLocation to empty, so the store is recognized as a // frame setup instruction by llvm::DwarfDebug::beginFunction(). - ApplyDebugLocation NL(*this); + auto NL = ApplyDebugLocation::CreateEmpty(*this); Builder.CreateAlignedStore(BlockPointer, Alloca, Align); BlockPointerDbgLoc = Alloca; } @@ -1186,9 +1189,9 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, // If we have a C++ 'this' reference, go ahead and force it into // existence now. if (blockDecl->capturesCXXThis()) { - llvm::Value *addr = Builder.CreateStructGEP(BlockPointer, - blockInfo.CXXThisIndex, - "block.captured-this"); + llvm::Value *addr = + Builder.CreateStructGEP(blockInfo.StructureType, BlockPointer, + blockInfo.CXXThisIndex, "block.captured-this"); CXXThisValue = Builder.CreateLoad(addr, "this"); } @@ -1218,8 +1221,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, EmitLambdaBlockInvokeBody(); else { PGO.assignRegionCounters(blockDecl, fn); - RegionCounter Cnt = getPGORegionCounter(blockDecl->getBody()); - Cnt.beginRegion(Builder); + incrementProfileCounter(blockDecl->getBody()); EmitStmt(blockDecl->getBody()); } @@ -1328,11 +1330,10 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { nullptr, SC_Static, false, false); - // Create a scope with an artificial location for the body of this function. - ApplyDebugLocation NL(*this); + auto NL = ApplyDebugLocation::CreateEmpty(*this); StartFunction(FD, C.VoidTy, Fn, FI, args); - ArtificialLocation AL(*this); - + // Create a scope with an artificial location for the body of this function. + auto AL = ApplyDebugLocation::CreateArtificial(*this); llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); llvm::Value *src = GetAddrOfLocalVar(&srcDecl); @@ -1404,8 +1405,10 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { } unsigned index = capture.getIndex(); - llvm::Value *srcField = Builder.CreateStructGEP(src, index); - llvm::Value *dstField = Builder.CreateStructGEP(dst, index); + llvm::Value *srcField = + Builder.CreateStructGEP(blockInfo.StructureType, src, index); + llvm::Value *dstField = + Builder.CreateStructGEP(blockInfo.StructureType, dst, index); // If there's an explicit copy expression, we do that. if (copyExpr) { @@ -1500,9 +1503,9 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { nullptr, SC_Static, false, false); // Create a scope with an artificial location for the body of this function. - ApplyDebugLocation NL(*this); + auto NL = ApplyDebugLocation::CreateEmpty(*this); StartFunction(FD, C.VoidTy, Fn, FI, args); - ArtificialLocation AL(*this); + auto AL = ApplyDebugLocation::CreateArtificial(*this); llvm::Type *structPtrTy = blockInfo.StructureType->getPointerTo(); @@ -1562,7 +1565,8 @@ CodeGenFunction::GenerateDestroyHelperFunction(const CGBlockInfo &blockInfo) { } unsigned index = capture.getIndex(); - llvm::Value *srcField = Builder.CreateStructGEP(src, index); + llvm::Value *srcField = + Builder.CreateStructGEP(blockInfo.StructureType, src, index); // If there's an explicit copy expression, we do that. if (dtor) { @@ -1801,13 +1805,15 @@ generateByrefCopyHelper(CodeGenFunction &CGF, llvm::Value *destField = CGF.GetAddrOfLocalVar(&dst); destField = CGF.Builder.CreateLoad(destField); destField = CGF.Builder.CreateBitCast(destField, byrefPtrType); - destField = CGF.Builder.CreateStructGEP(destField, valueFieldIndex, "x"); + destField = CGF.Builder.CreateStructGEP(&byrefType, destField, + valueFieldIndex, "x"); // src->x llvm::Value *srcField = CGF.GetAddrOfLocalVar(&src); srcField = CGF.Builder.CreateLoad(srcField); srcField = CGF.Builder.CreateBitCast(srcField, byrefPtrType); - srcField = CGF.Builder.CreateStructGEP(srcField, valueFieldIndex, "x"); + srcField = + CGF.Builder.CreateStructGEP(&byrefType, srcField, valueFieldIndex, "x"); byrefInfo.emitCopy(CGF, destField, srcField); } @@ -1868,7 +1874,7 @@ generateByrefDisposeHelper(CodeGenFunction &CGF, llvm::Value *V = CGF.GetAddrOfLocalVar(&src); V = CGF.Builder.CreateLoad(V); V = CGF.Builder.CreateBitCast(V, byrefType.getPointerTo(0)); - V = CGF.Builder.CreateStructGEP(V, byrefValueIndex, "x"); + V = CGF.Builder.CreateStructGEP(&byrefType, V, byrefValueIndex, "x"); byrefInfo.emitDispose(CGF, V); } @@ -1925,7 +1931,7 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType, const VarDecl &var = *emission.Variable; QualType type = var.getType(); - unsigned byrefValueIndex = getByRefValueLLVMField(&var); + unsigned byrefValueIndex = getByRefValueLLVMField(&var).second; if (const CXXRecordDecl *record = type->getAsCXXRecordDecl()) { const Expr *copyExpr = CGM.getContext().getBlockVarCopyInits(&var); @@ -1995,18 +2001,20 @@ CodeGenFunction::buildByrefHelpers(llvm::StructType &byrefType, return ::buildByrefHelpers(CGM, byrefType, byrefValueIndex, byrefInfo); } -unsigned CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const { +std::pair<llvm::Type *, unsigned> +CodeGenFunction::getByRefValueLLVMField(const ValueDecl *VD) const { assert(ByRefValueInfo.count(VD) && "Did not find value!"); - - return ByRefValueInfo.find(VD)->second.second; + + return ByRefValueInfo.find(VD)->second; } llvm::Value *CodeGenFunction::BuildBlockByrefAddress(llvm::Value *BaseAddr, const VarDecl *V) { - llvm::Value *Loc = Builder.CreateStructGEP(BaseAddr, 1, "forwarding"); + auto P = getByRefValueLLVMField(V); + llvm::Value *Loc = + Builder.CreateStructGEP(P.first, BaseAddr, 1, "forwarding"); Loc = Builder.CreateLoad(Loc); - Loc = Builder.CreateStructGEP(Loc, getByRefValueLLVMField(V), - V->getNameAsString()); + Loc = Builder.CreateStructGEP(P.first, Loc, P.second, V->getNameAsString()); return Loc; } @@ -2143,11 +2151,12 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) { if (type.isObjCGCWeak()) isa = 1; V = Builder.CreateIntToPtr(Builder.getInt32(isa), Int8PtrTy, "isa"); - Builder.CreateStore(V, Builder.CreateStructGEP(addr, 0, "byref.isa")); + Builder.CreateStore(V, + Builder.CreateStructGEP(nullptr, addr, 0, "byref.isa")); // Store the address of the variable into its own forwarding pointer. - Builder.CreateStore(addr, - Builder.CreateStructGEP(addr, 1, "byref.forwarding")); + Builder.CreateStore( + addr, Builder.CreateStructGEP(nullptr, addr, 1, "byref.forwarding")); // Blocks ABI: // c) the flags field is set to either 0 if no helper functions are @@ -2193,25 +2202,26 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) { printf("\n"); } } - + Builder.CreateStore(llvm::ConstantInt::get(IntTy, flags.getBitMask()), - Builder.CreateStructGEP(addr, 2, "byref.flags")); + Builder.CreateStructGEP(nullptr, addr, 2, "byref.flags")); CharUnits byrefSize = CGM.GetTargetTypeStoreSize(byrefType); V = llvm::ConstantInt::get(IntTy, byrefSize.getQuantity()); - Builder.CreateStore(V, Builder.CreateStructGEP(addr, 3, "byref.size")); + Builder.CreateStore(V, + Builder.CreateStructGEP(nullptr, addr, 3, "byref.size")); if (helpers) { - llvm::Value *copy_helper = Builder.CreateStructGEP(addr, 4); + llvm::Value *copy_helper = Builder.CreateStructGEP(nullptr, addr, 4); Builder.CreateStore(helpers->CopyHelper, copy_helper); - llvm::Value *destroy_helper = Builder.CreateStructGEP(addr, 5); + llvm::Value *destroy_helper = Builder.CreateStructGEP(nullptr, addr, 5); Builder.CreateStore(helpers->DisposeHelper, destroy_helper); } if (ByRefHasLifetime && HasByrefExtendedLayout) { llvm::Constant* ByrefLayoutInfo = CGM.getObjCRuntime().BuildByrefLayout(CGM, type); - llvm::Value *ByrefInfoAddr = Builder.CreateStructGEP(addr, helpers ? 6 : 4, - "byref.layout"); + llvm::Value *ByrefInfoAddr = + Builder.CreateStructGEP(nullptr, addr, helpers ? 6 : 4, "byref.layout"); // cast destination to pointer to source type. llvm::Type *DesTy = ByrefLayoutInfo->getType(); DesTy = DesTy->getPointerTo(); diff --git a/lib/CodeGen/CGBuilder.h b/lib/CodeGen/CGBuilder.h index 72ba4faa3c7c..6610659131f7 100644 --- a/lib/CodeGen/CGBuilder.h +++ b/lib/CodeGen/CGBuilder.h @@ -33,7 +33,7 @@ protected: llvm::BasicBlock *BB, llvm::BasicBlock::iterator InsertPt) const; private: - void operator=(const CGBuilderInserter &) LLVM_DELETED_FUNCTION; + void operator=(const CGBuilderInserter &) = delete; CodeGenFunction *CGF; }; diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 635e34207de7..272baac80897 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "CodeGenFunction.h" +#include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CodeGenModule.h" #include "TargetInfo.h" @@ -21,9 +22,11 @@ #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/IR/CallSite.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Intrinsics.h" +#include <sstream> using namespace clang; using namespace CodeGen; @@ -156,6 +159,27 @@ static Value *EmitFAbs(CodeGenFunction &CGF, Value *V) { return Call; } +/// Emit the computation of the sign bit for a floating point value. Returns +/// the i1 sign bit value. +static Value *EmitSignBit(CodeGenFunction &CGF, Value *V) { + LLVMContext &C = CGF.CGM.getLLVMContext(); + + llvm::Type *Ty = V->getType(); + int Width = Ty->getPrimitiveSizeInBits(); + llvm::Type *IntTy = llvm::IntegerType::get(C, Width); + V = CGF.Builder.CreateBitCast(V, IntTy); + if (Ty->isPPC_FP128Ty()) { + // The higher-order double comes first, and so we need to truncate the + // pair to extract the overall sign. The order of the pair is the same + // in both little- and big-Endian modes. + Width >>= 1; + IntTy = llvm::IntegerType::get(C, Width); + V = CGF.Builder.CreateTrunc(V, IntTy); + } + Value *Zero = llvm::Constant::getNullValue(IntTy); + return CGF.Builder.CreateICmpSLT(V, Zero); +} + static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *Fn, const CallExpr *E, llvm::Value *calleeValue) { return CGF.EmitCall(E->getCallee()->getType(), calleeValue, E, @@ -181,7 +205,7 @@ static llvm::Value *EmitOverflowIntrinsic(CodeGenFunction &CGF, "arguments have the same integer width?)"); llvm::Value *Callee = CGF.CGM.getIntrinsic(IntrinsicID, X->getType()); - llvm::Value *Tmp = CGF.Builder.CreateCall2(Callee, X, Y); + llvm::Value *Tmp = CGF.Builder.CreateCall(Callee, {X, Y}); Carry = CGF.Builder.CreateExtractValue(Tmp, 1); return CGF.Builder.CreateExtractValue(Tmp, 0); } @@ -230,8 +254,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, DstPtr = Builder.CreateBitCast(DstPtr, Type); SrcPtr = Builder.CreateBitCast(SrcPtr, Type); - return RValue::get(Builder.CreateCall2(CGM.getIntrinsic(Intrinsic::vacopy), - DstPtr, SrcPtr)); + return RValue::get(Builder.CreateCall(CGM.getIntrinsic(Intrinsic::vacopy), + {DstPtr, SrcPtr})); } case Builtin::BI__builtin_abs: case Builtin::BI__builtin_labs: @@ -309,7 +333,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::Type *ResultType = ConvertType(E->getType()); Value *ZeroUndef = Builder.getInt1(getTarget().isCLZForZeroUndef()); - Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef); + Value *Result = Builder.CreateCall(F, {ArgValue, ZeroUndef}); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, "cast"); @@ -326,7 +350,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::Type *ResultType = ConvertType(E->getType()); Value *ZeroUndef = Builder.getInt1(getTarget().isCLZForZeroUndef()); - Value *Result = Builder.CreateCall2(F, ArgValue, ZeroUndef); + Value *Result = Builder.CreateCall(F, {ArgValue, ZeroUndef}); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/true, "cast"); @@ -342,9 +366,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *F = CGM.getIntrinsic(Intrinsic::cttz, ArgType); llvm::Type *ResultType = ConvertType(E->getType()); - Value *Tmp = Builder.CreateAdd(Builder.CreateCall2(F, ArgValue, - Builder.getTrue()), - llvm::ConstantInt::get(ArgType, 1)); + Value *Tmp = + Builder.CreateAdd(Builder.CreateCall(F, {ArgValue, Builder.getTrue()}), + llvm::ConstantInt::get(ArgType, 1)); Value *Zero = llvm::Constant::getNullValue(ArgType); Value *IsZero = Builder.CreateICmpEQ(ArgValue, Zero, "iszero"); Value *Result = Builder.CreateSelect(IsZero, Zero, Tmp, "ffs"); @@ -389,11 +413,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, Value *ArgValue = EmitScalarExpr(E->getArg(0)); llvm::Type *ArgType = ArgValue->getType(); - Value *FnExpect = CGM.getIntrinsic(Intrinsic::expect, ArgType); Value *ExpectedValue = EmitScalarExpr(E->getArg(1)); + // Don't generate llvm.expect on -O0 as the backend won't use it for + // anything. + // Note, we still IRGen ExpectedValue because it could have side-effects. + if (CGM.getCodeGenOpts().OptimizationLevel == 0 |