diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-07-13 19:25:38 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-07-13 19:25:38 +0000 |
commit | 8746d127c04f5bbaf6c6e88cef8606ca5a6a54e9 (patch) | |
tree | 84c9d77f8c764f04bcef0b1da4eedfa233d67a46 /lib | |
parent | cf1b401909b5e54edfd80656b1a18eaa31f9f6f1 (diff) |
Notes
Diffstat (limited to 'lib')
111 files changed, 2128 insertions, 1167 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index a2ff176df11f..fd9723298fca 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -8523,7 +8523,10 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, RequiresICE = false; // Read the prefixed modifiers first. - bool Done = false, IsSpecialLong = false; + bool Done = false; + #ifndef NDEBUG + bool IsSpecialLong = false; + #endif while (!Done) { switch (*Str++) { default: Done = true; --Str; break; @@ -8549,7 +8552,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, // 'N' behaves like 'L' for all non LP64 targets and 'int' otherwise. assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); assert(HowLong == 0 && "Can't use both 'L' and 'N' modifiers!"); + #ifndef NDEBUG IsSpecialLong = true; + #endif if (Context.getTargetInfo().getLongWidth() == 32) ++HowLong; break; @@ -8558,7 +8563,9 @@ static QualType DecodeTypeFromStr(const char *&Str, const ASTContext &Context, // This modifier represents int64 type. assert(!IsSpecialLong && "Can't use two 'N' or 'W' modifiers!"); assert(HowLong == 0 && "Can't use both 'L' and 'W' modifiers!"); + #ifndef NDEBUG IsSpecialLong = true; + #endif switch (Context.getTargetInfo().getInt64Type()) { default: llvm_unreachable("Unexpected integer type"); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 267c6992af89..573a98efe980 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -573,6 +573,44 @@ static bool isSingleLineLanguageLinkage(const Decl &D) { return false; } +static bool isExportedFromModuleIntefaceUnit(const NamedDecl *D) { + switch (D->getModuleOwnershipKind()) { + case Decl::ModuleOwnershipKind::Unowned: + case Decl::ModuleOwnershipKind::ModulePrivate: + return false; + case Decl::ModuleOwnershipKind::Visible: + case Decl::ModuleOwnershipKind::VisibleWhenImported: + if (auto *M = D->getOwningModule()) + return M->Kind == Module::ModuleInterfaceUnit; + } + llvm_unreachable("unexpected module ownership kind"); +} + +static LinkageInfo getInternalLinkageFor(const NamedDecl *D) { + // Internal linkage declarations within a module interface unit are modeled + // as "module-internal linkage", which means that they have internal linkage + // formally but can be indirectly accessed from outside the module via inline + // functions and templates defined within the module. + if (auto *M = D->getOwningModule()) + if (M->Kind == Module::ModuleInterfaceUnit) + return LinkageInfo(ModuleInternalLinkage, DefaultVisibility, false); + + return LinkageInfo::internal(); +} + +static LinkageInfo getExternalLinkageFor(const NamedDecl *D) { + // C++ Modules TS [basic.link]/6.8: + // - A name declared at namespace scope that does not have internal linkage + // by the previous rules and that is introduced by a non-exported + // declaration has module linkage. + if (auto *M = D->getOwningModule()) + if (M->Kind == Module::ModuleInterfaceUnit) + if (!isExportedFromModuleIntefaceUnit(D)) + return LinkageInfo(ModuleLinkage, DefaultVisibility, false); + + return LinkageInfo::external(); +} + static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, LVComputationKind computation) { assert(D->getDeclContext()->getRedeclContext()->isFileContext() && @@ -588,16 +626,18 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (const auto *Var = dyn_cast<VarDecl>(D)) { // Explicitly declared static. if (Var->getStorageClass() == SC_Static) - return LinkageInfo::internal(); + return getInternalLinkageFor(Var); // - a non-inline, non-volatile object or reference that is explicitly // declared const or constexpr and neither explicitly declared extern // nor previously declared to have external linkage; or (there is no // equivalent in C99) + // The C++ modules TS adds "non-exported" to this list. if (Context.getLangOpts().CPlusPlus && Var->getType().isConstQualified() && !Var->getType().isVolatileQualified() && - !Var->isInline()) { + !Var->isInline() && + !isExportedFromModuleIntefaceUnit(Var)) { const VarDecl *PrevVar = Var->getPreviousDecl(); if (PrevVar) return getLVForDecl(PrevVar, computation); @@ -605,7 +645,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, if (Var->getStorageClass() != SC_Extern && Var->getStorageClass() != SC_PrivateExtern && !isSingleLineLanguageLinkage(*Var)) - return LinkageInfo::internal(); + return getInternalLinkageFor(Var); } for (const VarDecl *PrevVar = Var->getPreviousDecl(); PrevVar; @@ -615,7 +655,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, return PrevVar->getLinkageAndVisibility(); // Explicitly declared static. if (PrevVar->getStorageClass() == SC_Static) - return LinkageInfo::internal(); + return getInternalLinkageFor(Var); } } else if (const FunctionDecl *Function = D->getAsFunction()) { // C++ [temp]p4: @@ -624,7 +664,7 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // Explicitly declared static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) - return LinkageInfo(InternalLinkage, DefaultVisibility, false); + return getInternalLinkageFor(Function); } else if (const auto *IFD = dyn_cast<IndirectFieldDecl>(D)) { // - a data member of an anonymous union. const VarDecl *VD = IFD->getVarDecl(); @@ -637,7 +677,12 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, const auto *Var = dyn_cast<VarDecl>(D); const auto *Func = dyn_cast<FunctionDecl>(D); // FIXME: In C++11 onwards, anonymous namespaces should give decls - // within them internal linkage, not unique external linkage. + // within them (including those inside extern "C" contexts) internal + // linkage, not unique external linkage: + // + // C++11 [basic.link]p4: + // An unnamed namespace or a namespace declared directly or indirectly + // within an unnamed namespace has internal linkage. if ((!Var || !isFirstInExternCContext(Var)) && (!Func || !isFirstInExternCContext(Func))) return LinkageInfo::uniqueExternal(); @@ -718,7 +763,8 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // because of this, but unique-external linkage suits us. if (Context.getLangOpts().CPlusPlus && !isFirstInExternCContext(Var)) { LinkageInfo TypeLV = getLVForType(*Var->getType(), computation); - if (TypeLV.getLinkage() != ExternalLinkage) + if (TypeLV.getLinkage() != ExternalLinkage && + TypeLV.getLinkage() != ModuleLinkage) return LinkageInfo::uniqueExternal(); if (!LV.isVisibilityExplicit()) LV.mergeVisibility(TypeLV); @@ -816,7 +862,9 @@ static LinkageInfo getLVForNamespaceScopeDecl(const NamedDecl *D, // - a namespace (7.3), unless it is declared within an unnamed // namespace. - } else if (isa<NamespaceDecl>(D) && !D->isInAnonymousNamespace()) { + // + // We handled names in anonymous namespaces above. + } else if (isa<NamespaceDecl>(D)) { return LV; // By extension, we assign external linkage to Objective-C @@ -1125,6 +1173,8 @@ static LinkageInfo getLVForClosure(const DeclContext *DC, Decl *ContextDecl, if (const auto *ND = dyn_cast<NamedDecl>(DC)) return getLVForDecl(ND, computation); + // FIXME: We have a closure at TU scope with no context declaration. This + // should probably have no linkage. return LinkageInfo::external(); } @@ -1137,7 +1187,7 @@ static LinkageInfo getLVForLocalDecl(const NamedDecl *D, // This is a "void f();" which got merged with a file static. if (Function->getCanonicalDecl()->getStorageClass() == SC_Static) - return LinkageInfo::internal(); + return getInternalLinkageFor(Function); LinkageInfo LV; if (!hasExplicitVisibilityAlready(computation)) { @@ -1226,7 +1276,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, LVComputationKind computation) { // Internal_linkage attribute overrides other considerations. if (D->hasAttr<InternalLinkageAttr>()) - return LinkageInfo::internal(); + return getInternalLinkageFor(D); // Objective-C: treat all Objective-C declarations as having external // linkage. @@ -1259,8 +1309,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, case Decl::TypeAlias: // A typedef declaration has linkage if it gives a type a name for // linkage purposes. - if (!D->getASTContext().getLangOpts().CPlusPlus || - !cast<TypedefNameDecl>(D) + if (!cast<TypedefNameDecl>(D) ->getAnonDeclWithTypedefName(/*AnyRedecl*/true)) return LinkageInfo::none(); break; @@ -1276,14 +1325,14 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, case Decl::ObjCProperty: case Decl::ObjCPropertyImpl: case Decl::ObjCProtocol: - return LinkageInfo::external(); + return getExternalLinkageFor(D); case Decl::CXXRecord: { const auto *Record = cast<CXXRecordDecl>(D); if (Record->isLambda()) { if (!Record->getLambdaManglingNumber()) { // This lambda has no mangling number, so it's internal. - return LinkageInfo::internal(); + return getInternalLinkageFor(D); } // This lambda has its linkage/visibility determined: @@ -1299,7 +1348,7 @@ static LinkageInfo computeLVForDecl(const NamedDecl *D, const CXXRecordDecl *OuterMostLambda = getOutermostEnclosingLambda(Record); if (!OuterMostLambda->getLambdaManglingNumber()) - return LinkageInfo::internal(); + return getInternalLinkageFor(D); return getLVForClosure( OuterMostLambda->getDeclContext()->getRedeclContext(), @@ -1350,7 +1399,7 @@ public: LVComputationKind computation) { // Internal_linkage attribute overrides other considerations. if (D->hasAttr<InternalLinkageAttr>()) - return LinkageInfo::internal(); + return getInternalLinkageFor(D); if (computation == LVForLinkageOnly && D->hasCachedLinkage()) return LinkageInfo(D->getCachedLinkage(), DefaultVisibility, false); diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index a0594a020362..cd2c83a02f59 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -283,8 +283,10 @@ void Decl::setLexicalDeclContext(DeclContext *DC) { setLocalOwningModule(cast<Decl>(DC)->getOwningModule()); } - assert((!hasOwningModule() || getOwningModule()) && - "hidden declaration has no owning module"); + assert( + (getModuleOwnershipKind() != ModuleOwnershipKind::VisibleWhenImported || + getOwningModule()) && + "hidden declaration has no owning module"); } void Decl::setDeclContextsImpl(DeclContext *SemaDC, DeclContext *LexicalDC, diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 07d128ba555b..5cab48882251 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -1605,6 +1605,84 @@ CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { SC_None, false, false, SourceLocation()); } +CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, + bool IsAppleKext) { + assert(isVirtual() && "this method is expected to be virtual"); + + // When building with -fapple-kext, all calls must go through the vtable since + // the kernel linker can do runtime patching of vtables. + if (IsAppleKext) + return nullptr; + + // If the member function is marked 'final', we know that it can't be + // overridden and can therefore devirtualize it unless it's pure virtual. + if (hasAttr<FinalAttr>()) + return isPure() ? nullptr : this; + + // If Base is unknown, we cannot devirtualize. + if (!Base) + return nullptr; + + // If the base expression (after skipping derived-to-base conversions) is a + // class prvalue, then we can devirtualize. + Base = Base->getBestDynamicClassTypeExpr(); + if (Base->isRValue() && Base->getType()->isRecordType()) + return this; + + // If we don't even know what we would call, we can't devirtualize. + const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType(); + if (!BestDynamicDecl) + return nullptr; + + // There may be a method corresponding to MD in a derived class. + CXXMethodDecl *DevirtualizedMethod = + getCorrespondingMethodInClass(BestDynamicDecl); + + // If that method is pure virtual, we can't devirtualize. If this code is + // reached, the result would be UB, not a direct call to the derived class + // function, and we can't assume the derived class function is defined. + if (DevirtualizedMethod->isPure()) + return nullptr; + + // If that method is marked final, we can devirtualize it. + if (DevirtualizedMethod->hasAttr<FinalAttr>()) + return DevirtualizedMethod; + + // Similarly, if the class itself is marked 'final' it can't be overridden + // and we can therefore devirtualize the member function call. + if (BestDynamicDecl->hasAttr<FinalAttr>()) + return DevirtualizedMethod; + + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { + if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) + if (VD->getType()->isRecordType()) + // This is a record decl. We know the type and can devirtualize it. + return DevirtualizedMethod; + + return nullptr; + } + + // We can devirtualize calls on an object accessed by a class member access + // expression, since by C++11 [basic.life]p6 we know that it can't refer to + // a derived class object constructed in the same location. + if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base)) + if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl())) + return VD->getType()->isRecordType() ? DevirtualizedMethod : nullptr; + + // Likewise for calls on an object accessed by a (non-reference) pointer to + // member access. + if (auto *BO = dyn_cast<BinaryOperator>(Base)) { + if (BO->isPtrMemOp()) { + auto *MPT = BO->getRHS()->getType()->castAs<MemberPointerType>(); + if (MPT->getPointeeType()->isRecordType()) + return DevirtualizedMethod; + } + } + + // We can't devirtualize the call. + return nullptr; +} + bool CXXMethodDecl::isUsualDeallocationFunction() const { if (getOverloadedOperator() != OO_Delete && getOverloadedOperator() != OO_Array_Delete) diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index e836135cf2f9..0c0c861e5d56 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -1665,6 +1665,19 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, return true; } +/// Member pointers are constant expressions unless they point to a +/// non-virtual dllimport member function. +static bool CheckMemberPointerConstantExpression(EvalInfo &Info, + SourceLocation Loc, + QualType Type, + const APValue &Value) { + const ValueDecl *Member = Value.getMemberPointerDecl(); + const auto *FD = dyn_cast_or_null<CXXMethodDecl>(Member); + if (!FD) + return true; + return FD->isVirtual() || !FD->hasAttr<DLLImportAttr>(); +} + /// Check that this core constant expression is of literal type, and if not, /// produce an appropriate diagnostic. static bool CheckLiteralType(EvalInfo &Info, const Expr *E, @@ -1757,6 +1770,9 @@ static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc, return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal); } + if (Value.isMemberPointer()) + return CheckMemberPointerConstantExpression(Info, DiagLoc, Type, Value); + // Everything else is fine. return true; } @@ -9508,7 +9524,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { case BO_Mul: if (Result.isComplexFloat()) { // This is an implementation of complex multiplication according to the - // constraints laid out in C11 Annex G. The implemantion uses the + // constraints laid out in C11 Annex G. The implemention uses the // following naming scheme: // (a + ib) * (c + id) ComplexValue LHS = Result; @@ -9589,7 +9605,7 @@ bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { case BO_Div: if (Result.isComplexFloat()) { // This is an implementation of complex division according to the - // constraints laid out in C11 Annex G. The implemantion uses the + // constraints laid out in C11 Annex G. The implemention uses the // following naming scheme: // (a + ib) / (c + id) ComplexValue LHS = Result; diff --git a/lib/AST/ExternalASTMerger.cpp b/lib/AST/ExternalASTMerger.cpp index b746edaf6439..4f4a99794c5b 100644 --- a/lib/AST/ExternalASTMerger.cpp +++ b/lib/AST/ExternalASTMerger.cpp @@ -180,8 +180,3 @@ void ExternalASTMerger::FindExternalLexicalDecls( }); } -void ExternalASTMerger::CompleteType(TagDecl *Tag) { - SmallVector<Decl *, 0> Result; - FindExternalLexicalDecls(Tag, [](Decl::Kind) { return true; }, Result); - Tag->setHasExternalLexicalStorage(false); -} diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp index 3f66e58eb868..66b9940b8b08 100644 --- a/lib/AST/ODRHash.cpp +++ b/lib/AST/ODRHash.cpp @@ -228,6 +228,13 @@ public: Hash.AddQualType(T); } + void AddDecl(const Decl *D) { + Hash.AddBoolean(D); + if (D) { + Hash.AddDecl(D); + } + } + void Visit(const Decl *D) { ID.AddInteger(D->getKind()); Inherited::Visit(D); @@ -321,6 +328,16 @@ public: void VisitTypeAliasDecl(const TypeAliasDecl *D) { Inherited::VisitTypeAliasDecl(D); } + + void VisitFriendDecl(const FriendDecl *D) { + TypeSourceInfo *TSI = D->getFriendType(); + Hash.AddBoolean(TSI); + if (TSI) { + AddQualType(TSI->getType()); + } else { + AddDecl(D->getFriendDecl()); + } + } }; // Only allow a small portion of Decl's to be processed. Remove this once @@ -335,6 +352,7 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) { case Decl::AccessSpec: case Decl::CXXMethod: case Decl::Field: + case Decl::Friend: case Decl::StaticAssert: case Decl::TypeAlias: case Decl::Typedef: diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index 7c0f5543da04..ec15f34fb231 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -67,6 +67,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, bool addImplicitDtors, bool addInitializers, bool addTemporaryDtors, + bool addLifetime, bool synthesizeBodies, bool addStaticInitBranch, bool addCXXNewAllocator, @@ -77,6 +78,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, cfgBuildOptions.AddImplicitDtors = addImplicitDtors; cfgBuildOptions.AddInitializers = addInitializers; cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors; + cfgBuildOptions.AddLifetime = addLifetime; cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch; cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator; } diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 2a2b3d73b5ca..6a77455edeef 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -233,6 +233,7 @@ public: } int distance(const_iterator L); + const_iterator shared_parent(const_iterator L); }; friend class const_iterator; @@ -275,6 +276,30 @@ int LocalScope::const_iterator::distance(LocalScope::const_iterator L) { return D; } +/// Calculates the closest parent of this iterator +/// that is in a scope reachable through the parents of L. +/// I.e. when using 'goto' from this to L, the lifetime of all variables +/// between this and shared_parent(L) end. +LocalScope::const_iterator +LocalScope::const_iterator::shared_parent(LocalScope::const_iterator L) { + llvm::SmallPtrSet<const LocalScope *, 4> ScopesOfL; + while (true) { + ScopesOfL.insert(L.Scope); + if (L == const_iterator()) + break; + L = L.Scope->Prev; + } + + const_iterator F = *this; + while (true) { + if (ScopesOfL.count(F.Scope)) + return F; + assert(F != const_iterator() && + "L iterator is not reachable from F iterator."); + F = F.Scope->Prev; + } +} + /// 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. @@ -579,6 +604,10 @@ private: CFGBlock *addInitializer(CXXCtorInitializer *I); void addAutomaticObjDtors(LocalScope::const_iterator B, LocalScope::const_iterator E, Stmt *S); + void addLifetimeEnds(LocalScope::const_iterator B, + LocalScope::const_iterator E, Stmt *S); + void addAutomaticObjHandling(LocalScope::const_iterator B, + LocalScope::const_iterator E, Stmt *S); void addImplicitDtorsForDestructor(const CXXDestructorDecl *DD); // Local scopes creation. @@ -619,6 +648,10 @@ private: B->appendAutomaticObjDtor(VD, S, cfg->getBumpVectorContext()); } + void appendLifetimeEnds(CFGBlock *B, VarDecl *VD, Stmt *S) { + B->appendLifetimeEnds(VD, S, cfg->getBumpVectorContext()); + } + void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) { B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext()); } @@ -626,6 +659,10 @@ private: void prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E); + void prependAutomaticObjLifetimeWithTerminator(CFGBlock *Blk, + LocalScope::const_iterator B, + LocalScope::const_iterator E); + void addSuccessor(CFGBlock *B, CFGBlock *S, bool IsReachable = true) { B->addSuccessor(CFGBlock::AdjacentBlock(S, IsReachable), cfg->getBumpVectorContext()); @@ -957,7 +994,8 @@ private: return TryResult(); } - + + bool hasTrivialDestructor(VarDecl *VD); }; inline bool AddStmtChoice::alwaysAdd(CFGBuilder &builder, @@ -1031,6 +1069,9 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { assert(Succ == &cfg->getExit()); Block = nullptr; // the EXIT block is empty. Create all other blocks lazily. + assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) && + "AddImplicitDtors and AddLifetime cannot be used at the same time"); + if (BuildOpts.AddImplicitDtors) if (const CXXDestructorDecl *DD = dyn_cast_or_null<CXXDestructorDecl>(D)) addImplicitDtorsForDestructor(DD); @@ -1067,6 +1108,8 @@ std::unique_ptr<CFG> CFGBuilder::buildCFG(const Decl *D, Stmt *Statement) { if (LI == LabelMap.end()) continue; JumpTarget JT = LI->second; + prependAutomaticObjLifetimeWithTerminator(B, I->scopePosition, + JT.scopePosition); prependAutomaticObjDtorsWithTerminator(B, I->scopePosition, JT.scopePosition); addSuccessor(B, JT.block); @@ -1209,7 +1252,61 @@ static QualType getReferenceInitTemporaryType(ASTContext &Context, return Init->getType(); } - + +void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B, + LocalScope::const_iterator E, + Stmt *S) { + if (BuildOpts.AddImplicitDtors) + addAutomaticObjDtors(B, E, S); + if (BuildOpts.AddLifetime) + addLifetimeEnds(B, E, S); +} + +/// Add to current block automatic objects that leave the scope. +void CFGBuilder::addLifetimeEnds(LocalScope::const_iterator B, + LocalScope::const_iterator E, Stmt *S) { + if (!BuildOpts.AddLifetime) + return; + + if (B == E) + return; + + // To go from B to E, one first goes up the scopes from B to P + // then sideways in one scope from P to P' and then down + // the scopes from P' to E. + // The lifetime of all objects between B and P end. + LocalScope::const_iterator P = B.shared_parent(E); + int dist = B.distance(P); + if (dist <= 0) + return; + + // We need to perform the scope leaving in reverse order + SmallVector<VarDecl *, 10> DeclsTrivial; + SmallVector<VarDecl *, 10> DeclsNonTrivial; + DeclsTrivial.reserve(dist); + DeclsNonTrivial.reserve(dist); + + for (LocalScope::const_iterator I = B; I != P; ++I) + if (hasTrivialDestructor(*I)) + DeclsTrivial.push_back(*I); + else + DeclsNonTrivial.push_back(*I); + + autoCreateBlock(); + // object with trivial destructor end their lifetime last (when storage + // duration ends) + for (SmallVectorImpl<VarDecl *>::reverse_iterator I = DeclsTrivial.rbegin(), + E = DeclsTrivial.rend(); + I != E; ++I) + appendLifetimeEnds(Block, *I, S); + + for (SmallVectorImpl<VarDecl *>::reverse_iterator + I = DeclsNonTrivial.rbegin(), + E = DeclsNonTrivial.rend(); + I != E; ++I) + appendLifetimeEnds(Block, *I, S); +} + /// addAutomaticObjDtors - Add to current block automatic objects destructors /// for objects in range of local scope positions. Use S as trigger statement /// for destructors. @@ -1309,7 +1406,7 @@ LocalScope* CFGBuilder::createOrReuseLocalScope(LocalScope* Scope) { /// addLocalScopeForStmt - Add LocalScope to local scopes tree for statement /// that should create implicit scope (e.g. if/else substatements). void CFGBuilder::addLocalScopeForStmt(Stmt *S) { - if (!BuildOpts.AddImplicitDtors) + if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime) return; LocalScope *Scope = nullptr; @@ -1334,7 +1431,7 @@ void CFGBuilder::addLocalScopeForStmt(Stmt *S) { /// reuse Scope if not NULL. LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS, LocalScope* Scope) { - if (!BuildOpts.AddImplicitDtors) + if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime) return Scope; for (auto *DI : DS->decls()) @@ -1343,23 +1440,7 @@ LocalScope* CFGBuilder::addLocalScopeForDeclStmt(DeclStmt *DS, return Scope; } -/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will -/// create add scope for automatic objects and temporary objects bound to -/// const reference. Will reuse Scope if not NULL. -LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, - LocalScope* Scope) { - if (!BuildOpts.AddImplicitDtors) - return Scope; - - // Check if variable is local. - switch (VD->getStorageClass()) { - case SC_None: - case SC_Auto: - case SC_Register: - break; - default: return Scope; - } - +bool CFGBuilder::hasTrivialDestructor(VarDecl *VD) { // Check for const references bound to temporary. Set type to pointee. QualType QT = VD->getType(); if (QT.getTypePtr()->isReferenceType()) { @@ -1370,44 +1451,74 @@ LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, // temporaries, and a single declaration can extend multiple temporaries. // We should look at the storage duration on each nested // MaterializeTemporaryExpr instead. + const Expr *Init = VD->getInit(); if (!Init) - return Scope; + return true; // Lifetime-extending a temporary. bool FoundMTE = false; QT = getReferenceInitTemporaryType(*Context, Init, &FoundMTE); if (!FoundMTE) - return Scope; + return true; } // Check for constant size array. Set type to array element type. while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) { if (AT->getSize() == 0) - return Scope; + return true; QT = AT->getElementType(); } // Check if type is a C++ class with non-trivial destructor. if (const CXXRecordDecl *CD = QT->getAsCXXRecordDecl()) - if (CD->hasDefinition() && !CD->hasTrivialDestructor()) { + return !CD->hasDefinition() || CD->hasTrivialDestructor(); + return true; +} + +/// addLocalScopeForVarDecl - Add LocalScope for variable declaration. It will +/// create add scope for automatic objects and temporary objects bound to +/// const reference. Will reuse Scope if not NULL. +LocalScope* CFGBuilder::addLocalScopeForVarDecl(VarDecl *VD, + LocalScope* Scope) { + assert(!(BuildOpts.AddImplicitDtors && BuildOpts.AddLifetime) && + "AddImplicitDtors and AddLifetime cannot be used at the same time"); + if (!BuildOpts.AddImplicitDtors && !BuildOpts.AddLifetime) + return Scope; + + // Check if variable is local. + switch (VD->getStorageClass()) { + case SC_None: + case SC_Auto: + case SC_Register: + break; + default: return Scope; + } + + if (BuildOpts.AddImplicitDtors) { + if (!hasTrivialDestructor(VD)) { // Add the variable to scope Scope = createOrReuseLocalScope(Scope); Scope->addVar(VD); ScopePos = Scope->begin(); } + return Scope; + } + + assert(BuildOpts.AddLifetime); + // Add the variable to scope + Scope = createOrReuseLocalScope(Scope); + Scope->addVar(VD); + ScopePos = Scope->begin(); return Scope; } /// addLocalScopeAndDtors - For given statement add local scope for it and /// add destructors that will cleanup the scope. Will reuse Scope if not NULL. void CFGBuilder::addLocalScopeAndDtors(Stmt *S) { - if (!BuildOpts.AddImplicitDtors) - return; - LocalScope::const_iterator scopeBeginPos = ScopePos; addLocalScopeForStmt(S); - addAutomaticObjDtors(ScopePos, scopeBeginPos, S); + addAutomaticObjHandling(ScopePos, scopeBeginPos, S); } /// prependAutomaticObjDtorsWithTerminator - Prepend destructor CFGElements for @@ -1419,6 +1530,8 @@ void CFGBuilder::addLocalScopeAndDtors(Stmt *S) { /// no-return destructors properly. void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E) { + if (!BuildOpts.AddImplicitDtors) + return; BumpVectorContext &C = cfg->getBumpVectorContext(); CFGBlock::iterator InsertPos = Blk->beginAutomaticObjDtorsInsert(Blk->end(), B.distance(E), C); @@ -1427,6 +1540,21 @@ void CFGBuilder::prependAutomaticObjDtorsWithTerminator(CFGBlock *Blk, Blk->getTerminator()); } +/// prependAutomaticObjLifetimeWithTerminator - Prepend lifetime CFGElements for +/// variables with automatic storage duration to CFGBlock's elements vector. +/// Elements will be prepended to physical beginning of the vector which +/// happens to be logical end. Use blocks terminator as statement that specifies +/// where lifetime ends. +void CFGBuilder::prependAutomaticObjLifetimeWithTerminator( + CFGBlock *Blk, LocalScope::const_iterator B, LocalScope::const_iterator E) { + if (!BuildOpts.AddLifetime) + return; + BumpVectorContext &C = cfg->getBumpVectorContext(); + CFGBlock::iterator InsertPos = + Blk->beginLifetimeEndsInsert(Blk->end(), B.distance(E), C); + for (LocalScope::const_iterator I = B; I != E; ++I) + InsertPos = Blk->insertLifetimeEnds(InsertPos, *I, Blk->getTerminator()); +} /// Visit - Walk the subtree of a statement and add extra /// blocks for ternary operators, &&, and ||. We also process "," and /// DeclStmts (which may contain nested control-flow). @@ -1815,7 +1943,7 @@ CFGBlock *CFGBuilder::VisitBreakStmt(BreakStmt *B) { // If there is no target for the break, then we are looking at an incomplete // AST. This means that the CFG cannot be constructed. if (BreakJumpTarget.block) { - addAutomaticObjDtors(ScopePos, BreakJumpTarget.scopePosition, B); + addAutomaticObjHandling(ScopePos, BreakJumpTarget.scopePosition, B); addSuccessor(Block, BreakJumpTarget.block); } else badCFG = true; @@ -1947,13 +2075,12 @@ CFGBlock *CFGBuilder::VisitChooseExpr(ChooseExpr *C, CFGBlock *CFGBuilder::VisitCompoundStmt(CompoundStmt *C) { LocalScope::const_iterator scopeBeginPos = ScopePos; - if (BuildOpts.AddImplicitDtors) { - addLocalScopeForStmt(C); - } + addLocalScopeForStmt(C); + if (!C->body_empty() && !isa<ReturnStmt>(*C->body_rbegin())) { // If the body ends with a ReturnStmt, the dtors will be added in // VisitReturnStmt. - addAutomaticObjDtors(ScopePos, scopeBeginPos, C); + addAutomaticObjHandling(ScopePos, scopeBeginPos, C); } CFGBlock *LastBlock = Block; @@ -2183,7 +2310,7 @@ CFGBlock *CFGBuilder::VisitIfStmt(IfStmt *I) { if (VarDecl *VD = I->getConditionVariable()) addLocalScopeForVarDecl(VD); - addAutomaticObjDtors(ScopePos, save_scope_pos.get(), I); + addAutomaticObjHandling(ScopePos, save_scope_pos.get(), I); // The block we were processing is now finished. Make it the successor // block. @@ -2308,7 +2435,7 @@ CFGBlock *CFGBuilder::VisitReturnStmt(ReturnStmt *R) { // Create the new block. Block = createBlock(false); - addAutomaticObjDtors(ScopePos, LocalScope::const_iterator(), R); + addAutomaticObjHandling(ScopePos, LocalScope::const_iterator(), R); // If the one of the destructors does not return, we already have the Exit // block as a successor. @@ -2389,7 +2516,7 @@ CFGBlock *CFGBuilder::VisitGotoStmt(GotoStmt *G) { BackpatchBlocks.push_back(JumpSource(Block, ScopePos)); else { JumpTarget JT = I->second; - addAutomaticObjDtors(ScopePos, JT.scopePosition, G); + addAutomaticObjHandling(ScopePos, JT.scopePosition, G); addSuccessor(Block, JT.block); } @@ -2414,7 +2541,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { addLocalScopeForVarDecl(VD); LocalScope::const_iterator ContinueScopePos = ScopePos; - addAutomaticObjDtors(ScopePos, save_scope_pos.get(), F); + addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F); // "for" is a control-flow statement. Thus we stop processing the current // block. @@ -2466,7 +2593,7 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) { ContinueJumpTarget.block->setLoopTarget(F); // Loop body should end with destructor of Condition variable (if any). - addAutomaticObjDtors(ScopePos, LoopBeginScopePos, F); + addAutomaticObjHandling(ScopePos, LoopBeginScopePos, F); // If body is not a compound statement create implicit scope // and add destructors. @@ -2753,7 +2880,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { LocalScope::const_iterator LoopBeginScopePos = ScopePos; if (VarDecl *VD = W->getConditionVariable()) { addLocalScopeForVarDecl(VD); - addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W); + addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W); } // "while" is a control-flow statement. Thus we stop processing the current @@ -2788,7 +2915,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) { BreakJumpTarget = JumpTarget(LoopSuccessor, ScopePos); // Loop body should end with destructor of Condition variable (if any). - addAutomaticObjDtors(ScopePos, LoopBeginScopePos, W); + addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W); // If body is not a compound statement create implicit scope // and add destructors. @@ -3030,7 +3157,7 @@ CFGBlock *CFGBuilder::VisitContinueStmt(ContinueStmt *C) { // If there is no target for the continue, then we are looking at an // incomplete AST. This means the CFG cannot be constructed. if (ContinueJumpTarget.block) { - addAutomaticObjDtors(ScopePos, ContinueJumpTarget.scopePosition, C); + addAutomaticObjHandling(ScopePos, ContinueJumpTarget.scopePosition, C); addSuccessor(Block, ContinueJumpTarget.block); } else badCFG = true; @@ -3085,7 +3212,7 @@ CFGBlock *CFGBuilder::VisitSwitchStmt(SwitchStmt *Terminator) { if (VarDecl *VD = Terminator->getConditionVariable()) addLocalScopeForVarDecl(VD); - addAutomaticObjDtors(ScopePos, save_scope_pos.get(), Terminator); + addAutomaticObjHandling(ScopePos, save_scope_pos.get(), Terminator); if (Block) { if (badCFG) @@ -3373,7 +3500,7 @@ CFGBlock *CFGBuilder::VisitCXXCatchStmt(CXXCatchStmt *CS) { if (VarDecl *VD = CS->getExceptionDecl()) { LocalScope::const_iterator BeginScopePos = ScopePos; addLocalScopeForVarDecl(VD); - addAutomaticObjDtors(ScopePos, BeginScopePos, CS); + addAutomaticObjHandling(ScopePos, BeginScopePos, CS); } if (CS->getHandlerBlock()) @@ -3427,7 +3554,7 @@ CFGBlock *CFGBuilder::VisitCXXForRangeStmt(CXXForRangeStmt *S) { addLocalScopeForStmt(Begin); if (Stmt *End = S->getEndStmt()) addLocalScopeForStmt(End); - addAutomaticObjDtors(ScopePos, save_scope_pos.get(), S); + addAutomaticObjHandling(ScopePos, save_scope_pos.get(), S); LocalScope::const_iterator ContinueScopePos = ScopePos; @@ -3898,6 +4025,7 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { case CFGElement::Statement: case CFGElement::Initializer: case CFGElement::NewAllocator: + case CFGElement::LifetimeEnds: llvm_unreachable("getDestructorDecl should only be used with " "ImplicitDtors"); case CFGElement::AutomaticObjectDtor: { @@ -4308,6 +4436,12 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper, OS << ".~" << T->getAsCXXRecordDecl()->getName().str() << "()"; OS << " (Implicit destructor)\n"; + } else if (Optional<CFGLifetimeEnds> DE = E.getAs<CFGLifetimeEnds>()) { + const VarDecl *VD = DE->getVarDecl(); + Helper.handleDecl(VD, OS); + + OS << " (Lifetime ends)\n"; + } else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) { OS << "CFGNewAllocator("; if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr()) diff --git a/lib/Analysis/CloneDetection.cpp b/lib/Analysis/CloneDetection.cpp index ee848ac711d6..5ea74989a7ec 100644 --- a/lib/Analysis/CloneDetection.cpp +++ b/lib/Analysis/CloneDetection.cpp @@ -16,13 +16,13 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" -#include "clang/AST/StmtVisitor.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Support/Path.h" using namespace clang; +using namespace clang::clone_detection; StmtSequence::StmtSequence(const CompoundStmt *Stmt, const Decl *D, unsigned StartIndex, unsigned EndIndex) @@ -103,12 +103,8 @@ static void printMacroName(llvm::raw_string_ostream &MacroStack, MacroStack << " "; } -/// Returns a string that represents all macro expansions that expanded into the -/// given SourceLocation. -/// -/// If 'getMacroStack(A) == getMacroStack(B)' is true, then the SourceLocations -/// A and B are expanded from the same macros in the same order. -static std::string getMacroStack(SourceLocation Loc, ASTContext &Context) { +std::string clone_detection::getMacroStack(SourceLocation Loc, + ASTContext &Context) { std::string MacroStack; llvm::raw_string_ostream MacroStackStream(MacroStack); SourceManager &SM = Context.getSourceManager(); @@ -123,184 +119,6 @@ static std::string getMacroStack(SourceLocation Loc, ASTContext &Context) { return MacroStack; } -namespace { -typedef unsigned DataPiece; - -/// Collects the data of a single Stmt. -/// -/// This class defines what a code clone is: If it collects for two statements -/// the same data, then those two statements are considered to be clones of each -/// other. -/// -/// All collected data is forwarded to the given data consumer of the type T. -/// The data consumer class needs to provide a member method with the signature: -/// update(StringRef Str) -template <typename T> -class StmtDataCollector : public ConstStmtVisitor<StmtDataCollector<T>> { - - ASTContext &Context; - /// The data sink to which all data is forwarded. - T &DataConsumer; - -public: - /// Collects data of the given Stmt. - /// \param S The given statement. - /// \param Context The ASTContext of S. - /// \param DataConsumer The data sink to which all data is forwarded. - StmtDataCollector(const Stmt *S, ASTContext &Context, T &DataConsumer) - : Context(Context), DataConsumer(DataConsumer) { - this->Visit(S); - } - - // Below are utility methods for appending different data to the vector. - - void addData(DataPiece Integer) { - DataConsumer.update( - StringRef(reinterpret_cast<char *>(&Integer), sizeof(Integer))); - } - - void addData(llvm::StringRef Str) { DataConsumer.update(Str); } - - void addData(const QualType &QT) { addData(QT.getAsString()); } - -// The functions below collect the class specific data of each Stmt subclass. - -// Utility macro for defining a visit method for a given class. This method -// calls back to the ConstStmtVisitor to visit all parent classes. -#define DEF_ADD_DATA(CLASS, CODE) \ - void Visit##CLASS(const CLASS *S) { \ - CODE; \ - ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S); \ - } - - DEF_ADD_DATA(Stmt, { - addData(S->getStmtClass()); - // This ensures that macro generated code isn't identical to macro-generated - // code. - addData(getMacroStack(S->getLocStart(), Context)); - addData(getMacroStack(S->getLocEnd(), Context)); - }) - DEF_ADD_DATA(Expr, { addData(S->getType()); }) - - //--- Builtin functionality ----------------------------------------------// - DEF_ADD_DATA(ArrayTypeTraitExpr, { addData(S->getTrait()); }) - DEF_ADD_DATA(ExpressionTraitExpr, { addData(S->getTrait()); }) - DEF_ADD_DATA(PredefinedExpr, { addData(S->getIdentType()); }) - DEF_ADD_DATA(TypeTraitExpr, { - addData(S->getTrait()); - for (unsigned i = 0; i < S->getNumArgs(); ++i) - addData(S->getArg(i)->getType()); - }) - - //--- Calls --------------------------------------------------------------// - DEF_ADD_DATA(CallExpr, { - // Function pointers don't have a callee and we just skip hashing it. - if (const FunctionDecl *D = S->getDirectCallee()) { - // If the function is a template specialization, we also need to handle - // the template arguments as they are not included in the qualified name. - if (auto Args = D->getTemplateSpecializationArgs()) { - std::string ArgString; - - // Print all template arguments into ArgString - llvm::raw_string_ostream OS(ArgString); - for (unsigned i = 0; i < Args->size(); ++i) { - Args->get(i).print(Context.getLangOpts(), OS); - // Add a padding character so that 'foo<X, XX>()' != 'foo<XX, X>()'. - OS << '\n'; - } - OS.flush(); - - addData(ArgString); - } - addData(D->getQualifiedNameAsString()); - } - }) - - //--- Exceptions ---------------------------------------------------------// - DEF_ADD_DATA(CXXCatchStmt, { addData(S->getCaughtType()); }) - - //--- C++ OOP Stmts ------------------------------------------------------// - DEF_ADD_DATA(CXXDeleteExpr, { - addData(S->isArrayFormAsWritten()); - addData(S->isGlobalDelete()); - }) - - //--- Casts --------------------------------------------------------------// - DEF_ADD_DATA(ObjCBridgedCastExpr, { addData(S->getBridgeKind()); }) - - //--- Miscellaneous Exprs ------------------------------------------------// - DEF_ADD_DATA(BinaryOperator, { addData(S->getOpcode()); }) - DEF_ADD_DATA(UnaryOperator, { addData(S->getOpcode()); }) - - //--- Control flow -------------------------------------------------------// - DEF_ADD_DATA(GotoStmt, { addData(S->getLabel()->getName()); }) - DEF_ADD_DATA(IndirectGotoStmt, { - if (S->getConstantTarget()) - addData(S->getConstantTarget()->getName()); - }) - DEF_ADD_DATA(LabelStmt, { addData(S->getDecl()->getName()); }) - DEF_ADD_DATA(MSDependentExistsStmt, { addData(S->isIfExists()); }) - DEF_ADD_DATA(AddrLabelExpr, { addData(S->getLabel()->getName()); }) - - //--- Objective-C --------------------------------------------------------// - DEF_ADD_DATA(ObjCIndirectCopyRestoreExpr, { addData(S->shouldCopy()); }) - DEF_ADD_DATA(ObjCPropertyRefExpr, { - addData(S->isSuperReceiver()); - addData(S->isImplicitProperty()); - }) - DEF_ADD_DATA(ObjCAtCatchStmt, { addData(S->hasEllipsis()); }) - - //--- Miscellaneous Stmts ------------------------------------------------// - DEF_ADD_DATA(CXXFoldExpr, { - addData(S->isRightFold()); - addData(S->getOperator()); - }) - DEF_ADD_DATA(GenericSelectionExpr, { - for (unsigned i = 0; i < S->getNumAssocs(); ++i) { - addData(S->getAssocType(i)); - } - }) - DEF_ADD_DATA(LambdaExpr, { - for (const LambdaCapture &C : S->captures()) { - addData(C.isPackExpansion()); - addData(C.getCaptureKind()); - if (C.capturesVariable()) - addData(C.getCapturedVar()->getType()); - } - addData(S->isGenericLambda()); - addData(S->isMutable()); - }) - DEF_ADD_DATA(DeclStmt, { - auto numDecls = std::distance(S->decl_begin(), S->decl_end()); - addData(static_cast<DataPiece>(numDecls)); - for (const Decl *D : S->decls()) { - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - addData(VD->getType()); - } - } - }) - DEF_ADD_DATA(AsmStmt, { - addData(S->isSimple()); - addData(S->isVolatile()); - addData(S->generateAsmString(Context)); - for (unsigned i = 0; i < S->getNumInputs(); ++i) { - addData(S->getInputConstraint(i)); - } - for (unsigned i = 0; i < S->getNumOutputs(); ++i) { - addData(S->getOutputConstraint(i)); - } - for (unsigned i = 0; i < S->getNumClobbers(); ++i) { - addData(S->getClobber(i)); - } - }) - DEF_ADD_DATA(AttributedStmt, { - for (const Attr *A : S->getAttrs()) { - addData(std::string(A->getSpelling())); - } - }) -}; -} // end anonymous namespace - void CloneDetector::analyzeCodeBody(const Decl *D) { assert(D); assert(D->hasBody()); @@ -421,16 +239,27 @@ size_t RecursiveCloneTypeIIConstraint::saveHash( } if (CS) { - for (unsigned Length = 2; Length <= CS->size(); ++Length) { - for (unsigned Pos = 0; Pos <= CS->size() - Length; ++Pos) { - llvm::MD5 Hash; - for (unsigned i = Pos; i < Pos + Length; ++i) { - size_t ChildHash = ChildHashes[i]; - Hash.update(StringRef(reinterpret_cast<char *>(&ChildHash), - sizeof(ChildHash))); + // If we're in a CompoundStmt, we hash all possible combinations of child + // statements to find clones in those subsequences. + // We first go through every possible starting position of a subsequence. + for (unsigned Pos = 0; Pos < CS->size(); ++Pos) { + // Then we try all possible lengths this subsequence could have and + // reuse the same hash object to make sure we only hash every child + // hash exactly once. + llvm::MD5 Hash; + for (unsigned Length = 1; Length <= CS->size() - Pos; ++Length) { + // Grab the current child hash and put it into our hash. We do + // -1 on the index because we start counting the length at 1. + size_t ChildHash = ChildHashes[Pos + Length - 1]; + Hash.update( + StringRef(reinterpret_cast<char *>(&ChildHash), sizeof(ChildHash))); + // If we have at least two elements in our subsequence, we can start + // saving it. + if (Length > 1) { + llvm::MD5 SubHash = Hash; + StmtsByHash.push_back(std::make_pair( + createHash(SubHash), StmtSequence(CS, D, Pos, Pos + Length))); } - StmtsByHash.push_back(std::make_pair( - createHash(Hash), StmtSequence(CS, D, Pos, Pos + Length))); } } } diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 4f04489a4a10..50b4fc34ad3a 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -499,6 +499,10 @@ public: switch (Triple.getArch()) { default: break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: case llvm::Triple::ppc: case llvm::Triple::ppc64: case llvm::Triple::ppc64le: @@ -2049,7 +2053,7 @@ ArrayRef<const char *> NVPTXTargetInfo::getGCCRegNames() const { return llvm::makeArrayRef(GCCRegNames); } -static const LangAS::Map AMDGPUNonOpenCLPrivateIsZeroMap = { +static const LangAS::Map AMDGPUPrivIsZeroDefIsGenMap = { 4, // Default 1, // opencl_global 3, // opencl_local @@ -2059,7 +2063,7 @@ static const LangAS::Map AMDGPUNonOpenCLPrivateIsZeroMap = { 2, // cuda_constant 3 // cuda_shared }; -static const LangAS::Map AMDGPUNonOpenCLGenericIsZeroMap = { +static const LangAS::Map AMDGPUGenIsZeroDefIsGenMap = { 0, // Default 1, // opencl_global 3, // opencl_local @@ -2069,7 +2073,7 @@ static const LangAS::Map AMDGPUNonOpenCLGenericIsZeroMap = { 2, // cuda_constant 3 // cuda_shared }; -static const LangAS::Map AMDGPUOpenCLPrivateIsZeroMap = { +static const LangAS::Map AMDGPUPrivIsZeroDefIsPrivMap = { 0, // Default 1, // opencl_global 3, // opencl_local @@ -2079,7 +2083,7 @@ static const LangAS::Map AMDGPUOpenCLPrivateIsZeroMap = { 2, // cuda_constant 3 // cuda_shared }; -static const LangAS::Map AMDGPUOpenCLGenericIsZeroMap = { +static const LangAS::Map AMDGPUGenIsZeroDefIsPrivMap = { 5, // Default 1, // opencl_global 3, // opencl_local @@ -2184,20 +2188,37 @@ public: : DataLayoutStringR600); assert(DataLayout->getAllocaAddrSpace() == AS.Private); + setAddressSpaceMap(Triple.getOS() == llvm::Triple::Mesa3D || + Triple.getEnvironment() == llvm::Triple::OpenCL || + Triple.getEnvironmentName() == "amdgizcl" || + !isAMDGCN(Triple)); UseAddrSpaceMapMangling = true; + + // Set pointer width and alignment for target address space 0. + PointerWidth = PointerAlign = DataLayout->getPointerSizeInBits(); + if (getMaxPointerWidth() == 64) { + LongWidth = LongAlign = 64; + SizeType = UnsignedLong; + PtrDiffType = SignedLong; + IntPtrType = SignedLong; + } } - void adjust(LangOptions &Opts) override { - TargetInfo::adjust(Opts); + void setAddressSpaceMap(bool DefaultIsPrivate) { if (isGenericZero(getTriple())) { - AddrSpaceMap = Opts.OpenCL ? &AMDGPUOpenCLGenericIsZeroMap - : &AMDGPUNonOpenCLGenericIsZeroMap; + AddrSpaceMap = DefaultIsPrivate ? &AMDGPUGenIsZeroDefIsPrivMap + : &AMDGPUGenIsZeroDefIsGenMap; } else { - AddrSpaceMap = Opts.OpenCL ? &AMDGPUOpenCLPrivateIsZeroMap - : &AMDGPUNonOpenCLPrivateIsZeroMap; + AddrSpaceMap = DefaultIsPrivate ? &AMDGPUPrivIsZeroDefIsPrivMap + : &AMDGPUPrivIsZeroDefIsGenMap; } } + void adjust(LangOptions &Opts) override { + TargetInfo::adjust(Opts); + setAddressSpaceMap(Opts.OpenCL || !isAMDGCN(getTriple())); + } + uint64_t getPointerWidthV(unsigned AddrSpace) const override { if (GPU <= GK_CAYMAN) return 32; @@ -2208,6 +2229,10 @@ public: return 64; } + uint64_t getPointerAlignV(unsigned AddrSpace) const override { + return getPointerWidthV(AddrSpace); + } + uint64_t getMaxPointerWidth() const override { return getTriple().getArch() == llvm::Triple::amdgcn ? 64 : 32; } @@ -2383,14 +2408,13 @@ public: return LangAS::opencl_constant; } - /// \returns Target specific vtbl ptr address space. - unsigned getVtblPtrAddressSpace() const override { - // \todo: We currently have address spaces defined in AMDGPU Backend. It - // would be nice if we could use it here instead of using bare numbers (same - // applies to getDWARFAddressSpace). - return 2; // constant. + llvm::Optional<unsigned> getConstantAddressSpace() const override { + return LangAS::FirstTargetAddressSpace + AS.Constant; } + /// \returns Target specific vtbl ptr address space. + unsigned getVtblPtrAddressSpace() const override { return AS.Constant; } + /// \returns If a target requires an address within a target specific address /// space \p AddressSpace to be converted in order to be used, then return the /// corresponding target specific DWARF address space. @@ -3874,7 +3898,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case CK_PentiumMMX: Builder.defineMacro("__pentium_mmx__"); Builder.defineMacro("__tune_pentium_mmx__"); - // Fallthrough + LLVM_FALLTHROUGH; case CK_i586: case CK_Pentium: defineCPUMacros(Builder, "i586"); @@ -3884,15 +3908,15 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case CK_Pentium3M: case CK_PentiumM: Builder.defineMacro("__tune_pentium3__"); - // Fallthrough + LLVM_FALLTHROUGH; case CK_Pentium2: case CK_C3_2: Builder.defineMacro("__tune_pentium2__"); - // Fallthrough + LLVM_FALLTHROUGH; case CK_PentiumPro: Builder.defineMacro("__tune_i686__"); Builder.defineMacro("__tune_pentiumpro__"); - // Fallthrough + LLVM_FALLTHROUGH; case CK_i686: Builder.defineMacro("__i686"); Builder.defineMacro("__i686__"); @@ -3948,7 +3972,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, case CK_K6_2: Builder.defineMacro("__k6_2__"); Builder.defineMacro("__tune_k6_2__"); - // Fallthrough + LLVM_FALLTHROUGH; case CK_K6_3: if (CPU != CK_K6_2) { // In case of fallthrough // FIXME: GCC may be enabling these in cases where some other k6 @@ -3957,7 +3981,7 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__k6_3__"); Builder.defineMacro("__tune_k6_3__"); } - // Fallthrough + LLVM_FALLTHROUGH; case CK_K6: defineCPUMacros(Builder, "k6"); break; @@ -6310,9 +6334,6 @@ public: MacroBuilder &Builder) const { // Also include the ARMv8.1 defines getTargetDefinesARMV81A(Opts, Builder); - - if (FPU == NeonMode && HasFullFP16) - Builder.defineMacro("__ARM_FEATURE_FP16_VECTOR_ARITHMETIC", "1"); } void getTargetDefines(const LangOptions &Opts, @@ -7408,13 +7429,14 @@ class SystemZTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; static const char *const GCCRegNames[]; std::string CPU; + int ISARevision; bool HasTransactionalExecution; bool HasVector; public: SystemZTargetInfo(const llvm::Triple &Triple, const TargetOptions &) - : TargetInfo(Triple), CPU("z10"), HasTransactionalExecution(false), - HasVector(false) { + : TargetInfo(Triple), CPU("z10"), ISARevision(8), + HasTransactionalExecution(false), HasVector(false) { IntMaxType = SignedLong; Int64Type = SignedLong; TLSSupported = true; @@ -7436,14 +7458,7 @@ public: Builder.defineMacro("__zarch__"); Builder.defineMacro("__LONG_DOUBLE_128__"); - const std::string ISARev = llvm::StringSwitch<std::string>(CPU) - .Cases("arch8", "z10", "8") - .Cases("arch9", "z196", "9") - .Cases("arch10", "zEC12", "10") - .Cases("arch11", "z13", "11") - .Default(""); - if (!ISARev.empty()) - Builder.defineMacro("__ARCH__", ISARev); + Builder.defineMacro("__ARCH__", Twine(ISARevision)); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1"); Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2"); @@ -7476,37 +7491,35 @@ public: BuiltinVaListKind getBuiltinVaListKind() const override { return TargetInfo::SystemZBuiltinVaList; } + int getISARevision(const StringRef &Name) const { + return llvm::StringSwitch<int>(Name) + .Cases("arch8", "z10", 8) + .Cases("arch9", "z196", 9) + .Cases("arch10", "zEC12", 10) + .Cases("arch11", "z13", 11) + .Default(-1); + } bool setCPU(const std::string &Name) override { CPU = Name; - bool CPUKnown = llvm::StringSwitch<bool>(Name) - .Case("z10", true) - .Case("arch8", true) - .Case("z196", true) - .Case("arch9", true) - .Case("zEC12", true) - .Case("arch10", true) - .Case("z13", true) - .Case("arch11", true) - .Default(false); - - return CPUKnown; + ISARevision = getISARevision(CPU); + return ISARevision != -1; } bool initFeatureMap(llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU, const std::vector<std::string> &FeaturesVec) const override { - if (CPU == "zEC12" || CPU == "arch10") - Features["transactional-execution"] = true; - if (CPU == "z13" || CPU == "arch11") { + int ISARevision = getISARevision(CPU); + if (ISARevision >= 10) Features["transactional-execution"] = true; + if (ISARevision >= 11) Features["vector"] = true; - } return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } bool handleTargetFeatures(std::vector<std::string> &Features, DiagnosticsEngine &Diags) override { HasTransactionalExecution = false; + HasVector = false; for (const auto &Feature : Features) { if (Feature == "+transactional-execution") HasTransactionalExecution = true; @@ -7525,6 +7538,10 @@ public: bool hasFeature(StringRef Feature) const override { return llvm::StringSwitch<bool>(Feature) .Case("systemz", true) + .Case("arch8", ISARevision >= 8) + .Case("arch9", ISARevision >= 9) + .Case("arch10", ISARevision >= 10) + .Case("arch11", ISARevision >= 11) .Case("htm", HasTransactionalExecution) .Case("vx", HasVector) .Default(false); diff --git a/lib/CodeGen/BackendUtil.cpp b/lib/CodeGen/BackendUtil.cpp index 9b3850abcce7..513896d98634 100644 --- a/lib/CodeGen/BackendUtil.cpp +++ b/lib/CodeGen/BackendUtil.cpp @@ -998,7 +998,7 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M, std::unique_ptr<raw_pwrite_stream> OS, std::string SampleProfile, BackendAction Action) { - StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>> + StringMap<DenseMap<GlobalValue::GUID, GlobalValueSummary *>> ModuleToDefinedGVSummaries; CombinedIndex->collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 528a2b33acf8..181048957879 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -736,9 +736,9 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { llvm::Constant *isa = (!CGM.getContext().getLangOpts().OpenCL) ? CGM.getNSConcreteStackBlock() - : CGM.getNullPointer(cast<llvm::PointerType>( - CGM.getNSConcreteStackBlock()->getType()), - QualType(getContext().VoidPtrTy)); + : CGM.getNullPointer(VoidPtrPtrTy, + CGM.getContext().getPointerType( + QualType(CGM.getContext().VoidPtrTy))); isa = llvm::ConstantExpr::getBitCast(isa, VoidPtrTy); // Build the block descriptor. @@ -1141,12 +1141,11 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM, auto fields = builder.beginStruct(); // isa - fields.add( - (!CGM.getContext().getLangOpts().OpenCL) - ? CGM.getNSConcreteGlobalBlock() - : CGM.getNullPointer(cast<llvm::PointerType>( - CGM.getNSConcreteGlobalBlock()->getType()), - QualType(CGM.getContext().VoidPtrTy))); + fields.add((!CGM.getContext().getLangOpts().OpenCL) + ? CGM.getNSConcreteGlobalBlock() + : CGM.getNullPointer(CGM.VoidPtrPtrTy, + CGM.getContext().getPointerType(QualType( + CGM.getContext().VoidPtrTy)))); // __flags BlockFlags flags = BLOCK_IS_GLOBAL | BLOCK_HAS_SIGNATURE; @@ -1255,7 +1254,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, // For OpenCL passed block pointer can be private AS local variable or // global AS program scope variable (for the case with and without captures). - // Generic AS is used therefore to be able to accomodate both private and + // Generic AS is used therefore to be able to accommodate both private and // generic AS in one implementation. if (getLangOpts().OpenCL) selfTy = getContext().getPointerType(getContext().getAddrSpaceQualType( diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp index 2a6e92e7f3ce..bc902507c46e 100644 --- a/lib/CodeGen/CGBuiltin.cpp +++ b/lib/CodeGen/CGBuiltin.cpp @@ -1810,12 +1810,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, case Builtin::BI__atomic_signal_fence: case Builtin::BI__c11_atomic_thread_fence: case Builtin::BI__c11_atomic_signal_fence: { - llvm::SynchronizationScope Scope; + llvm::SyncScope::ID SSID; if (BuiltinID == Builtin::BI__atomic_signal_fence || BuiltinID == Builtin::BI__c11_atomic_signal_fence) - Scope = llvm::SingleThread; + SSID = llvm::SyncScope::SingleThread; else - Scope = llvm::CrossThread; + SSID = llvm::SyncScope::System; Value *Order = EmitScalarExpr(E->getArg(0)); if (isa<llvm::ConstantInt>(Order)) { int ord = cast<llvm::ConstantInt>(Order)->getZExtValue(); @@ -1825,17 +1825,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, break; case 1: // memory_order_consume case 2: // memory_order_acquire - Builder.CreateFence(llvm::AtomicOrdering::Acquire, Scope); + Builder.CreateFence(llvm::AtomicOrdering::Acquire, SSID); break; case 3: // memory_order_release - Builder.CreateFence(llvm::AtomicOrdering::Release, Scope); + Builder.CreateFence(llvm::AtomicOrdering::Release, SSID); break; case 4: // memory_order_acq_rel - Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, Scope); + Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, SSID); break; case 5: // memory_order_seq_cst - Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, - Scope); + Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, SSID); break; } return RValue::get(nullptr); @@ -1852,23 +1851,23 @@ RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD, llvm::SwitchInst *SI = Builder.CreateSwitch(Order, ContBB); Builder.SetInsertPoint(AcquireBB); - Builder.CreateFence(llvm::AtomicOrdering::Acquire, Scope); + Builder.CreateFence(llvm::AtomicOrdering::Acquire, SSID); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32(1), AcquireBB); SI->addCase(Builder.getInt32(2), AcquireBB); Builder.SetInsertPoint(ReleaseBB); - Builder.CreateFence(llvm::AtomicOrdering::Release, Scope); + Builder.CreateFence(llvm::AtomicOrdering::Release, SSID); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32(3), ReleaseBB); Builder.SetInsertPoint(AcqRelBB); - Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, Scope); + Builder.CreateFence(llvm::AtomicOrdering::AcquireRelease, SSID); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32(4), AcqRelBB); Builder.SetInsertPoint(SeqCstBB); - Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, Scope); + Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, SSID); Builder.CreateBr(ContBB); SI->addCase(Builder.getInt32(5), SeqCstBB); @@ -2956,9 +2955,8 @@ static llvm::VectorType *GetNeonType(CodeGenFunction *CGF, return llvm::VectorType::get(CGF->Int8Ty, V1Ty ? 1 : (8 << IsQuad)); case NeonTypeFlags::Int16: case NeonTypeFlags::Poly16: - return llvm::VectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad)); case NeonTypeFlags::Float16: - return llvm::VectorType::get(CGF->HalfTy, V1Ty ? 1 : (4 << IsQuad)); + return llvm::VectorType::get(CGF->Int16Ty, V1Ty ? 1 : (4 << IsQuad)); case NeonTypeFlags::Int32: return llvm::VectorType::get(CGF->Int32Ty, V1Ty ? 1 : (2 << IsQuad)); case NeonTypeFlags::Int64: @@ -2981,8 +2979,6 @@ static llvm::VectorType *GetFloatNeonType(CodeGenFunction *CGF, NeonTypeFlags IntTypeFlags) { int IsQuad = IntTypeFlags.isQuad(); switch (IntTypeFlags.getEltType()) { - case NeonTypeFlags::Int16: - return llvm::VectorType::get(CGF->HalfTy, (4 << IsQuad)); case NeonTypeFlags::Int32: return llvm::VectorType::get(CGF->FloatTy, (2 << IsQuad)); case NeonTypeFlags::Int64: @@ -3130,80 +3126,55 @@ static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = { NEONMAP1(vcvt_f16_f32, arm_neon_vcvtfp2hf, 0), NEONMAP1(vcvt_f32_f16, arm_neon_vcvthf2fp, 0), NEONMAP0(vcvt_f32_v), - NEONMAP2(vcvt_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), NEONMAP2(vcvt_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), - NEONMAP1(vcvt_n_s16_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s32_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s64_v, arm_neon_vcvtfp2fxs, 0), - NEONMAP1(vcvt_n_u16_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u32_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u64_v, arm_neon_vcvtfp2fxu, 0), - NEONMAP0(vcvt_s16_v), NEONMAP0(vcvt_s32_v), NEONMAP0(vcvt_s64_v), - NEONMAP0(vcvt_u16_v), NEONMAP0(vcvt_u32_v), NEONMAP0(vcvt_u64_v), - NEONMAP1(vcvta_s16_v, arm_neon_vcvtas, 0), NEONMAP1(vcvta_s32_v, arm_neon_vcvtas, 0), NEONMAP1(vcvta_s64_v, arm_neon_vcvtas, 0), NEONMAP1(vcvta_u32_v, arm_neon_vcvtau, 0), NEONMAP1(vcvta_u64_v, arm_neon_vcvtau, 0), - NEONMAP1(vcvtaq_s16_v, arm_neon_vcvtas, 0), NEONMAP1(vcvtaq_s32_v, arm_neon_vcvtas, 0), NEONMAP1(vcvtaq_s64_v, arm_neon_vcvtas, 0), - NEONMAP1(vcvtaq_u16_v, arm_neon_vcvtau, 0), NEONMAP1(vcvtaq_u32_v, arm_neon_vcvtau, 0), NEONMAP1(vcvtaq_u64_v, arm_neon_vcvtau, 0), - NEONMAP1(vcvtm_s16_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtm_s32_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtm_s64_v, arm_neon_vcvtms, 0), - NEONMAP1(vcvtm_u16_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtm_u32_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtm_u64_v, arm_neon_vcvtmu, 0), - NEONMAP1(vcvtmq_s16_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtmq_s32_v, arm_neon_vcvtms, 0), NEONMAP1(vcvtmq_s64_v, arm_neon_vcvtms, 0), - NEONMAP1(vcvtmq_u16_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtmq_u32_v, arm_neon_vcvtmu, 0), NEONMAP1(vcvtmq_u64_v, arm_neon_vcvtmu, 0), - NEONMAP1(vcvtn_s16_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtn_s32_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtn_s64_v, arm_neon_vcvtns, 0), - NEONMAP1(vcvtn_u16_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtn_u32_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtn_u64_v, arm_neon_vcvtnu, 0), - NEONMAP1(vcvtnq_s16_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtnq_s32_v, arm_neon_vcvtns, 0), NEONMAP1(vcvtnq_s64_v, arm_neon_vcvtns, 0), - NEONMAP1(vcvtnq_u16_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtnq_u32_v, arm_neon_vcvtnu, 0), NEONMAP1(vcvtnq_u64_v, arm_neon_vcvtnu, 0), - NEONMAP1(vcvtp_s16_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtp_s32_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtp_s64_v, arm_neon_vcvtps, 0), - NEONMAP1(vcvtp_u16_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtp_u32_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtp_u64_v, arm_neon_vcvtpu, 0), - NEONMAP1(vcvtpq_s16_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtpq_s32_v, arm_neon_vcvtps, 0), NEONMAP1(vcvtpq_s64_v, arm_neon_vcvtps, 0), - NEONMAP1(vcvtpq_u16_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtpq_u32_v, arm_neon_vcvtpu, 0), NEONMAP1(vcvtpq_u64_v, arm_neon_vcvtpu, 0), NEONMAP0(vcvtq_f32_v), - NEONMAP2(vcvtq_n_f16_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), NEONMAP2(vcvtq_n_f32_v, arm_neon_vcvtfxu2fp, arm_neon_vcvtfxs2fp, 0), - NEONMAP1(vcvtq_n_s16_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s32_v, arm_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s64_v, arm_neon_vcvtfp2fxs, 0), - NEONMAP1(vcvtq_n_u16_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u32_v, arm_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u64_v, arm_neon_vcvtfp2fxu, 0), - NEONMAP0(vcvtq_s16_v), NEONMAP0(vcvtq_s32_v), NEONMAP0(vcvtq_s64_v), - NEONMAP0(vcvtq_u16_v), NEONMAP0(vcvtq_u32_v), NEONMAP0(vcvtq_u64_v), NEONMAP0(vext_v), @@ -3366,27 +3337,19 @@ static const NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = { NEONMAP1(vcnt_v, ctpop, Add1ArgType), NEONMAP1(vcntq_v, ctpop, Add1ArgType), NEONMAP1(vcvt_f16_f32, aarch64_neon_vcvtfp2hf, 0), - NEONMAP0(vcvt_f16_v), NEONMAP1(vcvt_f32_f16, aarch64_neon_vcvthf2fp, 0), NEONMAP0(vcvt_f32_v), - NEONMAP2(vcvt_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvt_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvt_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), - NEONMAP1(vcvt_n_s16_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s32_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvt_n_s64_v, aarch64_neon_vcvtfp2fxs, 0), - NEONMAP1(vcvt_n_u16_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u32_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvt_n_u64_v, aarch64_neon_vcvtfp2fxu, 0), - NEONMAP0(vcvtq_f16_v), NEONMAP0(vcvtq_f32_v), - NEONMAP2(vcvtq_n_f16_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvtq_n_f32_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), NEONMAP2(vcvtq_n_f64_v, aarch64_neon_vcvtfxu2fp, aarch64_neon_vcvtfxs2fp, 0), - NEONMAP1(vcvtq_n_s16_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s32_v, aarch64_neon_vcvtfp2fxs, 0), NEONMAP1(vcvtq_n_s64_v, aarch64_neon_vcvtfp2fxs, 0), - NEONMAP1(vcvtq_n_u16_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u32_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtq_n_u64_v, aarch64_neon_vcvtfp2fxu, 0), NEONMAP1(vcvtx_f32_v, aarch64_neon_fcvtxn, AddRetType | Add1ArgType), @@ -3855,20 +3818,9 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( case NEON::BI__builtin_neon_vcageq_v: case NEON::BI__builtin_neon_vcagt_v: case NEON::BI__builtin_neon_vcagtq_v: { - llvm::Type *Ty; - switch (VTy->getScalarSizeInBits()) { - default: llvm_unreachable("unexpected type"); - case 32: - Ty = FloatTy; - break; - case 64: - Ty = DoubleTy; - break; - case 16: - Ty = HalfTy; - break; - } - llvm::Type *VecFlt = llvm::VectorType::get(Ty, VTy->getNumElements()); + llvm::Type *VecFlt = llvm::VectorType::get( + VTy->getScalarSizeInBits() == 32 ? FloatTy : DoubleTy, + VTy->getNumElements()); llvm::Type *Tys[] = { VTy, VecFlt }; Function *F = CGM.getIntrinsic(LLVMIntrinsic, Tys); return EmitNeonCall(F, Ops, NameHint); @@ -3885,16 +3837,8 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float32, false, Quad)); return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt") : Builder.CreateSIToFP(Ops[0], Ty, "vcvt"); - case NEON::BI__builtin_neon_vcvt_f16_v: - case NEON::BI__builtin_neon_vcvtq_f16_v: - Ops[0] = Builder.CreateBitCast(Ops[0], Ty); - Ty = GetNeonType(this, NeonTypeFlags(NeonTypeFlags::Float16, false, Quad)); - return Usgn ? Builder.CreateUIToFP(Ops[0], Ty, "vcvt") - : Builder.CreateSIToFP(Ops[0], Ty, "vcvt"); - case NEON::BI__builtin_neon_vcvt_n_f16_v: case NEON::BI__builtin_neon_vcvt_n_f32_v: case NEON::BI__builtin_neon_vcvt_n_f64_v: - case NEON::BI__builtin_neon_vcvtq_n_f16_v: case NEON::BI__builtin_neon_vcvtq_n_f32_v: case NEON::BI__builtin_neon_vcvtq_n_f64_v: { llvm::Type *Tys[2] = { GetFloatNeonType(this, Type), Ty }; @@ -3902,15 +3846,11 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( Function *F = CGM.getIntrinsic(Int, Tys); return EmitNeonCall(F, Ops, "vcvt_n"); } - case NEON::BI__builtin_neon_vcvt_n_s16_v: case NEON::BI__builtin_neon_vcvt_n_s32_v: - case NEON::BI__builtin_neon_vcvt_n_u16_v: case NEON::BI__builtin_neon_vcvt_n_u32_v: case NEON::BI__builtin_neon_vcvt_n_s64_v: case NEON::BI__builtin_neon_vcvt_n_u64_v: - case NEON::BI__builtin_neon_vcvtq_n_s16_v: case NEON::BI__builtin_neon_vcvtq_n_s32_v: - case NEON::BI__builtin_neon_vcvtq_n_u16_v: case NEON::BI__builtin_neon_vcvtq_n_u32_v: case NEON::BI__builtin_neon_vcvtq_n_s64_v: case NEON::BI__builtin_neon_vcvtq_n_u64_v: { @@ -3922,63 +3862,44 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( case NEON::BI__builtin_neon_vcvt_u32_v: case NEON::BI__builtin_neon_vcvt_s64_v: case NEON::BI__builtin_neon_vcvt_u64_v: - case NEON::BI__builtin_neon_vcvt_s16_v: - case NEON::BI__builtin_neon_vcvt_u16_v: case NEON::BI__builtin_neon_vcvtq_s32_v: case NEON::BI__builtin_neon_vcvtq_u32_v: case NEON::BI__builtin_neon_vcvtq_s64_v: - case NEON::BI__builtin_neon_vcvtq_u64_v: - case NEON::BI__builtin_neon_vcvtq_s16_v: - case NEON::BI__builtin_neon_vcvtq_u16_v: { + case NEON::BI__builtin_neon_vcvtq_u64_v: { Ops[0] = Builder.CreateBitCast(Ops[0], GetFloatNeonType(this, Type)); return Usgn ? Builder.CreateFPToUI(Ops[0], Ty, "vcvt") : Builder.CreateFPToSI(Ops[0], Ty, "vcvt"); } - case NEON::BI__builtin_neon_vcvta_s16_v: case NEON::BI__builtin_neon_vcvta_s32_v: case NEON::BI__builtin_neon_vcvta_s64_v: case NEON::BI__builtin_neon_vcvta_u32_v: case NEON::BI__builtin_neon_vcvta_u64_v: - case NEON::BI__builtin_neon_vcvtaq_s16_v: case NEON::BI__builtin_neon_vcvtaq_s32_v: case NEON::BI__builtin_neon_vcvtaq_s64_v: - case NEON::BI__builtin_neon_vcvtaq_u16_v: case NEON::BI__builtin_neon_vcvtaq_u32_v: case NEON::BI__builtin_neon_vcvtaq_u64_v: - case NEON::BI__builtin_neon_vcvtn_s16_v: case NEON::BI__builtin_neon_vcvtn_s32_v: case NEON::BI__builtin_neon_vcvtn_s64_v: - case NEON::BI__builtin_neon_vcvtn_u16_v: case NEON::BI__builtin_neon_vcvtn_u32_v: case NEON::BI__builtin_neon_vcvtn_u64_v: - case NEON::BI__builtin_neon_vcvtnq_s16_v: case NEON::BI__builtin_neon_vcvtnq_s32_v: case NEON::BI__builtin_neon_vcvtnq_s64_v: - case NEON::BI__builtin_neon_vcvtnq_u16_v: case NEON::BI__builtin_neon_vcvtnq_u32_v: case NEON::BI__builtin_neon_vcvtnq_u64_v: - case NEON::BI__builtin_neon_vcvtp_s16_v: case NEON::BI__builtin_neon_vcvtp_s32_v: case NEON::BI__builtin_neon_vcvtp_s64_v: - case NEON::BI__builtin_neon_vcvtp_u16_v: case NEON::BI__builtin_neon_vcvtp_u32_v: case NEON::BI__builtin_neon_vcvtp_u64_v: - case NEON::BI__builtin_neon_vcvtpq_s16_v: case NEON::BI__builtin_neon_vcvtpq_s32_v: case NEON::BI__builtin_neon_vcvtpq_s64_v: - case NEON::BI__builtin_neon_vcvtpq_u16_v: case NEON::BI__builtin_neon_vcvtpq_u32_v: case NEON::BI__builtin_neon_vcvtpq_u64_v: - case NEON::BI__builtin_neon_vcvtm_s16_v: case NEON::BI__builtin_neon_vcvtm_s32_v: case NEON::BI__builtin_neon_vcvtm_s64_v: - case NEON::BI__builtin_neon_vcvtm_u16_v: case NEON::BI__builtin_neon_vcvtm_u32_v: case NEON::BI__builtin_neon_vcvtm_u64_v: - case NEON::BI__builtin_neon_vcvtmq_s16_v: case NEON::BI__builtin_neon_vcvtmq_s32_v: case NEON::BI__builtin_neon_vcvtmq_s64_v: - case NEON::BI__builtin_neon_vcvtmq_u16_v: case NEON::BI__builtin_neon_vcvtmq_u32_v: case NEON::BI__builtin_neon_vcvtmq_u64_v: { llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; @@ -6188,9 +6109,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Ops[2] = EmitNeonSplat(Ops[2], cast<ConstantInt>(Ops[3])); return Builder.CreateCall(F, {Ops[2], Ops[1], Ops[0]}); } - case NEON::BI__builtin_neon_vfmah_lane_f16: case NEON::BI__builtin_neon_vfmas_lane_f32: - case NEON::BI__builtin_neon_vfmah_laneq_f16: case NEON::BI__builtin_neon_vfmas_laneq_f32: case NEON::BI__builtin_neon_vfmad_lane_f64: case NEON::BI__builtin_neon_vfmad_laneq_f64: { @@ -6365,25 +6284,18 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, case NEON::BI__builtin_neon_vcvt_u32_v: case NEON::BI__builtin_neon_vcvt_s64_v: case NEON::BI__builtin_neon_vcvt_u64_v: - case NEON::BI__builtin_neon_vcvt_s16_v: - case NEON::BI__builtin_neon_vcvt_u16_v: case NEON::BI__builtin_neon_vcvtq_s32_v: case NEON::BI__builtin_neon_vcvtq_u32_v: case NEON::BI__builtin_neon_vcvtq_s64_v: - case NEON::BI__builtin_neon_vcvtq_u64_v: - case NEON::BI__builtin_neon_vcvtq_s16_v: - case NEON::BI__builtin_neon_vcvtq_u16_v: { + case NEON::BI__builtin_neon_vcvtq_u64_v: { Ops[0] = Builder.CreateBitCast(Ops[0], GetFloatNeonType(this, Type)); if (usgn) return Builder.CreateFPToUI(Ops[0], Ty); return Builder.CreateFPToSI(Ops[0], Ty); } - case NEON::BI__builtin_neon_vcvta_s16_v: case NEON::BI__builtin_neon_vcvta_s32_v: - case NEON::BI__builtin_neon_vcvtaq_s16_v: case NEON::BI__builtin_neon_vcvtaq_s32_v: case NEON::BI__builtin_neon_vcvta_u32_v: - case NEON::BI__builtin_neon_vcvtaq_u16_v: case NEON::BI__builtin_neon_vcvtaq_u32_v: case NEON::BI__builtin_neon_vcvta_s64_v: case NEON::BI__builtin_neon_vcvtaq_s64_v: @@ -6393,13 +6305,9 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvta"); } - case NEON::BI__builtin_neon_vcvtm_s16_v: case NEON::BI__builtin_neon_vcvtm_s32_v: - case NEON::BI__builtin_neon_vcvtmq_s16_v: case NEON::BI__builtin_neon_vcvtmq_s32_v: - case NEON::BI__builtin_neon_vcvtm_u16_v: case NEON::BI__builtin_neon_vcvtm_u32_v: - case NEON::BI__builtin_neon_vcvtmq_u16_v: case NEON::BI__builtin_neon_vcvtmq_u32_v: case NEON::BI__builtin_neon_vcvtm_s64_v: case NEON::BI__builtin_neon_vcvtmq_s64_v: @@ -6409,13 +6317,9 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtm"); } - case NEON::BI__builtin_neon_vcvtn_s16_v: case NEON::BI__builtin_neon_vcvtn_s32_v: - case NEON::BI__builtin_neon_vcvtnq_s16_v: case NEON::BI__builtin_neon_vcvtnq_s32_v: - case NEON::BI__builtin_neon_vcvtn_u16_v: case NEON::BI__builtin_neon_vcvtn_u32_v: - case NEON::BI__builtin_neon_vcvtnq_u16_v: case NEON::BI__builtin_neon_vcvtnq_u32_v: case NEON::BI__builtin_neon_vcvtn_s64_v: case NEON::BI__builtin_neon_vcvtnq_s64_v: @@ -6425,13 +6329,9 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; return EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vcvtn"); } - case NEON::BI__builtin_neon_vcvtp_s16_v: case NEON::BI__builtin_neon_vcvtp_s32_v: - case NEON::BI__builtin_neon_vcvtpq_s16_v: case NEON::BI__builtin_neon_vcvtpq_s32_v: - case NEON::BI__builtin_neon_vcvtp_u16_v: case NEON::BI__builtin_neon_vcvtp_u32_v: - case NEON::BI__builtin_neon_vcvtpq_u16_v: case NEON::BI__builtin_neon_vcvtpq_u32_v: case NEON::BI__builtin_neon_vcvtp_s64_v: case NEON::BI__builtin_neon_vcvtpq_s64_v: @@ -6604,24 +6504,6 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv"); return Builder.CreateTrunc(Ops[0], Int16Ty); } - case NEON::BI__builtin_neon_vmaxv_f16: { - Int = Intrinsic::aarch64_neon_fmaxv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 4); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vmaxvq_f16: { - Int = Intrinsic::aarch64_neon_fmaxv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 8); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } case NEON::BI__builtin_neon_vminv_u8: { Int = Intrinsic::aarch64_neon_uminv; Ty = Int32Ty; @@ -6694,60 +6576,6 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv"); return Builder.CreateTrunc(Ops[0], Int16Ty); } - case NEON::BI__builtin_neon_vminv_f16: { - Int = Intrinsic::aarch64_neon_fminv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 4); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vminvq_f16: { - Int = Intrinsic::aarch64_neon_fminv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 8); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vmaxnmv_f16: { - Int = Intrinsic::aarch64_neon_fmaxnmv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 4); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxnmv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vmaxnmvq_f16: { - Int = Intrinsic::aarch64_neon_fmaxnmv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 8); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vmaxnmv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vminnmv_f16: { - Int = Intrinsic::aarch64_neon_fminnmv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 4); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminnmv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } - case NEON::BI__builtin_neon_vminnmvq_f16: { - Int = Intrinsic::aarch64_neon_fminnmv; - Ty = HalfTy; - VTy = llvm::VectorType::get(HalfTy, 8); - llvm::Type *Tys[2] = { Ty, VTy }; - Ops.push_back(EmitScalarExpr(E->getArg(0))); - Ops[0] = EmitNeonCall(CGM.getIntrinsic(Int, Tys), Ops, "vminnmv"); - return Builder.CreateTrunc(Ops[0], HalfTy); - } case NEON::BI__builtin_neon_vmul_n_f64: { Ops[0] = Builder.CreateBitCast(Ops[0], DoubleTy); Value *RHS = Builder.CreateBitCast(EmitScalarExpr(E->getArg(1)), DoubleTy); @@ -7506,6 +7334,8 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, AVX512PF, AVX512VBMI, AVX512IFMA, + AVX5124VNNIW, // TODO implement this fully + AVX5124FMAPS, // TODO implement this fully AVX512VPOPCNTDQ, MAX }; @@ -8208,13 +8038,13 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__faststorefence: { return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, - llvm::CrossThread); + llvm::SyncScope::System); } case X86::BI_ReadWriteBarrier: case X86::BI_ReadBarrier: case X86::BI_WriteBarrier: { return Builder.CreateFence(llvm::AtomicOrdering::SequentiallyConsistent, - llvm::SingleThread); + llvm::SyncScope::SingleThread); } case X86::BI_BitScanForward: case X86::BI_BitScanForward64: diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 13a156c7bbd7..cee656a62fe7 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -129,7 +129,7 @@ static void addExtParameterInfosForCall( paramInfos.resize(totalArgs); } -/// Adds the formal paramaters in FPT to the given prefix. If any parameter in +/// Adds the formal parameters in FPT to the given prefix. If any parameter in /// FPT has pass_object_size attrs, then we'll add parameters for those, too. static void appendParameterTypes(const CodeGenTypes &CGT, SmallVectorImpl<CanQualType> &prefix, diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp index 127d7df348ee..50d702c62268 100644 --- a/lib/CodeGen/CGClass.cpp +++ b/lib/CodeGen/CGClass.cpp @@ -2716,88 +2716,6 @@ llvm::Value *CodeGenFunction::EmitVTableTypeCheckedLoad( cast<llvm::PointerType>(VTable->getType())->getElementType()); } -bool -CodeGenFunction::CanDevirtualizeMemberFunctionCall(const Expr *Base, - const CXXMethodDecl *MD) { - // When building with -fapple-kext, all calls must go through the vtable since - // the kernel linker can do runtime patching of vtables. - if (getLangOpts().AppleKext) - return false; - - // If the member function is marked 'final', we know that it can't be - // overridden and can therefore devirtualize it unless it's pure virtual. - if (MD->hasAttr<FinalAttr>()) - return !MD->isPure(); - - // If the base expression (after skipping derived-to-base conversions) is a - // class prvalue, then we can devirtualize. - Base = Base->getBestDynamicClassTypeExpr(); - if (Base->isRValue() && Base->getType()->isRecordType()) - return true; - - // If we don't even know what we would call, we can't devirtualize. - const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType(); - if (!BestDynamicDecl) - return false; - - // There may be a method corresponding to MD in a derived class. - const CXXMethodDecl *DevirtualizedMethod = - MD->getCorrespondingMethodInClass(BestDynamicDecl); - - // If that method is pure virtual, we can't devirtualize. If this code is - // reached, the result would be UB, not a direct call to the derived class - // function, and we can't assume the derived class function is defined. - if (DevirtualizedMethod->isPure()) - return false; - - // If that method is marked final, we can devirtualize it. - if (DevirtualizedMethod->hasAttr<FinalAttr>()) - return true; - - // Similarly, if the class itself is marked 'final' it can't be overridden - // and we can therefore devirtualize the member function call. - if (BestDynamicDecl->hasAttr<FinalAttr>()) - return true; - - if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) { - if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) { - // This is a record decl. We know the type and can devirtualize it. - return VD->getType()->isRecordType(); - } - - return false; - } - - // We can devirtualize calls on an object accessed by a class member access - // expression, since by C++11 [basic.life]p6 we know that it can't refer to - // a derived class object constructed in the same location. However, we avoid - // devirtualizing a call to a template function that we could instantiate - // implicitly, but have not decided to do so. This is needed because if this - // function does not get instantiated, the devirtualization will create a - // direct call to a function whose body may not exist. In contrast, calls to - // template functions that are not defined in this TU are allowed to be - // devirtualized under assumption that it is user responsibility to - // instantiate them in some other TU. - if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base)) - if (const ValueDecl *VD = dyn_cast<ValueDecl>(ME->getMemberDecl())) - return VD->getType()->isRecordType() && - (MD->instantiationIsPending() || MD->isDefined() || - !MD->isImplicitlyInstantiable()); - - // Likewise for calls on an object accessed by a (non-reference) pointer to - // member access. - if (auto *BO = dyn_cast<BinaryOperator>(Base)) { - if (BO->isPtrMemOp()) { - auto *MPT = BO->getRHS()->getType()->castAs<MemberPointerType>(); - if (MPT->getPointeeType()->isRecordType()) - return true; - } - } - - // We can't devirtualize the call. - return false; -} - void CodeGenFunction::EmitForwardingCallToLambda( const CXXMethodDecl *callOperator, CallArgList &callArgs) { diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 4b656ea4a879..23517867437c 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -221,8 +221,8 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( Name = getStaticDeclName(*this, D); llvm::Type *LTy = getTypes().ConvertTypeForMem(Ty); - unsigned AddrSpace = - GetGlobalVarAddressSpace(&D, getContext().getTargetAddressSpace(Ty)); + unsigned AS = GetGlobalVarAddressSpace(&D); + unsigned TargetAS = getContext().getTargetAddressSpace(AS); // Local address space cannot have an initializer. llvm::Constant *Init = nullptr; @@ -231,12 +231,9 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( else Init = llvm::UndefValue::get(LTy); - llvm::GlobalVariable *GV = - new llvm::GlobalVariable(getModule(), LTy, - Ty.isConstant(getContext()), Linkage, - Init, Name, nullptr, - llvm::GlobalVariable::NotThreadLocal, - AddrSpace); + llvm::GlobalVariable *GV = new llvm::GlobalVariable( + getModule(), LTy, Ty.isConstant(getContext()), Linkage, Init, Name, + nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS); GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); setGlobalVisibility(GV, &D); @@ -254,11 +251,12 @@ llvm::Constant *CodeGenModule::getOrCreateStaticVarDecl( } // Make sure the result is of the correct type. - unsigned ExpectedAddrSpace = getContext().getTargetAddressSpace(Ty); + unsigned ExpectedAS = Ty.getAddressSpace(); llvm::Constant *Addr = GV; - if (AddrSpace != ExpectedAddrSpace) { - llvm::PointerType *PTy = llvm::PointerType::get(LTy, ExpectedAddrSpace); - Addr = llvm::ConstantExpr::getAddrSpaceCast(GV, PTy); + if (AS != ExpectedAS) { + Addr = getTargetCodeGenInfo().performAddrSpaceCast( + *this, GV, AS, ExpectedAS, + LTy->getPointerTo(getContext().getTargetAddressSpace(ExpectedAS))); } setStaticLocalDeclAddress(&D, Addr); diff --git a/lib/CodeGen/CGExpr.cpp b/lib/CodeGen/CGExpr.cpp index 2ee1c96a6619..9f40ee5a00a3 100644 --- a/lib/CodeGen/CGExpr.cpp +++ b/lib/CodeGen/CGExpr.cpp @@ -338,9 +338,10 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, } } -static Address -createReferenceTemporary(CodeGenFunction &CGF, - const MaterializeTemporaryExpr *M, const Expr *Inner) { +static Address createReferenceTemporary(CodeGenFunction &CGF, + const MaterializeTemporaryExpr *M, + const Expr *Inner) { + auto &TCG = CGF.getTargetHooks(); switch (M->getStorageDuration()) { case SD_FullExpression: case SD_Automatic: { @@ -353,13 +354,24 @@ createReferenceTemporary(CodeGenFunction &CGF, (Ty->isArrayType() || Ty->isRecordType()) && CGF.CGM.isTypeConstant(Ty, true)) if (llvm::Constant *Init = CGF.CGM.EmitConstantExpr(Inner, Ty, &CGF)) { - auto *GV = new llvm::GlobalVariable( - CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true, - llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp"); - CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty); - GV->setAlignment(alignment.getQuantity()); - // FIXME: Should we put the new global into a COMDAT? - return Address(GV, alignment); + if (auto AddrSpace = CGF.getTarget().getConstantAddressSpace()) { + auto AS = AddrSpace.getValue(); + auto *GV = new llvm::GlobalVariable( + CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true, + llvm::GlobalValue::PrivateLinkage, Init, ".ref.tmp", nullptr, + llvm::GlobalValue::NotThreadLocal, + CGF.getContext().getTargetAddressSpace(AS)); + CharUnits alignment = CGF.getContext().getTypeAlignInChars(Ty); + GV->setAlignment(alignment.getQuantity()); + llvm::Constant *C = GV; + if (AS != LangAS::Default) + C = TCG.performAddrSpaceCast( + CGF.CGM, GV, AS, LangAS::Default, + GV->getValueType()->getPointerTo( + CGF.getContext().getTargetAddressSpace(LangAS::Default))); + // FIXME: Should we put the new global into a COMDAT? + return Address(C, alignment); + } } return CGF.CreateMemTemp(Ty, "ref.tmp"); } @@ -440,9 +452,11 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { // Create and initialize the reference temporary. Address Object = createReferenceTemporary(*this, M, E); - if (auto *Var = dyn_cast<llvm::GlobalVariable>(Object.getPointer())) { + if (auto *Var = dyn_cast<llvm::GlobalVariable>( + Object.getPointer()->stripPointerCasts())) { Object = Address(llvm::ConstantExpr::getBitCast( - Var, ConvertTypeForMem(E->getType())->getPointerTo()), + cast<llvm::Constant>(Object.getPointer()), + ConvertTypeForMem(E->getType())->getPointerTo()), Object.getAlignment()); // If the temporary is a global and has a constant initializer or is a // constant temporary that we promoted to a global, we may have already diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index a9865f3703d4..ab170245284c 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -199,7 +199,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( bool CanUseVirtualCall = MD->isVirtual() && !HasQualifier; const CXXMethodDecl *DevirtualizedMethod = nullptr; - if (CanUseVirtualCall && CanDevirtualizeMemberFunctionCall(Base, MD)) { + if (CanUseVirtualCall && + MD->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) { const CXXRecordDecl *BestDynamicDecl = Base->getBestDynamicClassType(); DevirtualizedMethod = MD->getCorrespondingMethodInClass(BestDynamicDecl); assert(DevirtualizedMethod); diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp index 3df95a4e9b2a..a2ea0dec3e9d 100644 --- a/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/lib/CodeGen/CGOpenMPRuntime.cpp @@ -4157,9 +4157,15 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc, /*IsInitializer=*/true); enum { NoSchedule = 0, Grainsize = 1, NumTasks = 2 }; llvm::Value *TaskArgs[] = { - UpLoc, ThreadID, Result.NewTask, IfVal, LBLVal.getPointer(), - UBLVal.getPointer(), CGF.EmitLoadOfScalar(StLVal, SourceLocation()), - llvm::ConstantInt::getSigned(CGF.IntTy, Data.Nogroup ? 1 : 0), + UpLoc, + ThreadID, + Result.NewTask, + IfVal, + LBLVal.getPointer(), + UBLVal.getPointer(), + CGF.EmitLoadOfScalar(StLVal, SourceLocation()), + llvm::ConstantInt::getNullValue( + CGF.IntTy), // Always 0 because taskgroup emitted by the compiler llvm::ConstantInt::getSigned( CGF.IntTy, Data.Schedule.getPointer() ? Data.Schedule.getInt() ? NumTasks : Grainsize @@ -4168,10 +4174,9 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc, ? CGF.Builder.CreateIntCast(Data.Schedule.getPointer(), CGF.Int64Ty, /*isSigned=*/false) : llvm::ConstantInt::get(CGF.Int64Ty, /*V=*/0), - Result.TaskDupFn - ? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Result.TaskDupFn, - CGF.VoidPtrTy) - : llvm::ConstantPointerNull::get(CGF.VoidPtrTy)}; + Result.TaskDupFn ? CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + Result.TaskDupFn, CGF.VoidPtrTy) + : llvm::ConstantPointerNull::get(CGF.VoidPtrTy)}; CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_taskloop), TaskArgs); } diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp index 493cd627e418..71797e2e6fbe 100644 --- a/lib/CodeGen/CGStmtOpenMP.cpp +++ b/lib/CodeGen/CGStmtOpenMP.cpp @@ -4363,7 +4363,18 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) { CGF.CGM.getOpenMPRuntime().emitInlinedDirective(CGF, OMPD_taskloop, CodeGen); }; - EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data); + if (Data.Nogroup) + EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data); + else { + CGM.getOpenMPRuntime().emitTaskgroupRegion( + *this, + [&S, &BodyGen, &TaskGen, &Data](CodeGenFunction &CGF, + PrePostActionTy &Action) { + Action.Enter(CGF); + CGF.EmitOMPTaskBasedDirective(S, BodyGen, TaskGen, Data); + }, + S.getLocStart()); + } } void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) { diff --git a/lib/CodeGen/CodeGenABITypes.cpp b/lib/CodeGen/CodeGenABITypes.cpp index 166f44f816f3..0735a9c3dfbc 100644 --- a/lib/CodeGen/CodeGenABITypes.cpp +++ b/lib/CodeGen/CodeGenABITypes.cpp @@ -64,3 +64,19 @@ CodeGen::arrangeFreeFunctionCall(CodeGenModule &CGM, returnType, /*IsInstanceMethod=*/false, /*IsChainCall=*/false, argTypes, info, {}, args); } + +llvm::FunctionType * +CodeGen::convertFreeFunctionType(CodeGenModule &CGM, const FunctionDecl *FD) { + assert(FD != nullptr && "Expected a non-null function declaration!"); + llvm::Type *T = CGM.getTypes().ConvertFunctionType(FD->getType(), FD); + + if (auto FT = dyn_cast<llvm::FunctionType>(T)) + return FT; + + return nullptr; +} + +llvm::Type * +CodeGen::convertTypeForMemory(CodeGenModule &CGM, QualType T) { + return CGM.getTypes().ConvertTypeForMem(T); +} diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h index 6785111bd052..5933e029be8d 100644 --- a/lib/CodeGen/CodeGenFunction.h +++ b/lib/CodeGen/CodeGenFunction.h @@ -1479,6 +1479,9 @@ public: const TargetInfo &getTarget() const { return Target; } llvm::LLVMContext &getLLVMContext() { return CGM.getLLVMContext(); } + const TargetCodeGenInfo &getTargetHooks() const { + return CGM.getTargetCodeGenInfo(); + } //===--------------------------------------------------------------------===// // Cleanups @@ -1749,11 +1752,6 @@ public: llvm::Value *EmitVTableTypeCheckedLoad(const CXXRecordDecl *RD, llvm::Value *VTable, uint64_t VTableByteOffset); - /// CanDevirtualizeMemberFunctionCalls - Checks whether virtual calls on given - /// expr can be devirtualized. - bool CanDevirtualizeMemberFunctionCall(const Expr *Base, - const CXXMethodDecl *MD); - /// EnterDtorCleanups - Enter the cleanups necessary to complete the /// given phase of destruction for a destructor. The end result /// should call destructors on members and base classes in reverse @@ -3820,10 +3818,6 @@ public: private: QualType getVarArgType(const Expr *Arg); - const TargetCodeGenInfo &getTargetHooks() const { - return CGM.getTargetCodeGenInfo(); - } - void EmitDeclMetadata(); BlockByrefHelpers *buildByrefHelpers(llvm::StructType &byrefType, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 5319ccec163f..4b15b8ac4c71 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -98,7 +98,6 @@ CodeGenModule::CodeGenModule(ASTContext &C, const HeaderSearchOptions &HSO, Int16Ty = llvm::Type::getInt16Ty(LLVMContext); Int32Ty = llvm::Type::getInt32Ty(LLVMContext); Int64Ty = llvm::Type::getInt64Ty(LLVMContext); - HalfTy = llvm::Type::getHalfTy(LLVMContext); FloatTy = llvm::Type::getFloatTy(LLVMContext); DoubleTy = llvm::Type::getDoubleTy(LLVMContext); PointerWidthInBits = C.getTargetInfo().getPointerWidth(0); @@ -1099,7 +1098,7 @@ static void setLinkageAndVisibilityForGV(llvm::GlobalValue *GV, const NamedDecl *ND) { // Set linkage and visibility in case we never see a definition. LinkageInfo LV = ND->getLinkageAndVisibility(); - if (LV.getLinkage() != ExternalLinkage) { + if (!isExternallyVisible(LV.getLinkage())) { // Don't set internal linkage on declarations. } else { if (ND->hasAttr<DLLImportAttr>()) { @@ -2368,11 +2367,13 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, return llvm::ConstantExpr::getBitCast(Entry, Ty); } - unsigned AddrSpace = GetGlobalVarAddressSpace(D, Ty->getAddressSpace()); + auto AddrSpace = GetGlobalVarAddressSpace(D); + auto TargetAddrSpace = getContext().getTargetAddressSpace(AddrSpace); + auto *GV = new llvm::GlobalVariable( getModule(), Ty->getElementType(), false, llvm::GlobalValue::ExternalLinkage, nullptr, MangledName, nullptr, - llvm::GlobalVariable::NotThreadLocal, AddrSpace); + llvm::GlobalVariable::NotThreadLocal, TargetAddrSpace); // If we already created a global with the same mangled name (but different // type) before, take its name and remove it from its parent. @@ -2429,8 +2430,15 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, GV->setSection(".cp.rodata"); } - if (AddrSpace != Ty->getAddressSpace()) - return llvm::ConstantExpr::getAddrSpaceCast(GV, Ty); + auto ExpectedAS = + D ? D->getType().getAddressSpace() + : static_cast<unsigned>(LangOpts.OpenCL ? LangAS::opencl_global + : LangAS::Default); + assert(getContext().getTargetAddressSpace(ExpectedAS) == + Ty->getPointerAddressSpace()); + if (AddrSpace != ExpectedAS) + return getTargetCodeGenInfo().performAddrSpaceCast(*this, GV, AddrSpace, + ExpectedAS, Ty); return GV; } @@ -2564,18 +2572,28 @@ CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { getDataLayout().getTypeStoreSizeInBits(Ty)); } -unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D, - unsigned AddrSpace) { - if (D && LangOpts.CUDA && LangOpts.CUDAIsDevice) { - if (D->hasAttr<CUDAConstantAttr>()) - AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_constant); - else if (D->hasAttr<CUDASharedAttr>()) - AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_shared); +unsigned CodeGenModule::GetGlobalVarAddressSpace(const VarDecl *D) { + unsigned AddrSpace; + if (LangOpts.OpenCL) { + AddrSpace = D ? D->getType().getAddressSpace() + : static_cast<unsigned>(LangAS::opencl_global); + assert(AddrSpace == LangAS::opencl_global || + AddrSpace == LangAS::opencl_constant || + AddrSpace == LangAS::opencl_local || + AddrSpace >= LangAS::FirstTargetAddressSpace); + return AddrSpace; + } + + if (LangOpts.CUDA && LangOpts.CUDAIsDevice) { + if (D && D->hasAttr<CUDAConstantAttr>()) + return LangAS::cuda_constant; + else if (D && D->hasAttr<CUDASharedAttr>()) + return LangAS::cuda_shared; else - AddrSpace = getContext().getTargetAddressSpace(LangAS::cuda_device); + return LangAS::cuda_device; } - return AddrSpace; + return getTargetCodeGenInfo().getGlobalVarAddressSpace(*this, D); } template<typename SomeDecl> @@ -2728,10 +2746,9 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, // "extern int x[];") and then a definition of a different type (e.g. // "int x[10];"). This also happens when an initializer has a different type // from the type of the global (this happens with unions). - if (!GV || - GV->getType()->getElementType() != InitType || + if (!GV || GV->getType()->getElementType() != InitType || GV->getType()->getAddressSpace() != - GetGlobalVarAddressSpace(D, getContext().getTargetAddressSpace(ASTTy))) { + getContext().getTargetAddressSpace(GetGlobalVarAddressSpace(D))) { // Move the old entry aside so that we'll create a new one. Entry->setName(StringRef()); @@ -3740,20 +3757,26 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary( Linkage = llvm::GlobalVariable::InternalLinkage; } } - unsigned AddrSpace = GetGlobalVarAddressSpace( - VD, getContext().getTargetAddressSpace(MaterializedType)); + unsigned AddrSpace = + VD ? GetGlobalVarAddressSpace(VD) : MaterializedType.getAddressSpace(); + auto TargetAS = getContext().getTargetAddressSpace(AddrSpace); auto *GV = new llvm::GlobalVariable( getModule(), Type, Constant, Linkage, InitialValue, Name.c_str(), - /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, - AddrSpace); + /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAS); setGlobalVisibility(GV, VD); GV->setAlignment(Align.getQuantity()); if (supportsCOMDAT() && GV->isWeakForLinker()) GV->setComdat(TheModule.getOrInsertComdat(GV->getName())); if (VD->getTLSKind()) setTLSMode(GV, *VD); - MaterializedGlobalTemporaryMap[E] = GV; - return ConstantAddress(GV, Align); + llvm::Constant *CV = GV; + if (AddrSpace != LangAS::Default) + CV = getTargetCodeGenInfo().performAddrSpaceCast( + *this, GV, AddrSpace, LangAS::Default, + Type->getPointerTo( + getContext().getTargetAddressSpace(LangAS::Default))); + MaterializedGlobalTemporaryMap[E] = CV; + return ConstantAddress(CV, Align); } /// EmitObjCPropertyImplementations - Emit information for synthesized diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index c5f1a2b409ee..b162e72d1992 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -710,11 +710,15 @@ public: SourceLocation Loc = SourceLocation(), bool TLS = false); - /// Return the address space of the underlying global variable for D, as + /// Return the AST address space of the underlying global variable for D, as /// determined by its declaration. Normally this is the same as the address /// space of D's type, but in CUDA, address spaces are associated with - /// declarations, not types. - unsigned GetGlobalVarAddressSpace(const VarDecl *D, unsigned AddrSpace); + /// declarations, not types. If D is nullptr, return the default address + /// space for global variable. + /// + /// For languages without explicit address spaces, if D has default address + /// space, target-specific global or constant address space may be returned. + unsigned GetGlobalVarAddressSpace(const VarDecl *D); /// Return the llvm::Constant for the address of the given global variable. /// If Ty is non-null and if the global doesn't exist, then it will be created diff --git a/lib/CodeGen/CodeGenTypeCache.h b/lib/CodeGen/CodeGenTypeCache.h index 6910d36733dc..450eab48a3b4 100644 --- a/lib/CodeGen/CodeGenTypeCache.h +++ b/lib/CodeGen/CodeGenTypeCache.h @@ -36,7 +36,7 @@ struct CodeGenTypeCache { /// i8, i16, i32, and i64 llvm::IntegerType *Int8Ty, *Int16Ty, *Int32Ty, *Int64Ty; /// float, double - llvm::Type *HalfTy, *FloatTy, *DoubleTy; + llvm::Type *FloatTy, *DoubleTy; /// int llvm::IntegerType *IntTy; diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 39efb9f43921..c82b9677eacf 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -2732,7 +2732,9 @@ static bool ShouldUseExternalRTTIDescriptor(CodeGenModule &CGM, // function. bool IsDLLImport = RD->hasAttr<DLLImportAttr>(); if (CGM.getVTables().isVTableExternal(RD)) - return IsDLLImport ? false : true; + return IsDLLImport && !CGM.getTriple().isWindowsItaniumEnvironment() + ? false + : true; if (IsDLLImport) return true; @@ -2957,6 +2959,8 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM, return llvm::GlobalValue::InternalLinkage; case VisibleNoLinkage: + case ModuleInternalLinkage: + case ModuleLinkage: case ExternalLinkage: // RTTI is not enabled, which means that this type info struct is going // to be used for exception handling. Give it linkonce_odr linkage. @@ -2968,7 +2972,8 @@ static llvm::GlobalVariable::LinkageTypes getTypeInfoLinkage(CodeGenModule &CGM, if (RD->hasAttr<WeakAttr>()) return llvm::GlobalValue::WeakODRLinkage; if (CGM.getTriple().isWindowsItaniumEnvironment()) - if (RD->hasAttr<DLLImportAttr>()) + if (RD->hasAttr<DLLImportAttr>() && + ShouldUseExternalRTTIDescriptor(CGM, Ty)) return llvm::GlobalValue::ExternalLinkage; if (RD->isDynamicClass()) { llvm::GlobalValue::LinkageTypes LT = CGM.getVTableLinkage(RD); @@ -3181,7 +3186,8 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(QualType Ty, bool Force, if (DLLExport || (RD && RD->hasAttr<DLLExportAttr>())) { TypeName->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); GV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); - } else if (CGM.getLangOpts().RTTI && RD && RD->hasAttr<DLLImportAttr>()) { + } else if (RD && RD->hasAttr<DLLImportAttr>() && + ShouldUseExternalRTTIDescriptor(CGM, Ty)) { TypeName->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index e68a16e0bd51..78b510bb4665 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -3425,6 +3425,8 @@ static llvm::GlobalValue::LinkageTypes getLinkageForRTTI(QualType Ty) { return llvm::GlobalValue::InternalLinkage; case VisibleNoLinkage: + case ModuleInternalLinkage: + case ModuleLinkage: case ExternalLinkage: return llvm::GlobalValue::LinkOnceODRLinkage; } diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 8d00e055306d..eeebd60a2d20 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -416,14 +416,34 @@ llvm::Constant *TargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule & return llvm::ConstantPointerNull::get(T); } +unsigned TargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const { + assert(!CGM.getLangOpts().OpenCL && + !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) && + "Address space agnostic languages only"); + return D ? D->getType().getAddressSpace() + : static_cast<unsigned>(LangAS::Default); +} + llvm::Value *TargetCodeGenInfo::performAddrSpaceCast( CodeGen::CodeGenFunction &CGF, llvm::Value *Src, unsigned SrcAddr, unsigned DestAddr, llvm::Type *DestTy, bool isNonNull) const { // Since target may map different address spaces in AST to the same address // space, an address space conversion may end up as a bitcast. + if (auto *C = dyn_cast<llvm::Constant>(Src)) + return performAddrSpaceCast(CGF.CGM, C, SrcAddr, DestAddr, DestTy); return CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src, DestTy); } +llvm::Constant * +TargetCodeGenInfo::performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *Src, + unsigned SrcAddr, unsigned DestAddr, + llvm::Type *DestTy) const { + // Since target may map different address spaces in AST to the same address + // space, an address space conversion may end up as a bitcast. + return llvm::ConstantExpr::getPointerCast(Src, DestTy); +} + static bool isEmptyRecord(ASTContext &Context, QualType T, bool AllowArrays); /// isEmptyField - Return true iff a the field is "empty", that is it @@ -7325,6 +7345,8 @@ public: return LangAS::FirstTargetAddressSpace + getABIInfo().getDataLayout().getAllocaAddrSpace(); } + unsigned getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const override; }; } @@ -7408,6 +7430,31 @@ llvm::Constant *AMDGPUTargetCodeGenInfo::getNullPointer( llvm::ConstantPointerNull::get(NPT), PT); } +unsigned +AMDGPUTargetCodeGenInfo::getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const { + assert(!CGM.getLangOpts().OpenCL && + !(CGM.getLangOpts().CUDA && CGM.getLangOpts().CUDAIsDevice) && + "Address space agnostic languages only"); + unsigned DefaultGlobalAS = + LangAS::FirstTargetAddressSpace + + CGM.getContext().getTargetAddressSpace(LangAS::opencl_global); + if (!D) + return DefaultGlobalAS; + + unsigned AddrSpace = D->getType().getAddressSpace(); + assert(AddrSpace == LangAS::Default || + AddrSpace >= LangAS::FirstTargetAddressSpace); + if (AddrSpace != LangAS::Default) + return AddrSpace; + + if (CGM.isTypeConstant(D->getType(), false)) { + if (auto ConstAS = CGM.getTarget().getConstantAddressSpace()) + return ConstAS.getValue(); + } + return DefaultGlobalAS; +} + //===----------------------------------------------------------------------===// // SPARC v8 ABI Implementation. // Based on the SPARC Compliance Definition version 2.4.1. diff --git a/lib/CodeGen/TargetInfo.h b/lib/CodeGen/TargetInfo.h index 247d01dcb086..952ef96c4aef 100644 --- a/lib/CodeGen/TargetInfo.h +++ b/lib/CodeGen/TargetInfo.h @@ -229,6 +229,13 @@ public: virtual llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM, llvm::PointerType *T, QualType QT) const; + /// Get target favored AST address space of a global variable for languages + /// other than OpenCL and CUDA. + /// If \p D is nullptr, returns the default target favored address space + /// for global variable. + virtual unsigned getGlobalVarAddressSpace(CodeGenModule &CGM, + const VarDecl *D) const; + /// Get the AST address space for alloca. virtual unsigned getASTAllocaAddressSpace() const { return LangAS::Default; } @@ -243,6 +250,15 @@ public: unsigned DestAddr, llvm::Type *DestTy, bool IsNonNull = false) const; + + /// Perform address space cast of a constant expression of pointer type. + /// \param V is the LLVM constant to be casted to another address space. + /// \param SrcAddr is the language address space of \p V. + /// \param DestAddr is the targeted language address space. + /// \param DestTy is the destination LLVM pointer type. + virtual llvm::Constant * + performAddrSpaceCast(CodeGenModule &CGM, llvm::Constant *V, unsigned SrcAddr, + unsigned DestAddr, llvm::Type *DestTy) const; }; } // namespace CodeGen diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index faced0697ed9..42478013ccec 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -572,8 +572,22 @@ void Driver::CreateOffloadingDeviceToolChains(Compilation &C, if (TT.getArch() == llvm::Triple::UnknownArch) Diag(clang::diag::err_drv_invalid_omp_target) << Val; else { - const ToolChain &TC = getToolChain(C.getInputArgs(), TT); - C.addOffloadDeviceToolChain(&TC, Action::OFK_OpenMP); + const ToolChain *TC; + // CUDA toolchains have to be selected differently. They pair host + // and device in their implementation. + if (TT.isNVPTX()) { + const ToolChain *HostTC = + C.getSingleOffloadToolChain<Action::OFK_Host>(); + assert(HostTC && "Host toolchain should be always defined."); + auto &CudaTC = + ToolChains[TT.str() + "/" + HostTC->getTriple().str()]; + if (!CudaTC) + CudaTC = llvm::make_unique<toolchains::CudaToolChain>( + *this, TT, *HostTC, C.getInputArgs()); + TC = CudaTC.get(); + } else + TC = &getToolChain(C.getInputArgs(), TT); + C.addOffloadDeviceToolChain(TC, Action::OFK_OpenMP); } } } else @@ -1247,11 +1261,20 @@ bool Driver::HandleImmediateArgs(const Compilation &C) { StringRef PassedFlags = A->getValue(); std::vector<std::string> SuggestedCompletions; + unsigned short DisableFlags = options::NoDriverOption | options::Unsupported | options::Ignored; + // We want to show cc1-only options only when clang is invoked as "clang -cc1". + // When clang is invoked as "clang -cc1", we add "#" to the beginning of an --autocomplete + // option so that the clang driver can distinguish whether it is requested to show cc1-only options or not. + if (PassedFlags[0] == '#') { + DisableFlags &= ~options::NoDriverOption; + PassedFlags = PassedFlags.substr(1); + } + if (PassedFlags.find(',') == StringRef::npos) { // If the flag is in the form of "--autocomplete=-foo", // we were requested to print out all option names that start with "-foo". // For example, "--autocomplete=-fsyn" is expanded to "-fsyntax-only". - SuggestedCompletions = Opts->findByPrefix(PassedFlags); + SuggestedCompletions = Opts->findByPrefix(PassedFlags, DisableFlags); } else { // If the flag is in the form of "--autocomplete=foo,bar", we were // requested to print out all option values for "-foo" that start with diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 4f82503276f4..2be7f0f69004 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -544,9 +544,9 @@ void ToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, // Each toolchain should provide the appropriate include flags. } -void ToolChain::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { -} +void ToolChain::addClangTargetOptions( + const ArgList &DriverArgs, ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const {} void ToolChain::addClangWarningOptions(ArgStringList &CC1Args) const {} diff --git a/lib/Driver/ToolChains/Arch/ARM.cpp b/lib/Driver/ToolChains/Arch/ARM.cpp index 8cafd3c74bfb..95b86f784f91 100644 --- a/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/lib/Driver/ToolChains/Arch/ARM.cpp @@ -179,6 +179,18 @@ arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { ABI = FloatABI::Hard; break; + case llvm::Triple::NetBSD: + switch (Triple.getEnvironment()) { + case llvm::Triple::EABIHF: + case llvm::Triple::GNUEABIHF: + ABI = FloatABI::Hard; + break; + default: + ABI = FloatABI::Soft; + break; + } + break; + case llvm::Triple::FreeBSD: switch (Triple.getEnvironment()) { case llvm::Triple::GNUEABIHF: diff --git a/lib/Driver/ToolChains/Arch/Mips.cpp b/lib/Driver/ToolChains/Arch/Mips.cpp index 33eff32b9731..b45dcd6db678 100644 --- a/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/lib/Driver/ToolChains/Arch/Mips.cpp @@ -227,12 +227,11 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, O.matches(options::OPT_fno_PIE) || O.matches(options::OPT_fno_pie)); } - if (IsN64 && NonPIC) { + if (IsN64 && NonPIC) Features.push_back("+noabicalls"); - } else { + else AddTargetFeature(Args, Features, options::OPT_mno_abicalls, options::OPT_mabicalls, "noabicalls"); - } mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args); if (FloatABI == mips::FloatABI::Soft) { @@ -298,13 +297,11 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg, options::OPT_modd_spreg, "nooddspreg"); - - if (Arg *A = Args.getLastArg(options::OPT_mmadd4, options::OPT_mno_madd4)) { - if (A->getOption().matches(options::OPT_mmadd4)) - Features.push_back("-nomadd4"); - else - Features.push_back("+nomadd4"); - } + AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4, + "nomadd4"); + AddTargetFeature(Args, Features, options::OPT_mlong_calls, + options::OPT_mno_long_calls, "long-calls"); + AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt,"mt"); } mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) { diff --git a/lib/Driver/ToolChains/BareMetal.cpp b/lib/Driver/ToolChains/BareMetal.cpp index 66246f6d71cd..5dc6dfad927b 100644 --- a/lib/Driver/ToolChains/BareMetal.cpp +++ b/lib/Driver/ToolChains/BareMetal.cpp @@ -98,7 +98,8 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, } void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { CC1Args.push_back("-nostdsysteminc"); } diff --git a/lib/Driver/ToolChains/BareMetal.h b/lib/Driver/ToolChains/BareMetal.h index 064c1199735b..4b74899fa53e 100644 --- a/lib/Driver/ToolChains/BareMetal.h +++ b/lib/Driver/ToolChains/BareMetal.h @@ -54,7 +54,8 @@ public: void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; std::string findLibCxxIncludePath(ToolChain::CXXStdlibType LibType) const; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 3731aa83ef06..e759e3ec619a 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -2544,7 +2544,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, AsynchronousUnwindTables)) CmdArgs.push_back("-munwind-tables"); - getToolChain().addClangTargetOptions(Args, CmdArgs); + getToolChain().addClangTargetOptions(Args, CmdArgs, + JA.getOffloadingDeviceKind()); if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2974,6 +2975,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->claim(); } + for (const Arg *A : + Args.filtered(options::OPT_clang_ignored_legacy_options_Group)) { + D.Diag(diag::warn_ignored_clang_option) << A->getAsString(Args); + A->claim(); + } + claimNoWarnArgs(Args); Args.AddAllArgs(CmdArgs, options::OPT_R_Group); diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp index e8bb703054de..00bd60bc24bb 100644 --- a/lib/Driver/ToolChains/CommonArgs.cpp +++ b/lib/Driver/ToolChains/CommonArgs.cpp @@ -524,6 +524,7 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, CmdArgs.push_back("-lm"); // There's no libdl on FreeBSD or RTEMS. if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && + TC.getTriple().getOS() != llvm::Triple::NetBSD && TC.getTriple().getOS() != llvm::Triple::RTEMS) CmdArgs.push_back("-ldl"); } diff --git a/lib/Driver/ToolChains/Cuda.cpp b/lib/Driver/ToolChains/Cuda.cpp index 42bf164f1b3f..935a5a37ada5 100644 --- a/lib/Driver/ToolChains/Cuda.cpp +++ b/lib/Driver/ToolChains/Cuda.cpp @@ -338,24 +338,31 @@ CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, void CudaToolChain::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - HostTC.addClangTargetOptions(DriverArgs, CC1Args); + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadingKind) const { + HostTC.addClangTargetOptions(DriverArgs, CC1Args, DeviceOffloadingKind); - CC1Args.push_back("-fcuda-is-device"); + StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); + assert(!GpuArch.empty() && "Must have an explicit GPU arch."); + assert((DeviceOffloadingKind == Action::OFK_OpenMP || + DeviceOffloadingKind == Action::OFK_Cuda) && + "Only OpenMP or CUDA offloading kinds are supported for NVIDIA GPUs."); - if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, - options::OPT_fno_cuda_flush_denormals_to_zero, false)) - CC1Args.push_back("-fcuda-flush-denormals-to-zero"); + if (DeviceOffloadingKind == Action::OFK_Cuda) { + CC1Args.push_back("-fcuda-is-device"); - if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, - options::OPT_fno_cuda_approx_transcendentals, false)) - CC1Args.push_back("-fcuda-approx-transcendentals"); + if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, + options::OPT_fno_cuda_flush_denormals_to_zero, false)) + CC1Args.push_back("-fcuda-flush-denormals-to-zero"); - if (DriverArgs.hasArg(options::OPT_nocudalib)) - return; + if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, + options::OPT_fno_cuda_approx_transcendentals, false)) + CC1Args.push_back("-fcuda-approx-transcendentals"); + + if (DriverArgs.hasArg(options::OPT_nocudalib)) + return; + } - StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); - assert(!GpuArch.empty() && "Must have an explicit GPU arch."); std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch); if (LibDeviceFile.empty()) { @@ -396,6 +403,24 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, const OptTable &Opts = getDriver().getOpts(); + // For OpenMP device offloading, append derived arguments. Make sure + // flags are not duplicated. + // TODO: Append the compute capability. + if (DeviceOffloadKind == Action::OFK_OpenMP) { + for (Arg *A : Args){ + bool IsDuplicate = false; + for (Arg *DALArg : *DAL){ + if (A == DALArg) { + IsDuplicate = true; + break; + } + } + if (!IsDuplicate) + DAL->append(A); + } + return DAL; + } + for (Arg *A : Args) { if (A->getOption().matches(options::OPT_Xarch__)) { // Skip this argument unless the architecture matches BoundArch diff --git a/lib/Driver/ToolChains/Cuda.h b/lib/Driver/ToolChains/Cuda.h index acdb4c4efd6d..e66fc23d82f3 100644 --- a/lib/Driver/ToolChains/Cuda.h +++ b/lib/Driver/ToolChains/Cuda.h @@ -130,7 +130,8 @@ public: TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; // Never try to use the integrated assembler with CUDA; always fork out to // ptxas. diff --git a/lib/Driver/ToolChains/Darwin.cpp b/lib/Driver/ToolChains/Darwin.cpp index 7b61095c3ba9..ba1a5ee95594 100644 --- a/lib/Driver/ToolChains/Darwin.cpp +++ b/lib/Driver/ToolChains/Darwin.cpp @@ -1118,6 +1118,27 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, } } +/// Returns the most appropriate macOS target version for the current process. +/// +/// If the macOS SDK version is the same or earlier than the system version, +/// then the SDK version is returned. Otherwise the system version is returned. +static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) { + unsigned Major, Minor, Micro; + llvm::Triple SystemTriple(llvm::sys::getProcessTriple()); + if (!SystemTriple.isMacOSX()) + return MacOSSDKVersion; + SystemTriple.getMacOSXVersion(Major, Minor, Micro); + VersionTuple SystemVersion(Major, Minor, Micro); + bool HadExtra; + if (!Driver::GetReleaseVersion(MacOSSDKVersion, Major, Minor, Micro, + HadExtra)) + return MacOSSDKVersion; + VersionTuple SDKVersion(Major, Minor, Micro); + if (SDKVersion > SystemVersion) + return SystemVersion.getAsString(); + return MacOSSDKVersion; +} + void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { const OptTable &Opts = getDriver().getOpts(); @@ -1229,7 +1250,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { SDK.startswith("iPhoneSimulator")) iOSTarget = Version; else if (SDK.startswith("MacOSX")) - OSXTarget = Version; + OSXTarget = getSystemOrSDKMacOSVersion(Version); else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator")) WatchOSTarget = Version; @@ -1708,7 +1729,8 @@ bool Darwin::isAlignedAllocationUnavailable() const { } void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const { if (isAlignedAllocationUnavailable()) CC1Args.push_back("-faligned-alloc-unavailable"); } diff --git a/lib/Driver/ToolChains/Darwin.h b/lib/Driver/ToolChains/Darwin.h index ffcdf9a71a46..6cb1d04b78c0 100644 --- a/lib/Driver/ToolChains/Darwin.h +++ b/lib/Driver/ToolChains/Darwin.h @@ -390,7 +390,8 @@ protected: bool isAlignedAllocationUnavailable() const; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; StringRef getPlatformFamily() const; static StringRef getSDKName(StringRef isysroot); diff --git a/lib/Driver/ToolChains/Fuchsia.cpp b/lib/Driver/ToolChains/Fuchsia.cpp index b8757cf4aa73..d8b8fe8f0bfe 100644 --- a/lib/Driver/ToolChains/Fuchsia.cpp +++ b/lib/Driver/ToolChains/Fuchsia.cpp @@ -131,16 +131,44 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, /// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly. +static std::string normalizeTriple(llvm::Triple Triple) { + SmallString<64> T; + T += Triple.getArchName(); + T += "-"; + T += Triple.getOSName(); + return T.str(); +} + +static std::string getTargetDir(const Driver &D, + llvm::Triple Triple) { + SmallString<128> P(llvm::sys::path::parent_path(D.Dir)); + llvm::sys::path::append(P, "lib", normalizeTriple(Triple)); + return P.str(); +} + Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - - getFilePaths().push_back(D.SysRoot + "/lib"); - getFilePaths().push_back(D.ResourceDir + "/lib/fuchsia"); + : ToolChain(D, Triple, Args) { + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != D.Dir) + getProgramPaths().push_back(D.Dir); + + SmallString<128> P(getTargetDir(D, getTriple())); + llvm::sys::path::append(P, "lib"); + getFilePaths().push_back(P.str()); + + if (!D.SysRoot.empty()) { + SmallString<128> P(D.SysRoot); + llvm::sys::path::append(P, "lib"); + getFilePaths().push_back(P.str()); + } } -Tool *Fuchsia::buildAssembler() const { - return new tools::gnutools::Assembler(*this); +std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType) const { + llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); + Triple.setTriple(normalizeTriple(Triple)); + return Triple.getTriple(); } Tool *Fuchsia::buildLinker() const { @@ -172,7 +200,8 @@ Fuchsia::GetCXXStdlibType(const ArgList &Args) const { } void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { if (DriverArgs.hasFlag(options::OPT_fuse_init_array, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fuse-init-array"); @@ -207,19 +236,44 @@ void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, return; } - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); + if (!D.SysRoot.empty()) { + SmallString<128> P(D.SysRoot); + llvm::sys::path::append(P, "include"); + addExternCSystemInclude(DriverArgs, CC1Args, P.str()); + } } -std::string Fuchsia::findLibCxxIncludePath() const { - return getDriver().SysRoot + "/include/c++/v1"; +void Fuchsia::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: { + SmallString<128> P(getTargetDir(getDriver(), getTriple())); + llvm::sys::path::append(P, "include", "c++", "v1"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + break; + } + + default: + llvm_unreachable("invalid stdlib name"); + } } void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - (void) GetCXXStdlibType(Args); - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lunwind"); + switch (GetCXXStdlibType(Args)) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lunwind"); + break; + + case ToolChain::CST_Libstdcxx: + llvm_unreachable("invalid stdlib name"); + } } SanitizerMask Fuchsia::getSupportedSanitizers() const { diff --git a/lib/Driver/ToolChains/Fuchsia.h b/lib/Driver/ToolChains/Fuchsia.h index 1a8c9903fe4d..a723a99dfa3b 100644 --- a/lib/Driver/ToolChains/Fuchsia.h +++ b/lib/Driver/ToolChains/Fuchsia.h @@ -35,18 +35,29 @@ public: namespace toolchains { -class LLVM_LIBRARY_VISIBILITY Fuchsia : public Generic_ELF { +class LLVM_LIBRARY_VISIBILITY Fuchsia : public ToolChain { public: Fuchsia(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - bool isPIEDefault() const override { return true; } bool HasNativeLLVMSupport() const override { return true; } bool IsIntegratedAssemblerDefault() const override { return true; } + RuntimeLibType GetDefaultRuntimeLibType() const override { + return ToolChain::RLT_CompilerRT; + } + CXXStdlibType GetDefaultCXXStdlibType() const override { + return ToolChain::CST_Libcxx; + } + bool isPICDefault() const override { return false; } + bool isPIEDefault() const override { return true; } + bool isPICDefaultForced() const override { return false; } llvm::DebuggerKind getDefaultDebuggerTuning() const override { return llvm::DebuggerKind::GDB; } + std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, + types::ID InputType) const override; + SanitizerMask getSupportedSanitizers() const override; RuntimeLibType @@ -55,11 +66,14 @@ public: GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - std::string findLibCxxIncludePath() const override; + void + AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; @@ -68,7 +82,6 @@ public: } protected: - Tool *buildAssembler() const override; Tool *buildLinker() const override; }; diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp index bca5d3a3f28b..ad5f7df50d2e 100644 --- a/lib/Driver/ToolChains/Gnu.cpp +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -2461,7 +2461,8 @@ Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef, void Generic_ELF::anchor() {} void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); bool UseInitArrayDefault = getTriple().getArch() == llvm::Triple::aarch64 || diff --git a/lib/Driver/ToolChains/Gnu.h b/lib/Driver/ToolChains/Gnu.h index 1dc1ad49e305..cdf610054401 100644 --- a/lib/Driver/ToolChains/Gnu.h +++ b/lib/Driver/ToolChains/Gnu.h @@ -341,7 +341,8 @@ public: : Generic_GCC(D, Triple, Args) {} void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; }; } // end namespace toolchains diff --git a/lib/Driver/ToolChains/Hexagon.cpp b/lib/Driver/ToolChains/Hexagon.cpp index 1d7bcf8e4df0..9bf1590e6a37 100644 --- a/lib/Driver/ToolChains/Hexagon.cpp +++ b/lib/Driver/ToolChains/Hexagon.cpp @@ -428,7 +428,8 @@ unsigned HexagonToolChain::getOptimizationLevel( } void HexagonToolChain::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { if (DriverArgs.hasArg(options::OPT_ffp_contract)) return; unsigned OptLevel = getOptimizationLevel(DriverArgs); diff --git a/lib/Driver/ToolChains/Hexagon.h b/lib/Driver/ToolChains/Hexagon.h index 78f97a3d59fd..7f9a6b2f34b9 100644 --- a/lib/Driver/ToolChains/Hexagon.h +++ b/lib/Driver/ToolChains/Hexagon.h @@ -69,7 +69,8 @@ public: ~HexagonToolChain() override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; diff --git a/lib/Driver/ToolChains/NetBSD.cpp b/lib/Driver/ToolChains/NetBSD.cpp index d7d3ad61df42..a1a3108cb28d 100644 --- a/lib/Driver/ToolChains/NetBSD.cpp +++ b/lib/Driver/ToolChains/NetBSD.cpp @@ -15,6 +15,7 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" using namespace clang::driver; @@ -246,6 +247,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); Args.AddAllArgs(CmdArgs, options::OPT_r); + bool NeedsSanitizerDeps = addSanitizerRuntimes(getToolChain(), Args, CmdArgs); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); unsigned Major, Minor, Micro; @@ -279,6 +281,8 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } + if (NeedsSanitizerDeps) + linkSanitizerRuntimeDeps(getToolChain(), CmdArgs); if (Args.hasArg(options::OPT_pthread)) CmdArgs.push_back("-lpthread"); CmdArgs.push_back("-lc"); @@ -410,3 +414,12 @@ void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/g++", "", "", "", "", DriverArgs, CC1Args); } + +SanitizerMask NetBSD::getSupportedSanitizers() const { + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + if (IsX86_64) { + Res |= SanitizerKind::Address; + } + return Res; +} diff --git a/lib/Driver/ToolChains/NetBSD.h b/lib/Driver/ToolChains/NetBSD.h index d53aa6867872..412d0815e81a 100644 --- a/lib/Driver/ToolChains/NetBSD.h +++ b/lib/Driver/ToolChains/NetBSD.h @@ -66,6 +66,7 @@ public: llvm::opt::ArgStringList &CC1Args) const override; bool IsUnwindTablesDefault() const override { return true; } + SanitizerMask getSupportedSanitizers() const override; protected: Tool *buildAssembler() const override; diff --git a/lib/Driver/ToolChains/WebAssembly.cpp b/lib/Driver/ToolChains/WebAssembly.cpp index fcb6418b2517..058bc42323e2 100644 --- a/lib/Driver/ToolChains/WebAssembly.cpp +++ b/lib/Driver/ToolChains/WebAssembly.cpp @@ -134,7 +134,8 @@ bool WebAssembly::SupportsProfiling() const { return false; } bool WebAssembly::HasNativeLLVMSupport() const { return true; } void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { if (DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array, options::OPT_fno_use_init_array, true)) CC1Args.push_back("-fuse-init-array"); diff --git a/lib/Driver/ToolChains/WebAssembly.h b/lib/Driver/ToolChains/WebAssembly.h index ca42fc651a6d..2999db477f79 100644 --- a/lib/Driver/ToolChains/WebAssembly.h +++ b/lib/Driver/ToolChains/WebAssembly.h @@ -53,7 +53,8 @@ private: bool SupportsProfiling() const override; bool HasNativeLLVMSupport() const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; RuntimeLibType GetDefaultRuntimeLibType() const override; CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; void AddClangSystemIncludeArgs( diff --git a/lib/Driver/ToolChains/XCore.cpp b/lib/Driver/ToolChains/XCore.cpp index c3ae9582124f..43175ad7d632 100644 --- a/lib/Driver/ToolChains/XCore.cpp +++ b/lib/Driver/ToolChains/XCore.cpp @@ -124,7 +124,8 @@ void XCoreToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, } void XCoreToolChain::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { + ArgStringList &CC1Args, + Action::OffloadKind) const { CC1Args.push_back("-nostdsysteminc"); } diff --git a/lib/Driver/ToolChains/XCore.h b/lib/Driver/ToolChains/XCore.h index 4084b1cdec13..00c89bd15f78 100644 --- a/lib/Driver/ToolChains/XCore.h +++ b/lib/Driver/ToolChains/XCore.h @@ -67,7 +67,8 @@ public: AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; diff --git a/lib/Format/ContinuationIndenter.cpp b/lib/Format/ContinuationIndenter.cpp index 4197587a74c0..3bf1cd8f7c13 100644 --- a/lib/Format/ContinuationIndenter.cpp +++ b/lib/Format/ContinuationIndenter.cpp @@ -66,6 +66,16 @@ static bool startsNextParameter(const FormatToken &Current, !Style.BreakBeforeInheritanceComma)); } +static bool opensProtoMessageField(const FormatToken &LessTok, + const FormatStyle &Style) { + if (LessTok.isNot(tok::less)) + return false; + return Style.Language == FormatStyle::LK_TextProto || + (Style.Language == FormatStyle::LK_Proto && + (LessTok.NestingLevel > 0 || + (LessTok.Previous && LessTok.Previous->is(tok::equal)))); +} + ContinuationIndenter::ContinuationIndenter(const FormatStyle &Style, const AdditionalKeywords &Keywords, const SourceManager &SourceMgr, @@ -94,6 +104,13 @@ LineState ContinuationIndenter::getInitialState(unsigned FirstIndent, State.LowestLevelOnLine = 0; State.IgnoreStackForComparison = false; + if (Style.Language == FormatStyle::LK_TextProto) { + // We need this in order to deal with the bin packing of text fields at + // global scope. + State.Stack.back().AvoidBinPacking = true; + State.Stack.back().BreakBeforeParameter = true; + } + // The first token has already been indented and thus consumed. moveStateToNextToken(State, DryRun, /*Newline=*/false); return State; @@ -176,7 +193,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) { return true; if (((Previous.is(TT_DictLiteral) && Previous.is(tok::l_brace)) || (Previous.is(TT_ArrayInitializerLSquare) && - Previous.ParameterCount > 1)) && + Previous.ParameterCount > 1) || + opensProtoMessageField(Previous, Style)) && Style.ColumnLimit > 0 && getLengthToMatchingParen(Previous) + State.Column - 1 > getColumnLimit(State)) @@ -501,13 +519,6 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, } } -static bool lessOpensProtoMessageField(const FormatToken &LessTok, - const LineState &State) { - assert(LessTok.is(tok::less)); - return LessTok.NestingLevel > 0 || - (LessTok.Previous && LessTok.Previous->is(tok::equal)); -} - unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, bool DryRun) { FormatToken &Current = *State.NextToken; @@ -650,9 +661,7 @@ unsigned ContinuationIndenter::addTokenOnNewLine(LineState &State, // before the corresponding } or ]. if (PreviousNonComment && (PreviousNonComment->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || - (Style.Language == FormatStyle::LK_Proto && - PreviousNonComment->is(tok::less) && - lessOpensProtoMessageField(*PreviousNonComment, State)) || + opensProtoMessageField(*PreviousNonComment, Style) || (PreviousNonComment->is(TT_TemplateString) && PreviousNonComment->opensScope()))) State.Stack.back().BreakBeforeClosingBrace = true; @@ -695,7 +704,9 @@ unsigned ContinuationIndenter::getNewLineColumn(const LineState &State) { return Current.NestingLevel == 0 ? State.FirstIndent : State.Stack.back().Indent; if ((Current.isOneOf(tok::r_brace, tok::r_square) || - (Current.is(tok::greater) && Style.Language == FormatStyle::LK_Proto)) && + (Current.is(tok::greater) && + (Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto))) && State.Stack.size() > 1) { if (Current.closesBlockOrBlockTypeList(Style)) return State.Stack[State.Stack.size() - 2].NestedBlockIndent; @@ -1050,8 +1061,7 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, unsigned NestedBlockIndent = std::max(State.Stack.back().StartOfFunctionCall, State.Stack.back().NestedBlockIndent); if (Current.isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) || - (Style.Language == FormatStyle::LK_Proto && Current.is(tok::less) && - lessOpensProtoMessageField(Current, State))) { + opensProtoMessageField(Current, Style)) { if (Current.opensBlockOrBlockTypeList(Style)) { NewIndent = Style.IndentWidth + std::min(State.Column, State.Stack.back().NestedBlockIndent); @@ -1064,7 +1074,9 @@ void ContinuationIndenter::moveStatePastScopeOpener(LineState &State, Current.MatchingParen->Previous->is(tok::comma); AvoidBinPacking = EndsInComma || Current.is(TT_DictLiteral) || - Style.Language == FormatStyle::LK_Proto || !Style.BinPackArguments || + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto || + !Style.BinPackArguments || (NextNoComment && NextNoComment->isOneOf(TT_DesignatedInitializerPeriod, TT_DesignatedInitializerLSquare)); diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp index bb6781d79517..aa4ed8c42a70 100644 --- a/lib/Format/Format.cpp +++ b/lib/Format/Format.cpp @@ -56,6 +56,7 @@ template <> struct ScalarEnumerationTraits<FormatStyle::LanguageKind> { IO.enumCase(Value, "ObjC", FormatStyle::LK_ObjC); IO.enumCase(Value, "Proto", FormatStyle::LK_Proto); IO.enumCase(Value, "TableGen", FormatStyle::LK_TableGen); + IO.enumCase(Value, "TextProto", FormatStyle::LK_TextProto); } }; @@ -631,6 +632,12 @@ FormatStyle getLLVMStyle() { } FormatStyle getGoogleStyle(FormatStyle::LanguageKind Language) { + if (Language == FormatStyle::LK_TextProto) { + FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_Proto); + GoogleStyle.Language = FormatStyle::LK_TextProto; + return GoogleStyle; + } + FormatStyle GoogleStyle = getLLVMStyle(); GoogleStyle.Language = Language; diff --git a/lib/Format/FormatToken.h b/lib/Format/FormatToken.h index 0fe91adcd472..a60361a8e5fa 100644 --- a/lib/Format/FormatToken.h +++ b/lib/Format/FormatToken.h @@ -21,6 +21,7 @@ #include "clang/Format/Format.h" #include "clang/Lex/Lexer.h" #include <memory> +#include <unordered_set> namespace clang { namespace format { @@ -466,7 +467,8 @@ struct FormatToken { (is(tok::l_brace) && (BlockKind == BK_Block || is(TT_DictLiteral) || (!Style.Cpp11BracedListStyle && NestingLevel == 0))) || - (is(tok::less) && Style.Language == FormatStyle::LK_Proto); + (is(tok::less) && (Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto)); } /// \brief Same as opensBlockOrBlockTypeList, but for the closing token. @@ -639,6 +641,7 @@ struct AdditionalKeywords { kw_is = &IdentTable.get("is"); kw_let = &IdentTable.get("let"); kw_module = &IdentTable.get("module"); + kw_readonly = &IdentTable.get("readonly"); kw_set = &IdentTable.get("set"); kw_type = &IdentTable.get("type"); kw_var = &IdentTable.get("var"); @@ -671,6 +674,15 @@ struct AdditionalKeywords { kw_qsignals = &IdentTable.get("Q_SIGNALS"); kw_slots = &IdentTable.get("slots"); kw_qslots = &IdentTable.get("Q_SLOTS"); + + // Keep this at the end of the constructor to make sure everything here is + // already initialized. + JsExtraKeywords = std::unordered_set<IdentifierInfo *>( + {kw_as, kw_async, kw_await, kw_declare, kw_finally, kw_from, + kw_function, kw_get, kw_import, kw_is, kw_let, kw_module, kw_readonly, + kw_set, kw_type, kw_var, kw_yield, + // Keywords from the Java section. + kw_abstract, kw_extends, kw_implements, kw_instanceof, kw_interface}); } // Context sensitive keywords. @@ -699,6 +711,7 @@ struct AdditionalKeywords { IdentifierInfo *kw_is; IdentifierInfo *kw_let; IdentifierInfo *kw_module; + IdentifierInfo *kw_readonly; IdentifierInfo *kw_set; IdentifierInfo *kw_type; IdentifierInfo *kw_var; @@ -732,6 +745,18 @@ struct AdditionalKeywords { IdentifierInfo *kw_qsignals; IdentifierInfo *kw_slots; IdentifierInfo *kw_qslots; + + /// \brief Returns \c true if \p Tok is a true JavaScript identifier, returns + /// \c false if it is a keyword or a pseudo keyword. + bool IsJavaScriptIdentifier(const FormatToken &Tok) const { + return Tok.is(tok::identifier) && + JsExtraKeywords.find(Tok.Tok.getIdentifierInfo()) == + JsExtraKeywords.end(); + } + +private: + /// \brief The JavaScript keywords beyond the C++ keyword set. + std::unordered_set<IdentifierInfo *> JsExtraKeywords; }; } // namespace format diff --git a/lib/Format/TokenAnnotator.cpp b/lib/Format/TokenAnnotator.cpp index d78a37532fe8..c6e90a9175e1 100644 --- a/lib/Format/TokenAnnotator.cpp +++ b/lib/Format/TokenAnnotator.cpp @@ -90,7 +90,8 @@ private: } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace) || (CurrentToken->isOneOf(tok::colon, tok::question) && InExprContext && - Style.Language != FormatStyle::LK_Proto)) + Style.Language != FormatStyle::LK_Proto && + Style.Language != FormatStyle::LK_TextProto)) return false; // If a && or || is found and interpreted as a binary operator, this set // of angles is likely part of something like "a < b && c > d". If the @@ -453,7 +454,8 @@ private: FormatToken *Previous = CurrentToken->getPreviousNonComment(); if (((CurrentToken->is(tok::colon) && (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) || - Style.Language == FormatStyle::LK_Proto) && + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) && (Previous->Tok.getIdentifierInfo() || Previous->is(tok::string_literal))) Previous->Type = TT_SelectorName; @@ -536,8 +538,13 @@ private: } } if (Contexts.back().ColonIsDictLiteral || - Style.Language == FormatStyle::LK_Proto) { + Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) { Tok->Type = TT_DictLiteral; + if (Style.Language == FormatStyle::LK_TextProto) { + if (FormatToken *Previous = Tok->getPreviousNonComment()) + Previous->Type = TT_SelectorName; + } } else if (Contexts.back().ColonIsObjCMethodExpr || Line.startsWith(TT_ObjCMethodSpecifier)) { Tok->Type = TT_ObjCMethodExpr; @@ -635,12 +642,22 @@ private: return false; break; case tok::l_brace: + if (Style.Language == FormatStyle::LK_TextProto) { + FormatToken *Previous =Tok->getPreviousNonComment(); + if (Previous && Previous->Type != TT_DictLiteral) + Previous->Type = TT_SelectorName; + } if (!parseBrace()) return false; break; case tok::less: if (parseAngle()) { Tok->Type = TT_TemplateOpener; + if (Style.Language == FormatStyle::LK_TextProto) { + FormatToken *Previous = Tok->getPreviousNonComment(); + if (Previous && Previous->Type != TT_DictLiteral) + Previous->Type = TT_SelectorName; + } } else { Tok->Type = TT_BinaryOperator; NonTemplateLess.insert(Tok); @@ -1572,7 +1589,8 @@ private: return prec::Conditional; if (NextNonComment && Current->is(TT_SelectorName) && (NextNonComment->is(TT_DictLiteral) || - (Style.Language == FormatStyle::LK_Proto && + ((Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) && NextNonComment->is(tok::less)))) return prec::Assignment; if (Current->is(TT_JsComputedPropertyName)) @@ -1676,17 +1694,26 @@ void TokenAnnotator::setCommentLineLevels( for (SmallVectorImpl<AnnotatedLine *>::reverse_iterator I = Lines.rbegin(), E = Lines.rend(); I != E; ++I) { - bool CommentLine = (*I)->First; + bool CommentLine = true; for (const FormatToken *Tok = (*I)->First; Tok; Tok = Tok->Next) { if (!Tok->is(tok::comment)) { CommentLine = false; break; } } - if (NextNonCommentLine && CommentLine) - (*I)->Level = NextNonCommentLine->Level; - else + + if (NextNonCommentLine && CommentLine) { + // If the comment is currently aligned with the line immediately following + // it, that's probably intentional and we should keep it. + bool AlignedWithNextLine = + NextNonCommentLine->First->NewlinesBefore <= 1 && + NextNonCommentLine->First->OriginalColumn == + (*I)->First->OriginalColumn; + if (AlignedWithNextLine) + (*I)->Level = NextNonCommentLine->Level; + } else { NextNonCommentLine = (*I)->First->isNot(tok::r_brace) ? (*I) : nullptr; + } setCommentLineLevels((*I)->Children); } @@ -2274,7 +2301,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Style.isCpp()) { if (Left.is(tok::kw_operator)) return Right.is(tok::coloncolon); - } else if (Style.Language == FormatStyle::LK_Proto) { + } else if (Style.Language == FormatStyle::LK_Proto || + Style.Language == FormatStyle::LK_TextProto) { if (Right.is(tok::period) && Left.isOneOf(Keywords.kw_optional, Keywords.kw_required, Keywords.kw_repeated, Keywords.kw_extend)) @@ -2282,6 +2310,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Right.is(tok::l_paren) && Left.isOneOf(Keywords.kw_returns, Keywords.kw_option)) return true; + if (Right.isOneOf(tok::l_brace, tok::less) && Left.is(TT_SelectorName)) + return true; } else if (Style.Language == FormatStyle::LK_JavaScript) { if (Left.is(TT_JsFatArrow)) return true; @@ -2300,7 +2330,11 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if ((Left.is(TT_TemplateString) && Left.TokenText.endswith("${")) || (Right.is(TT_TemplateString) && Right.TokenText.startswith("}"))) return false; - if (Left.is(tok::identifier) && Right.is(TT_TemplateString)) + // In tagged template literals ("html`bar baz`"), there is no space between + // the tag identifier and the template string. getIdentifierInfo makes sure + // that the identifier is not a pseudo keyword like `yield`, either. + if (Left.is(tok::identifier) && Keywords.IsJavaScriptIdentifier(Left) && + Right.is(TT_TemplateString)) return false; if (Right.is(tok::star) && Left.isOneOf(Keywords.kw_function, Keywords.kw_yield)) @@ -2604,11 +2638,12 @@ bool TokenAnnotator::canBreakBefore(const AnnotatedLine &Line, } else if (Style.Language == FormatStyle::LK_JavaScript) { const FormatToken *NonComment = Right.getPreviousNonComment(); if (NonComment && - NonComment->isOneOf( - tok::kw_return, tok::kw_continue, tok::kw_break, tok::kw_throw, - Keywords.kw_interface, Keywords.kw_type, tok::kw_static, - tok::kw_public, tok::kw_private, tok::kw_protected, - Keywords.kw_abstract, Keywords.kw_get, Keywords.kw_set)) + NonComment->isOneOf(tok::kw_return, tok::kw_continue, tok::kw_break, + tok::kw_throw, Keywords.kw_interface, + Keywords.kw_type, tok::kw_static, tok::kw_public, + tok::kw_private, tok::kw_protected, + Keywords.kw_readonly, Keywords.kw_abstract, + Keywords.kw_get, Keywords.kw_set)) return false; // Otherwise automatic semicolon insertion would trigger. if (Left.is(TT_JsFatArrow) && Right.is(tok::l_brace)) return false; diff --git a/lib/Format/UnwrappedLineParser.cpp b/lib/Format/UnwrappedLineParser.cpp index ba3a4c17ee12..4b57919d1929 100644 --- a/lib/Format/UnwrappedLineParser.cpp +++ b/lib/Format/UnwrappedLineParser.cpp @@ -286,7 +286,10 @@ void UnwrappedLineParser::parseFile() { !Line->InPPDirective && Style.Language != FormatStyle::LK_JavaScript; ScopedDeclarationState DeclarationState(*Line, DeclarationScopeStack, MustBeDeclaration); - parseLevel(/*HasOpeningBrace=*/false); + if (Style.Language == FormatStyle::LK_TextProto) + parseBracedList(); + else + parseLevel(/*HasOpeningBrace=*/false); // Make sure to format the remaining tokens. flushComments(true); addUnwrappedLine(); @@ -832,6 +835,7 @@ void UnwrappedLineParser::parseStructuralElement() { case tok::at: nextToken(); if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); break; } @@ -996,8 +1000,10 @@ void UnwrappedLineParser::parseStructuralElement() { switch (FormatTok->Tok.getKind()) { case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); + } break; case tok::kw_enum: // Ignore if this is part of "template <enum ...". @@ -1176,12 +1182,15 @@ void UnwrappedLineParser::parseStructuralElement() { } nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); - else if (Style.Language == FormatStyle::LK_Proto && - FormatTok->Tok.is(tok::less)) + } else if (Style.Language == FormatStyle::LK_Proto && + FormatTok->Tok.is(tok::less)) { + nextToken(); parseBracedList(/*ContinueOnSemicolons=*/false, /*ClosingBraceKind=*/tok::greater); + } break; case tok::l_square: parseSquare(); @@ -1345,6 +1354,7 @@ bool UnwrappedLineParser::tryToParseBracedList() { assert(FormatTok->BlockKind != BK_Unknown); if (FormatTok->BlockKind == BK_Block) return false; + nextToken(); parseBracedList(); return true; } @@ -1352,7 +1362,6 @@ bool UnwrappedLineParser::tryToParseBracedList() { bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, tok::TokenKind ClosingBraceKind) { bool HasError = false; - nextToken(); // FIXME: Once we have an expression parser in the UnwrappedLineParser, // replace this by using parseAssigmentExpression() inside. @@ -1407,6 +1416,7 @@ bool UnwrappedLineParser::parseBracedList(bool ContinueOnSemicolons, // Assume there are no blocks inside a braced init list apart // from the ones we explicitly parse out (like lambdas). FormatTok->BlockKind = BK_BracedInit; + nextToken(); parseBracedList(); break; case tok::semi: @@ -1459,8 +1469,10 @@ void UnwrappedLineParser::parseParens() { break; case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); + } break; case tok::kw_class: if (Style.Language == FormatStyle::LK_JavaScript) @@ -1508,8 +1520,10 @@ void UnwrappedLineParser::parseSquare() { } case tok::at: nextToken(); - if (FormatTok->Tok.is(tok::l_brace)) + if (FormatTok->Tok.is(tok::l_brace)) { + nextToken(); parseBracedList(); + } break; default: nextToken(); @@ -1836,6 +1850,7 @@ bool UnwrappedLineParser::parseEnum() { } // Parse enum body. + nextToken(); bool HasError = !parseBracedList(/*ContinueOnSemicolons=*/true); if (HasError) { if (FormatTok->is(tok::semi)) @@ -1870,6 +1885,7 @@ void UnwrappedLineParser::parseJavaEnumBody() { FormatTok = Tokens->setPosition(StoredPosition); if (IsSimple) { + nextToken(); parseBracedList(); addUnwrappedLine(); return; @@ -2081,6 +2097,7 @@ void UnwrappedLineParser::parseJavaScriptEs6ImportExport() { } if (FormatTok->is(tok::l_brace)) { FormatTok->BlockKind = BK_Block; + nextToken(); parseBracedList(); } else { nextToken(); diff --git a/lib/Frontend/FrontendActions.cpp b/lib/Frontend/FrontendActions.cpp index 0fbcc1c7399e..d42400183a43 100644 --- a/lib/Frontend/FrontendActions.cpp +++ b/lib/Frontend/FrontendActions.cpp @@ -163,6 +163,16 @@ GenerateModuleAction::CreateASTConsumer(CompilerInstance &CI, return llvm::make_unique<MultiplexConsumer>(std::move(Consumers)); } +bool GenerateModuleFromModuleMapAction::BeginSourceFileAction( + CompilerInstance &CI) { + if (!CI.getLangOpts().Modules) { + CI.getDiagnostics().Report(diag::err_module_build_requires_fmodules); + return false; + } + + return GenerateModuleAction::BeginSourceFileAction(CI); +} + std::unique_ptr<raw_pwrite_stream> GenerateModuleFromModuleMapAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { diff --git a/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/lib/Frontend/Rewrite/RewriteModernObjC.cpp index 83290a6fbc28..38be684cec86 100644 --- a/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -146,7 +146,7 @@ namespace { llvm::DenseMap<BlockExpr *, std::string> RewrittenBlockExprs; llvm::DenseMap<ObjCInterfaceDecl *, - llvm::SmallPtrSet<ObjCIvarDecl *, 8> > ReferencedIvars; + llvm::SmallSetVector<ObjCIvarDecl *, 8> > ReferencedIvars; // ivar bitfield grouping containers llvm::DenseSet<const ObjCInterfaceDecl *> ObjCInterefaceHasBitfieldGroups; @@ -1013,7 +1013,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, Setr = "\nextern \"C\" __declspec(dllimport) " "void objc_setProperty (id, SEL, long, id, bool, bool);\n"; } - + RewriteObjCMethodDecl(OID->getContainingInterface(), PD->getSetterMethodDecl(), Setr); Setr += "{ "; @@ -3965,10 +3965,11 @@ void RewriteModernObjC::RewriteIvarOffsetSymbols(ObjCInterfaceDecl *CDecl, std::string &Result) { // write out ivar offset symbols which have been referenced in an ivar // access expression. - llvm::SmallPtrSet<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl]; + llvm::SmallSetVector<ObjCIvarDecl *, 8> Ivars = ReferencedIvars[CDecl]; + if (Ivars.empty()) return; - + llvm::DenseSet<std::pair<const ObjCInterfaceDecl*, unsigned> > GroupSymbolOutput; for (ObjCIvarDecl *IvarDecl : Ivars) { const ObjCInterfaceDecl *IDecl = IvarDecl->getContainingInterface(); @@ -6068,7 +6069,7 @@ void RewriteModernObjC::Initialize(ASTContext &context) { Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; } -/// RewriteIvarOffsetComputation - This rutine synthesizes computation of +/// RewriteIvarOffsetComputation - This routine synthesizes computation of /// ivar offset. void RewriteModernObjC::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, std::string &Result) { diff --git a/lib/Frontend/Rewrite/RewriteObjC.cpp b/lib/Frontend/Rewrite/RewriteObjC.cpp index 7d809c610c86..5a1e001d65b8 100644 --- a/lib/Frontend/Rewrite/RewriteObjC.cpp +++ b/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -5052,7 +5052,7 @@ void RewriteObjCFragileABI::Initialize(ASTContext &context) { Preamble += "\n#define __OFFSETOFIVAR__(TYPE, MEMBER) ((long long) &((TYPE *)0)->MEMBER)\n"; } -/// RewriteIvarOffsetComputation - This rutine synthesizes computation of +/// RewriteIvarOffsetComputation - This routine synthesizes computation of /// ivar offset. void RewriteObjCFragileABI::RewriteIvarOffsetComputation(ObjCIvarDecl *ivar, std::string &Result) { diff --git a/lib/Frontend/SerializedDiagnosticReader.cpp b/lib/Frontend/SerializedDiagnosticReader.cpp index 8a8161488f44..08b7087fbad6 100644 --- a/lib/Frontend/SerializedDiagnosticReader.cpp +++ b/lib/Frontend/SerializedDiagnosticReader.cpp @@ -27,6 +27,9 @@ std::error_code SerializedDiagnosticReader::readDiagnostics(StringRef File) { llvm::BitstreamCursor Stream(**Buffer); Optional<llvm::BitstreamBlockInfo> BlockInfo; + if (Stream.AtEndOfStream()) + return SDError::InvalidSignature; + // Sniff for the signature. if (Stream.Read(8) != 'D' || Stream.Read(8) != 'I' || diff --git a/lib/Frontend/TextDiagnostic.cpp b/lib/Frontend/TextDiagnostic.cpp index 1e12ea5e597a..6a72b00c602b 100644 --- a/lib/Frontend/TextDiagnostic.cpp +++ b/lib/Frontend/TextDiagnostic.cpp @@ -1052,7 +1052,8 @@ static void highlightRange(const CharSourceRange &R, std::fill(CaretLine.begin()+StartColNo,CaretLine.begin()+EndColNo,'~'); } -static std::string buildFixItInsertionLine(unsigned LineNo, +static std::string buildFixItInsertionLine(FileID FID, + unsigned LineNo, const SourceColumnMap &map, ArrayRef<FixItHint> Hints, const SourceManager &SM, @@ -1069,7 +1070,8 @@ static std::string buildFixItInsertionLine(unsigned LineNo, // code contains no newlines and is on the same line as the caret. std::pair<FileID, unsigned> HintLocInfo = SM.getDecomposedExpansionLoc(I->RemoveRange.getBegin()); - if (LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && + if (FID == HintLocInfo.first && + LineNo == SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) && StringRef(I->CodeToInsert).find_first_of("\n\r") == StringRef::npos) { // Insert the new code into the line just below the code // that the user wrote. @@ -1105,9 +1107,6 @@ static std::string buildFixItInsertionLine(unsigned LineNo, PrevHintEndCol = HintCol + llvm::sys::locale::columnWidth(I->CodeToInsert); - } else { - FixItInsertionLine.clear(); - break; } } } @@ -1222,7 +1221,7 @@ void TextDiagnostic::emitSnippetAndCaret( } std::string FixItInsertionLine = buildFixItInsertionLine( - LineNo, sourceColMap, Hints, SM, DiagOpts.get()); + FID, LineNo, sourceColMap, Hints, SM, DiagOpts.get()); // If the source line is too long for our terminal, select only the // "interesting" source region within that line. diff --git a/lib/Headers/bmiintrin.h b/lib/Headers/bmiintrin.h index 361e5f720ea1..e812a1632b91 100644 --- a/lib/Headers/bmiintrin.h +++ b/lib/Headers/bmiintrin.h @@ -318,7 +318,7 @@ __blsi_u64(unsigned long long __X) /// /// \param __X /// An unsigned 64-bit integer used to create the mask. -/// \returns A unsigned 64-bit integer containing the newly created mask. +/// \returns An unsigned 64-bit integer containing the newly created mask. static __inline__ unsigned long long __DEFAULT_FN_ATTRS __blsmsk_u64(unsigned long long __X) { diff --git a/lib/Headers/cpuid.h b/lib/Headers/cpuid.h index 400dcfacd552..2dd0add236b8 100644 --- a/lib/Headers/cpuid.h +++ b/lib/Headers/cpuid.h @@ -79,7 +79,7 @@ #define signature_VORTEX_edx 0x36387865 #define signature_VORTEX_ecx 0x436f5320 -/* Features in %ecx for level 1 */ +/* Features in %ecx for leaf 1 */ #define bit_SSE3 0x00000001 #define bit_PCLMULQDQ 0x00000002 #define bit_PCLMUL bit_PCLMULQDQ /* for gcc compat */ @@ -114,7 +114,7 @@ #define bit_F16C 0x20000000 #define bit_RDRND 0x40000000 -/* Features in %edx for level 1 */ +/* Features in %edx for leaf 1 */ #define bit_FPU 0x00000001 #define bit_VME 0x00000002 #define bit_DE 0x00000004 @@ -147,44 +147,95 @@ #define bit_TM 0x20000000 #define bit_PBE 0x80000000 -/* Features in %ebx for level 7 sub-leaf 0 */ +/* Features in %ebx for leaf 7 sub-leaf 0 */ #define bit_FSGSBASE 0x00000001 +#define bit_SGX 0x00000004 +#define bit_BMI 0x00000008 +#define bit_HLE 0x00000010 +#define bit_AVX2 0x00000020 #define bit_SMEP 0x00000080 +#define bit_BMI2 0x00000100 #define bit_ENH_MOVSB 0x00000200 +#define bit_RTM 0x00000800 +#define bit_MPX 0x00004000 +#define bit_AVX512F 0x00010000 +#define bit_AVX512DQ 0x00020000 +#define bit_RDSEED 0x00040000 +#define bit_ADX 0x00080000 +#define bit_AVX512IFMA 0x00200000 +#define bit_CLFLUSHOPT 0x00800000 +#define bit_CLWB 0x01000000 +#define bit_AVX512PF 0x04000000 +#define bit_AVX51SER 0x08000000 +#define bit_AVX512CD 0x10000000 +#define bit_SHA 0x20000000 +#define bit_AVX512BW 0x40000000 +#define bit_AVX512VL 0x80000000 + +/* Features in %ecx for leaf 7 sub-leaf 0 */ +#define bit_PREFTCHWT1 0x00000001 +#define bit_AVX512VBMI 0x00000002 +#define bit_PKU 0x00000004 +#define bit_OSPKE 0x00000010 +#define bit_AVX512VPOPCNTDQ 0x00004000 +#define bit_RDPID 0x00400000 + +/* Features in %edx for leaf 7 sub-leaf 0 */ +#define bit_AVX5124VNNIW 0x00000004 +#define bit_AVX5124FMAPS 0x00000008 + +/* Features in %eax for leaf 13 sub-leaf 1 */ +#define bit_XSAVEOPT 0x00000001 +#define bit_XSAVEC 0x00000002 +#define bit_XSAVES 0x00000008 + +/* Features in %ecx for leaf 0x80000001 */ +#define bit_LAHF_LM 0x00000001 +#define bit_ABM 0x00000020 +#define bit_SSE4a 0x00000040 +#define bit_PRFCHW 0x00000100 +#define bit_XOP 0x00000800 +#define bit_LWP 0x00008000 +#define bit_FMA4 0x00010000 +#define bit_TBM 0x00200000 +#define bit_MWAITX 0x20000000 + +/* Features in %edx for leaf 0x80000001 */ +#define bit_MMXEXT 0x00400000 +#define bit_LM 0x20000000 +#define bit_3DNOWP 0x40000000 +#define bit_3DNOW 0x80000000 + +/* Features in %ebx for leaf 0x80000001 */ +#define bit_CLZERO 0x00000001 + #if __i386__ -#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \ +#define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \ __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \ - : "0"(__level)) + : "0"(__leaf)) -#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \ +#define __cpuid_count(__leaf, __count, __eax, __ebx, __ecx, __edx) \ __asm("cpuid" : "=a"(__eax), "=b" (__ebx), "=c"(__ecx), "=d"(__edx) \ - : "0"(__level), "2"(__count)) + : "0"(__leaf), "2"(__count)) #else /* x86-64 uses %rbx as the base register, so preserve it. */ -#define __cpuid(__level, __eax, __ebx, __ecx, __edx) \ +#define __cpuid(__leaf, __eax, __ebx, __ecx, __edx) \ __asm(" xchgq %%rbx,%q1\n" \ " cpuid\n" \ " xchgq %%rbx,%q1" \ : "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \ - : "0"(__level)) + : "0"(__leaf)) -#define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \ +#define __cpuid_count(__leaf, __count, __eax, __ebx, __ecx, __edx) \ __asm(" xchgq %%rbx,%q1\n" \ " cpuid\n" \ " xchgq %%rbx,%q1" \ : "=a"(__eax), "=r" (__ebx), "=c"(__ecx), "=d"(__edx) \ - : "0"(__level), "2"(__count)) + : "0"(__leaf), "2"(__count)) #endif -static __inline int __get_cpuid (unsigned int __level, unsigned int *__eax, - unsigned int *__ebx, unsigned int *__ecx, - unsigned int *__edx) { - __cpuid(__level, *__eax, *__ebx, *__ecx, *__edx); - return 1; -} - -static __inline int __get_cpuid_max (unsigned int __level, unsigned int *__sig) +static __inline int __get_cpuid_max (unsigned int __leaf, unsigned int *__sig) { unsigned int __eax, __ebx, __ecx, __edx; #if __i386__ @@ -208,8 +259,35 @@ static __inline int __get_cpuid_max (unsigned int __level, unsigned int *__sig) return 0; #endif - __cpuid(__level, __eax, __ebx, __ecx, __edx); + __cpuid(__leaf, __eax, __ebx, __ecx, __edx); if (__sig) *__sig = __ebx; return __eax; } + +static __inline int __get_cpuid (unsigned int __leaf, unsigned int *__eax, + unsigned int *__ebx, unsigned int *__ecx, + unsigned int *__edx) +{ + unsigned int __max_leaf = __get_cpuid_max(__leaf & 0x80000000, 0); + + if (__max_leaf == 0 || __max_leaf < __leaf) + return 0; + + __cpuid(__leaf, *__eax, *__ebx, *__ecx, *__edx); + return 1; +} + +static __inline int __get_cpuid_count (unsigned int __leaf, + unsigned int __subleaf, + unsigned int *__eax, unsigned int *__ebx, + unsigned int *__ecx, unsigned int *__edx) +{ + unsigned int __max_leaf = __get_cpuid_max(__leaf & 0x80000000, 0); + + if (__max_leaf == 0 || __max_leaf < __leaf) + return 0; + + __cpuid_count(__leaf, __subleaf, *__eax, *__ebx, *__ecx, *__edx); + return 1; +} diff --git a/lib/Headers/immintrin.h b/lib/Headers/immintrin.h index e22dd231427d..c5f25bfcb5c1 100644 --- a/lib/Headers/immintrin.h +++ b/lib/Headers/immintrin.h @@ -212,6 +212,15 @@ _rdrand32_step(unsigned int *__p) return __builtin_ia32_rdrand32_step(__p); } +#ifdef __x86_64__ +static __inline__ int __attribute__((__always_inline__, __nodebug__, __target__("rdrnd"))) +_rdrand64_step(unsigned long long *__p) +{ + return __builtin_ia32_rdrand64_step(__p); +} +#endif +#endif /* __RDRND__ */ + /* __bit_scan_forward */ static __inline__ int __attribute__((__always_inline__, __nodebug__)) _bit_scan_forward(int __A) { @@ -224,15 +233,6 @@ _bit_scan_reverse(int __A) { return 31 - __builtin_clz(__A); } -#ifdef __x86_64__ -static __inline__ int __attribute__((__always_inline__, __nodebug__, __target__("rdrnd"))) -_rdrand64_step(unsigned long long *__p) -{ - return __builtin_ia32_rdrand64_step(__p); -} -#endif -#endif /* __RDRND__ */ - #if !defined(_MSC_VER) || __has_feature(modules) || defined(__FSGSBASE__) #ifdef __x86_64__ static __inline__ unsigned int __attribute__((__always_inline__, __nodebug__, __target__("fsgsbase"))) diff --git a/lib/Headers/mmintrin.h b/lib/Headers/mmintrin.h index 5a7968bec842..4b38d51713d8 100644 --- a/lib/Headers/mmintrin.h +++ b/lib/Headers/mmintrin.h @@ -1289,7 +1289,7 @@ _mm_cmpgt_pi32(__m64 __m1, __m64 __m2) /// /// \headerfile <x86intrin.h> /// -/// This intrinsic corresponds to the the <c> VXORPS / XORPS </c> instruction. +/// This intrinsic corresponds to the <c> VXORPS / XORPS </c> instruction. /// /// \returns An initialized 64-bit integer vector with all elements set to zero. static __inline__ __m64 __DEFAULT_FN_ATTRS diff --git a/lib/Index/IndexBody.cpp b/lib/Index/IndexBody.cpp index d3632b8b9b15..6bbd38102509 100644 --- a/lib/Index/IndexBody.cpp +++ b/lib/Index/IndexBody.cpp @@ -230,7 +230,31 @@ public: SmallVector<SymbolRelation, 2> Relations; addCallRole(Roles, Relations); Stmt *Containing = getParentStmt(); - if (E->isImplicit() || (Containing && isa<PseudoObjectExpr>(Containing))) + + auto IsImplicitProperty = [](const PseudoObjectExpr *POE) -> bool { + const auto *E = POE->getSyntacticForm(); + if (const auto *BinOp = dyn_cast<BinaryOperator>(E)) + E = BinOp->getLHS(); + const auto *PRE = dyn_cast<ObjCPropertyRefExpr>(E); + if (!PRE) + return false; + if (PRE->isExplicitProperty()) + return false; + if (const ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) { + // Class properties that are explicitly defined using @property + // declarations are represented implicitly as there is no ivar for + // class properties. + if (Getter->isClassMethod() && + Getter->getCanonicalDecl()->findPropertyDecl()) + return false; + } + return true; + }; + bool IsPropCall = Containing && isa<PseudoObjectExpr>(Containing); + // Implicit property message sends are not 'implicit'. + if ((E->isImplicit() || IsPropCall) && + !(IsPropCall && + IsImplicitProperty(cast<PseudoObjectExpr>(Containing)))) Roles |= (unsigned)SymbolRole::Implicit; if (isDynamic(E)) { diff --git a/lib/Index/IndexDecl.cpp b/lib/Index/IndexDecl.cpp index d1127722c8ca..c5230c0f9acf 100644 --- a/lib/Index/IndexDecl.cpp +++ b/lib/Index/IndexDecl.cpp @@ -618,6 +618,8 @@ public: Template.is<ClassTemplateDecl *>() ? (Decl *)Template.get<ClassTemplateDecl *>() : Template.get<ClassTemplatePartialSpecializationDecl *>(); + if (!D->isThisDeclarationADefinition()) + IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); IndexCtx.indexTagDecl( D, SymbolRelation(SymbolRoleSet(SymbolRole::RelationSpecializationOf), SpecializationOf)); diff --git a/lib/Index/IndexSymbol.cpp b/lib/Index/IndexSymbol.cpp index bf358a372149..0dc3720208ca 100644 --- a/lib/Index/IndexSymbol.cpp +++ b/lib/Index/IndexSymbol.cpp @@ -69,11 +69,13 @@ bool index::isFunctionLocalSymbol(const Decl *D) { if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { switch (ND->getFormalLinkage()) { case NoLinkage: - case VisibleNoLinkage: case InternalLinkage: return true; + case VisibleNoLinkage: case UniqueExternalLinkage: + case ModuleInternalLinkage: llvm_unreachable("Not a sema linkage"); + case ModuleLinkage: case ExternalLinkage: return false; } diff --git a/lib/Index/IndexingContext.cpp b/lib/Index/IndexingContext.cpp index 754bc84ff4b2..c4aa51d62f02 100644 --- a/lib/Index/IndexingContext.cpp +++ b/lib/Index/IndexingContext.cpp @@ -229,6 +229,12 @@ static bool isDeclADefinition(const Decl *D, const DeclContext *ContainerDC, AST return false; } +/// Whether the given NamedDecl should be skipped because it has no name. +static bool shouldSkipNamelessDecl(const NamedDecl *ND) { + return ND->getDeclName().isEmpty() && !isa<TagDecl>(ND) && + !isa<ObjCCategoryDecl>(ND); +} + static const Decl *adjustParent(const Decl *Parent) { if (!Parent) return nullptr; @@ -243,8 +249,8 @@ static const Decl *adjustParent(const Decl *Parent) { } else if (auto RD = dyn_cast<RecordDecl>(Parent)) { if (RD->isAnonymousStructOrUnion()) continue; - } else if (auto FD = dyn_cast<FieldDecl>(Parent)) { - if (FD->getDeclName().isEmpty()) + } else if (auto ND = dyn_cast<NamedDecl>(Parent)) { + if (shouldSkipNamelessDecl(ND)) continue; } return Parent; @@ -315,9 +321,7 @@ bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc, const DeclContext *ContainerDC) { if (D->isImplicit() && !isa<ObjCMethodDecl>(D)) return true; - if (!isa<NamedDecl>(D) || - (cast<NamedDecl>(D)->getDeclName().isEmpty() && - !isa<TagDecl>(D) && !isa<ObjCCategoryDecl>(D))) + if (!isa<NamedDecl>(D) || shouldSkipNamelessDecl(cast<NamedDecl>(D))) return true; SourceManager &SM = Ctx->getSourceManager(); diff --git a/lib/Lex/Lexer.cpp b/lib/Lex/Lexer.cpp index 012189aa6f9f..61bcef8cb760 100644 --- a/lib/Lex/Lexer.cpp +++ b/lib/Lex/Lexer.cpp @@ -2550,7 +2550,7 @@ bool Lexer::LexEndOfFile(Token &Result, const char *CurPtr) { return true; } - if (PP->isRecordingPreamble() && !PP->isInMainFile()) { + if (PP->isRecordingPreamble() && PP->isInPrimaryFile()) { PP->setRecordedPreambleConditionalStack(ConditionalStack); ConditionalStack.clear(); } diff --git a/lib/Lex/PPLexerChange.cpp b/lib/Lex/PPLexerChange.cpp index 1c0cd5636835..5a589d6a17b3 100644 --- a/lib/Lex/PPLexerChange.cpp +++ b/lib/Lex/PPLexerChange.cpp @@ -46,12 +46,6 @@ bool Preprocessor::isInPrimaryFile() const { }); } -bool Preprocessor::isInMainFile() const { - if (IsFileLexer()) - return IncludeMacroStack.size() == 0; - return true; -} - /// getCurrentLexer - Return the current file lexer being lexed from. Note /// that this ignores any potentially active macro expansions and _Pragma /// expansions going on at the time. diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp index f9a399cd7fd7..63f39524d12a 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -535,7 +535,9 @@ void Preprocessor::EnterMainSourceFile() { // Start parsing the predefines. EnterSourceFile(FID, nullptr, SourceLocation()); +} +void Preprocessor::replayPreambleConditionalStack() { // Restore the conditional stack from the preamble, if there is one. if (PreambleConditionalStack.isReplaying()) { CurPPLexer->setConditionalLevels(PreambleConditionalStack.getStack()); diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index cc1e8850a523..b68559485a5e 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -889,7 +889,7 @@ bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { // If the opening brace is not preceded by one of these tokens, we are // missing the mem-initializer-id. In order to recover better, we need // to use heuristics to determine if this '{' is most likely the - // begining of a brace-init-list or the function body. + // beginning of a brace-init-list or the function body. // Check the token after the corresponding '}'. TentativeParsingAction PA(*this); if (SkipUntil(tok::r_brace) && diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 07054546f42f..a4610698c46d 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -6650,7 +6650,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) { return; } - // If we get here, the operand to the typeof was an expresion. + // If we get here, the operand to the typeof was an expression. if (Operand.isInvalid()) { DS.SetTypeSpecError(); return; diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index aacb00e8be64..44b87af01abd 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -1866,7 +1866,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, } } - // If we get here, the operand to the typeof/sizeof/alignof was an expresion. + // If we get here, the operand to the typeof/sizeof/alignof was an expression. isCastExpr = false; return Operand; } @@ -1972,7 +1972,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { if (OpTok.isOneOf(tok::kw_alignof, tok::kw__Alignof)) Diag(OpTok, diag::ext_alignof_expr) << OpTok.getIdentifierInfo(); - // If we get here, the operand to the sizeof/alignof was an expresion. + // If we get here, the operand to the sizeof/alignof was an expression. if (!Operand.isInvalid()) Operand = Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), ExprKind, diff --git a/lib/Parse/ParseObjc.cpp b/lib/Parse/ParseObjc.cpp index caa6323d3209..f7410b8a092a 100644 --- a/lib/Parse/ParseObjc.cpp +++ b/lib/Parse/ParseObjc.cpp @@ -2255,7 +2255,7 @@ Parser::ObjCImplParsingDataRAII::~ObjCImplParsingDataRAII() { void Parser::ObjCImplParsingDataRAII::finish(SourceRange AtEnd) { assert(!Finished); - P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl); + P.Actions.DefaultSynthesizeProperties(P.getCurScope(), Dcl, AtEnd.getBegin()); for (size_t i = 0; i < LateParsedObjCMethods.size(); ++i) P.ParseLexedObjCMethodDefs(*LateParsedObjCMethods[i], true/*Methods*/); diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index af29b5e9c673..4aa9a5971929 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -516,6 +516,8 @@ void Parser::Initialize() { // Prime the lexer look-ahead. ConsumeToken(); + + PP.replayPreambleConditionalStack(); } void Parser::LateTemplateParserCleanupCallback(void *P) { @@ -526,6 +528,8 @@ void Parser::LateTemplateParserCleanupCallback(void *P) { } bool Parser::ParseFirstTopLevelDecl(DeclGroupPtrTy &Result) { + Actions.ActOnStartOfTranslationUnit(); + // C11 6.9p1 says translation units must have at least one top-level // declaration. C++ doesn't have this restriction. We also don't want to // complain if we have a precompiled header, although technically if the PCH diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index fd2d07957c2b..f83baa790b49 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -394,15 +394,21 @@ static bool hasThrowOutNonThrowingFunc(SourceLocation &OpLoc, CFG *BodyCFG) { static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, const FunctionDecl *FD) { - if (!S.getSourceManager().isInSystemHeader(OpLoc)) { + if (!S.getSourceManager().isInSystemHeader(OpLoc) && + FD->getTypeSourceInfo()) { S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD; if (S.getLangOpts().CPlusPlus11 && (isa<CXXDestructorDecl>(FD) || FD->getDeclName().getCXXOverloadedOperator() == OO_Delete || - FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) - S.Diag(FD->getLocation(), diag::note_throw_in_dtor); - else - S.Diag(FD->getLocation(), diag::note_throw_in_function); + FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) { + if (const auto *Ty = FD->getTypeSourceInfo()->getType()-> + getAs<FunctionProtoType>()) + S.Diag(FD->getLocation(), diag::note_throw_in_dtor) + << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec() + << FD->getExceptionSpecSourceRange(); + } else + S.Diag(FD->getLocation(), diag::note_throw_in_function) + << FD->getExceptionSpecSourceRange(); } } @@ -420,8 +426,7 @@ static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, static bool isNoexcept(const FunctionDecl *FD) { const auto *FPT = FD->getType()->castAs<FunctionProtoType>(); - if (FPT->getExceptionSpecType() != EST_None && - FPT->isNothrow(FD->getASTContext())) + if (FPT->isNothrow(FD->getASTContext())) return true; return false; } diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp index 2fa5718d4e9b..3d321d561e60 100644 --- a/lib/Sema/DelayedDiagnostic.cpp +++ b/lib/Sema/DelayedDiagnostic.cpp @@ -22,7 +22,8 @@ using namespace sema; DelayedDiagnostic DelayedDiagnostic::makeAvailability(AvailabilityResult AR, SourceLocation Loc, - const NamedDecl *D, + const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, StringRef Msg, @@ -31,7 +32,8 @@ DelayedDiagnostic::makeAvailability(AvailabilityResult AR, DD.Kind = Availability; DD.Triggered = false; DD.Loc = Loc; - DD.AvailabilityData.Decl = D; + DD.AvailabilityData.ReferringDecl = ReferringDecl; + DD.AvailabilityData.OffendingDecl = OffendingDecl; DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass; DD.AvailabilityData.ObjCProperty = ObjCProperty; char *MessageData = nullptr; diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 34f5e26be810..dc9f977d41ac 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -705,6 +705,18 @@ void Sema::emitAndClearUnusedLocalTypedefWarnings() { UnusedLocalTypedefNameCandidates.clear(); } +/// This is called before the very first declaration in the translation unit +/// is parsed. Note that the ASTContext may have already injected some +/// declarations. +void Sema::ActOnStartOfTranslationUnit() { + if (getLangOpts().ModulesTS) { + // We start in the global module; all those declarations are implicitly + // module-private (though they do not have module linkage). + Context.getTranslationUnitDecl()->setModuleOwnershipKind( + Decl::ModuleOwnershipKind::ModulePrivate); + } +} + /// ActOnEndOfTranslationUnit - This is called at the very end of the /// translation unit when EOF is reached and all but the top-level scope is /// popped. diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index 7d534263f468..ba2049d8a606 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -143,6 +143,9 @@ namespace { }; } +static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, + QualType DestType); + // The Try functions attempt a specific way of casting. If they succeed, they // return TC_Success. If their way of casting is not appropriate for the given // arguments, they return TC_NotApplicable and *may* set diag to a diagnostic @@ -427,6 +430,10 @@ static void diagnoseBadCast(Sema &S, unsigned msg, CastType castType, /// the same kind of pointer (plain or to-member). Unlike the Sema function, /// this one doesn't care if the two pointers-to-member don't point into the /// same class. This is because CastsAwayConstness doesn't care. +/// And additionally, it handles C++ references. If both the types are +/// references, then their pointee types are returned, +/// else if only one of them is reference, it's pointee type is returned, +/// and the other type is returned as-is. static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { const PointerType *T1PtrType = T1->getAs<PointerType>(), *T2PtrType = T2->getAs<PointerType>(); @@ -475,6 +482,26 @@ static bool UnwrapDissimilarPointerTypes(QualType& T1, QualType& T2) { return true; } + const LValueReferenceType *T1RefType = T1->getAs<LValueReferenceType>(), + *T2RefType = T2->getAs<LValueReferenceType>(); + if (T1RefType && T2RefType) { + T1 = T1RefType->getPointeeType(); + T2 = T2RefType->getPointeeType(); + return true; + } + + if (T1RefType) { + T1 = T1RefType->getPointeeType(); + // T2 = T2; + return true; + } + + if (T2RefType) { + // T1 = T1; + T2 = T2RefType->getPointeeType(); + return true; + } + return false; } @@ -503,11 +530,13 @@ CastsAwayConstness(Sema &Self, QualType SrcType, QualType DestType, // the rules are non-trivial. So first we construct Tcv *...cv* as described // in C++ 5.2.11p8. assert((SrcType->isAnyPointerType() || SrcType->isMemberPointerType() || - SrcType->isBlockPointerType()) && + SrcType->isBlockPointerType() || + DestType->isLValueReferenceType()) && "Source type is not pointer or pointer to member."); assert((DestType->isAnyPointerType() || DestType->isMemberPointerType() || - DestType->isBlockPointerType()) && - "Destination type is not pointer or pointer to member."); + DestType->isBlockPointerType() || + DestType->isLValueReferenceType()) && + "Destination type is not pointer or pointer to member, or reference."); QualType UnwrappedSrcType = Self.Context.getCanonicalType(SrcType), UnwrappedDestType = Self.Context.getCanonicalType(DestType); @@ -2177,6 +2206,8 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, bool ListInitialization) { + assert(Self.getLangOpts().CPlusPlus); + // Handle placeholders. if (isPlaceholder()) { // C-style casts can resolve __unknown_any types. @@ -2580,30 +2611,42 @@ void CastOperation::CheckCStyleCast() { if (Kind == CK_BitCast) checkCastAlign(); +} + +/// DiagnoseCastQual - Warn whenever casts discards a qualifiers, be it either +/// const, volatile or both. +static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, + QualType DestType) { + if (SrcExpr.isInvalid()) + return; + + QualType SrcType = SrcExpr.get()->getType(); + if (!((SrcType->isAnyPointerType() && DestType->isAnyPointerType()) || + DestType->isLValueReferenceType())) + return; - // -Wcast-qual QualType TheOffendingSrcType, TheOffendingDestType; Qualifiers CastAwayQualifiers; - if (SrcType->isAnyPointerType() && DestType->isAnyPointerType() && - CastsAwayConstness(Self, SrcType, DestType, true, false, - &TheOffendingSrcType, &TheOffendingDestType, - &CastAwayQualifiers)) { - int qualifiers = -1; - if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) { - qualifiers = 0; - } else if (CastAwayQualifiers.hasConst()) { - qualifiers = 1; - } else if (CastAwayQualifiers.hasVolatile()) { - qualifiers = 2; - } - // This is a variant of int **x; const int **y = (const int **)x; - if (qualifiers == -1) - Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2) << - SrcType << DestType; - else - Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual) << - TheOffendingSrcType << TheOffendingDestType << qualifiers; - } + if (!CastsAwayConstness(Self, SrcType, DestType, true, false, + &TheOffendingSrcType, &TheOffendingDestType, + &CastAwayQualifiers)) + return; + + int qualifiers = -1; + if (CastAwayQualifiers.hasConst() && CastAwayQualifiers.hasVolatile()) { + qualifiers = 0; + } else if (CastAwayQualifiers.hasConst()) { + qualifiers = 1; + } else if (CastAwayQualifiers.hasVolatile()) { + qualifiers = 2; + } + // This is a variant of int **x; const int **y = (const int **)x; + if (qualifiers == -1) + Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual2) + << SrcType << DestType; + else + Self.Diag(SrcExpr.get()->getLocStart(), diag::warn_cast_qual) + << TheOffendingSrcType << TheOffendingDestType << qualifiers; } ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, @@ -2624,6 +2667,9 @@ ExprResult Sema::BuildCStyleCastExpr(SourceLocation LPLoc, if (Op.SrcExpr.isInvalid()) return ExprError(); + // -Wcast-qual + DiagnoseCastQual(Op.Self, Op.SrcExpr, Op.DestType); + return Op.complete(CStyleCastExpr::Create(Context, Op.ResultType, Op.ValueKind, Op.Kind, Op.SrcExpr.get(), &Op.BasePath, CastTypeInfo, LPLoc, RPLoc)); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 845c4bf61b7a..8446601334ee 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -309,7 +309,8 @@ static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { Expr *BlockArg = TheCall->getArg(0); if (!isBlockPointer(BlockArg)) { S.Diag(BlockArg->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) << "block"; + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; return true; } return checkOpenCLBlockArgs(S, BlockArg); @@ -394,24 +395,24 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { // First argument always needs to be a queue_t type. if (!Arg0->getType()->isQueueT()) { S.Diag(TheCall->getArg(0)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) - << S.Context.OCLQueueTy; + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << S.Context.OCLQueueTy; return true; } // Second argument always needs to be a kernel_enqueue_flags_t enum value. if (!Arg1->getType()->isIntegerType()) { S.Diag(TheCall->getArg(1)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) - << "'kernel_enqueue_flags_t' (i.e. uint)"; + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "'kernel_enqueue_flags_t' (i.e. uint)"; return true; } // Third argument is always an ndrange_t type. if (Arg2->getType().getUnqualifiedType().getAsString() != "ndrange_t") { S.Diag(TheCall->getArg(2)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) - << "'ndrange_t'"; + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "'ndrange_t'"; return true; } @@ -420,8 +421,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { if (NumArgs == 4) { // check that the last argument is the right block type. if (!isBlockPointer(Arg3)) { - S.Diag(Arg3->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) - << "block"; + S.Diag(Arg3->getLocStart(), diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; return true; } // we have a block type, check the prototype @@ -443,8 +444,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { // check common block argument. Expr *Arg6 = TheCall->getArg(6); if (!isBlockPointer(Arg6)) { - S.Diag(Arg6->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) - << "block"; + S.Diag(Arg6->getLocStart(), diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "block"; return true; } if (checkOpenCLBlockArgs(S, Arg6)) @@ -453,8 +454,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { // Forth argument has to be any integer type. if (!Arg3->getType()->isIntegerType()) { S.Diag(TheCall->getArg(3)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) - << "integer"; + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << "integer"; return true; } // check remaining common arguments. @@ -466,7 +467,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { Expr::NPC_ValueDependentIsNotNull) && !Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) { S.Diag(TheCall->getArg(4)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << S.Context.getPointerType(S.Context.OCLClkEventTy); return true; } @@ -477,7 +479,8 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { !(Arg5->getType()->isPointerType() && Arg5->getType()->getPointeeType()->isClkEventT())) { S.Diag(TheCall->getArg(5)->getLocStart(), - diag::err_opencl_enqueue_kernel_expected_type) + diag::err_opencl_builtin_expected_type) + << TheCall->getDirectCallee() << S.Context.getPointerType(S.Context.OCLClkEventTy); return true; } @@ -12094,6 +12097,8 @@ void Sema::RefersToMemberWithReducedAlignment( if (ME->isArrow()) BaseType = BaseType->getPointeeType(); RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl(); + if (RD->isInvalidDecl()) + return; ValueDecl *MD = ME->getMemberDecl(); auto *FD = dyn_cast<FieldDecl>(MD); diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp index b05c0998d3dd..dc7d8e4e9cec 100644 --- a/lib/Sema/SemaCoroutine.cpp +++ b/lib/Sema/SemaCoroutine.cpp @@ -43,9 +43,10 @@ static bool lookupMember(Sema &S, const char *Name, CXXRecordDecl *RD, /// Look up the std::coroutine_traits<...>::promise_type for the given /// function type. -static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, - SourceLocation KwLoc, - SourceLocation FuncLoc) { +static QualType lookupPromiseType(Sema &S, const FunctionDecl *FD, + SourceLocation KwLoc) { + const FunctionProtoType *FnType = FD->getType()->castAs<FunctionProtoType>(); + const SourceLocation FuncLoc = FD->getLocation(); // FIXME: Cache std::coroutine_traits once we've found it. NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace(); if (!StdExp) { @@ -71,16 +72,35 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, return QualType(); } - // Form template argument list for coroutine_traits<R, P1, P2, ...>. + // Form template argument list for coroutine_traits<R, P1, P2, ...> according + // to [dcl.fct.def.coroutine]3 TemplateArgumentListInfo Args(KwLoc, KwLoc); - Args.addArgument(TemplateArgumentLoc( - TemplateArgument(FnType->getReturnType()), - S.Context.getTrivialTypeSourceInfo(FnType->getReturnType(), KwLoc))); - // FIXME: If the function is a non-static member function, add the type - // of the implicit object parameter before the formal parameters. - for (QualType T : FnType->getParamTypes()) + auto AddArg = [&](QualType T) { Args.addArgument(TemplateArgumentLoc( TemplateArgument(T), S.Context.getTrivialTypeSourceInfo(T, KwLoc))); + }; + AddArg(FnType->getReturnType()); + // If the function is a non-static member function, add the type + // of the implicit object parameter before the formal parameters. + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (MD->isInstance()) { + // [over.match.funcs]4 + // For non-static member functions, the type of the implicit object + // parameter is + // -- "lvalue reference to cv X" for functions declared without a + // ref-qualifier or with the & ref-qualifier + // -- "rvalue reference to cv X" for functions declared with the && + // ref-qualifier + QualType T = + MD->getThisType(S.Context)->getAs<PointerType>()->getPointeeType(); + T = FnType->getRefQualifier() == RQ_RValue + ? S.Context.getRValueReferenceType(T) + : S.Context.getLValueReferenceType(T, /*SpelledAsLValue*/ true); + AddArg(T); + } + } + for (QualType T : FnType->getParamTypes()) + AddArg(T); // Build the template-id. QualType CoroTrait = @@ -424,12 +444,16 @@ static ExprResult buildPromiseCall(Sema &S, VarDecl *Promise, VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) { assert(isa<FunctionDecl>(CurContext) && "not in a function scope"); auto *FD = cast<FunctionDecl>(CurContext); + bool IsThisDependentType = [&] { + if (auto *MD = dyn_cast_or_null<CXXMethodDecl>(FD)) + return MD->isInstance() && MD->getThisType(Context)->isDependentType(); + else + return false; + }(); - QualType T = - FD->getType()->isDependentType() - ? Context.DependentTy - : lookupPromiseType(*this, FD->getType()->castAs<FunctionProtoType>(), - Loc, FD->getLocation()); + QualType T = FD->getType()->isDependentType() || IsThisDependentType + ? Context.DependentTy + : lookupPromiseType(*this, FD, Loc); if (T.isNull()) return nullptr; @@ -721,8 +745,6 @@ static Expr *buildStdNoThrowDeclRef(Sema &S, SourceLocation Loc) { return nullptr; } - // FIXME: Mark the variable as ODR used. This currently does not work - // likely due to the scope at in which this function is called. auto *VD = Result.getAsSingle<VarDecl>(); if (!VD) { Result.suppressDiagnostics(); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ef8a408f90de..31b24f91c1d9 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1998,8 +1998,7 @@ static void filterNonConflictingPreviousTypedefDecls(Sema &S, // If both declarations give a tag declaration a typedef name for linkage // purposes, then they declare the same entity. - if (S.getLangOpts().CPlusPlus && - OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) && + if (OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true) && Decl->getAnonDeclWithTypedefName()) continue; } @@ -2117,7 +2116,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, auto *OldTag = OldTD->getAnonDeclWithTypedefName(/*AnyRedecl*/true); auto *NewTag = New->getAnonDeclWithTypedefName(); NamedDecl *Hidden = nullptr; - if (getLangOpts().CPlusPlus && OldTag && NewTag && + if (OldTag && NewTag && OldTag->getCanonicalDecl() != NewTag->getCanonicalDecl() && !hasVisibleDefinition(OldTag, &Hidden)) { // There is a definition of this tag, but it is not visible. Use it @@ -16055,8 +16054,6 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, return nullptr; } - // FIXME: Create a ModuleDecl and return it. - // FIXME: Most of this work should be done by the preprocessor rather than // here, in order to support macro import. @@ -16070,6 +16067,8 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, ModuleName += Piece.first->getName(); } + // FIXME: If we've already seen a module-declaration, report an error. + // If a module name was explicitly specified on the command line, it must be // correct. if (!getLangOpts().CurrentModule.empty() && @@ -16082,6 +16081,7 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName; auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + Module *Mod; switch (MDK) { case ModuleDeclKind::Module: { @@ -16100,12 +16100,9 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, } // Create a Module for the module that we're defining. - Module *Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); + Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); assert(Mod && "module creation should not fail"); - - // Enter the semantic scope of the module. - ActOnModuleBegin(ModuleLoc, Mod); - return nullptr; + break; } case ModuleDeclKind::Partition: @@ -16115,14 +16112,26 @@ Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation StartLoc, case ModuleDeclKind::Implementation: std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc( PP.getIdentifierInfo(ModuleName), Path[0].second); - - DeclResult Import = ActOnModuleImport(ModuleLoc, ModuleLoc, ModuleNameLoc); - if (Import.isInvalid()) + Mod = getModuleLoader().loadModule(ModuleLoc, Path, Module::AllVisible, + /*IsIncludeDirective=*/false); + if (!Mod) return nullptr; - return ConvertDeclToDeclGroup(Import.get()); + break; } - llvm_unreachable("unexpected module decl kind"); + // Enter the semantic scope of the module. + ModuleScopes.push_back({}); + ModuleScopes.back().Module = Mod; + ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); + VisibleModules.setVisible(Mod, ModuleLoc); + + // From now on, we have an owning module for all declarations we see. + // However, those declarations are module-private unless explicitly + // exported. + Context.getTranslationUnitDecl()->setLocalOwningModule(Mod); + + // FIXME: Create a ModuleDecl. + return nullptr; } DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, @@ -16311,6 +16320,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, CurContext->addDecl(D); PushDeclContext(S, D); + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported); return D; } diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 1929bc539188..5fb79a6bf630 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -6929,8 +6929,34 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context, DeclVersion >= ForceAvailabilityFromVersion; } +static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) { + for (Decl *Ctx = OrigCtx; Ctx; + Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) { + if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx)) + return cast<NamedDecl>(Ctx); + if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) { + if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx)) + return Imp->getClassInterface(); + return CD; + } + } + + return dyn_cast<NamedDecl>(OrigCtx); +} + +/// Actually emit an availability diagnostic for a reference to an unavailable +/// decl. +/// +/// \param Ctx The context that the reference occurred in +/// \param ReferringDecl The exact declaration that was referenced. +/// \param OffendingDecl A related decl to \c ReferringDecl that has an +/// availability attribute corrisponding to \c K attached to it. Note that this +/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and +/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl +/// and OffendingDecl is the EnumDecl. static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, - Decl *Ctx, const NamedDecl *D, + Decl *Ctx, const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, @@ -6938,7 +6964,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, // Diagnostics for deprecated or unavailable. unsigned diag, diag_message, diag_fwdclass_message; unsigned diag_available_here = diag::note_availability_specified_here; - SourceLocation NoteLocation = D->getLocation(); + SourceLocation NoteLocation = OffendingDecl->getLocation(); // Matches 'diag::note_property_attribute' options. unsigned property_note_select; @@ -6947,7 +6973,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, unsigned available_here_select_kind; VersionTuple DeclVersion; - if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, D)) + if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl)) DeclVersion = AA->getIntroduced(); if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) @@ -6961,7 +6987,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; property_note_select = /* deprecated */ 0; available_here_select_kind = /* deprecated */ 2; - if (const auto *attr = D->getAttr<DeprecatedAttr>()) + if (const auto *attr = OffendingDecl->getAttr<DeprecatedAttr>()) NoteLocation = attr->getLocation(); break; @@ -6973,13 +6999,14 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, property_note_select = /* unavailable */ 1; available_here_select_kind = /* unavailable */ 0; - if (auto attr = D->getAttr<UnavailableAttr>()) { + if (auto attr = OffendingDecl->getAttr<UnavailableAttr>()) { if (attr->isImplicit() && attr->getImplicitReason()) { // Most of these failures are due to extra restrictions in ARC; // reflect that in the primary diagnostic when applicable. auto flagARCError = [&] { if (S.getLangOpts().ObjCAutoRefCount && - S.getSourceManager().isInSystemHeader(D->getLocation())) + S.getSourceManager().isInSystemHeader( + OffendingDecl->getLocation())) diag = diag::err_unavailable_in_arc; }; @@ -7022,7 +7049,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, // not specified for deployment targets >= to iOS 11 or equivalent or // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or // later. - const AvailabilityAttr *AA = getAttrForPlatform(S.getASTContext(), D); + const AvailabilityAttr *AA = + getAttrForPlatform(S.getASTContext(), OffendingDecl); VersionTuple Introduced = AA->getIntroduced(); bool NewWarning = shouldDiagnoseAvailabilityByDefault( S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), @@ -7045,9 +7073,9 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, CharSourceRange UseRange; StringRef Replacement; if (K == AR_Deprecated) { - if (auto attr = D->getAttr<DeprecatedAttr>()) + if (auto attr = OffendingDecl->getAttr<DeprecatedAttr>()) Replacement = attr->getReplacement(); - if (auto attr = getAttrForPlatform(S.Context, D)) + if (auto attr = getAttrForPlatform(S.Context, OffendingDecl)) Replacement = attr->getReplacement(); if (!Replacement.empty()) @@ -7056,21 +7084,21 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, } if (!Message.empty()) { - S.Diag(Loc, diag_message) << D << Message + S.Diag(Loc, diag_message) << ReferringDecl << Message << (UseRange.isValid() ? FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << D + S.Diag(Loc, diag) << ReferringDecl << (UseRange.isValid() ? FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else { - S.Diag(Loc, diag_fwdclass_message) << D + S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << (UseRange.isValid() ? FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); @@ -7078,16 +7106,16 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, // The declaration can have multiple availability attributes, we are looking // at one of them. - const AvailabilityAttr *A = getAttrForPlatform(S.Context, D); + const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); if (A && A->isInherited()) { - for (const Decl *Redecl = D->getMostRecentDecl(); Redecl; + for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl; Redecl = Redecl->getPreviousDecl()) { const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context, Redecl); if (AForRedecl && !AForRedecl->isInherited()) { // If D is a declaration with inherited attributes, the note should // point to the declaration with actual attributes. - S.Diag(Redecl->getLocation(), diag_available_here) << D + S.Diag(Redecl->getLocation(), diag_available_here) << OffendingDecl << available_here_select_kind; break; } @@ -7095,10 +7123,19 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, } else S.Diag(NoteLocation, diag_available_here) - << D << available_here_select_kind; + << OffendingDecl << available_here_select_kind; if (K == AR_NotYetIntroduced) - S.Diag(Loc, diag::note_partial_availability_silence) << D; + if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { + if (auto *TD = dyn_cast<TagDecl>(Enclosing)) + if (TD->getDeclName().isEmpty()) { + S.Diag(TD->getLocation(), diag::note_partial_availability_silence) + << /*Anonymous*/1 << TD->getKindName(); + return; + } + S.Diag(Enclosing->getLocation(), diag::note_partial_availability_silence) + << /*Named*/0 << Enclosing; + } } static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, @@ -7108,9 +7145,9 @@ static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, DD.Triggered = true; DoEmitAvailabilityWarning( - S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityDecl(), - DD.getAvailabilityMessage(), DD.Loc, DD.getUnknownObjCClass(), - DD.getObjCProperty(), false); + S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(), + DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), DD.Loc, + DD.getUnknownObjCClass(), DD.getObjCProperty(), false); } void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { @@ -7169,22 +7206,25 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) { } void Sema::EmitAvailabilityWarning(AvailabilityResult AR, - NamedDecl *D, StringRef Message, - SourceLocation Loc, + const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, + StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCProperty, + const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { // Delay if we're currently parsing a declaration. if (DelayedDiagnostics.shouldDelayDiagnostics()) { - DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability( - AR, Loc, D, UnknownObjCClass, ObjCProperty, Message, - ObjCPropertyAccess)); + DelayedDiagnostics.add( + DelayedDiagnostic::makeAvailability( + AR, Loc, ReferringDecl, OffendingDecl, UnknownObjCClass, + ObjCProperty, Message, ObjCPropertyAccess)); return; } Decl *Ctx = cast<Decl>(getCurLexicalContext()); - DoEmitAvailabilityWarning(*this, AR, Ctx, D, Message, Loc, UnknownObjCClass, - ObjCProperty, ObjCPropertyAccess); + DoEmitAvailabilityWarning(*this, AR, Ctx, ReferringDecl, OffendingDecl, + Message, Loc, UnknownObjCClass, ObjCProperty, + ObjCPropertyAccess); } namespace { @@ -7336,19 +7376,21 @@ public: void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( NamedDecl *D, SourceRange Range) { - - VersionTuple ContextVersion = AvailabilityStack.back(); - if (AvailabilityResult Result = - SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr)) { + AvailabilityResult Result; + const NamedDecl *OffendingDecl; + std::tie(Result, OffendingDecl) = + SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr); + if (Result != AR_Available) { // All other diagnostic kinds have already been handled in // DiagnoseAvailabilityOfDecl. if (Result != AR_NotYetIntroduced) return; - const AvailabilityAttr *AA = getAttrForPlatform(SemaRef.getASTContext(), D); + const AvailabilityAttr *AA = + getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl); VersionTuple Introduced = AA->getIntroduced(); - if (ContextVersion >= Introduced) + if (AvailabilityStack.back() >= Introduced) return; // If the context of this function is less available than D, we should not @@ -7373,8 +7415,9 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( SemaRef.getASTContext().getTargetInfo().getPlatformName()) << Introduced.getAsString(); - SemaRef.Diag(D->getLocation(), diag::note_availability_specified_here) - << D << /* partial */ 3; + SemaRef.Diag(OffendingDecl->getLocation(), + diag::note_availability_specified_here) + << OffendingDecl << /* partial */ 3; auto FixitDiag = SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 2c8080dbf02b..778b8062f68c 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -458,7 +458,10 @@ static void diagnoseUseOfProtocols(Sema &TheSema, // Diagnose availability in the context of the ObjC container. Sema::ContextRAII SavedContext(TheSema, CD); for (unsigned i = 0; i < NumProtoRefs; ++i) { - (void)TheSema.DiagnoseUseOfDecl(ProtoRefs[i], ProtoLocs[i]); + (void)TheSema.DiagnoseUseOfDecl(ProtoRefs[i], ProtoLocs[i], + /*UnknownObjCClass=*/nullptr, + /*ObjCPropertyAccess=*/false, + /*AvoidPartialAvailabilityChecks=*/true); } } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index f49df6b3216d..8016bf99889f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -87,24 +87,9 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { } } -static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) { - const auto *OMD = dyn_cast<ObjCMethodDecl>(D); - if (!OMD) - return false; - const ObjCInterfaceDecl *OID = OMD->getClassInterface(); - if (!OID) - return false; - - for (const ObjCCategoryDecl *Cat : OID->visible_categories()) - if (ObjCMethodDecl *CatMeth = - Cat->getMethod(OMD->getSelector(), OMD->isInstanceMethod())) - if (!CatMeth->hasAttr<AvailabilityAttr>()) - return true; - return false; -} - -AvailabilityResult -Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) { +std::pair<AvailabilityResult, const NamedDecl *> +Sema::ShouldDiagnoseAvailabilityOfDecl(const NamedDecl *D, + std::string *Message) { AvailabilityResult Result = D->getAvailability(Message); // For typedefs, if the typedef declaration appears available look @@ -121,78 +106,61 @@ Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) { } // Forward class declarations get their attributes from their definition. - if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { + if (const ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { if (IDecl->getDefinition()) { D = IDecl->getDefinition(); Result = D->getAvailability(Message); } } - if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) + if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) if (Result == AR_Available) { const DeclContext *DC = ECD->getDeclContext(); - if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC)) + if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) { Result = TheEnumDecl->getAvailability(Message); + D = TheEnumDecl; + } } - if (Result == AR_NotYetIntroduced) { - // Don't do this for enums, they can't be redeclared. - if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D)) - return AR_Available; - - bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited(); - // Objective-C method declarations in categories are not modelled as - // redeclarations, so manually look for a redeclaration in a category - // if necessary. - if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D)) - Warn = false; - // In general, D will point to the most recent redeclaration. However, - // for `@class A;` decls, this isn't true -- manually go through the - // redecl chain in that case. - if (Warn && isa<ObjCInterfaceDecl>(D)) - for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; - Redecl = Redecl->getPreviousDecl()) - if (!Redecl->hasAttr<AvailabilityAttr>() || - Redecl->getAttr<AvailabilityAttr>()->isInherited()) - Warn = false; - - return Warn ? AR_NotYetIntroduced : AR_Available; - } - - return Result; + return {Result, D}; } static void DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, - bool ObjCPropertyAccess) { + bool ObjCPropertyAccess, + bool AvoidPartialAvailabilityChecks = false) { std::string Message; + AvailabilityResult Result; + const NamedDecl* OffendingDecl; // See if this declaration is unavailable, deprecated, or partial. - if (AvailabilityResult Result = - S.ShouldDiagnoseAvailabilityOfDecl(D, &Message)) { + std::tie(Result, OffendingDecl) = S.ShouldDiagnoseAvailabilityOfDecl(D, &Message); + if (Result == AR_Available) + return; - if (Result == AR_NotYetIntroduced) { - if (S.getCurFunctionOrMethodDecl()) { - S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true; - return; - } else if (S.getCurBlock() || S.getCurLambda()) { - S.getCurFunction()->HasPotentialAvailabilityViolations = true; - return; - } + if (Result == AR_NotYetIntroduced) { + if (AvoidPartialAvailabilityChecks) + return; + if (S.getCurFunctionOrMethodDecl()) { + S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true; + return; + } else if (S.getCurBlock() || S.getCurLambda()) { + S.getCurFunction()->HasPotentialAvailabilityViolations = true; + return; } + } - const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { - AvailabilityResult PDeclResult = PD->getAvailability(nullptr); - if (PDeclResult == Result) - ObjCPDecl = PD; - } + const ObjCPropertyDecl *ObjCPDecl = nullptr; + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { + AvailabilityResult PDeclResult = PD->getAvailability(nullptr); + if (PDeclResult == Result) + ObjCPDecl = PD; } - - S.EmitAvailabilityWarning(Result, D, Message, Loc, UnknownObjCClass, - ObjCPDecl, ObjCPropertyAccess); } + + S.EmitAvailabilityWarning(Result, D, OffendingDecl, Message, Loc, + UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess); } /// \brief Emit a note explaining that this function is deleted. @@ -310,7 +278,8 @@ void Sema::MaybeSuggestAddingStaticToDecl(const FunctionDecl *Cur) { /// bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, - bool ObjCPropertyAccess) { + bool ObjCPropertyAccess, + bool AvoidPartialAvailabilityChecks) { if (getLangOpts().CPlusPlus && isa<FunctionDecl>(D)) { // If there were any diagnostics suppressed by template argument deduction, // emit them now. @@ -395,7 +364,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, } DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, - ObjCPropertyAccess); + ObjCPropertyAccess, + AvoidPartialAvailabilityChecks); DiagnoseUnusedOfDecl(*this, D, Loc); @@ -14695,24 +14665,24 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, ME->performsVirtualDispatch(SemaRef.getLangOpts()); if (!IsVirtualCall) return; - const Expr *Base = ME->getBase(); - const CXXRecordDecl *MostDerivedClassDecl = Base->getBestDynamicClassType(); - if (!MostDerivedClassDecl) - return; - CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl); - if (!DM || DM->isPure()) - return; - SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); + + // If it's possible to devirtualize the call, mark the called function + // referenced. + CXXMethodDecl *DM = MD->getDevirtualizedMethod( + ME->getBase(), SemaRef.getLangOpts().AppleKext); + if (DM) + SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); } /// \brief Perform reference-marking and odr-use handling for a DeclRefExpr. -void Sema::MarkDeclRefReferenced(DeclRefExpr *E) { +void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { // TODO: update this with DR# once a defect report is filed. // C++11 defect. The address of a pure member should not be an ODR use, even // if it's a qualified reference. bool OdrUse = true; - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl())) - if (Method->isVirtual()) + if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getDecl())) + if (Method->isVirtual() && + !Method->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) OdrUse = false; MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse); } diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index b18de7e94686..c3d0e2db76b6 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -1842,10 +1842,6 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, FoundDecl, Field); if (Base.isInvalid()) return ExprError(); - MemberExpr *ME = - BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS, - /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, - MemberNameInfo, MemberType, VK, OK); // Build a reference to a private copy for non-static data members in // non-static member functions, privatized by OpenMP constructs. @@ -1855,7 +1851,10 @@ Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field)) return getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc); } - return ME; + + return BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS, + /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, + MemberNameInfo, MemberType, VK, OK); } /// Builds an implicit member access expression. The current context diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index d6b70610d461..46f2ba376006 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -1595,7 +1595,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, ContainsUnexpandedParameterPack); // If the lambda expression's call operator is not explicitly marked constexpr // and we are not in a dependent context, analyze the call operator to infer - // its constexpr-ness, supressing diagnostics while doing so. + // its constexpr-ness, suppressing diagnostics while doing so. if (getLangOpts().CPlusPlus1z && !CallOperator->isInvalidDecl() && !CallOperator->isConstexpr() && !isa<CoroutineBodyStmt>(CallOperator->getBody()) && diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index 2e7fb875a276..85596ed52e9d 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -1395,6 +1395,20 @@ bool Sema::hasVisibleMergedDefinition(NamedDecl *Def) { return false; } +bool Sema::hasMergedDefinitionInCurrentModule(NamedDecl *Def) { + // FIXME: When not in local visibility mode, we can't tell the difference + // between a declaration being visible because we merged a local copy of + // the same declaration into it, and it being visible because its owning + // module is visible. + if (Def->getModuleOwnershipKind() == Decl::ModuleOwnershipKind::Visible && + getLangOpts().ModulesLocalVisibility) + return true; + for (Module *Merged : Context.getModulesWithMergedDefinition(Def)) + if (Merged->getTopLevelModuleName() == getLangOpts().CurrentModule) + return true; + return false; +} + template<typename ParmDecl> static bool hasVisibleDefaultArgument(Sema &S, const ParmDecl *D, @@ -1495,23 +1509,40 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { assert(D->isHidden() && "should not call this: not in slow case"); Module *DeclModule = SemaRef.getOwningModule(D); - assert(DeclModule && "hidden decl not from a module"); - - // If the owning module is visible, and the decl is not module private, - // then the decl is visible too. (Module private is ignored within the same - // top-level module.) - // FIXME: Check the owning module for module-private declarations rather than - // assuming "same AST file" is the same thing as "same module". - if ((!D->isFromASTFile() || !D->isModulePrivate()) && - (SemaRef.isModuleVisible(DeclModule) || - SemaRef.hasVisibleMergedDefinition(D))) - return true; + if (!DeclModule) { + // A module-private declaration with no owning module means this is in the + // global module in the C++ Modules TS. This is visible within the same + // translation unit only. + // FIXME: Don't assume that "same translation unit" means the same thing + // as "not from an AST file". + assert(D->isModulePrivate() && "hidden decl has no module"); + if (!D->isFromASTFile() || SemaRef.hasMergedDefinitionInCurrentModule(D)) + return true; + } else { + // If the owning module is visible, and the decl is not module private, + // then the decl is visible too. (Module private is ignored within the same + // top-level module.) + if (D->isModulePrivate() + ? DeclModule->getTopLevelModuleName() == + SemaRef.getLangOpts().CurrentModule || + SemaRef.hasMergedDefinitionInCurrentModule(D) + : SemaRef.isModuleVisible(DeclModule) || + SemaRef.hasVisibleMergedDefinition(D)) + return true; + } + + // Determine whether a decl context is a file context for the purpose of + // visibility. This looks through some (export and linkage spec) transparent + // contexts, but not others (enums). + auto IsEffectivelyFileContext = [](const DeclContext *DC) { + return DC->isFileContext() || isa<LinkageSpecDecl>(DC) || + isa<ExportDecl>(DC); + }; - // If this declaration is not at namespace scope nor module-private, + // If this declaration is not at namespace scope // then it is visible if its lexical parent has a visible definition. DeclContext *DC = D->getLexicalDeclContext(); - if (!D->isModulePrivate() && DC && !DC->isFileContext() && - !isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC)) { + if (DC && !IsEffectivelyFileContext(DC)) { // For a parameter, check whether our current template declaration's // lexical context is visible, not whether there's some other visible // definition of it, because parameters aren't "within" the definition. @@ -1519,32 +1550,45 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { // In C++ we need to check for a visible definition due to ODR merging, // and in C we must not because each declaration of a function gets its own // set of declarations for tags in prototype scope. - if ((D->isTemplateParameter() || isa<ParmVarDecl>(D) - || (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) - ? isVisible(SemaRef, cast<NamedDecl>(DC)) - : SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC))) { - if (SemaRef.CodeSynthesisContexts.empty() && - // FIXME: Do something better in this case. - !SemaRef.getLangOpts().ModulesLocalVisibility) { - // Cache the fact that this declaration is implicitly visible because - // its parent has a visible definition. - D->setVisibleDespiteOwningModule(); - } - return true; + bool VisibleWithinParent; + if (D->isTemplateParameter() || isa<ParmVarDecl>(D) || + (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) + VisibleWithinParent = isVisible(SemaRef, cast<NamedDecl>(DC)); + else if (D->isModulePrivate()) { + // A module-private declaration is only visible if an enclosing lexical + // parent was merged with another definition in the current module. + VisibleWithinParent = false; + do { + if (SemaRef.hasMergedDefinitionInCurrentModule(cast<NamedDecl>(DC))) { + VisibleWithinParent = true; + break; + } + DC = DC->getLexicalParent(); + } while (!IsEffectivelyFileContext(DC)); + } else { + VisibleWithinParent = SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC)); } - return false; + + if (VisibleWithinParent && SemaRef.CodeSynthesisContexts.empty() && + // FIXME: Do something better in this case. + !SemaRef.getLangOpts().ModulesLocalVisibility) { + // Cache the fact that this declaration is implicitly visible because + // its parent has a visible definition. + D->setVisibleDespiteOwningModule(); + } + return VisibleWithinParent; } + // FIXME: All uses of DeclModule below this point should also check merged + // modules. + if (!DeclModule) + return false; + // Find the extra places where we need to look. llvm::DenseSet<Module*> &LookupModules = SemaRef.getLookupModules(); if (LookupModules.empty()) return false; - if (!DeclModule) { - DeclModule = SemaRef.getOwningModule(D); - assert(DeclModule && "hidden decl not from a module"); - } - // If our lookup set contains the decl's module, it's visible. if (LookupModules.count(DeclModule)) return true; diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 6c5716454874..62a771bcffa0 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -1676,8 +1676,9 @@ static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl, /// \brief Default synthesizes all properties which must be synthesized /// in class's \@implementation. -void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, - ObjCInterfaceDecl *IDecl) { +void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, + ObjCInterfaceDecl *IDecl, + SourceLocation AtEnd) { ObjCInterfaceDecl::PropertyMap PropMap; ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder; IDecl->collectPropertiesToImplement(PropMap, PropertyOrder); @@ -1725,6 +1726,10 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, diag::warn_auto_synthesizing_protocol_property) << Prop << Proto; Diag(Prop->getLocation(), diag::note_property_declare); + std::string FixIt = + (Twine("@synthesize ") + Prop->getName() + ";\n\n").str(); + Diag(AtEnd, diag::note_add_synthesize_directive) + << FixItHint::CreateInsertion(AtEnd, FixIt); } continue; } @@ -1764,7 +1769,8 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, } } -void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { +void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D, + SourceLocation AtEnd) { if (!LangOpts.ObjCDefaultSynthProperties || LangOpts.ObjCRuntime.isFragile()) return; ObjCImplementationDecl *IC=dyn_cast_or_null<ObjCImplementationDecl>(D); @@ -1772,7 +1778,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { return; if (ObjCInterfaceDecl* IDecl = IC->getClassInterface()) if (!IDecl->isObjCRequiresPropertyDefs()) - DefaultSynthesizeProperties(S, IC, IDecl); + DefaultSynthesizeProperties(S, IC, IDecl, AtEnd); } static void DiagnoseUnimplementedAccessor( diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 49da0e499771..1e0b6c158348 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -6106,6 +6106,33 @@ static bool checkGrainsizeNumTasksClauses(Sema &S, return ErrorFound; } +static bool checkReductionClauseWithNogroup(Sema &S, + ArrayRef<OMPClause *> Clauses) { + OMPClause *ReductionClause = nullptr; + OMPClause *NogroupClause = nullptr; + for (auto *C : Clauses) { + if (C->getClauseKind() == OMPC_reduction) { + ReductionClause = C; + if (NogroupClause) + break; + continue; + } + if (C->getClauseKind() == OMPC_nogroup) { + NogroupClause = C; + if (ReductionClause) + break; + continue; + } + } + if (ReductionClause && NogroupClause) { + S.Diag(ReductionClause->getLocStart(), diag::err_omp_reduction_with_nogroup) + << SourceRange(NogroupClause->getLocStart(), + NogroupClause->getLocEnd()); + return true; + } + return false; +} + StmtResult Sema::ActOnOpenMPTaskLoopDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, @@ -6132,6 +6159,11 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective( // not appear on the same taskloop directive. if (checkGrainsizeNumTasksClauses(*this, Clauses)) return StmtError(); + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // If a reduction clause is present on the taskloop directive, the nogroup + // clause must not be specified. + if (checkReductionClauseWithNogroup(*this, Clauses)) + return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc, @@ -6175,6 +6207,11 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( // not appear on the same taskloop directive. if (checkGrainsizeNumTasksClauses(*this, Clauses)) return StmtError(); + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // If a reduction clause is present on the taskloop directive, the nogroup + // clause must not be specified. + if (checkReductionClauseWithNogroup(*this, Clauses)) + return StmtError(); getCurFunction()->setHasBranchProtectedScope(); return OMPTaskLoopSimdDirective::Create(Context, StartLoc, EndLoc, @@ -9399,6 +9436,12 @@ OMPClause *Sema::ActOnOpenMPReductionClause( SimpleRefExpr, RefRes.get()); if (!PostUpdateRes.isUsable()) continue; + if (isOpenMPTaskingDirective(DSAStack->getCurrentDirective())) { + Diag(RefExpr->getExprLoc(), + diag::err_omp_reduction_non_addressable_expression) + << RefExpr->getSourceRange(); + continue; + } ExprPostUpdates.push_back( IgnoredValueConversions(PostUpdateRes.get()).get()); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 5cc13f391d11..36f24fd9c463 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -48,7 +48,7 @@ static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) { /// A convenience routine for creating a decayed reference to a function. static ExprResult CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, - bool HadMultipleCandidates, + const Expr *Base, bool HadMultipleCandidates, SourceLocation Loc = SourceLocation(), const DeclarationNameLoc &LocInfo = DeclarationNameLoc()){ if (S.DiagnoseUseOfDecl(FoundDecl, Loc)) @@ -68,7 +68,7 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, if (HadMultipleCandidates) DRE->setHadMultipleCandidates(true); - S.MarkDeclRefReferenced(DRE); + S.MarkDeclRefReferenced(DRE, Base); return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()), CK_FunctionToPointerDecay); } @@ -9830,6 +9830,15 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, return; } + // We found a specific requirement that disabled the enable_if. + if (PDiag && PDiag->second.getDiagID() == + diag::err_typename_nested_not_found_requirement) { + S.Diag(Templated->getLocation(), + diag::note_ovl_candidate_disabled_by_requirement) + << PDiag->second.getStringArg(0) << TemplateArgString; + return; + } + // Format the SFINAE diagnostic into the argument string. // FIXME: Add a general mechanism to include a PartialDiagnostic *'s // formatted message in another diagnostic. @@ -11937,6 +11946,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, FunctionDecl *FnDecl = Best->Function; if (FnDecl) { + Expr *Base = nullptr; // We matched an overloaded operator. Build a call to that // operator. @@ -11949,7 +11959,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, Best->FoundDecl, Method); if (InputRes.isInvalid()) return ExprError(); - Input = InputRes.get(); + Base = Input = InputRes.get(); } else { // Convert the arguments. ExprResult InputInit @@ -11965,7 +11975,8 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, // Build the actual expression node. ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, Best->FoundDecl, - HadMultipleCandidates, OpLoc); + Base, HadMultipleCandidates, + OpLoc); if (FnExpr.isInvalid()) return ExprError(); @@ -12150,6 +12161,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, FunctionDecl *FnDecl = Best->Function; if (FnDecl) { + Expr *Base = nullptr; // We matched an overloaded operator. Build a call to that // operator. @@ -12171,7 +12183,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Best->FoundDecl, Method); if (Arg0.isInvalid()) return ExprError(); - Args[0] = Arg0.getAs<Expr>(); + Base = Args[0] = Arg0.getAs<Expr>(); Args[1] = RHS = Arg1.getAs<Expr>(); } else { // Convert the arguments. @@ -12195,7 +12207,7 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // Build the actual expression node. ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, - Best->FoundDecl, + Best->FoundDecl, Base, HadMultipleCandidates, OpLoc); if (FnExpr.isInvalid()) return ExprError(); @@ -12417,6 +12429,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, OpLocInfo.setCXXOperatorNameRange(SourceRange(LLoc, RLoc)); ExprResult FnExpr = CreateFunctionRefExpr(*this, FnDecl, Best->FoundDecl, + Base, HadMultipleCandidates, OpLocInfo.getLoc(), OpLocInfo.getInfo()); @@ -12975,7 +12988,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, Context.DeclarationNames.getCXXOperatorName(OO_Call), LParenLoc); OpLocInfo.setCXXOperatorNameRange(SourceRange(LParenLoc, RParenLoc)); ExprResult NewFn = CreateFunctionRefExpr(*this, Method, Best->FoundDecl, - HadMultipleCandidates, + Obj, HadMultipleCandidates, OpLocInfo.getLoc(), OpLocInfo.getInfo()); if (NewFn.isInvalid()) @@ -13166,7 +13179,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, // Build the operator call. ExprResult FnExpr = CreateFunctionRefExpr(*this, Method, Best->FoundDecl, - HadMultipleCandidates, OpLoc); + Base, HadMultipleCandidates, OpLoc); if (FnExpr.isInvalid()) return ExprError(); @@ -13225,7 +13238,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, FunctionDecl *FD = Best->Function; ExprResult Fn = CreateFunctionRefExpr(*this, FD, Best->FoundDecl, - HadMultipleCandidates, + nullptr, HadMultipleCandidates, SuffixInfo.getLoc(), SuffixInfo.getInfo()); if (Fn.isInvalid()) diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index b6b429d1f25c..d159172a6990 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -1176,8 +1176,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { AtIndexGetter = S.LookupMethodInObjectType(AtIndexGetterSelector, ResultType, true /*instance*/); - bool receiverIdType = (BaseT->isObjCIdType() || - BaseT->isObjCQualifiedIdType()); if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) { AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(), @@ -1203,7 +1201,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { } if (!AtIndexGetter) { - if (!receiverIdType) { + if (!BaseT->isObjCIdType()) { S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_method_not_found) << BaseExpr->getType() << 0 << arrayRef; return false; @@ -1284,9 +1282,6 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { } AtIndexSetter = S.LookupMethodInObjectType(AtIndexSetterSelector, ResultType, true /*instance*/); - - bool receiverIdType = (BaseT->isObjCIdType() || - BaseT->isObjCQualifiedIdType()); if (!AtIndexSetter && S.getLangOpts().DebuggerObjCLiteral) { TypeSourceInfo *ReturnTInfo = nullptr; @@ -1321,7 +1316,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { } if (!AtIndexSetter) { - if (!receiverIdType) { + if (!BaseT->isObjCIdType()) { S.Diag(BaseExpr->getExprLoc(), diag::err_objc_subscript_method_not_found) << BaseExpr->getType() << 1 << arrayRef; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index eed10b077eb8..2a38a1f8e1d8 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -1544,23 +1544,78 @@ namespace { // A visitor to determine if a continue or break statement is a // subexpression. - class BreakContinueFinder : public EvaluatedExprVisitor<BreakContinueFinder> { + class BreakContinueFinder : public ConstEvaluatedExprVisitor<BreakContinueFinder> { SourceLocation BreakLoc; SourceLocation ContinueLoc; + bool InSwitch = false; + public: - BreakContinueFinder(Sema &S, Stmt* Body) : + BreakContinueFinder(Sema &S, const Stmt* Body) : Inherited(S.Context) { Visit(Body); } - typedef EvaluatedExprVisitor<BreakContinueFinder> Inherited; + typedef ConstEvaluatedExprVisitor<BreakContinueFinder> Inherited; - void VisitContinueStmt(ContinueStmt* E) { + void VisitContinueStmt(const ContinueStmt* E) { ContinueLoc = E->getContinueLoc(); } - void VisitBreakStmt(BreakStmt* E) { - BreakLoc = E->getBreakLoc(); + void VisitBreakStmt(const BreakStmt* E) { + if (!InSwitch) + BreakLoc = E->getBreakLoc(); + } + + void VisitSwitchStmt(const SwitchStmt* S) { + if (const Stmt *Init = S->getInit()) + Visit(Init); + if (const Stmt *CondVar = S->getConditionVariableDeclStmt()) + Visit(CondVar); + if (const Stmt *Cond = S->getCond()) + Visit(Cond); + + // Don't return break statements from the body of a switch. + InSwitch = true; + if (const Stmt *Body = S->getBody()) + Visit(Body); + InSwitch = false; + } + + void VisitForStmt(const ForStmt *S) { + // Only visit the init statement of a for loop; the body + // has a different break/continue scope. + if (const Stmt *Init = S->getInit()) + Visit(Init); + } + + void VisitWhileStmt(const WhileStmt *) { + // Do nothing; the children of a while loop have a different + // break/continue scope. + } + + void VisitDoStmt(const DoStmt *) { + // Do nothing; the children of a while loop have a different + // break/continue scope. + } + + void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { + // Only visit the initialization of a for loop; the body + // has a different break/continue scope. + if (const Stmt *Range = S->getRangeStmt()) + Visit(Range); + if (const Stmt *Begin = S->getBeginStmt()) + Visit(Begin); + if (const Stmt *End = S->getEndStmt()) + Visit(End); + } + + void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { + // Only visit the initialization of a for loop; the body + // has a different break/continue scope. + if (const Stmt *Element = S->getElement()) + Visit(Element); + if (const Stmt *Collection = S->getCollection()) + Visit(Collection); } bool ContinueFound() { return ContinueLoc.isValid(); } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index a8923ce9e27d..e9b38551683c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2806,6 +2806,101 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, llvm_unreachable("unexpected BuiltinTemplateDecl!"); } +/// Determine whether this alias template is "enable_if_t". +static bool isEnableIfAliasTemplate(TypeAliasTemplateDecl *AliasTemplate) { + return AliasTemplate->getName().equals("enable_if_t"); +} + +/// Collect all of the separable terms in the given condition, which +/// might be a conjunction. +/// +/// FIXME: The right answer is to convert the logical expression into +/// disjunctive normal form, so we can find the first failed term +/// within each possible clause. +static void collectConjunctionTerms(Expr *Clause, + SmallVectorImpl<Expr *> &Terms) { + if (auto BinOp = dyn_cast<BinaryOperator>(Clause->IgnoreParenImpCasts())) { + if (BinOp->getOpcode() == BO_LAnd) { + collectConjunctionTerms(BinOp->getLHS(), Terms); + collectConjunctionTerms(BinOp->getRHS(), Terms); + } + + return; + } + + Terms.push_back(Clause); +} + +// The ranges-v3 library uses an odd pattern of a top-level "||" with +// a left-hand side that is value-dependent but never true. Identify +// the idiom and ignore that term. +static Expr *lookThroughRangesV3Condition(Preprocessor &PP, Expr *Cond) { + // Top-level '||'. + auto *BinOp = dyn_cast<BinaryOperator>(Cond->IgnoreParenImpCasts()); + if (!BinOp) return Cond; + + if (BinOp->getOpcode() != BO_LOr) return Cond; + + // With an inner '==' that has a literal on the right-hand side. + Expr *LHS = BinOp->getLHS(); + auto *InnerBinOp = dyn_cast<BinaryOperator>(LHS->IgnoreParenImpCasts()); + if (!InnerBinOp) return Cond; + + if (InnerBinOp->getOpcode() != BO_EQ || + !isa<IntegerLiteral>(InnerBinOp->getRHS())) + return Cond; + + // If the inner binary operation came from a macro expansion named + // CONCEPT_REQUIRES or CONCEPT_REQUIRES_, return the right-hand side + // of the '||', which is the real, user-provided condition. + SourceLocation Loc = InnerBinOp->getExprLoc(); + if (!Loc.isMacroID()) return Cond; + + StringRef MacroName = PP.getImmediateMacroName(Loc); + if (MacroName == "CONCEPT_REQUIRES" || MacroName == "CONCEPT_REQUIRES_") + return BinOp->getRHS(); + + return Cond; +} + +/// Find the failed subexpression within enable_if, and describe it +/// with a string. +static std::pair<Expr *, std::string> +findFailedEnableIfCondition(Sema &S, Expr *Cond) { + Cond = lookThroughRangesV3Condition(S.PP, Cond); + + // Separate out all of the terms in a conjunction. + SmallVector<Expr *, 4> Terms; + collectConjunctionTerms(Cond, Terms); + + // Determine which term failed. + Expr *FailedCond = nullptr; + for (Expr *Term : Terms) { + // The initialization of the parameter from the argument is + // a constant-evaluated context. + EnterExpressionEvaluationContext ConstantEvaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + bool Succeeded; + if (Term->EvaluateAsBooleanCondition(Succeeded, S.Context) && + !Succeeded) { + FailedCond = Term->IgnoreParenImpCasts(); + break; + } + } + + if (!FailedCond) + FailedCond = Cond->IgnoreParenImpCasts(); + + std::string Description; + { + llvm::raw_string_ostream Out(Description); + FailedCond->printPretty(Out, nullptr, + PrintingPolicy(S.Context.getLangOpts())); + } + return { FailedCond, Description }; +} + QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { @@ -2852,12 +2947,12 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, if (Pattern->isInvalidDecl()) return QualType(); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted); + TemplateArgumentList StackTemplateArgs(TemplateArgumentList::OnStack, + Converted); // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; - TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs); unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth(); for (unsigned I = 0; I < Depth; ++I) TemplateArgLists.addOuterTemplateArguments(None); @@ -2870,8 +2965,42 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, CanonType = SubstType(Pattern->getUnderlyingType(), TemplateArgLists, AliasTemplate->getLocation(), AliasTemplate->getDeclName()); - if (CanonType.isNull()) + if (CanonType.isNull()) { + // If this was enable_if and we failed to find the nested type + // within enable_if in a SFINAE context, dig out the specific + // enable_if condition that failed and present that instead. + if (isEnableIfAliasTemplate(AliasTemplate)) { + if (auto DeductionInfo = isSFINAEContext()) { + if (*DeductionInfo && + (*DeductionInfo)->hasSFINAEDiagnostic() && + (*DeductionInfo)->peekSFINAEDiagnostic().second.getDiagID() == + diag::err_typename_nested_not_found_enable_if && + TemplateArgs[0].getArgument().getKind() + == TemplateArgument::Expression) { + Expr *FailedCond; + std::string FailedDescription; + std::tie(FailedCond, FailedDescription) = + findFailedEnableIfCondition( + *this, TemplateArgs[0].getSourceExpression()); + + // Remove the old SFINAE diagnostic. + PartialDiagnosticAt OldDiag = + {SourceLocation(), PartialDiagnostic::NullDiagnostic()}; + (*DeductionInfo)->takeSFINAEDiagnostic(OldDiag); + + // Add a new SFINAE diagnostic specifying which condition + // failed. + (*DeductionInfo)->addSFINAEDiagnostic( + OldDiag.first, + PDiag(diag::err_typename_nested_not_found_requirement) + << FailedDescription + << FailedCond->getSourceRange()); + } + } + } + return QualType(); + } } else if (Name.isDependent() || TemplateSpecializationType::anyDependentTemplateArguments( TemplateArgs, InstantiationDependent)) { @@ -5190,10 +5319,16 @@ enum NullPointerValueKind { /// value of the appropriate type. static NullPointerValueKind isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, - QualType ParamType, Expr *Arg) { + QualType ParamType, Expr *Arg, + Decl *Entity = nullptr) { if (Arg->isValueDependent() || Arg->isTypeDependent()) return NPV_NotNullPointer; + // dllimport'd entities aren't constant but are available inside of template + // arguments. + if (Entity && Entity->hasAttr<DLLImportAttr>()) + return NPV_NotNullPointer; + if (!S.isCompleteType(Arg->getExprLoc(), ParamType)) llvm_unreachable( "Incomplete parameter type in isNullPointerValueTemplateArgument!"); @@ -5437,14 +5572,8 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, // If our parameter has pointer type, check for a null template value. if (ParamType->isPointerType() || ParamType->isNullPtrType()) { - NullPointerValueKind NPV; - // dllimport'd entities aren't constant but are available inside of template - // arguments. - if (Entity && Entity->hasAttr<DLLImportAttr>()) - NPV = NPV_NotNullPointer; - else - NPV = isNullPointerValueTemplateArgument(S, Param, ParamType, ArgIn); - switch (NPV) { + switch (isNullPointerValueTemplateArgument(S, Param, ParamType, ArgIn, + Entity)) { case NPV_NullPointer: S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), @@ -5636,39 +5765,8 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, TemplateArgument &Converted) { bool Invalid = false; - // Check for a null pointer value. Expr *Arg = ResultArg; - switch (isNullPointerValueTemplateArgument(S, Param, ParamType, Arg)) { - case NPV_Error: - return true; - case NPV_NullPointer: - S.Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); - Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), - /*isNullPtr*/true); - return false; - case NPV_NotNullPointer: - break; - } - bool ObjCLifetimeConversion; - if (S.IsQualificationConversion(Arg->getType(), - ParamType.getNonReferenceType(), - false, ObjCLifetimeConversion)) { - Arg = S.ImpCastExprToType(Arg, ParamType, CK_NoOp, - Arg->getValueKind()).get(); - ResultArg = Arg; - } else if (!S.Context.hasSameUnqualifiedType(Arg->getType(), - ParamType.getNonReferenceType())) { - // We can't perform this conversion. - S.Diag(Arg->getLocStart(), diag::err_template_arg_not_convertible) - << Arg->getType() << ParamType << Arg->getSourceRange(); - S.Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } - - // See through any implicit casts we added to fix the type. - while (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(Arg)) - Arg = Cast->getSubExpr(); // C++ [temp.arg.nontype]p1: // @@ -5725,6 +5823,37 @@ static bool CheckTemplateArgumentPointerToMember(Sema &S, DRE = nullptr; } + ValueDecl *Entity = DRE ? DRE->getDecl() : nullptr; + + // Check for a null pointer value. + switch (isNullPointerValueTemplateArgument(S, Param, ParamType, ResultArg, + Entity)) { + case NPV_Error: + return true; + case NPV_NullPointer: + S.Diag(ResultArg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); + Converted = TemplateArgument(S.Context.getCanonicalType(ParamType), + /*isNullPtr*/true); + return false; + case NPV_NotNullPointer: + break; + } + + if (S.IsQualificationConversion(ResultArg->getType(), + ParamType.getNonReferenceType(), false, + ObjCLifetimeConversion)) { + ResultArg = S.ImpCastExprToType(ResultArg, ParamType, CK_NoOp, + ResultArg->getValueKind()) + .get(); + } else if (!S.Context.hasSameUnqualifiedType( + ResultArg->getType(), ParamType.getNonReferenceType())) { + // We can't perform this conversion. + S.Diag(ResultArg->getLocStart(), diag::err_template_arg_not_convertible) + << ResultArg->getType() << ParamType << ResultArg->getSourceRange(); + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } + if (!DRE) return S.Diag(Arg->getLocStart(), diag::err_template_arg_not_pointer_to_member_form) @@ -9290,7 +9419,7 @@ Sema::ActOnTypenameType(Scope *S, /// Determine whether this failed name lookup should be treated as being /// disabled by a usage of std::enable_if. static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, - SourceRange &CondRange) { + SourceRange &CondRange, Expr *&Cond) { // We must be looking for a ::type... if (!II.isStr("type")) return false; @@ -9320,6 +9449,19 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, // Assume the first template argument is the condition. CondRange = EnableIfTSTLoc.getArgLoc(0).getSourceRange(); + + // Dig out the condition. + Cond = nullptr; + if (EnableIfTSTLoc.getArgLoc(0).getArgument().getKind() + != TemplateArgument::Expression) + return true; + + Cond = EnableIfTSTLoc.getArgLoc(0).getSourceExpression(); + + // Ignore Boolean literals; they add no value. + if (isa<CXXBoolLiteralExpr>(Cond->IgnoreParenCasts())) + Cond = nullptr; + return true; } @@ -9363,9 +9505,25 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // If we're looking up 'type' within a template named 'enable_if', produce // a more specific diagnostic. SourceRange CondRange; - if (isEnableIf(QualifierLoc, II, CondRange)) { + Expr *Cond = nullptr; + if (isEnableIf(QualifierLoc, II, CondRange, Cond)) { + // If we have a condition, narrow it down to the specific failed + // condition. + if (Cond) { + Expr *FailedCond; + std::string FailedDescription; + std::tie(FailedCond, FailedDescription) = + findFailedEnableIfCondition(*this, Cond); + + Diag(FailedCond->getExprLoc(), + diag::err_typename_nested_not_found_requirement) + << FailedDescription + << FailedCond->getSourceRange(); + return QualType(); + } + Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if) - << Ctx << CondRange; + << Ctx << CondRange; return QualType(); } diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 3aee3c04001d..678ecfc9a3d9 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -9314,6 +9314,7 @@ void ASTReader::diagnoseOdrViolations() { TypeAlias, TypeDef, Var, + Friend, Other } FirstDiffType = Other, SecondDiffType = Other; @@ -9347,6 +9348,8 @@ void ASTReader::diagnoseOdrViolations() { return TypeDef; case Decl::Var: return Var; + case Decl::Friend: + return Friend; } }; @@ -9463,6 +9466,9 @@ void ASTReader::diagnoseOdrViolations() { VarSingleInitializer, VarDifferentInitializer, VarConstexpr, + FriendTypeFunction, + FriendType, + FriendFunction, }; // These lambdas have the common portions of the ODR diagnostics. This @@ -9973,6 +9979,53 @@ void ASTReader::diagnoseOdrViolations() { } break; } + case Friend: { + FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl); + FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl); + + NamedDecl *FirstND = FirstFriend->getFriendDecl(); + NamedDecl *SecondND = SecondFriend->getFriendDecl(); + + TypeSourceInfo *FirstTSI = FirstFriend->getFriendType(); + TypeSourceInfo *SecondTSI = SecondFriend->getFriendType(); + + if (FirstND && SecondND) { + ODRDiagError(FirstFriend->getFriendLoc(), + FirstFriend->getSourceRange(), FriendFunction) + << FirstND; + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendFunction) + << SecondND; + + Diagnosed = true; + break; + } + + if (FirstTSI && SecondTSI) { + QualType FirstFriendType = FirstTSI->getType(); + QualType SecondFriendType = SecondTSI->getType(); + assert(ComputeQualTypeODRHash(FirstFriendType) != + ComputeQualTypeODRHash(SecondFriendType)); + ODRDiagError(FirstFriend->getFriendLoc(), + FirstFriend->getSourceRange(), FriendType) + << FirstFriendType; + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendType) + << SecondFriendType; + Diagnosed = true; + break; + } + + ODRDiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(), + FriendTypeFunction) + << (FirstTSI == nullptr); + ODRDiagNote(SecondFriend->getFriendLoc(), + SecondFriend->getSourceRange(), FriendTypeFunction) + << (SecondTSI == nullptr); + + Diagnosed = true; + break; + } } if (Diagnosed == true) diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 4d9ddd2ff506..abed2586561a 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -573,6 +573,8 @@ void ASTDeclReader::VisitDecl(Decl *D) { else Reader.HiddenNamesMap[Owner].push_back(D); } + } else if (ModulePrivate) { + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::ModulePrivate); } } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index c6129d326cb6..f7a49e41009d 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -1462,7 +1462,7 @@ void ASTWriter::WriteControlBlock(Preprocessor &PP, ASTContext &Context, } // Module map file - if (WritingModule) { + if (WritingModule && WritingModule->Kind == Module::ModuleMapModule) { Record.clear(); auto &Map = PP.getHeaderSearchInfo().getModuleMap(); diff --git a/lib/Serialization/ASTWriterDecl.cpp b/lib/Serialization/ASTWriterDecl.cpp index 2d648cb103cb..ec21ca2276c1 100644 --- a/lib/Serialization/ASTWriterDecl.cpp +++ b/lib/Serialization/ASTWriterDecl.cpp @@ -2233,8 +2233,18 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) { Writer->ClearSwitchCaseIDs(); assert(FD->doesThisDeclarationHaveABody()); - bool ModulesCodegen = Writer->Context->getLangOpts().ModulesCodegen && - Writer->WritingModule && !FD->isDependentContext(); + bool ModulesCodegen = false; + if (Writer->WritingModule && !FD->isDependentContext()) { + // Under -fmodules-codegen, codegen is performed for all defined functions. + // When building a C++ Modules TS module interface unit, a strong definition + // in the module interface is provided by the compilation of that module + // interface unit, not by its users. (Inline functions are still emitted + // in module users.) + ModulesCodegen = + Writer->Context->getLangOpts().ModulesCodegen || + (Writer->WritingModule->Kind == Module::ModuleInterfaceUnit && + Writer->Context->GetGVALinkageForFunction(FD) == GVA_StrongExternal); + } Record->push_back(ModulesCodegen); if (ModulesCodegen) Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(FD)); diff --git a/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/lib/StaticAnalyzer/Core/AnalysisManager.cpp index 54634fdffeb5..83e67662e614 100644 --- a/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -23,9 +23,10 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags, AnalyzerOptions &Options, CodeInjector *injector) : AnaCtxMgr(Options.UnoptimizedCFG, - /*AddImplicitDtors=*/true, + Options.includeImplicitDtorsInCFG(), /*AddInitializers=*/true, Options.includeTemporaryDtorsInCFG(), + Options.includeLifetimeInCFG(), Options.shouldSynthesizeBodies(), Options.shouldConditionalizeStaticInitializers(), /*addCXXNewAllocator=*/true, diff --git a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp index 11b9f8c4f725..6f48fcb9e20c 100644 --- a/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp +++ b/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp @@ -172,6 +172,17 @@ bool AnalyzerOptions::includeTemporaryDtorsInCFG() { /* Default = */ false); } +bool AnalyzerOptions::includeImplicitDtorsInCFG() { + return getBooleanOption(IncludeImplicitDtorsInCFG, + "cfg-implicit-dtors", + /* Default = */ true); +} + +bool AnalyzerOptions::includeLifetimeInCFG() { + return getBooleanOption(IncludeLifetimeInCFG, "cfg-lifetime", + /* Default = */ false); +} + bool AnalyzerOptions::mayInlineCXXStandardLibrary() { return getBooleanOption(InlineCXXStandardLibrary, "c++-stdlib-inlining", diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index f84c0ee800a3..eee5400fe177 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -362,6 +362,8 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred, case CFGElement::TemporaryDtor: ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred); return; + case CFGElement::LifetimeEnds: + return; } } diff --git a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp index 6aa6da560e60..d91786f74919 100644 --- a/lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ b/lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -578,6 +578,7 @@ getLocationForCaller(const StackFrameContext *SFC, } case CFGElement::TemporaryDtor: case CFGElement::NewAllocator: + case CFGElement::LifetimeEnds: llvm_unreachable("not yet implemented!"); } diff --git a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp index 9c28457b2139..f09f9696f5ad 100644 --- a/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp +++ b/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp @@ -71,18 +71,15 @@ SVal SimpleSValBuilder::dispatchCast(SVal Val, QualType CastTy) { } SVal SimpleSValBuilder::evalCastFromNonLoc(NonLoc val, QualType castTy) { - bool isLocType = Loc::isLocType(castTy); - if (val.getAs<nonloc::PointerToMember>()) return val; if (Optional<nonloc::LocAsInteger> LI = val.getAs<nonloc::LocAsInteger>()) { if (isLocType) return LI->getLoc(); - // FIXME: Correctly support promotions/truncations. - unsigned castSize = Context.getTypeSize(castTy); + unsigned castSize = Context.getIntWidth(castTy); if (castSize == LI->getNumBits()) return val; return makeLocAsInteger(LI->getLoc(), castSize); @@ -173,7 +170,7 @@ SVal SimpleSValBuilder::evalCastFromLoc(Loc val, QualType castTy) { } if (castTy->isIntegralOrEnumerationType()) { - unsigned BitWidth = Context.getTypeSize(castTy); + unsigned BitWidth = Context.getIntWidth(castTy); if (!val.getAs<loc::ConcreteInt>()) return makeLocAsInteger(val, BitWidth); diff --git a/lib/Tooling/ArgumentsAdjusters.cpp b/lib/Tooling/ArgumentsAdjusters.cpp index 48b925c698a7..ac9fd3c5cade 100644 --- a/lib/Tooling/ArgumentsAdjusters.cpp +++ b/lib/Tooling/ArgumentsAdjusters.cpp @@ -42,7 +42,7 @@ ArgumentsAdjuster getClangStripOutputAdjuster() { AdjustedArgs.push_back(Args[i]); if (Arg == "-o") { - // Output is specified as -o foo. Skip the next argument also. + // Output is specified as -o foo. Skip the next argument too. ++i; } // Else, the output is specified as -ofoo. Just do nothing. @@ -51,6 +51,26 @@ ArgumentsAdjuster getClangStripOutputAdjuster() { }; } +ArgumentsAdjuster getClangStripDependencyFileAdjuster() { + return [](const CommandLineArguments &Args, StringRef /*unused*/) { + CommandLineArguments AdjustedArgs; + for (size_t i = 0, e = Args.size(); i < e; ++i) { + StringRef Arg = Args[i]; + // All dependency-file options begin with -M. These include -MM, + // -MF, -MG, -MP, -MT, -MQ, -MD, and -MMD. + if (!Arg.startswith("-M")) + AdjustedArgs.push_back(Args[i]); + + if ((Arg == "-MF") || (Arg == "-MT") || (Arg == "-MQ") || + (Arg == "-MD") || (Arg == "-MMD")) { + // Output is specified as -MX foo. Skip the next argument also. + ++i; + } + } + return AdjustedArgs; + }; +} + ArgumentsAdjuster getInsertArgumentAdjuster(const CommandLineArguments &Extra, ArgumentInsertPosition Pos) { return [Extra, Pos](const CommandLineArguments &Args, StringRef /*unused*/) { @@ -83,4 +103,3 @@ ArgumentsAdjuster combineAdjusters(ArgumentsAdjuster First, } // end namespace tooling } // end namespace clang - diff --git a/lib/Tooling/Core/Diagnostic.cpp b/lib/Tooling/Core/Diagnostic.cpp index 3bbc2b901e38..9e4833f2eff4 100644 --- a/lib/Tooling/Core/Diagnostic.cpp +++ b/lib/Tooling/Core/Diagnostic.cpp @@ -35,9 +35,9 @@ Diagnostic::Diagnostic(llvm::StringRef DiagnosticName, BuildDirectory(BuildDirectory) {} Diagnostic::Diagnostic(llvm::StringRef DiagnosticName, - DiagnosticMessage &Message, - llvm::StringMap<Replacements> &Fix, - SmallVector<DiagnosticMessage, 1> &Notes, + const DiagnosticMessage &Message, + const llvm::StringMap<Replacements> &Fix, + const SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel, llvm::StringRef BuildDirectory) : DiagnosticName(DiagnosticName), Message(Message), Fix(Fix), Notes(Notes), DiagLevel(DiagLevel), BuildDirectory(BuildDirectory) {} diff --git a/lib/Tooling/Tooling.cpp b/lib/Tooling/Tooling.cpp index 2e093dd9afc8..c84fbf473753 100644 --- a/lib/Tooling/Tooling.cpp +++ b/lib/Tooling/Tooling.cpp @@ -100,7 +100,6 @@ clang::CompilerInvocation *newInvocation( *Diagnostics); Invocation->getFrontendOpts().DisableFree = false; Invocation->getCodeGenOpts().DisableFree = false; - Invocation->getDependencyOutputOpts() = DependencyOutputOptions(); return Invocation; } @@ -140,9 +139,11 @@ bool runToolOnCodeWithArgs( OverlayFileSystem->pushOverlay(InMemoryFileSystem); llvm::IntrusiveRefCntPtr<FileManager> Files( new FileManager(FileSystemOptions(), OverlayFileSystem)); - ToolInvocation Invocation(getSyntaxOnlyToolArgs(ToolName, Args, FileNameRef), - ToolAction, Files.get(), - std::move(PCHContainerOps)); + ArgumentsAdjuster Adjuster = getClangStripDependencyFileAdjuster(); + ToolInvocation Invocation( + getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef), + ToolAction, Files.get(), + std::move(PCHContainerOps)); SmallString<1024> CodeStorage; InMemoryFileSystem->addFile(FileNameRef, 0, @@ -510,7 +511,8 @@ buildASTFromCode(const Twine &Code, const Twine &FileName, std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( const Twine &Code, const std::vector<std::string> &Args, const Twine &FileName, const Twine &ToolName, - std::shared_ptr<PCHContainerOperations> PCHContainerOps) { + std::shared_ptr<PCHContainerOperations> PCHContainerOps, + ArgumentsAdjuster Adjuster) { SmallString<16> FileNameStorage; StringRef FileNameRef = FileName.toNullTerminatedStringRef(FileNameStorage); @@ -523,8 +525,10 @@ std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( OverlayFileSystem->pushOverlay(InMemoryFileSystem); llvm::IntrusiveRefCntPtr<FileManager> Files( new FileManager(FileSystemOptions(), OverlayFileSystem)); - ToolInvocation Invocation(getSyntaxOnlyToolArgs(ToolName, Args, FileNameRef), - &Action, Files.get(), std::move(PCHContainerOps)); + + ToolInvocation Invocation( + getSyntaxOnlyToolArgs(ToolName, Adjuster(Args, FileNameRef), FileNameRef), + &Action, Files.get(), std::move(PCHContainerOps)); SmallString<1024> CodeStorage; InMemoryFileSystem->addFile(FileNameRef, 0, |