diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2020-01-17 20:45:01 +0000 |
| commit | 706b4fc47bbc608932d3b491ae19a3b9cde9497b (patch) | |
| tree | 4adf86a776049cbf7f69a1929c4babcbbef925eb /clang/lib | |
| parent | 7cc9cf2bf09f069cb2dd947ead05d0b54301fb71 (diff) | |
Notes
Diffstat (limited to 'clang/lib')
363 files changed, 27110 insertions, 11625 deletions
diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp index 4abb04fef5b8..4c6e9f2432f6 100644 --- a/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/clang/lib/ARCMigrate/ObjCMT.cpp @@ -1092,7 +1092,7 @@ static bool AvailabilityAttrsMatch(Attr *At1, Attr *At2) { const AvailabilityAttr *AA1 = dyn_cast<AvailabilityAttr>(At1); if (!AA1) return true; - const AvailabilityAttr *AA2 = dyn_cast<AvailabilityAttr>(At2); + const AvailabilityAttr *AA2 = cast<AvailabilityAttr>(At2); VersionTuple Introduced1 = AA1->getIntroduced(); VersionTuple Deprecated1 = AA1->getDeprecated(); @@ -1371,7 +1371,7 @@ static bool IsVoidStarType(QualType Ty) { Ty = TD->getDecl()->getUnderlyingType(); // Is the type void*? - const PointerType* PT = Ty->getAs<PointerType>(); + const PointerType* PT = Ty->castAs<PointerType>(); if (PT->getPointeeType().getUnqualifiedType()->isVoidType()) return true; return IsVoidStarType(PT->getPointeeType()); diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp new file mode 100644 index 000000000000..fc32e768d92f --- /dev/null +++ b/clang/lib/AST/ASTConcept.cpp @@ -0,0 +1,55 @@ +//===--- ASTConcept.cpp - Concepts Related AST Data Structures --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file defines AST data structures related to concepts. +/// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConcept.h" +#include "clang/AST/ASTContext.h" +using namespace clang; + +ASTConstraintSatisfaction::ASTConstraintSatisfaction(const ASTContext &C, + const ConstraintSatisfaction &Satisfaction): + NumRecords{Satisfaction.Details.size()}, + IsSatisfied{Satisfaction.IsSatisfied} { + for (unsigned I = 0; I < NumRecords; ++I) { + auto &Detail = Satisfaction.Details[I]; + if (Detail.second.is<Expr *>()) + new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I) + UnsatisfiedConstraintRecord{Detail.first, + UnsatisfiedConstraintRecord::second_type( + Detail.second.get<Expr *>())}; + else { + auto &SubstitutionDiagnostic = + *Detail.second.get<std::pair<SourceLocation, StringRef> *>(); + unsigned MessageSize = SubstitutionDiagnostic.second.size(); + char *Mem = new (C) char[MessageSize]; + memcpy(Mem, SubstitutionDiagnostic.second.data(), MessageSize); + auto *NewSubstDiag = new (C) std::pair<SourceLocation, StringRef>( + SubstitutionDiagnostic.first, StringRef(Mem, MessageSize)); + new (getTrailingObjects<UnsatisfiedConstraintRecord>() + I) + UnsatisfiedConstraintRecord{Detail.first, + UnsatisfiedConstraintRecord::second_type( + NewSubstDiag)}; + } + } +} + + +ASTConstraintSatisfaction * +ASTConstraintSatisfaction::Create(const ASTContext &C, + const ConstraintSatisfaction &Satisfaction) { + std::size_t size = + totalSizeToAlloc<UnsatisfiedConstraintRecord>( + Satisfaction.Details.size()); + void *Mem = C.Allocate(size, alignof(ASTConstraintSatisfaction)); + return new (Mem) ASTConstraintSatisfaction(C, Satisfaction); +} diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index cda51ec755a8..a51429264dbe 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -14,6 +14,7 @@ #include "CXXABI.h" #include "Interp/Context.h" #include "clang/AST/APValue.h" +#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/ASTTypeTraits.h" #include "clang/AST/Attr.h" @@ -98,6 +99,32 @@ using namespace clang; enum FloatingRank { Float16Rank, HalfRank, FloatRank, DoubleRank, LongDoubleRank, Float128Rank }; +const Expr *ASTContext::traverseIgnored(const Expr *E) const { + return traverseIgnored(const_cast<Expr *>(E)); +} + +Expr *ASTContext::traverseIgnored(Expr *E) const { + if (!E) + return nullptr; + + switch (Traversal) { + case ast_type_traits::TK_AsIs: + return E; + case ast_type_traits::TK_IgnoreImplicitCastsAndParentheses: + return E->IgnoreParenImpCasts(); + case ast_type_traits::TK_IgnoreUnlessSpelledInSource: + return E->IgnoreUnlessSpelledInSource(); + } + llvm_unreachable("Invalid Traversal type!"); +} + +ast_type_traits::DynTypedNode +ASTContext::traverseIgnored(const ast_type_traits::DynTypedNode &N) const { + if (const auto *E = N.get<Expr>()) { + return ast_type_traits::DynTypedNode::create(*traverseIgnored(E)); + } + return N; +} /// \returns location that is relevant when searching for Doc comments related /// to \p D. @@ -163,7 +190,9 @@ static SourceLocation getDeclLocForCommentSearch(const Decl *D, if (isa<ObjCMethodDecl>(D) || isa<ObjCContainerDecl>(D) || isa<ObjCPropertyDecl>(D) || isa<RedeclarableTemplateDecl>(D) || - isa<ClassTemplateSpecializationDecl>(D)) + isa<ClassTemplateSpecializationDecl>(D) || + // Allow association with Y across {} in `typedef struct X {} Y`. + isa<TypedefDecl>(D)) return D->getBeginLoc(); else { const SourceLocation DeclLoc = D->getLocation(); @@ -632,8 +661,9 @@ comments::FullComment *ASTContext::getCommentForDecl( return FC; } -void +void ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, + const ASTContext &C, TemplateTemplateParmDecl *Parm) { ID.AddInteger(Parm->getDepth()); ID.AddInteger(Parm->getPosition()); @@ -647,6 +677,16 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { ID.AddInteger(0); ID.AddBoolean(TTP->isParameterPack()); + const TypeConstraint *TC = TTP->getTypeConstraint(); + ID.AddBoolean(TC != nullptr); + if (TC) + TC->getImmediatelyDeclaredConstraint()->Profile(ID, C, + /*Canonical=*/true); + if (TTP->isExpandedParameterPack()) { + ID.AddBoolean(true); + ID.AddInteger(TTP->getNumExpansionParameters()); + } else + ID.AddBoolean(false); continue; } @@ -668,8 +708,12 @@ ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, auto *TTP = cast<TemplateTemplateParmDecl>(*P); ID.AddInteger(2); - Profile(ID, TTP); + Profile(ID, C, TTP); } + Expr *RequiresClause = Parm->getTemplateParameters()->getRequiresClause(); + ID.AddBoolean(RequiresClause != nullptr); + if (RequiresClause) + RequiresClause->Profile(ID, C, /*Canonical=*/true); } TemplateTemplateParmDecl * @@ -677,7 +721,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( TemplateTemplateParmDecl *TTP) const { // Check if we already have a canonical template template parameter. llvm::FoldingSetNodeID ID; - CanonicalTemplateTemplateParm::Profile(ID, TTP); + CanonicalTemplateTemplateParm::Profile(ID, *this, TTP); void *InsertPos = nullptr; CanonicalTemplateTemplateParm *Canonical = CanonTemplateTemplateParms.FindNodeOrInsertPos(ID, InsertPos); @@ -691,15 +735,79 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( for (TemplateParameterList::const_iterator P = Params->begin(), PEnd = Params->end(); P != PEnd; ++P) { - if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) - CanonParams.push_back( - TemplateTypeParmDecl::Create(*this, getTranslationUnitDecl(), - SourceLocation(), - SourceLocation(), - TTP->getDepth(), - TTP->getIndex(), nullptr, false, - TTP->isParameterPack())); - else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { + if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { + TemplateTypeParmDecl *NewTTP = TemplateTypeParmDecl::Create(*this, + getTranslationUnitDecl(), SourceLocation(), SourceLocation(), + TTP->getDepth(), TTP->getIndex(), nullptr, false, + TTP->isParameterPack(), TTP->hasTypeConstraint(), + TTP->isExpandedParameterPack() ? + llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None); + if (const auto *TC = TTP->getTypeConstraint()) { + // This is a bit ugly - we need to form a new immediately-declared + // constraint that references the new parameter; this would ideally + // require semantic analysis (e.g. template<C T> struct S {}; - the + // converted arguments of C<T> could be an argument pack if C is + // declared as template<typename... T> concept C = ...). + // We don't have semantic analysis here so we dig deep into the + // ready-made constraint expr and change the thing manually. + Expr *IDC = TC->getImmediatelyDeclaredConstraint(); + ConceptSpecializationExpr *CSE; + if (const auto *Fold = dyn_cast<CXXFoldExpr>(IDC)) + CSE = cast<ConceptSpecializationExpr>(Fold->getLHS()); + else + CSE = cast<ConceptSpecializationExpr>(IDC); + ArrayRef<TemplateArgument> OldConverted = CSE->getTemplateArguments(); + SmallVector<TemplateArgument, 3> NewConverted; + NewConverted.reserve(OldConverted.size()); + + QualType ParamAsArgument(NewTTP->getTypeForDecl(), 0); + if (OldConverted.front().getKind() == TemplateArgument::Pack) { + // The case: + // template<typename... T> concept C = true; + // template<C<int> T> struct S; -> constraint is C<{T, int}> + NewConverted.push_back(ParamAsArgument); + for (auto &Arg : OldConverted.front().pack_elements().drop_front(1)) + NewConverted.push_back(Arg); + TemplateArgument NewPack(NewConverted); + + NewConverted.clear(); + NewConverted.push_back(NewPack); + assert(OldConverted.size() == 1 && + "Template parameter pack should be the last parameter"); + } else { + assert(OldConverted.front().getKind() == TemplateArgument::Type && + "Unexpected first argument kind for immediately-declared " + "constraint"); + NewConverted.push_back(ParamAsArgument); + for (auto &Arg : OldConverted.drop_front(1)) + NewConverted.push_back(Arg); + } + Expr *NewIDC = ConceptSpecializationExpr::Create(*this, + NestedNameSpecifierLoc(), /*TemplateKWLoc=*/SourceLocation(), + CSE->getConceptNameInfo(), /*FoundDecl=*/CSE->getNamedConcept(), + CSE->getNamedConcept(), + // Actually canonicalizing a TemplateArgumentLoc is difficult so we + // simply omit the ArgsAsWritten + /*ArgsAsWritten=*/nullptr, NewConverted, nullptr); + + if (auto *OrigFold = dyn_cast<CXXFoldExpr>(IDC)) + NewIDC = new (*this) CXXFoldExpr(OrigFold->getType(), + SourceLocation(), NewIDC, + BinaryOperatorKind::BO_LAnd, + SourceLocation(), /*RHS=*/nullptr, + SourceLocation(), + /*NumExpansions=*/None); + + NewTTP->setTypeConstraint( + NestedNameSpecifierLoc(), + DeclarationNameInfo(TC->getNamedConcept()->getDeclName(), + SourceLocation()), /*FoundDecl=*/nullptr, + // Actually canonicalizing a TemplateArgumentLoc is difficult so we + // simply omit the ArgsAsWritten + CSE->getNamedConcept(), /*ArgsAsWritten=*/nullptr, NewIDC); + } + CanonParams.push_back(NewTTP); + } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { QualType T = getCanonicalType(NTTP->getType()); TypeSourceInfo *TInfo = getTrivialTypeSourceInfo(T); NonTypeTemplateParmDecl *Param; @@ -738,9 +846,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( cast<TemplateTemplateParmDecl>(*P))); } - assert(!TTP->getTemplateParameters()->getRequiresClause() && - "Unexpected requires-clause on template template-parameter"); - Expr *const CanonRequiresClause = nullptr; + Expr *CanonRequiresClause = nullptr; + if (Expr *RequiresClause = TTP->getTemplateParameters()->getRequiresClause()) + CanonRequiresClause = RequiresClause; TemplateTemplateParmDecl *CanonTTP = TemplateTemplateParmDecl::Create(*this, getTranslationUnitDecl(), @@ -769,6 +877,7 @@ CXXABI *ASTContext::createCXXABI(const TargetInfo &T) { if (!LangOpts.CPlusPlus) return nullptr; switch (T.getCXXABI().getKind()) { + case TargetCXXABI::Fuchsia: case TargetCXXABI::GenericARM: // Same as Itanium at this level case TargetCXXABI::iOS: case TargetCXXABI::iOS64: @@ -797,15 +906,18 @@ static const LangASMap *getAddressSpaceMap(const TargetInfo &T, // The fake address space map must have a distinct entry for each // language-specific address space. static const unsigned FakeAddrSpaceMap[] = { - 0, // Default - 1, // opencl_global - 3, // opencl_local - 2, // opencl_constant - 0, // opencl_private - 4, // opencl_generic - 5, // cuda_device - 6, // cuda_constant - 7 // cuda_shared + 0, // Default + 1, // opencl_global + 3, // opencl_local + 2, // opencl_constant + 0, // opencl_private + 4, // opencl_generic + 5, // cuda_device + 6, // cuda_constant + 7, // cuda_shared + 8, // ptr32_sptr + 9, // ptr32_uptr + 10 // ptr64 }; return &FakeAddrSpaceMap; } else { @@ -832,7 +944,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, : ConstantArrayTypes(this_()), FunctionProtoTypes(this_()), TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), - SubstTemplateTemplateParmPacks(this_()), SourceMgr(SM), LangOpts(LOpts), + SubstTemplateTemplateParmPacks(this_()), + CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts), SanitizerBL(new SanitizerBlacklist(LangOpts.SanitizerBlacklistFiles, SM)), XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles, LangOpts.XRayNeverInstrumentFiles, @@ -875,10 +988,6 @@ ASTContext::~ASTContext() { A != AEnd; ++A) A->second->~AttrVec(); - for (std::pair<const MaterializeTemporaryExpr *, APValue *> &MTVPair : - MaterializedTemporaryValues) - MTVPair.second->~APValue(); - for (const auto &Value : ModuleInitializers) Value.second->~PerModuleInitializers(); @@ -895,15 +1004,15 @@ class ASTContext::ParentMap { /// only storing a unique pointer to them. using ParentMapPointers = llvm::DenseMap< const void *, - llvm::PointerUnion4<const Decl *, const Stmt *, - ast_type_traits::DynTypedNode *, ParentVector *>>; + llvm::PointerUnion<const Decl *, const Stmt *, + ast_type_traits::DynTypedNode *, ParentVector *>>; /// Parent map for nodes without pointer identity. We store a full /// DynTypedNode for all keys. using ParentMapOtherNodes = llvm::DenseMap< ast_type_traits::DynTypedNode, - llvm::PointerUnion4<const Decl *, const Stmt *, - ast_type_traits::DynTypedNode *, ParentVector *>>; + llvm::PointerUnion<const Decl *, const Stmt *, + ast_type_traits::DynTypedNode *, ParentVector *>>; ParentMapPointers PointerParents; ParentMapOtherNodes OtherParents; @@ -959,7 +1068,7 @@ public: void ASTContext::setTraversalScope(const std::vector<Decl *> &TopLevelDecls) { TraversalScope = TopLevelDecls; - Parents.reset(); + Parents.clear(); } void ASTContext::AddDeallocation(void (*Callback)(void *), void *Data) const { @@ -2438,7 +2547,7 @@ structHasUniqueObjectRepresentations(const ASTContext &Context, return llvm::None; SmallVector<std::pair<QualType, int64_t>, 4> Bases; - for (const auto Base : ClassDecl->bases()) { + for (const auto &Base : ClassDecl->bases()) { // Empty types can be inherited from, and non-empty types can potentially // have tail padding, so just make sure there isn't an error. if (!isStructEmpty(Base.getType())) { @@ -2456,7 +2565,7 @@ structHasUniqueObjectRepresentations(const ASTContext &Context, Layout.getBaseClassOffset(R.first->getAsCXXRecordDecl()); }); - for (const auto Base : Bases) { + for (const auto &Base : Bases) { int64_t BaseOffset = Context.toBits( Layout.getBaseClassOffset(Base.first->getAsCXXRecordDecl())); int64_t BaseSize = Base.second; @@ -2654,8 +2763,7 @@ const ObjCInterfaceDecl *ASTContext::getObjContainingInterface( /// Get the copy initialization expression of VarDecl, or nullptr if /// none exists. -ASTContext::BlockVarCopyInit -ASTContext::getBlockVarCopyInit(const VarDecl*VD) const { +BlockVarCopyInit ASTContext::getBlockVarCopyInit(const VarDecl *VD) const { assert(VD && "Passed null params"); assert(VD->hasAttr<BlocksAttr>() && "getBlockVarCopyInits - not __block var"); @@ -2809,6 +2917,16 @@ QualType ASTContext::getObjCGCQualType(QualType T, return getExtQualType(TypeNode, Quals); } +QualType ASTContext::removePtrSizeAddrSpace(QualType T) const { + if (const PointerType *Ptr = T->getAs<PointerType>()) { + QualType Pointee = Ptr->getPointeeType(); + if (isPtrSizeAddressSpace(Pointee.getAddressSpace())) { + return getPointerType(removeAddrSpaceQualType(Pointee)); + } + } + return T; +} + const FunctionType *ASTContext::adjustFunctionType(const FunctionType *T, FunctionType::ExtInfo Info) { if (T->getExtInfo() == Info) @@ -2883,6 +3001,29 @@ bool ASTContext::hasSameFunctionTypeIgnoringExceptionSpec(QualType T, getFunctionTypeWithExceptionSpec(U, EST_None))); } +QualType ASTContext::getFunctionTypeWithoutPtrSizes(QualType T) { + if (const auto *Proto = T->getAs<FunctionProtoType>()) { + QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType()); + SmallVector<QualType, 16> Args(Proto->param_types()); + for (unsigned i = 0, n = Args.size(); i != n; ++i) + Args[i] = removePtrSizeAddrSpace(Args[i]); + return getFunctionType(RetTy, Args, Proto->getExtProtoInfo()); + } + + if (const FunctionNoProtoType *Proto = T->getAs<FunctionNoProtoType>()) { + QualType RetTy = removePtrSizeAddrSpace(Proto->getReturnType()); + return getFunctionNoProtoType(RetTy, Proto->getExtInfo()); + } + + return T; +} + +bool ASTContext::hasSameFunctionTypeIgnoringPtrSizes(QualType T, QualType U) { + return hasSameType(T, U) || + hasSameType(getFunctionTypeWithoutPtrSizes(T), + getFunctionTypeWithoutPtrSizes(U)); +} + void ASTContext::adjustExceptionSpec( FunctionDecl *FD, const FunctionProtoType::ExceptionSpecInfo &ESI, bool AsWritten) { @@ -3547,10 +3688,10 @@ ASTContext::getDependentVectorType(QualType VecType, Expr *SizeExpr, (void)CanonCheck; DependentVectorTypes.InsertNode(New, InsertPos); } else { - QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr, - SourceLocation()); + QualType CanonExtTy = getDependentSizedExtVectorType(CanonVecTy, SizeExpr, + SourceLocation()); New = new (*this, TypeAlignment) DependentVectorType( - *this, VecType, Canon, SizeExpr, AttrLoc, VecKind); + *this, VecType, CanonExtTy, SizeExpr, AttrLoc, VecKind); } } @@ -3620,10 +3761,10 @@ ASTContext::getDependentSizedExtVectorType(QualType vecType, (void)CanonCheck; DependentSizedExtVectorTypes.InsertNode(New, InsertPos); } else { - QualType Canon = getDependentSizedExtVectorType(CanonVecTy, SizeExpr, - SourceLocation()); - New = new (*this, TypeAlignment) - DependentSizedExtVectorType(*this, vecType, Canon, SizeExpr, AttrLoc); + QualType CanonExtTy = getDependentSizedExtVectorType(CanonVecTy, SizeExpr, + SourceLocation()); + New = new (*this, TypeAlignment) DependentSizedExtVectorType( + *this, vecType, CanonExtTy, SizeExpr, AttrLoc); } } @@ -3877,10 +4018,11 @@ QualType ASTContext::getFunctionTypeInternal( auto ESH = FunctionProtoType::getExceptionSpecSize( EPI.ExceptionSpec.Type, EPI.ExceptionSpec.Exceptions.size()); size_t Size = FunctionProtoType::totalSizeToAlloc< - QualType, FunctionType::FunctionTypeExtraBitfields, + QualType, SourceLocation, FunctionType::FunctionTypeExtraBitfields, FunctionType::ExceptionType, Expr *, FunctionDecl *, FunctionProtoType::ExtParameterInfo, Qualifiers>( - NumArgs, FunctionProtoType::hasExtraBitfields(EPI.ExceptionSpec.Type), + NumArgs, EPI.Variadic, + FunctionProtoType::hasExtraBitfields(EPI.ExceptionSpec.Type), ESH.NumExceptionType, ESH.NumExprPtr, ESH.NumFunctionDeclPtr, EPI.ExtParameterInfos ? NumArgs : 0, EPI.TypeQuals.hasNonFastQualifiers() ? 1 : 0); @@ -6813,21 +6955,19 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, S += ObjCEncodingForEnumType(this, cast<EnumType>(CT)); return; - case Type::Complex: { - const auto *CT = T->castAs<ComplexType>(); + case Type::Complex: S += 'j'; - getObjCEncodingForTypeImpl(CT->getElementType(), S, ObjCEncOptions(), + getObjCEncodingForTypeImpl(T->castAs<ComplexType>()->getElementType(), S, + ObjCEncOptions(), /*Field=*/nullptr); return; - } - case Type::Atomic: { - const auto *AT = T->castAs<AtomicType>(); + case Type::Atomic: S += 'A'; - getObjCEncodingForTypeImpl(AT->getValueType(), S, ObjCEncOptions(), + getObjCEncodingForTypeImpl(T->castAs<AtomicType>()->getValueType(), S, + ObjCEncOptions(), /*Field=*/nullptr); return; - } // encoding for pointer or reference types. case Type::Pointer: @@ -8645,8 +8785,8 @@ QualType ASTContext::mergeFunctionParameterTypes(QualType lhs, QualType rhs, QualType ASTContext::mergeFunctionTypes(QualType lhs, QualType rhs, bool OfBlockPointer, bool Unqualified) { - const auto *lbase = lhs->getAs<FunctionType>(); - const auto *rbase = rhs->getAs<FunctionType>(); + const auto *lbase = lhs->castAs<FunctionType>(); + const auto *rbase = rhs->castAs<FunctionType>(); const auto *lproto = dyn_cast<FunctionProtoType>(lbase); const auto *rproto = dyn_cast<FunctionProtoType>(rbase); bool allLTypes = true; @@ -10170,6 +10310,7 @@ MangleContext *ASTContext::createMangleContext(const TargetInfo *T) { if (!T) T = Target; switch (T->getCXXABI().getKind()) { + case TargetCXXABI::Fuchsia: case TargetCXXABI::GenericAArch64: case TargetCXXABI::GenericItanium: case TargetCXXABI::GenericARM: @@ -10324,21 +10465,6 @@ unsigned ASTContext::getParameterIndex(const ParmVarDecl *D) const { return I->second; } -APValue * -ASTContext::getMaterializedTemporaryValue(const MaterializeTemporaryExpr *E, - bool MayCreate) { - assert(E && E->getStorageDuration() == SD_Static && - "don't need to cache the computed value for this temporary"); - if (MayCreate) { - APValue *&MTVI = MaterializedTemporaryValues[E]; - if (!MTVI) - MTVI = new (*this) APValue; - return MTVI; - } - - return MaterializedTemporaryValues.lookup(E); -} - QualType ASTContext::getStringLiteralArrayType(QualType EltTy, unsigned Length) const { // A C++ string literal has a const-qualified element type (C++ 2.13.4p1). @@ -10410,7 +10536,8 @@ createDynTypedNode(const NestedNameSpecifierLoc &Node) { class ASTContext::ParentMap::ASTVisitor : public RecursiveASTVisitor<ASTVisitor> { public: - ASTVisitor(ParentMap &Map) : Map(Map) {} + ASTVisitor(ParentMap &Map, ASTContext &Context) + : Map(Map), Context(Context) {} private: friend class RecursiveASTVisitor<ASTVisitor>; @@ -10480,9 +10607,12 @@ private: } bool TraverseStmt(Stmt *StmtNode) { - return TraverseNode( - StmtNode, StmtNode, [&] { return VisitorBase::TraverseStmt(StmtNode); }, - &Map.PointerParents); + Stmt *FilteredNode = StmtNode; + if (auto *ExprNode = dyn_cast_or_null<Expr>(FilteredNode)) + FilteredNode = Context.traverseIgnored(ExprNode); + return TraverseNode(FilteredNode, FilteredNode, + [&] { return VisitorBase::TraverseStmt(FilteredNode); }, + &Map.PointerParents); } bool TraverseTypeLoc(TypeLoc TypeLocNode) { @@ -10500,20 +10630,22 @@ private: } ParentMap ⤅ + ASTContext &Context; llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack; }; ASTContext::ParentMap::ParentMap(ASTContext &Ctx) { - ASTVisitor(*this).TraverseAST(Ctx); + ASTVisitor(*this, Ctx).TraverseAST(Ctx); } ASTContext::DynTypedNodeList ASTContext::getParents(const ast_type_traits::DynTypedNode &Node) { - if (!Parents) + std::unique_ptr<ParentMap> &P = Parents[Traversal]; + if (!P) // We build the parent map for the traversal scope (usually whole TU), as // hasAncestor can escape any subtree. - Parents = std::make_unique<ParentMap>(*this); - return Parents->getParents(Node); + P = std::make_unique<ParentMap>(*this); + return P->getParents(Node); } bool @@ -10763,3 +10895,66 @@ QualType ASTContext::getCorrespondingSignedFixedPointType(QualType Ty) const { llvm_unreachable("Unexpected unsigned fixed point type"); } } + +ParsedTargetAttr +ASTContext::filterFunctionTargetAttrs(const TargetAttr *TD) const { + assert(TD != nullptr); + ParsedTargetAttr ParsedAttr = TD->parse(); + + ParsedAttr.Features.erase( + llvm::remove_if(ParsedAttr.Features, + [&](const std::string &Feat) { + return !Target->isValidFeatureName( + StringRef{Feat}.substr(1)); + }), + ParsedAttr.Features.end()); + return ParsedAttr; +} + +void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, + const FunctionDecl *FD) const { + if (FD) + getFunctionFeatureMap(FeatureMap, GlobalDecl().getWithDecl(FD)); + else + Target->initFeatureMap(FeatureMap, getDiagnostics(), + Target->getTargetOpts().CPU, + Target->getTargetOpts().Features); +} + +// Fills in the supplied string map with the set of target features for the +// passed in function. +void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, + GlobalDecl GD) const { + StringRef TargetCPU = Target->getTargetOpts().CPU; + const FunctionDecl *FD = GD.getDecl()->getAsFunction(); + if (const auto *TD = FD->getAttr<TargetAttr>()) { + ParsedTargetAttr ParsedAttr = filterFunctionTargetAttrs(TD); + + // Make a copy of the features as passed on the command line into the + // beginning of the additional features from the function to override. + ParsedAttr.Features.insert( + ParsedAttr.Features.begin(), + Target->getTargetOpts().FeaturesAsWritten.begin(), + Target->getTargetOpts().FeaturesAsWritten.end()); + + if (ParsedAttr.Architecture != "" && + Target->isValidCPUName(ParsedAttr.Architecture)) + TargetCPU = ParsedAttr.Architecture; + + // Now populate the feature map, first with the TargetCPU which is either + // the default or a new one from the target attribute string. Then we'll use + // the passed in features (FeaturesAsWritten) along with the new ones from + // the attribute. + Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, + ParsedAttr.Features); + } else if (const auto *SD = FD->getAttr<CPUSpecificAttr>()) { + llvm::SmallVector<StringRef, 32> FeaturesTmp; + Target->getCPUSpecificCPUDispatchFeatures( + SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp); + std::vector<std::string> Features(FeaturesTmp.begin(), FeaturesTmp.end()); + Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); + } else { + Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, + Target->getTargetOpts().Features); + } +} diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 30985441031d..ea4d0dea58a3 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -300,8 +300,7 @@ ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, // Give some additional info on vector types. These are either not desugared // or displaying complex __attribute__ expressions so add details of the // type and element count. - if (Ty->isVectorType()) { - const VectorType *VTy = Ty->getAs<VectorType>(); + if (const auto *VTy = Ty->getAs<VectorType>()) { std::string DecoratedString; llvm::raw_string_ostream OS(DecoratedString); const char *Values = VTy->getNumElements() > 1 ? "values" : "value"; @@ -338,6 +337,21 @@ void clang::FormatASTNodeDiagnosticArgument( switch (Kind) { default: llvm_unreachable("unknown ArgumentKind"); + case DiagnosticsEngine::ak_addrspace: { + assert(Modifier.empty() && Argument.empty() && + "Invalid modifier for Qualfiers argument"); + + auto S = Qualifiers::getAddrSpaceAsString(static_cast<LangAS>(Val)); + if (S.empty()) { + OS << (Context.getLangOpts().OpenCL ? "default" : "generic"); + OS << " address space"; + } else { + OS << "address space"; + OS << " '" << S << "'"; + } + NeedQuotes = false; + break; + } case DiagnosticsEngine::ak_qual: { assert(Modifier.empty() && Argument.empty() && "Invalid modifier for Qualfiers argument"); @@ -348,7 +362,7 @@ void clang::FormatASTNodeDiagnosticArgument( OS << "unqualified"; NeedQuotes = false; } else { - OS << Q.getAsString(); + OS << S; } break; } @@ -589,8 +603,7 @@ class TemplateDiff { unsigned ReadNode; public: - DiffTree() : - CurrentNode(0), NextFreeNode(1) { + DiffTree() : CurrentNode(0), NextFreeNode(1), ReadNode(0) { FlatTree.push_back(DiffNode()); } diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 54acca7dc62c..22fb67478c96 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -44,6 +44,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeVisitor.h" #include "clang/AST/UnresolvedSet.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/ExceptionSpecificationType.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" @@ -297,6 +298,48 @@ namespace clang { return nullptr; } + void addDeclToContexts(Decl *FromD, Decl *ToD) { + if (Importer.isMinimalImport()) { + // In minimal import case the decl must be added even if it is not + // contained in original context, for LLDB compatibility. + // FIXME: Check if a better solution is possible. + if (!FromD->getDescribedTemplate() && + FromD->getFriendObjectKind() == Decl::FOK_None) + ToD->getLexicalDeclContext()->addDeclInternal(ToD); + return; + } + + DeclContext *FromDC = FromD->getDeclContext(); + DeclContext *FromLexicalDC = FromD->getLexicalDeclContext(); + DeclContext *ToDC = ToD->getDeclContext(); + DeclContext *ToLexicalDC = ToD->getLexicalDeclContext(); + + bool Visible = false; + if (FromDC->containsDeclAndLoad(FromD)) { + ToDC->addDeclInternal(ToD); + Visible = true; + } + if (ToDC != ToLexicalDC && FromLexicalDC->containsDeclAndLoad(FromD)) { + ToLexicalDC->addDeclInternal(ToD); + Visible = true; + } + + // If the Decl was added to any context, it was made already visible. + // Otherwise it is still possible that it should be visible. + if (!Visible) { + if (auto *FromNamed = dyn_cast<NamedDecl>(FromD)) { + auto *ToNamed = cast<NamedDecl>(ToD); + DeclContextLookupResult FromLookup = + FromDC->lookup(FromNamed->getDeclName()); + for (NamedDecl *ND : FromLookup) + if (ND == FromNamed) { + ToDC->makeDeclVisibleInContext(ToNamed); + break; + } + } + } + } + public: explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {} @@ -483,6 +526,9 @@ namespace clang { ExpectedDecl VisitUsingDirectiveDecl(UsingDirectiveDecl *D); ExpectedDecl VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); ExpectedDecl VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); + ExpectedDecl VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D); + ExpectedDecl + VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D); Expected<ObjCTypeParamList *> ImportObjCTypeParamList(ObjCTypeParamList *list); @@ -644,6 +690,11 @@ namespace clang { Expected<FunctionDecl *> FindFunctionTemplateSpecialization( FunctionDecl *FromFD); + + // Returns true if the given function has a placeholder return type and + // that type is declared inside the body of the function. + // E.g. auto f() { struct X{}; return X(); } + bool hasAutoReturnTypeDeclaredInside(FunctionDecl *D); }; template <typename InContainerTy> @@ -1543,6 +1594,10 @@ Error ASTNodeImporter::ImportDeclParts( DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc) { // Check if RecordDecl is in FunctionDecl parameters to avoid infinite loop. // example: int struct_in_proto(struct data_t{int a;int b;} *d); + // FIXME: We could support these constructs by importing a different type of + // this parameter and by importing the original type of the parameter only + // after the FunctionDecl is created. See + // VisitFunctionDecl::UsedDifferentProtoType. DeclContext *OrigDC = D->getDeclContext(); FunctionDecl *FunDecl; if (isa<RecordDecl>(D) && (FunDecl = dyn_cast<FunctionDecl>(OrigDC)) && @@ -1679,7 +1734,34 @@ ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { Error ChildErrors = Error::success(); for (auto *From : FromDC->decls()) { ExpectedDecl ImportedOrErr = import(From); - if (!ImportedOrErr) { + + // If we are in the process of ImportDefinition(...) for a RecordDecl we + // want to make sure that we are also completing each FieldDecl. There + // are currently cases where this does not happen and this is correctness + // fix since operations such as code generation will expect this to be so. + if (ImportedOrErr) { + FieldDecl *FieldFrom = dyn_cast_or_null<FieldDecl>(From); + Decl *ImportedDecl = (Decl*)*ImportedOrErr; + FieldDecl *FieldTo = dyn_cast_or_null<FieldDecl>(ImportedDecl); + if (FieldFrom && FieldTo) { + const RecordType *RecordFrom = FieldFrom->getType()->getAs<RecordType>(); + const RecordType *RecordTo = FieldTo->getType()->getAs<RecordType>(); + if (RecordFrom && RecordTo) { + RecordDecl *FromRecordDecl = RecordFrom->getDecl(); + RecordDecl *ToRecordDecl = RecordTo->getDecl(); + + if (FromRecordDecl->isCompleteDefinition() && + !ToRecordDecl->isCompleteDefinition()) { + Error Err = ImportDefinition(FromRecordDecl, ToRecordDecl); + + if (Err && AccumulateChildErrors) + ChildErrors = joinErrors(std::move(ChildErrors), std::move(Err)); + else + consumeError(std::move(Err)); + } + } + } + } else { if (AccumulateChildErrors) ChildErrors = joinErrors(std::move(ChildErrors), ImportedOrErr.takeError()); @@ -2224,6 +2306,9 @@ ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); if (!BeginLocOrErr) return BeginLocOrErr.takeError(); + ExpectedSLoc RBraceLocOrErr = import(D->getRBraceLoc()); + if (!RBraceLocOrErr) + return RBraceLocOrErr.takeError(); // Create the "to" namespace, if needed. NamespaceDecl *ToNamespace = MergeWithNamespace; @@ -2233,6 +2318,7 @@ ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(), /*PrevDecl=*/nullptr)) return ToNamespace; + ToNamespace->setRBraceLoc(*RBraceLocOrErr); ToNamespace->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToNamespace); @@ -2541,9 +2627,10 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { SourceLocation ToBeginLoc; NestedNameSpecifierLoc ToQualifierLoc; QualType ToIntegerType; - if (auto Imp = importSeq( - D->getBeginLoc(), D->getQualifierLoc(), D->getIntegerType())) - std::tie(ToBeginLoc, ToQualifierLoc, ToIntegerType) = *Imp; + SourceRange ToBraceRange; + if (auto Imp = importSeq(D->getBeginLoc(), D->getQualifierLoc(), + D->getIntegerType(), D->getBraceRange())) + std::tie(ToBeginLoc, ToQualifierLoc, ToIntegerType, ToBraceRange) = *Imp; else return Imp.takeError(); @@ -2557,6 +2644,7 @@ ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { D2->setQualifierInfo(ToQualifierLoc); D2->setIntegerType(ToIntegerType); + D2->setBraceRange(ToBraceRange); D2->setAccess(D->getAccess()); D2->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(D2); @@ -2718,11 +2806,7 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { D2 = D2CXX; D2->setAccess(D->getAccess()); D2->setLexicalDeclContext(LexicalDC); - if (!DCXX->getDescribedClassTemplate() || DCXX->isImplicit()) - LexicalDC->addDeclInternal(D2); - - if (LexicalDC != DC && D->isInIdentifierNamespace(Decl::IDNS_TagFriend)) - DC->makeDeclVisibleInContext(D2); + addDeclToContexts(D, D2); if (ClassTemplateDecl *FromDescribed = DCXX->getDescribedClassTemplate()) { @@ -2788,9 +2872,13 @@ ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { Name.getAsIdentifierInfo(), PrevDecl)) return D2; D2->setLexicalDeclContext(LexicalDC); - LexicalDC->addDeclInternal(D2); + addDeclToContexts(D, D2); } + if (auto BraceRangeOrErr = import(D->getBraceRange())) + D2->setBraceRange(*BraceRangeOrErr); + else + return BraceRangeOrErr.takeError(); if (auto QualifierLocOrErr = import(D->getQualifierLoc())) D2->setQualifierInfo(*QualifierLocOrErr); else @@ -2991,6 +3079,46 @@ Error ASTNodeImporter::ImportFunctionDeclBody(FunctionDecl *FromFD, return Error::success(); } +// Returns true if the given D has a DeclContext up to the TranslationUnitDecl +// which is equal to the given DC. +static bool isAncestorDeclContextOf(const DeclContext *DC, const Decl *D) { + const DeclContext *DCi = D->getDeclContext(); + while (DCi != D->getTranslationUnitDecl()) { + if (DCi == DC) + return true; + DCi = DCi->getParent(); + } + return false; +} + +bool ASTNodeImporter::hasAutoReturnTypeDeclaredInside(FunctionDecl *D) { + QualType FromTy = D->getType(); + const FunctionProtoType *FromFPT = FromTy->getAs<FunctionProtoType>(); + assert(FromFPT && "Must be called on FunctionProtoType"); + if (AutoType *AutoT = FromFPT->getReturnType()->getContainedAutoType()) { + QualType DeducedT = AutoT->getDeducedType(); + if (const RecordType *RecordT = + DeducedT.isNull() ? nullptr : dyn_cast<RecordType>(DeducedT)) { + RecordDecl *RD = RecordT->getDecl(); + assert(RD); + if (isAncestorDeclContextOf(D, RD)) { + assert(RD->getLexicalDeclContext() == RD->getDeclContext()); + return true; + } + } + } + if (const TypedefType *TypedefT = + dyn_cast<TypedefType>(FromFPT->getReturnType())) { + TypedefNameDecl *TD = TypedefT->getDecl(); + assert(TD); + if (isAncestorDeclContextOf(D, TD)) { + assert(TD->getLexicalDeclContext() == TD->getDeclContext()); + return true; + } + } + return false; +} + ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { SmallVector<Decl *, 2> Redecls = getCanonicalForwardRedeclChain(D); @@ -3114,32 +3242,49 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { return std::move(Err); QualType FromTy = D->getType(); - bool usedDifferentExceptionSpec = false; - - if (const auto *FromFPT = D->getType()->getAs<FunctionProtoType>()) { + // Set to true if we do not import the type of the function as is. There are + // cases when the original type would result in an infinite recursion during + // the import. To avoid an infinite recursion when importing, we create the + // FunctionDecl with a simplified function type and update it only after the + // relevant AST nodes are already imported. + bool UsedDifferentProtoType = false; + if (const auto *FromFPT = FromTy->getAs<FunctionProtoType>()) { + QualType FromReturnTy = FromFPT->getReturnType(); + // Functions with auto return type may define a struct inside their body + // and the return type could refer to that struct. + // E.g.: auto foo() { struct X{}; return X(); } + // To avoid an infinite recursion when importing, create the FunctionDecl + // with a simplified return type. + if (hasAutoReturnTypeDeclaredInside(D)) { + FromReturnTy = Importer.getFromContext().VoidTy; + UsedDifferentProtoType = true; + } FunctionProtoType::ExtProtoInfo FromEPI = FromFPT->getExtProtoInfo(); // FunctionProtoType::ExtProtoInfo's ExceptionSpecDecl can point to the // FunctionDecl that we are importing the FunctionProtoType for. // To avoid an infinite recursion when importing, create the FunctionDecl - // with a simplified function type and update it afterwards. + // with a simplified function type. if (FromEPI.ExceptionSpec.SourceDecl || FromEPI.ExceptionSpec.SourceTemplate || FromEPI.ExceptionSpec.NoexceptExpr) { FunctionProtoType::ExtProtoInfo DefaultEPI; - FromTy = Importer.getFromContext().getFunctionType( - FromFPT->getReturnType(), FromFPT->getParamTypes(), DefaultEPI); - usedDifferentExceptionSpec = true; + FromEPI = DefaultEPI; + UsedDifferentProtoType = true; } + FromTy = Importer.getFromContext().getFunctionType( + FromReturnTy, FromFPT->getParamTypes(), FromEPI); } QualType T; TypeSourceInfo *TInfo; SourceLocation ToInnerLocStart, ToEndLoc; NestedNameSpecifierLoc ToQualifierLoc; + Expr *TrailingRequiresClause; if (auto Imp = importSeq( FromTy, D->getTypeSourceInfo(), D->getInnerLocStart(), - D->getQualifierLoc(), D->getEndLoc())) - std::tie(T, TInfo, ToInnerLocStart, ToQualifierLoc, ToEndLoc) = *Imp; + D->getQualifierLoc(), D->getEndLoc(), D->getTrailingRequiresClause())) + std::tie(T, TInfo, ToInnerLocStart, ToQualifierLoc, ToEndLoc, + TrailingRequiresClause) = *Imp; else return Imp.takeError(); @@ -3168,7 +3313,10 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { ExplicitSpecifier( ExplicitExpr, FromConstructor->getExplicitSpecifier().getKind()), - D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind())) + D->isInlineSpecified(), D->isImplicit(), D->getConstexprKind(), + InheritedConstructor(), // FIXME: Properly import inherited + // constructor info + TrailingRequiresClause)) return ToFunction; } else if (CXXDestructorDecl *FromDtor = dyn_cast<CXXDestructorDecl>(D)) { @@ -3186,7 +3334,7 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { if (GetImportedOrCreateDecl<CXXDestructorDecl>( ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), - D->isImplicit(), D->getConstexprKind())) + D->isImplicit(), D->getConstexprKind(), TrailingRequiresClause)) return ToFunction; CXXDestructorDecl *ToDtor = cast<CXXDestructorDecl>(ToFunction); @@ -3206,20 +3354,21 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { ToInnerLocStart, NameInfo, T, TInfo, D->isInlineSpecified(), ExplicitSpecifier(ExplicitExpr, FromConversion->getExplicitSpecifier().getKind()), - D->getConstexprKind(), SourceLocation())) + D->getConstexprKind(), SourceLocation(), TrailingRequiresClause)) return ToFunction; } else if (auto *Method = dyn_cast<CXXMethodDecl>(D)) { if (GetImportedOrCreateDecl<CXXMethodDecl>( ToFunction, D, Importer.getToContext(), cast<CXXRecordDecl>(DC), ToInnerLocStart, NameInfo, T, TInfo, Method->getStorageClass(), Method->isInlineSpecified(), D->getConstexprKind(), - SourceLocation())) + SourceLocation(), TrailingRequiresClause)) return ToFunction; } else { if (GetImportedOrCreateDecl( ToFunction, D, Importer.getToContext(), DC, ToInnerLocStart, NameInfo, T, TInfo, D->getStorageClass(), D->isInlineSpecified(), - D->hasWrittenPrototype(), D->getConstexprKind())) + D->hasWrittenPrototype(), D->getConstexprKind(), + TrailingRequiresClause)) return ToFunction; } @@ -3263,14 +3412,6 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { } } - if (usedDifferentExceptionSpec) { - // Update FunctionProtoType::ExtProtoInfo. - if (ExpectedType TyOrErr = import(D->getType())) - ToFunction->setType(*TyOrErr); - else - return TyOrErr.takeError(); - } - // Import the describing template function, if any. if (FromFT) { auto ToFTOrErr = import(FromFT); @@ -3302,29 +3443,21 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { return std::move(Err); } + // Import and set the original type in case we used another type. + if (UsedDifferentProtoType) { + if (ExpectedType TyOrErr = import(D->getType())) + ToFunction->setType(*TyOrErr); + else + return TyOrErr.takeError(); + } + // FIXME: Other bits to merge? // If it is a template, import all related things. if (Error Err = ImportTemplateInformation(D, ToFunction)) return std::move(Err); - bool IsFriend = D->isInIdentifierNamespace(Decl::IDNS_OrdinaryFriend); - - // TODO Can we generalize this approach to other AST nodes as well? - if (D->getDeclContext()->containsDeclAndLoad(D)) - DC->addDeclInternal(ToFunction); - if (DC != LexicalDC && D->getLexicalDeclContext()->containsDeclAndLoad(D)) - LexicalDC->addDeclInternal(ToFunction); - - // Friend declaration's lexical context is the befriending class, but the - // semantic context is the enclosing scope of the befriending class. - // We want the friend functions to be found in the semantic context by lookup. - // FIXME should we handle this generically in VisitFriendDecl? - // In Other cases when LexicalDC != DC we don't want it to be added, - // e.g out-of-class definitions like void B::f() {} . - if (LexicalDC != DC && IsFriend) { - DC->makeDeclVisibleInContext(ToFunction); - } + addDeclToContexts(D, ToFunction); if (auto *FromCXXMethod = dyn_cast<CXXMethodDecl>(D)) if (Error Err = ImportOverriddenMethods(cast<CXXMethodDecl>(ToFunction), @@ -3772,10 +3905,7 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) { if (D->isConstexpr()) ToVar->setConstexpr(true); - if (D->getDeclContext()->containsDeclAndLoad(D)) - DC->addDeclInternal(ToVar); - if (DC != LexicalDC && D->getLexicalDeclContext()->containsDeclAndLoad(D)) - LexicalDC->addDeclInternal(ToVar); + addDeclToContexts(D, ToVar); // Import the rest of the chain. I.e. import all subsequent declarations. for (++RedeclIt; RedeclIt != Redecls.end(); ++RedeclIt) { @@ -3961,10 +4091,10 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { ObjCMethodDecl *ToMethod; if (GetImportedOrCreateDecl( - ToMethod, D, Importer.getToContext(), Loc, - ToEndLoc, Name.getObjCSelector(), ToReturnType, - ToReturnTypeSourceInfo, DC, D->isInstanceMethod(), D->isVariadic(), - D->isPropertyAccessor(), D->isImplicit(), D->isDefined(), + ToMethod, D, Importer.getToContext(), Loc, ToEndLoc, + Name.getObjCSelector(), ToReturnType, ToReturnTypeSourceInfo, DC, + D->isInstanceMethod(), D->isVariadic(), D->isPropertyAccessor(), + D->isSynthesizedAccessorStub(), D->isImplicit(), D->isDefined(), D->getImplementationControl(), D->hasRelatedResultType())) return ToMethod; @@ -3996,6 +4126,14 @@ ExpectedDecl ASTNodeImporter::VisitObjCMethodDecl(ObjCMethodDecl *D) { ToMethod->setLexicalDeclContext(LexicalDC); LexicalDC->addDeclInternal(ToMethod); + + // Implicit params are declared when Sema encounters the definition but this + // never happens when the method is imported. Manually declare the implicit + // params now that the MethodDecl knows its class interface. + if (D->getSelfDecl()) + ToMethod->createImplicitParams(Importer.getToContext(), + ToMethod->getClassInterface()); + return ToMethod; } @@ -4464,6 +4602,20 @@ ExpectedDecl ASTNodeImporter::VisitUnresolvedUsingTypenameDecl( return ToUsing; } +ExpectedDecl ASTNodeImporter::VisitBuiltinTemplateDecl(BuiltinTemplateDecl *D) { + Decl* ToD = nullptr; + switch (D->getBuiltinTemplateKind()) { + case BuiltinTemplateKind::BTK__make_integer_seq: + ToD = Importer.getToContext().getMakeIntegerSeqDecl(); + break; + case BuiltinTemplateKind::BTK__type_pack_element: + ToD = Importer.getToContext().getTypePackElementDecl(); + break; + } + assert(ToD && "BuiltinTemplateDecl of unsupported kind!"); + Importer.MapImported(D, ToD); + return ToD; +} Error ASTNodeImporter::ImportDefinition( ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, ImportDefinitionKind Kind) { @@ -4945,7 +5097,7 @@ ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { // context. This context will be fixed when the actual template declaration // is created. - // FIXME: Import default argument. + // FIXME: Import default argument and constraint expression. ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); if (!BeginLocOrErr) @@ -4956,12 +5108,47 @@ ASTNodeImporter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { return LocationOrErr.takeError(); TemplateTypeParmDecl *ToD = nullptr; - (void)GetImportedOrCreateDecl( + if (GetImportedOrCreateDecl( ToD, D, Importer.getToContext(), Importer.getToContext().getTranslationUnitDecl(), *BeginLocOrErr, *LocationOrErr, D->getDepth(), D->getIndex(), Importer.Import(D->getIdentifier()), - D->wasDeclaredWithTypename(), D->isParameterPack()); + D->wasDeclaredWithTypename(), D->isParameterPack(), + D->hasTypeConstraint())) + return ToD; + + // Import the type-constraint + if (const TypeConstraint *TC = D->getTypeConstraint()) { + NestedNameSpecifierLoc ToNNS; + DeclarationName ToName; + SourceLocation ToNameLoc; + NamedDecl *ToFoundDecl; + ConceptDecl *ToNamedConcept; + Expr *ToIDC; + if (auto Imp = importSeq(TC->getNestedNameSpecifierLoc(), + TC->getConceptNameInfo().getName(), TC->getConceptNameInfo().getLoc(), + TC->getFoundDecl(), TC->getNamedConcept(), + TC->getImmediatelyDeclaredConstraint())) + std::tie(ToNNS, ToName, ToNameLoc, ToFoundDecl, ToNamedConcept, + ToIDC) = *Imp; + else + return Imp.takeError(); + + TemplateArgumentListInfo ToTAInfo; + const auto *ASTTemplateArgs = TC->getTemplateArgsAsWritten(); + if (ASTTemplateArgs) + if (Error Err = ImportTemplateArgumentListInfo(*ASTTemplateArgs, + ToTAInfo)) + return std::move(Err); + + ToD->setTypeConstraint(ToNNS, DeclarationNameInfo(ToName, ToNameLoc), + ToFoundDecl, ToNamedConcept, + ASTTemplateArgs ? + ASTTemplateArgumentListInfo::Create(Importer.getToContext(), + ToTAInfo) : nullptr, + ToIDC); + } + return ToD; } @@ -5033,7 +5220,6 @@ template <typename T> static auto getTemplateDefinition(T *D) -> T * { } ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { - bool IsFriend = D->getFriendObjectKind() != Decl::FOK_None; // Import the major distinguishing characteristics of this class template. DeclContext *DC, *LexicalDC; @@ -5059,6 +5245,8 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { Decl *Found = FoundDecl; auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found); if (FoundTemplate) { + if (!hasSameVisibilityContext(FoundTemplate, D)) + continue; if (IsStructuralMatch(D, FoundTemplate)) { ClassTemplateDecl *TemplateWithDef = @@ -5108,10 +5296,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { D2->setAccess(D->getAccess()); D2->setLexicalDeclContext(LexicalDC); - if (D->getDeclContext()->containsDeclAndLoad(D)) - DC->addDeclInternal(D2); - if (DC != LexicalDC && D->getLexicalDeclContext()->containsDeclAndLoad(D)) - LexicalDC->addDeclInternal(D2); + addDeclToContexts(D, D2); if (FoundByLookup) { auto *Recent = @@ -5137,9 +5322,6 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { D2->setPreviousDecl(Recent); } - if (LexicalDC != DC && IsFriend) - DC->makeDeclVisibleInContext(D2); - if (FromTemplated->isCompleteDefinition() && !ToTemplated->isCompleteDefinition()) { // FIXME: Import definition! @@ -5164,16 +5346,25 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( if (Error Err = ImportTemplateArguments( D->getTemplateArgs().data(), D->getTemplateArgs().size(), TemplateArgs)) return std::move(Err); - - // Try to find an existing specialization with these template arguments. + // Try to find an existing specialization with these template arguments and + // template parameter list. void *InsertPos = nullptr; ClassTemplateSpecializationDecl *PrevDecl = nullptr; ClassTemplatePartialSpecializationDecl *PartialSpec = dyn_cast<ClassTemplatePartialSpecializationDecl>(D); - if (PartialSpec) - PrevDecl = - ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos); - else + + // Import template parameters. + TemplateParameterList *ToTPList = nullptr; + + if (PartialSpec) { + auto ToTPListOrErr = import(PartialSpec->getTemplateParameters()); + if (!ToTPListOrErr) + return ToTPListOrErr.takeError(); + ToTPList = *ToTPListOrErr; + PrevDecl = ClassTemplate->findPartialSpecialization(TemplateArgs, + *ToTPListOrErr, + InsertPos); + } else PrevDecl = ClassTemplate->findSpecialization(TemplateArgs, InsertPos); if (PrevDecl) { @@ -5232,13 +5423,9 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( return std::move(Err); CanonInjType = CanonInjType.getCanonicalType(); - auto ToTPListOrErr = import(PartialSpec->getTemplateParameters()); - if (!ToTPListOrErr) - return ToTPListOrErr.takeError(); - if (GetImportedOrCreateDecl<ClassTemplatePartialSpecializationDecl>( D2, D, Importer.getToContext(), D->getTagKind(), DC, - *BeginLocOrErr, *IdLocOrErr, *ToTPListOrErr, ClassTemplate, + *BeginLocOrErr, *IdLocOrErr, ToTPList, ClassTemplate, llvm::makeArrayRef(TemplateArgs.data(), TemplateArgs.size()), ToTAInfo, CanonInjType, cast_or_null<ClassTemplatePartialSpecializationDecl>(PrevDecl))) @@ -5246,10 +5433,11 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( // Update InsertPos, because preceding import calls may have invalidated // it by adding new specializations. - if (!ClassTemplate->findPartialSpecialization(TemplateArgs, InsertPos)) + auto *PartSpec2 = cast<ClassTemplatePartialSpecializationDecl>(D2); + if (!ClassTemplate->findPartialSpecialization(TemplateArgs, ToTPList, + InsertPos)) // Add this partial specialization to the class template. - ClassTemplate->AddPartialSpecialization( - cast<ClassTemplatePartialSpecializationDecl>(D2), InsertPos); + ClassTemplate->AddPartialSpecialization(PartSpec2, InsertPos); } else { // Not a partial specialization. if (GetImportedOrCreateDecl( @@ -5275,6 +5463,11 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateSpecializationDecl( LexicalDC->addDeclInternal(D2); } + if (auto BraceRangeOrErr = import(D->getBraceRange())) + D2->setBraceRange(*BraceRangeOrErr); + else + return BraceRangeOrErr.takeError(); + // Import the qualifier, if any. if (auto LocOrErr = import(D->getQualifierLoc())) D2->setQualifierInfo(*LocOrErr); @@ -6273,7 +6466,8 @@ ExpectedStmt ASTNodeImporter::VisitDeclRefExpr(DeclRefExpr *E) { TemplateArgumentListInfo *ToResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { if (Error Err = - ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo)) + ImportTemplateArgumentListInfo(E->getLAngleLoc(), E->getRAngleLoc(), + E->template_arguments(), ToTAInfo)) return std::move(Err); ToResInfo = &ToTAInfo; } @@ -6989,23 +7183,52 @@ ASTNodeImporter::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) { E->requiresZeroInitialization()); } +ExpectedDecl ASTNodeImporter::VisitLifetimeExtendedTemporaryDecl( + LifetimeExtendedTemporaryDecl *D) { + DeclContext *DC, *LexicalDC; + if (Error Err = ImportDeclContext(D, DC, LexicalDC)) + return std::move(Err); + + auto Imp = importSeq(D->getTemporaryExpr(), D->getExtendingDecl()); + // FIXME: the APValue should be imported as well if present. + if (!Imp) + return Imp.takeError(); + + Expr *Temporary; + ValueDecl *ExtendingDecl; + std::tie(Temporary, ExtendingDecl) = *Imp; + // FIXME: Should ManglingNumber get numbers associated with 'to' context? + + LifetimeExtendedTemporaryDecl *To; + if (GetImportedOrCreateDecl(To, D, Temporary, ExtendingDecl, + D->getManglingNumber())) + return To; + + To->setLexicalDeclContext(LexicalDC); + LexicalDC->addDeclInternal(To); + return To; +} + ExpectedStmt ASTNodeImporter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { - auto Imp = importSeq( - E->getType(), E->GetTemporaryExpr(), E->getExtendingDecl()); + auto Imp = importSeq(E->getType(), + E->getLifetimeExtendedTemporaryDecl() ? nullptr + : E->getSubExpr(), + E->getLifetimeExtendedTemporaryDecl()); if (!Imp) return Imp.takeError(); QualType ToType; Expr *ToTemporaryExpr; - const ValueDecl *ToExtendingDecl; - std::tie(ToType, ToTemporaryExpr, ToExtendingDecl) = *Imp; + LifetimeExtendedTemporaryDecl *ToMaterializedDecl; + std::tie(ToType, ToTemporaryExpr, ToMaterializedDecl) = *Imp; + if (!ToTemporaryExpr) + ToTemporaryExpr = cast<Expr>(ToMaterializedDecl->getTemporaryExpr()); - auto *ToMTE = new (Importer.getToContext()) MaterializeTemporaryExpr( - ToType, ToTemporaryExpr, E->isBoundToLvalueReference()); + auto *ToMTE = new (Importer.getToContext()) MaterializeTemporaryExpr( + ToType, ToTemporaryExpr, E->isBoundToLvalueReference(), + ToMaterializedDecl); - // FIXME: Should ManglingNumber get numbers associated with 'to' context? - ToMTE->setExtendingDecl(ToExtendingDecl, E->getManglingNumber()); return ToMTE; } @@ -7320,20 +7543,19 @@ ExpectedStmt ASTNodeImporter::VisitCXXDependentScopeMemberExpr( ExpectedStmt ASTNodeImporter::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { - auto Imp = importSeq( - E->getQualifierLoc(), E->getTemplateKeywordLoc(), E->getDeclName(), - E->getExprLoc(), E->getLAngleLoc(), E->getRAngleLoc()); + auto Imp = importSeq(E->getQualifierLoc(), E->getTemplateKeywordLoc(), + E->getDeclName(), E->getNameInfo().getLoc(), + E->getLAngleLoc(), E->getRAngleLoc()); if (!Imp) return Imp.takeError(); NestedNameSpecifierLoc ToQualifierLoc; - SourceLocation ToTemplateKeywordLoc, ToExprLoc, ToLAngleLoc, ToRAngleLoc; + SourceLocation ToTemplateKeywordLoc, ToNameLoc, ToLAngleLoc, ToRAngleLoc; DeclarationName ToDeclName; - std::tie( - ToQualifierLoc, ToTemplateKeywordLoc, ToDeclName, ToExprLoc, - ToLAngleLoc, ToRAngleLoc) = *Imp; + std::tie(ToQualifierLoc, ToTemplateKeywordLoc, ToDeclName, ToNameLoc, + ToLAngleLoc, ToRAngleLoc) = *Imp; - DeclarationNameInfo ToNameInfo(ToDeclName, ToExprLoc); + DeclarationNameInfo ToNameInfo(ToDeclName, ToNameLoc); if (Error Err = ImportDeclarationNameLoc(E->getNameInfo(), ToNameInfo)) return std::move(Err); @@ -7398,7 +7620,7 @@ ASTNodeImporter::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { else return ToDOrErr.takeError(); - if (E->hasExplicitTemplateArgs() && E->getTemplateKeywordLoc().isValid()) { + if (E->hasExplicitTemplateArgs()) { TemplateArgumentListInfo ToTAInfo; if (Error Err = ImportTemplateArgumentListInfo( E->getLAngleLoc(), E->getRAngleLoc(), E->template_arguments(), @@ -7452,8 +7674,9 @@ ASTNodeImporter::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { TemplateArgumentListInfo ToTAInfo; TemplateArgumentListInfo *ResInfo = nullptr; if (E->hasExplicitTemplateArgs()) { - if (Error Err = - ImportTemplateArgumentListInfo(E->template_arguments(), ToTAInfo)) + TemplateArgumentListInfo FromTAInfo; + E->copyTemplateArgumentsInto(FromTAInfo); + if (Error Err = ImportTemplateArgumentListInfo(FromTAInfo, ToTAInfo)) return std::move(Err); ResInfo = &ToTAInfo; } @@ -8266,8 +8489,14 @@ ASTImporter::Import(NestedNameSpecifierLoc FromNNS) { return std::move(Err); TypeSourceInfo *TSI = getToContext().getTrivialTypeSourceInfo( QualType(Spec->getAsType(), 0), ToTLoc); - Builder.Extend(getToContext(), ToLocalBeginLoc, TSI->getTypeLoc(), - ToLocalEndLoc); + if (Kind == NestedNameSpecifier::TypeSpecWithTemplate) + // ToLocalBeginLoc is here the location of the 'template' keyword. + Builder.Extend(getToContext(), ToLocalBeginLoc, TSI->getTypeLoc(), + ToLocalEndLoc); + else + // No location for 'template' keyword here. + Builder.Extend(getToContext(), SourceLocation{}, TSI->getTypeLoc(), + ToLocalEndLoc); break; } diff --git a/clang/lib/AST/ASTTypeTraits.cpp b/clang/lib/AST/ASTTypeTraits.cpp index 6b7f6ec51086..a5570c329ae8 100644 --- a/clang/lib/AST/ASTTypeTraits.cpp +++ b/clang/lib/AST/ASTTypeTraits.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OpenMPClause.h" namespace clang { namespace ast_type_traits { diff --git a/clang/lib/AST/Comment.cpp b/clang/lib/AST/Comment.cpp index 23dc7ba93591..a02cc9d119fe 100644 --- a/clang/lib/AST/Comment.cpp +++ b/clang/lib/AST/Comment.cpp @@ -379,11 +379,11 @@ StringRef TParamCommandComment::getParamName(const FullComment *FC) const { assert(isPositionValid()); const TemplateParameterList *TPL = FC->getDeclInfo()->TemplateParameters; for (unsigned i = 0, e = getDepth(); i != e; ++i) { - if (i == e-1) + assert(TPL && "Unknown TemplateParameterList"); + if (i == e - 1) return TPL->getParam(getIndex(i))->getName(); const NamedDecl *Param = TPL->getParam(getIndex(i)); - if (const TemplateTemplateParmDecl *TTP = - dyn_cast<TemplateTemplateParmDecl>(Param)) + if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) TPL = TTP->getTemplateParameters(); } return ""; diff --git a/clang/lib/AST/CommentSema.cpp b/clang/lib/AST/CommentSema.cpp index 69d61dc55162..53c1832d1dd2 100644 --- a/clang/lib/AST/CommentSema.cpp +++ b/clang/lib/AST/CommentSema.cpp @@ -676,9 +676,8 @@ void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) { D->hasAttr<UnavailableAttr>()) return; - Diag(Command->getLocation(), - diag::warn_doc_deprecated_not_sync) - << Command->getSourceRange(); + Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync) + << Command->getSourceRange() << Command->getCommandMarker(); // Try to emit a fixit with a deprecation attribute. if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { @@ -689,24 +688,41 @@ void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) { FD->doesThisDeclarationHaveABody()) return; - StringRef AttributeSpelling = "__attribute__((deprecated))"; + const LangOptions &LO = FD->getASTContext().getLangOpts(); + const bool DoubleSquareBracket = LO.CPlusPlus14 || LO.C2x; + StringRef AttributeSpelling = + DoubleSquareBracket ? "[[deprecated]]" : "__attribute__((deprecated))"; if (PP) { - TokenValue Tokens[] = { - tok::kw___attribute, tok::l_paren, tok::l_paren, - PP->getIdentifierInfo("deprecated"), - tok::r_paren, tok::r_paren - }; - StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), - Tokens); - if (!MacroName.empty()) - AttributeSpelling = MacroName; + // Try to find a replacement macro: + // - In C2x/C++14 we prefer [[deprecated]]. + // - If not found or an older C/C++ look for __attribute__((deprecated)). + StringRef MacroName; + if (DoubleSquareBracket) { + TokenValue Tokens[] = {tok::l_square, tok::l_square, + PP->getIdentifierInfo("deprecated"), + tok::r_square, tok::r_square}; + MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens); + if (!MacroName.empty()) + AttributeSpelling = MacroName; + } + + if (MacroName.empty()) { + TokenValue Tokens[] = { + tok::kw___attribute, tok::l_paren, + tok::l_paren, PP->getIdentifierInfo("deprecated"), + tok::r_paren, tok::r_paren}; + StringRef MacroName = + PP->getLastMacroWithSpelling(FD->getLocation(), Tokens); + if (!MacroName.empty()) + AttributeSpelling = MacroName; + } } - SmallString<64> TextToInsert(" "); - TextToInsert += AttributeSpelling; - Diag(FD->getEndLoc(), diag::note_add_deprecation_attr) - << FixItHint::CreateInsertion(FD->getEndLoc().getLocWithOffset(1), - TextToInsert); + SmallString<64> TextToInsert = AttributeSpelling; + TextToInsert += " "; + SourceLocation Loc = FD->getSourceRange().getBegin(); + Diag(Loc, diag::note_add_deprecation_attr) + << FixItHint::CreateInsertion(Loc, TextToInsert); } } @@ -1127,6 +1143,7 @@ Sema::getInlineCommandRenderKind(StringRef Name) const { .Case("b", InlineCommandComment::RenderBold) .Cases("c", "p", InlineCommandComment::RenderMonospaced) .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized) + .Case("anchor", InlineCommandComment::RenderAnchor) .Default(InlineCommandComment::RenderNormal); } diff --git a/clang/lib/AST/ComparisonCategories.cpp b/clang/lib/AST/ComparisonCategories.cpp index ee4c1b0443a3..07673230357f 100644 --- a/clang/lib/AST/ComparisonCategories.cpp +++ b/clang/lib/AST/ComparisonCategories.cpp @@ -19,6 +19,26 @@ using namespace clang; +Optional<ComparisonCategoryType> +clang::getComparisonCategoryForBuiltinCmp(QualType T) { + using CCT = ComparisonCategoryType; + + if (T->isIntegralOrEnumerationType()) + return CCT::StrongOrdering; + + if (T->isRealFloatingType()) + return CCT::PartialOrdering; + + // C++2a [expr.spaceship]p8: If the composite pointer type is an object + // pointer type, p <=> q is of type std::strong_ordering. + // Note: this assumes neither operand is a null pointer constant. + if (T->isObjectPointerType()) + return CCT::StrongOrdering; + + // TODO: Extend support for operator<=> to ObjC types. + return llvm::None; +} + bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const { assert(VD && "must have var decl"); if (!VD->checkInitIsICE()) @@ -59,7 +79,7 @@ ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo( // a new entry representing it. DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup( &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind))); - if (Lookup.size() != 1 || !isa<VarDecl>(Lookup.front())) + if (Lookup.empty() || !isa<VarDecl>(Lookup.front())) return nullptr; Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front())); return &Objects.back(); @@ -70,7 +90,7 @@ static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx, if (!StdNS) { DeclContextLookupResult Lookup = Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std")); - if (Lookup.size() == 1) + if (!Lookup.empty()) StdNS = dyn_cast<NamespaceDecl>(Lookup.front()); } return StdNS; @@ -81,7 +101,7 @@ static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx, ComparisonCategoryType Kind) { StringRef Name = ComparisonCategories::getCategoryString(Kind); DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name)); - if (Lookup.size() == 1) + if (!Lookup.empty()) if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front())) return RD; return nullptr; @@ -150,10 +170,6 @@ QualType ComparisonCategoryInfo::getType() const { StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) { using CCKT = ComparisonCategoryType; switch (Kind) { - case CCKT::WeakEquality: - return "weak_equality"; - case CCKT::StrongEquality: - return "strong_equality"; case CCKT::PartialOrdering: return "partial_ordering"; case CCKT::WeakOrdering: @@ -169,12 +185,8 @@ StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) { switch (Kind) { case CCVT::Equal: return "equal"; - case CCVT::Nonequal: - return "nonequal"; case CCVT::Equivalent: return "equivalent"; - case CCVT::Nonequivalent: - return "nonequivalent"; case CCVT::Less: return "less"; case CCVT::Greater: @@ -190,20 +202,11 @@ ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) { using CCT = ComparisonCategoryType; using CCR = ComparisonCategoryResult; std::vector<CCR> Values; - Values.reserve(6); - Values.push_back(CCR::Equivalent); - bool IsStrong = (Type == CCT::StrongEquality || Type == CCT::StrongOrdering); - if (IsStrong) - Values.push_back(CCR::Equal); - if (Type == CCT::StrongOrdering || Type == CCT::WeakOrdering || - Type == CCT::PartialOrdering) { - Values.push_back(CCR::Less); - Values.push_back(CCR::Greater); - } else { - Values.push_back(CCR::Nonequivalent); - if (IsStrong) - Values.push_back(CCR::Nonequal); - } + Values.reserve(4); + bool IsStrong = Type == CCT::StrongOrdering; + Values.push_back(IsStrong ? CCR::Equal : CCR::Equivalent); + Values.push_back(CCR::Less); + Values.push_back(CCR::Greater); if (Type == CCT::PartialOrdering) Values.push_back(CCR::Unordered); return Values; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 80235d8496d2..0d30f64b992e 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" +#include "clang/AST/Attr.h" #include "clang/AST/CanonicalType.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -55,8 +56,8 @@ #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" @@ -901,6 +902,10 @@ LinkageComputer::getLVForNamespaceScopeDecl(const NamedDecl *D, if (!isExternallyVisible(LV.getLinkage())) return LinkageInfo(LV.getLinkage(), DefaultVisibility, false); + // Mark the symbols as hidden when compiling for the device. + if (Context.getLangOpts().OpenMP && Context.getLangOpts().OpenMPIsDevice) + LV.mergeVisibility(HiddenVisibility, /*newExplicit=*/false); + return LV; } @@ -1815,6 +1820,12 @@ SourceLocation DeclaratorDecl::getTypeSpecStartLoc() const { return SourceLocation(); } +SourceLocation DeclaratorDecl::getTypeSpecEndLoc() const { + TypeSourceInfo *TSI = getTypeSourceInfo(); + if (TSI) return TSI->getTypeLoc().getEndLoc(); + return SourceLocation(); +} + void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { if (QualifierLoc) { // Make sure the extended decl info is allocated. @@ -1828,23 +1839,27 @@ void DeclaratorDecl::setQualifierInfo(NestedNameSpecifierLoc QualifierLoc) { } // Set qualifier info. getExtInfo()->QualifierLoc = QualifierLoc; - } else { + } else if (hasExtInfo()) { // Here Qualifier == 0, i.e., we are removing the qualifier (if any). - if (hasExtInfo()) { - if (getExtInfo()->NumTemplParamLists == 0) { - // Save type source info pointer. - TypeSourceInfo *savedTInfo = getExtInfo()->TInfo; - // Deallocate the extended decl info. - getASTContext().Deallocate(getExtInfo()); - // Restore savedTInfo into (non-extended) decl info. - DeclInfo = savedTInfo; - } - else - getExtInfo()->QualifierLoc = QualifierLoc; - } + getExtInfo()->QualifierLoc = QualifierLoc; } } +void DeclaratorDecl::setTrailingRequiresClause(Expr *TrailingRequiresClause) { + assert(TrailingRequiresClause); + // Make sure the extended decl info is allocated. + if (!hasExtInfo()) { + // Save (non-extended) type source info pointer. + auto *savedTInfo = DeclInfo.get<TypeSourceInfo*>(); + // Allocate external info struct. + DeclInfo = new (getASTContext()) ExtInfo; + // Restore savedTInfo into (extended) decl info. + getExtInfo()->TInfo = savedTInfo; + } + // Set requires clause info. + getExtInfo()->TrailingRequiresClause = TrailingRequiresClause; +} + void DeclaratorDecl::setTemplateParameterListsInfo( ASTContext &Context, ArrayRef<TemplateParameterList *> TPLists) { assert(!TPLists.empty()); @@ -2766,10 +2781,11 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, StorageClass S, bool isInlineSpecified, - ConstexprSpecKind ConstexprKind) + ConstexprSpecKind ConstexprKind, + Expr *TrailingRequiresClause) : DeclaratorDecl(DK, DC, NameInfo.getLoc(), NameInfo.getName(), T, TInfo, StartLoc), - DeclContext(DK), redeclarable_base(C), ODRHash(0), + DeclContext(DK), redeclarable_base(C), Body(), ODRHash(0), EndRangeLoc(NameInfo.getEndLoc()), DNLoc(NameInfo.getInfo()) { assert(T.isNull() || T->isFunctionType()); FunctionDeclBits.SClass = S; @@ -2784,16 +2800,20 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, FunctionDeclBits.IsTrivialForCall = false; FunctionDeclBits.IsDefaulted = false; FunctionDeclBits.IsExplicitlyDefaulted = false; + FunctionDeclBits.HasDefaultedFunctionInfo = false; FunctionDeclBits.HasImplicitReturnZero = false; FunctionDeclBits.IsLateTemplateParsed = false; FunctionDeclBits.ConstexprKind = ConstexprKind; FunctionDeclBits.InstantiationIsPending = false; FunctionDeclBits.UsesSEHTry = false; + FunctionDeclBits.UsesFPIntrin = false; FunctionDeclBits.HasSkippedBody = false; FunctionDeclBits.WillHaveBody = false; FunctionDeclBits.IsMultiVersion = false; FunctionDeclBits.IsCopyDeductionCandidate = false; FunctionDeclBits.HasODRHash = false; + if (TrailingRequiresClause) + setTrailingRequiresClause(TrailingRequiresClause); } void FunctionDecl::getNameForDiagnostic( @@ -2810,6 +2830,32 @@ bool FunctionDecl::isVariadic() const { return false; } +FunctionDecl::DefaultedFunctionInfo * +FunctionDecl::DefaultedFunctionInfo::Create(ASTContext &Context, + ArrayRef<DeclAccessPair> Lookups) { + DefaultedFunctionInfo *Info = new (Context.Allocate( + totalSizeToAlloc<DeclAccessPair>(Lookups.size()), + std::max(alignof(DefaultedFunctionInfo), alignof(DeclAccessPair)))) + DefaultedFunctionInfo; + Info->NumLookups = Lookups.size(); + std::uninitialized_copy(Lookups.begin(), Lookups.end(), + Info->getTrailingObjects<DeclAccessPair>()); + return Info; +} + +void FunctionDecl::setDefaultedFunctionInfo(DefaultedFunctionInfo *Info) { + assert(!FunctionDeclBits.HasDefaultedFunctionInfo && "already have this"); + assert(!Body && "can't replace function body with defaulted function info"); + + FunctionDeclBits.HasDefaultedFunctionInfo = true; + DefaultedInfo = Info; +} + +FunctionDecl::DefaultedFunctionInfo * +FunctionDecl::getDefaultedFunctionInfo() const { + return FunctionDeclBits.HasDefaultedFunctionInfo ? DefaultedInfo : nullptr; +} + bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const { for (auto I : redecls()) { if (I->doesThisDeclarationHaveABody()) { @@ -2821,8 +2867,7 @@ bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const { return false; } -bool FunctionDecl::hasTrivialBody() const -{ +bool FunctionDecl::hasTrivialBody() const { Stmt *S = getBody(); if (!S) { // Since we don't have a body for this function, we don't know if it's @@ -2850,6 +2895,8 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { if (!hasBody(Definition)) return nullptr; + assert(!Definition->FunctionDeclBits.HasDefaultedFunctionInfo && + "definition should not have a body"); if (Definition->Body) return Definition->Body.get(getASTContext().getExternalSource()); @@ -2857,7 +2904,8 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { } void FunctionDecl::setBody(Stmt *B) { - Body = B; + FunctionDeclBits.HasDefaultedFunctionInfo = false; + Body = LazyDeclStmtPtr(B); if (B) EndRangeLoc = B->getEndLoc(); } @@ -2998,6 +3046,14 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const return Params == FPT->getNumParams(); } +bool FunctionDecl::isInlineBuiltinDeclaration() const { + if (!getBuiltinID()) + return false; + + const FunctionDecl *Definition; + return hasBody(Definition) && Definition->isInlineSpecified(); +} + bool FunctionDecl::isDestroyingOperatorDelete() const { // C++ P0722: // Within a class C, a single object deallocation function with signature @@ -3115,10 +3171,17 @@ FunctionDecl *FunctionDecl::getCanonicalDecl() { return getFirstDecl(); } /// functions as their wrapped builtins. This shouldn't be done in general, but /// it's useful in Sema to diagnose calls to wrappers based on their semantics. unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const { - if (!getIdentifier()) - return 0; + unsigned BuiltinID; + + if (const auto *AMAA = getAttr<ArmMveAliasAttr>()) { + BuiltinID = AMAA->getBuiltinName()->getBuiltinID(); + } else { + if (!getIdentifier()) + return 0; + + BuiltinID = getIdentifier()->getBuiltinID(); + } - unsigned BuiltinID = getIdentifier()->getBuiltinID(); if (!BuiltinID) return 0; @@ -3142,7 +3205,8 @@ unsigned FunctionDecl::getBuiltinID(bool ConsiderWrapperFunctions) const { // If the function is marked "overloadable", it has a different mangled name // and is not the C library function. - if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>()) + if (!ConsiderWrapperFunctions && hasAttr<OverloadableAttr>() && + !hasAttr<ArmMveAliasAttr>()) return 0; if (!Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) @@ -3290,9 +3354,9 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body.isValid(); + FoundBody |= Prev->doesThisDeclarationHaveABody(); - if (Prev->Body) { + if (Prev->doesThisDeclarationHaveABody()) { // If it's not the case that both 'inline' and 'extern' are // specified on the definition, then it is always externally visible. if (!Prev->isInlineSpecified() || @@ -3315,19 +3379,21 @@ bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const { const FunctionDecl *Prev = this; bool FoundBody = false; while ((Prev = Prev->getPreviousDecl())) { - FoundBody |= Prev->Body.isValid(); + FoundBody |= Prev->doesThisDeclarationHaveABody(); if (RedeclForcesDefC99(Prev)) return false; } return FoundBody; } -SourceRange FunctionDecl::getReturnTypeSourceRange() const { +FunctionTypeLoc FunctionDecl::getFunctionTypeLoc() const { const TypeSourceInfo *TSI = getTypeSourceInfo(); - if (!TSI) - return SourceRange(); - FunctionTypeLoc FTL = - TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>(); + return TSI ? TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>() + : FunctionTypeLoc(); +} + +SourceRange FunctionDecl::getReturnTypeSourceRange() const { + FunctionTypeLoc FTL = getFunctionTypeLoc(); if (!FTL) return SourceRange(); @@ -3342,16 +3408,25 @@ SourceRange FunctionDecl::getReturnTypeSourceRange() const { return RTRange; } -SourceRange FunctionDecl::getExceptionSpecSourceRange() const { - const TypeSourceInfo *TSI = getTypeSourceInfo(); - if (!TSI) - return SourceRange(); - FunctionTypeLoc FTL = - TSI->getTypeLoc().IgnoreParens().getAs<FunctionTypeLoc>(); - if (!FTL) +SourceRange FunctionDecl::getParametersSourceRange() const { + unsigned NP = getNumParams(); + SourceLocation EllipsisLoc = getEllipsisLoc(); + + if (NP == 0 && EllipsisLoc.isInvalid()) return SourceRange(); - return FTL.getExceptionSpecRange(); + SourceLocation Begin = + NP > 0 ? ParamInfo[0]->getSourceRange().getBegin() : EllipsisLoc; + SourceLocation End = EllipsisLoc.isValid() + ? EllipsisLoc + : ParamInfo[NP - 1]->getSourceRange().getEnd(); + + return SourceRange(Begin, End); +} + +SourceRange FunctionDecl::getExceptionSpecSourceRange() const { + FunctionTypeLoc FTL = getFunctionTypeLoc(); + return FTL ? FTL.getExceptionSpecRange() : SourceRange(); } /// For an inline function definition in C, or for a gnu_inline function @@ -3812,6 +3887,11 @@ unsigned FunctionDecl::getMemoryFunctionKind() const { case Builtin::BImemcpy: return Builtin::BImemcpy; + case Builtin::BI__builtin_mempcpy: + case Builtin::BI__builtin___mempcpy_chk: + case Builtin::BImempcpy: + return Builtin::BImempcpy; + case Builtin::BI__builtin_memmove: case Builtin::BI__builtin___memmove_chk: case Builtin::BImemmove: @@ -3869,6 +3949,8 @@ unsigned FunctionDecl::getMemoryFunctionKind() const { return Builtin::BImemset; else if (FnInfo->isStr("memcpy")) return Builtin::BImemcpy; + else if (FnInfo->isStr("mempcpy")) + return Builtin::BImempcpy; else if (FnInfo->isStr("memmove")) return Builtin::BImemmove; else if (FnInfo->isStr("memcmp")) @@ -4582,7 +4664,7 @@ LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, unsigned ID) { } void LabelDecl::setMSAsmLabel(StringRef Name) { - char *Buffer = new (getASTContext(), 1) char[Name.size() + 1]; +char *Buffer = new (getASTContext(), 1) char[Name.size() + 1]; memcpy(Buffer, Name.data(), Name.size()); Buffer[Name.size()] = '\0'; MSAsmName = Buffer; @@ -4623,10 +4705,12 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, QualType T, TypeSourceInfo *TInfo, StorageClass SC, bool isInlineSpecified, bool hasWrittenPrototype, - ConstexprSpecKind ConstexprKind) { + ConstexprSpecKind ConstexprKind, + Expr *TrailingRequiresClause) { FunctionDecl *New = new (C, DC) FunctionDecl(Function, C, DC, StartLoc, NameInfo, T, TInfo, - SC, isInlineSpecified, ConstexprKind); + SC, isInlineSpecified, ConstexprKind, + TrailingRequiresClause); New->setHasWrittenPrototype(hasWrittenPrototype); return New; } @@ -4634,7 +4718,7 @@ FunctionDecl *FunctionDecl::Create(ASTContext &C, DeclContext *DC, FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) FunctionDecl(Function, C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, - SC_None, false, CSK_unspecified); + SC_None, false, CSK_unspecified, nullptr); } BlockDecl *BlockDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L) { diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 77a3a4c679a1..6ee767ccecf7 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -803,6 +803,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case OMPRequires: case OMPCapturedExpr: case Empty: + case LifetimeExtendedTemporary: // Never looked up by name. return 0; } diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 12ec44fa0279..2ead1e70ea0d 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTLambda.h" #include "clang/AST/ASTMutationListener.h" #include "clang/AST/ASTUnresolvedSet.h" +#include "clang/AST/Attr.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclTemplate.h" @@ -413,7 +414,7 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().HasIrrelevantDestructor = false; // C++11 [class.copy]p18: - // The implicitly-declared copy assignment oeprator for a class X will + // The implicitly-declared copy assignment operator for a class X will // have the form 'X& X::operator=(const X&)' if each direct base class B // of X has a copy assignment operator whose parameter is of type 'const // B&', 'const volatile B&', or 'B' [...] @@ -737,49 +738,55 @@ void CXXRecordDecl::addedMember(Decl *D) { // Handle constructors. if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) { - if (!Constructor->isImplicit()) { - // Note that we have a user-declared constructor. - data().UserDeclaredConstructor = true; + if (Constructor->isInheritingConstructor()) { + // Ignore constructor shadow declarations. They are lazily created and + // so shouldn't affect any properties of the class. + } else { + if (!Constructor->isImplicit()) { + // Note that we have a user-declared constructor. + data().UserDeclaredConstructor = true; - // C++ [class]p4: - // A POD-struct is an aggregate class [...] - // Since the POD bit is meant to be C++03 POD-ness, clear it even if the - // type is technically an aggregate in C++0x since it wouldn't be in 03. - data().PlainOldData = false; - } + // C++ [class]p4: + // A POD-struct is an aggregate class [...] + // Since the POD bit is meant to be C++03 POD-ness, clear it even if + // the type is technically an aggregate in C++0x since it wouldn't be + // in 03. + data().PlainOldData = false; + } - if (Constructor->isDefaultConstructor()) { - SMKind |= SMF_DefaultConstructor; + if (Constructor->isDefaultConstructor()) { + SMKind |= SMF_DefaultConstructor; - if (Constructor->isUserProvided()) - data().UserProvidedDefaultConstructor = true; - if (Constructor->isConstexpr()) - data().HasConstexprDefaultConstructor = true; - if (Constructor->isDefaulted()) - data().HasDefaultedDefaultConstructor = true; - } + if (Constructor->isUserProvided()) + data().UserProvidedDefaultConstructor = true; + if (Constructor->isConstexpr()) + data().HasConstexprDefaultConstructor = true; + if (Constructor->isDefaulted()) + data().HasDefaultedDefaultConstructor = true; + } - if (!FunTmpl) { - unsigned Quals; - if (Constructor->isCopyConstructor(Quals)) { - SMKind |= SMF_CopyConstructor; + if (!FunTmpl) { + unsigned Quals; + if (Constructor->isCopyConstructor(Quals)) { + SMKind |= SMF_CopyConstructor; - if (Quals & Qualifiers::Const) - data().HasDeclaredCopyConstructorWithConstParam = true; - } else if (Constructor->isMoveConstructor()) - SMKind |= SMF_MoveConstructor; - } + if (Quals & Qualifiers::Const) + data().HasDeclaredCopyConstructorWithConstParam = true; + } else if (Constructor->isMoveConstructor()) + SMKind |= SMF_MoveConstructor; + } - // C++11 [dcl.init.aggr]p1: DR1518 - // An aggregate is an array or a class with no user-provided [or] - // explicit [...] constructors - // C++20 [dcl.init.aggr]p1: - // An aggregate is an array or a class with no user-declared [...] - // constructors - if (getASTContext().getLangOpts().CPlusPlus2a - ? !Constructor->isImplicit() - : (Constructor->isUserProvided() || Constructor->isExplicit())) - data().Aggregate = false; + // C++11 [dcl.init.aggr]p1: DR1518 + // An aggregate is an array or a class with no user-provided [or] + // explicit [...] constructors + // C++20 [dcl.init.aggr]p1: + // An aggregate is an array or a class with no user-declared [...] + // constructors + if (getASTContext().getLangOpts().CPlusPlus2a + ? !Constructor->isImplicit() + : (Constructor->isUserProvided() || Constructor->isExplicit())) + data().Aggregate = false; + } } // Handle constructors, including those inherited from base classes. @@ -1511,14 +1518,12 @@ static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { /// \param VOutput the set to which to add conversions from virtual bases /// \param HiddenVBaseCs the set of conversions which were hidden in a /// virtual base along some inheritance path -static void CollectVisibleConversions(ASTContext &Context, - CXXRecordDecl *Record, - bool InVirtual, - AccessSpecifier Access, - const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes, - ASTUnresolvedSet &Output, - UnresolvedSetImpl &VOutput, - llvm::SmallPtrSet<NamedDecl*, 8> &HiddenVBaseCs) { +static void CollectVisibleConversions( + ASTContext &Context, const CXXRecordDecl *Record, bool InVirtual, + AccessSpecifier Access, + const llvm::SmallPtrSet<CanQualType, 8> &ParentHiddenTypes, + ASTUnresolvedSet &Output, UnresolvedSetImpl &VOutput, + llvm::SmallPtrSet<NamedDecl *, 8> &HiddenVBaseCs) { // The set of types which have conversions in this class or its // subclasses. As an optimization, we don't copy the derived set // unless it might change. @@ -1559,7 +1564,7 @@ static void CollectVisibleConversions(ASTContext &Context, // Collect information recursively from any base classes. for (const auto &I : Record->bases()) { - const RecordType *RT = I.getType()->getAs<RecordType>(); + const auto *RT = I.getType()->getAs<RecordType>(); if (!RT) continue; AccessSpecifier BaseAccess @@ -1577,7 +1582,7 @@ static void CollectVisibleConversions(ASTContext &Context, /// This would be extremely straightforward if it weren't for virtual /// bases. It might be worth special-casing that, really. static void CollectVisibleConversions(ASTContext &Context, - CXXRecordDecl *Record, + const CXXRecordDecl *Record, ASTUnresolvedSet &Output) { // The collection of all conversions in virtual bases that we've // found. These will be added to the output as long as they don't @@ -1601,7 +1606,7 @@ static void CollectVisibleConversions(ASTContext &Context, // Recursively collect conversions from base classes. for (const auto &I : Record->bases()) { - const RecordType *RT = I.getType()->getAs<RecordType>(); + const auto *RT = I.getType()->getAs<RecordType>(); if (!RT) continue; CollectVisibleConversions(Context, cast<CXXRecordDecl>(RT->getDecl()), @@ -1620,7 +1625,7 @@ static void CollectVisibleConversions(ASTContext &Context, /// getVisibleConversionFunctions - get all conversion functions visible /// in current class; including conversion function templates. llvm::iterator_range<CXXRecordDecl::conversion_iterator> -CXXRecordDecl::getVisibleConversionFunctions() { +CXXRecordDecl::getVisibleConversionFunctions() const { ASTContext &Ctx = getASTContext(); ASTUnresolvedSet *Set; @@ -2042,16 +2047,19 @@ CXXMethodDecl *CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD, QualType T, TypeSourceInfo *TInfo, StorageClass SC, bool isInline, ConstexprSpecKind ConstexprKind, - SourceLocation EndLocation) { + SourceLocation EndLocation, + Expr *TrailingRequiresClause) { return new (C, RD) CXXMethodDecl(CXXMethod, C, RD, StartLoc, NameInfo, T, TInfo, SC, - isInline, ConstexprKind, EndLocation); + isInline, ConstexprKind, EndLocation, + TrailingRequiresClause); } CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) CXXMethodDecl( CXXMethod, C, nullptr, SourceLocation(), DeclarationNameInfo(), - QualType(), nullptr, SC_None, false, CSK_unspecified, SourceLocation()); + QualType(), nullptr, SC_None, false, CSK_unspecified, SourceLocation(), + nullptr); } CXXMethodDecl *CXXMethodDecl::getDevirtualizedMethod(const Expr *Base, @@ -2432,9 +2440,11 @@ CXXConstructorDecl::CXXConstructorDecl( ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared, - ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited) + ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited, + Expr *TrailingRequiresClause) : CXXMethodDecl(CXXConstructor, C, RD, StartLoc, NameInfo, T, TInfo, - SC_None, isInline, ConstexprKind, SourceLocation()) { + SC_None, isInline, ConstexprKind, SourceLocation(), + TrailingRequiresClause) { setNumCtorInitializers(0); setInheritingConstructor(static_cast<bool>(Inherited)); setImplicit(isImplicitlyDeclared); @@ -2458,7 +2468,7 @@ CXXConstructorDecl *CXXConstructorDecl::CreateDeserialized(ASTContext &C, auto *Result = new (C, ID, Extra) CXXConstructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, ExplicitSpecifier(), false, false, - CSK_unspecified, InheritedConstructor()); + CSK_unspecified, InheritedConstructor(), nullptr); Result->setInheritingConstructor(isInheritingConstructor); Result->CXXConstructorDeclBits.HasTrailingExplicitSpecifier = hasTraillingExplicit; @@ -2470,7 +2480,8 @@ CXXConstructorDecl *CXXConstructorDecl::Create( ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, ExplicitSpecifier ES, bool isInline, bool isImplicitlyDeclared, - ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited) { + ConstexprSpecKind ConstexprKind, InheritedConstructor Inherited, + Expr *TrailingRequiresClause) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName && "Name must refer to a constructor"); @@ -2479,7 +2490,8 @@ CXXConstructorDecl *CXXConstructorDecl::Create( Inherited ? 1 : 0, ES.getExpr() ? 1 : 0); return new (C, RD, Extra) CXXConstructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, ES, isInline, - isImplicitlyDeclared, ConstexprKind, Inherited); + isImplicitlyDeclared, ConstexprKind, Inherited, + TrailingRequiresClause); } CXXConstructorDecl::init_const_iterator CXXConstructorDecl::init_begin() const { @@ -2600,19 +2612,22 @@ CXXDestructorDecl * CXXDestructorDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) CXXDestructorDecl(C, nullptr, SourceLocation(), DeclarationNameInfo(), - QualType(), nullptr, false, false, CSK_unspecified); + QualType(), nullptr, false, false, CSK_unspecified, + nullptr); } CXXDestructorDecl *CXXDestructorDecl::Create( ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, - bool isInline, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind) { + bool isInline, bool isImplicitlyDeclared, ConstexprSpecKind ConstexprKind, + Expr *TrailingRequiresClause) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXDestructorName && "Name must refer to a destructor"); return new (C, RD) CXXDestructorDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, - isImplicitlyDeclared, ConstexprKind); + isImplicitlyDeclared, ConstexprKind, + TrailingRequiresClause); } void CXXDestructorDecl::setOperatorDelete(FunctionDecl *OD, Expr *ThisArg) { @@ -2631,20 +2646,20 @@ CXXConversionDecl * CXXConversionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) CXXConversionDecl( C, nullptr, SourceLocation(), DeclarationNameInfo(), QualType(), nullptr, - false, ExplicitSpecifier(), CSK_unspecified, SourceLocation()); + false, ExplicitSpecifier(), CSK_unspecified, SourceLocation(), nullptr); } CXXConversionDecl *CXXConversionDecl::Create( ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, const DeclarationNameInfo &NameInfo, QualType T, TypeSourceInfo *TInfo, bool isInline, ExplicitSpecifier ES, ConstexprSpecKind ConstexprKind, - SourceLocation EndLocation) { + SourceLocation EndLocation, Expr *TrailingRequiresClause) { assert(NameInfo.getName().getNameKind() == DeclarationName::CXXConversionFunctionName && "Name must refer to a conversion function"); return new (C, RD) CXXConversionDecl(C, RD, StartLoc, NameInfo, T, TInfo, isInline, ES, - ConstexprKind, EndLocation); + ConstexprKind, EndLocation, TrailingRequiresClause); } bool CXXConversionDecl::isLambdaToBlockPointerConversion() const { @@ -2796,6 +2811,36 @@ NamespaceAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) { SourceLocation(), nullptr); } +void LifetimeExtendedTemporaryDecl::anchor() {} + +/// Retrieve the storage duration for the materialized temporary. +StorageDuration LifetimeExtendedTemporaryDecl::getStorageDuration() const { + const ValueDecl *ExtendingDecl = getExtendingDecl(); + if (!ExtendingDecl) + return SD_FullExpression; + // FIXME: This is not necessarily correct for a temporary materialized + // within a default initializer. + if (isa<FieldDecl>(ExtendingDecl)) + return SD_Automatic; + // FIXME: This only works because storage class specifiers are not allowed + // on decomposition declarations. + if (isa<BindingDecl>(ExtendingDecl)) + return ExtendingDecl->getDeclContext()->isFunctionOrMethod() ? SD_Automatic + : SD_Static; + return cast<VarDecl>(ExtendingDecl)->getStorageDuration(); +} + +APValue *LifetimeExtendedTemporaryDecl::getOrCreateValue(bool MayCreate) const { + assert(getStorageDuration() == SD_Static && + "don't need to cache the computed value for this temporary"); + if (MayCreate && !Value) { + Value = (new (getASTContext()) APValue); + getASTContext().addDestruction(Value); + } + assert(Value && "may not be null"); + return Value; +} + void UsingShadowDecl::anchor() {} UsingShadowDecl::UsingShadowDecl(Kind K, ASTContext &C, DeclContext *DC, diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index bf748fbab8e9..9a84e3c4a510 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -775,14 +775,12 @@ ObjCMethodDecl *ObjCInterfaceDecl::lookupPrivateMethod( // ObjCMethodDecl //===----------------------------------------------------------------------===// -ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, - Selector SelInfo, QualType T, - TypeSourceInfo *ReturnTInfo, - DeclContext *contextDecl, bool isInstance, - bool isVariadic, bool isPropertyAccessor, - bool isImplicitlyDeclared, bool isDefined, - ImplementationControl impControl, - bool HasRelatedResultType) +ObjCMethodDecl::ObjCMethodDecl( + SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo, + QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl, + bool isInstance, bool isVariadic, bool isPropertyAccessor, + bool isSynthesizedAccessorStub, bool isImplicitlyDeclared, bool isDefined, + ImplementationControl impControl, bool HasRelatedResultType) : NamedDecl(ObjCMethod, contextDecl, beginLoc, SelInfo), DeclContext(ObjCMethod), MethodDeclType(T), ReturnTInfo(ReturnTInfo), DeclEndLoc(endLoc) { @@ -793,6 +791,7 @@ ObjCMethodDecl::ObjCMethodDecl(SourceLocation beginLoc, SourceLocation endLoc, setInstanceMethod(isInstance); setVariadic(isVariadic); setPropertyAccessor(isPropertyAccessor); + setSynthesizedAccessorStub(isSynthesizedAccessorStub); setDefined(isDefined); setIsRedeclaration(false); setHasRedeclaration(false); @@ -810,12 +809,13 @@ ObjCMethodDecl *ObjCMethodDecl::Create( ASTContext &C, SourceLocation beginLoc, SourceLocation endLoc, Selector SelInfo, QualType T, TypeSourceInfo *ReturnTInfo, DeclContext *contextDecl, bool isInstance, bool isVariadic, - bool isPropertyAccessor, bool isImplicitlyDeclared, bool isDefined, - ImplementationControl impControl, bool HasRelatedResultType) { + bool isPropertyAccessor, bool isSynthesizedAccessorStub, + bool isImplicitlyDeclared, bool isDefined, ImplementationControl impControl, + bool HasRelatedResultType) { return new (C, contextDecl) ObjCMethodDecl( beginLoc, endLoc, SelInfo, T, ReturnTInfo, contextDecl, isInstance, - isVariadic, isPropertyAccessor, isImplicitlyDeclared, isDefined, - impControl, HasRelatedResultType); + isVariadic, isPropertyAccessor, isSynthesizedAccessorStub, + isImplicitlyDeclared, isDefined, impControl, HasRelatedResultType); } ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { @@ -823,6 +823,10 @@ ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, unsigned ID) { Selector(), QualType(), nullptr, nullptr); } +bool ObjCMethodDecl::isDirectMethod() const { + return hasAttr<ObjCDirectAttr>(); +} + bool ObjCMethodDecl::isThisDeclarationADesignatedInitializer() const { return getMethodFamily() == OMF_init && hasAttr<ObjCDesignatedInitializerAttr>(); @@ -952,24 +956,32 @@ ObjCMethodDecl *ObjCMethodDecl::getNextRedeclarationImpl() { ObjCMethodDecl *ObjCMethodDecl::getCanonicalDecl() { auto *CtxD = cast<Decl>(getDeclContext()); + const auto &Sel = getSelector(); if (auto *ImplD = dyn_cast<ObjCImplementationDecl>(CtxD)) { - if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) - if (ObjCMethodDecl *MD = IFD->getMethod(getSelector(), - isInstanceMethod())) + if (ObjCInterfaceDecl *IFD = ImplD->getClassInterface()) { + // When the container is the ObjCImplementationDecl (the primary + // @implementation), then the canonical Decl is either in + // the class Interface, or in any of its extension. + // + // So when we don't find it in the ObjCInterfaceDecl, + // sift through extensions too. + if (ObjCMethodDecl *MD = IFD->getMethod(Sel, isInstanceMethod())) return MD; + for (auto *Ext : IFD->known_extensions()) + if (ObjCMethodDecl *MD = Ext->getMethod(Sel, isInstanceMethod())) + return MD; + } } else if (auto *CImplD = dyn_cast<ObjCCategoryImplDecl>(CtxD)) { if (ObjCCategoryDecl *CatD = CImplD->getCategoryDecl()) - if (ObjCMethodDecl *MD = CatD->getMethod(getSelector(), - isInstanceMethod())) + if (ObjCMethodDecl *MD = CatD->getMethod(Sel, isInstanceMethod())) return MD; } if (isRedeclaration()) { // It is possible that we have not done deserializing the ObjCMethod yet. ObjCMethodDecl *MD = - cast<ObjCContainerDecl>(CtxD)->getMethod(getSelector(), - isInstanceMethod()); + cast<ObjCContainerDecl>(CtxD)->getMethod(Sel, isInstanceMethod()); return MD ? MD : this; } @@ -1077,7 +1089,7 @@ ObjCMethodFamily ObjCMethodDecl::getMethodFamily() const { QualType ObjCMethodDecl::getSelfType(ASTContext &Context, const ObjCInterfaceDecl *OID, bool &selfIsPseudoStrong, - bool &selfIsConsumed) { + bool &selfIsConsumed) const { QualType selfTy; selfIsPseudoStrong = false; selfIsConsumed = false; @@ -1306,6 +1318,11 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { if (isPropertyAccessor()) { const auto *Container = cast<ObjCContainerDecl>(getParent()); + // For accessor stubs, go back to the interface. + if (auto *ImplDecl = dyn_cast<ObjCImplDecl>(Container)) + if (isSynthesizedAccessorStub()) + Container = ImplDecl->getClassInterface(); + bool IsGetter = (NumArgs == 0); bool IsInstance = isInstanceMethod(); @@ -1358,6 +1375,15 @@ ObjCMethodDecl::findPropertyDecl(bool CheckOverrides) const { } } + assert(isSynthesizedAccessorStub() && "expected an accessor stub"); + for (const auto *Cat : ClassDecl->known_categories()) { + if (Cat == Container) + continue; + + if (const auto *Found = findMatchingProperty(Cat)) + return Found; + } + llvm_unreachable("Marked as a property accessor but no property found!"); } diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 608b0b44072b..4cedcbed0644 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -108,8 +108,8 @@ namespace { void printTemplateParameters(const TemplateParameterList *Params, bool OmitTemplateKW = false); - void printTemplateArguments(const TemplateArgumentList &Args, - const TemplateParameterList *Params = nullptr); + void printTemplateArguments(llvm::ArrayRef<TemplateArgument> Args); + void printTemplateArguments(llvm::ArrayRef<TemplateArgumentLoc> Args); void prettyPrintAttributes(Decl *D); void prettyPrintPragmas(Decl *D); void printDeclType(QualType T, StringRef DeclName, bool Pack = false); @@ -625,21 +625,26 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (Policy.FullyQualifiedName) { Proto += D->getQualifiedNameAsString(); } else { + llvm::raw_string_ostream OS(Proto); if (!Policy.SuppressScope) { if (const NestedNameSpecifier *NS = D->getQualifier()) { - llvm::raw_string_ostream OS(Proto); NS->print(OS, Policy); } } - Proto += D->getNameInfo().getAsString(); + D->getNameInfo().printName(OS, Policy); } if (GuideDecl) Proto = GuideDecl->getDeducedTemplate()->getDeclName().getAsString(); - if (const TemplateArgumentList *TArgs = D->getTemplateSpecializationArgs()) { + if (D->isFunctionTemplateSpecialization()) { llvm::raw_string_ostream POut(Proto); DeclPrinter TArgPrinter(POut, SubPolicy, Context, Indentation); - TArgPrinter.printTemplateArguments(*TArgs); + const auto *TArgAsWritten = D->getTemplateSpecializationArgsAsWritten(); + if (TArgAsWritten && !Policy.PrintCanonicalTypes) + TArgPrinter.printTemplateArguments(TArgAsWritten->arguments()); + else if (const TemplateArgumentList *TArgs = + D->getTemplateSpecializationArgs()) + TArgPrinter.printTemplateArguments(TArgs->asArray()); } QualType Ty = D->getType(); @@ -735,6 +740,11 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Proto.clear(); } Out << Proto; + + if (Expr *TrailingRequiresClause = D->getTrailingRequiresClause()) { + Out << " requires "; + TrailingRequiresClause->printPretty(Out, nullptr, SubPolicy, Indentation); + } } else { Ty.print(Out, Policy, Proto); } @@ -957,10 +967,15 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { if (D->getIdentifier()) { Out << ' ' << *D; - if (auto S = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) - printTemplateArguments(S->getTemplateArgs(), S->getTemplateParameters()); - else if (auto S = dyn_cast<ClassTemplateSpecializationDecl>(D)) - printTemplateArguments(S->getTemplateArgs()); + if (auto S = dyn_cast<ClassTemplateSpecializationDecl>(D)) { + ArrayRef<TemplateArgument> Args = S->getTemplateArgs().asArray(); + if (!Policy.PrintCanonicalTypes) + if (const auto* TSI = S->getTypeAsWritten()) + if (const auto *TST = + dyn_cast<TemplateSpecializationType>(TSI->getType())) + Args = TST->template_arguments(); + printTemplateArguments(Args); + } } if (D->isCompleteDefinition()) { @@ -1001,19 +1016,12 @@ void DeclPrinter::VisitCXXRecordDecl(CXXRecordDecl *D) { void DeclPrinter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { const char *l; - switch (D->getLanguage()) { - case LinkageSpecDecl::lang_c: + if (D->getLanguage() == LinkageSpecDecl::lang_c) l = "C"; - break; - case LinkageSpecDecl::lang_cxx_14: - l = "C++14"; - break; - case LinkageSpecDecl::lang_cxx_11: - l = "C++11"; - break; - case LinkageSpecDecl::lang_cxx: + else { + assert(D->getLanguage() == LinkageSpecDecl::lang_cxx && + "unknown language in linkage specification"); l = "C++"; - break; } Out << "extern \"" << l << "\" "; @@ -1045,7 +1053,9 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params, if (auto TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { - if (TTP->wasDeclaredWithTypename()) + if (const TypeConstraint *TC = TTP->getTypeConstraint()) + TC->print(Out, Policy); + else if (TTP->wasDeclaredWithTypename()) Out << "typename"; else Out << "class"; @@ -1083,40 +1093,22 @@ void DeclPrinter::printTemplateParameters(const TemplateParameterList *Params, Out << ' '; } -void DeclPrinter::printTemplateArguments(const TemplateArgumentList &Args, - const TemplateParameterList *Params) { +void DeclPrinter::printTemplateArguments(ArrayRef<TemplateArgument> Args) { Out << "<"; for (size_t I = 0, E = Args.size(); I < E; ++I) { - const TemplateArgument &A = Args[I]; if (I) Out << ", "; - if (Params) { - if (A.getKind() == TemplateArgument::Type) - if (auto T = A.getAsType()->getAs<TemplateTypeParmType>()) { - auto P = cast<TemplateTypeParmDecl>(Params->getParam(T->getIndex())); - Out << *P; - continue; - } - if (A.getKind() == TemplateArgument::Template) { - if (auto T = A.getAsTemplate().getAsTemplateDecl()) - if (auto TD = dyn_cast<TemplateTemplateParmDecl>(T)) { - auto P = cast<TemplateTemplateParmDecl>( - Params->getParam(TD->getIndex())); - Out << *P; - continue; - } - } - if (A.getKind() == TemplateArgument::Expression) { - if (auto E = dyn_cast<DeclRefExpr>(A.getAsExpr())) - if (auto N = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) { - auto P = cast<NonTypeTemplateParmDecl>( - Params->getParam(N->getIndex())); - Out << *P; - continue; - } - } - } - A.print(Policy, Out); + Args[I].print(Policy, Out); + } + Out << ">"; +} + +void DeclPrinter::printTemplateArguments(ArrayRef<TemplateArgumentLoc> Args) { + Out << "<"; + for (size_t I = 0, E = Args.size(); I < E; ++I) { + if (I) + Out << ", "; + Args[I].getArgument().print(Policy, Out); } Out << ">"; } @@ -1469,6 +1461,11 @@ void DeclPrinter::VisitObjCPropertyDecl(ObjCPropertyDecl *PDecl) { first = false; } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_direct) { + Out << (first ? "" : ", ") << "direct"; + first = false; + } + if (PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) { Out << (first ? "" : ", ") << "nonatomic"; diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 7e013c6c54d8..95a2e26e0df8 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -43,35 +43,46 @@ using namespace clang; // TemplateParameterList Implementation //===----------------------------------------------------------------------===// -TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc, + +TemplateParameterList::TemplateParameterList(const ASTContext& C, + SourceLocation TemplateLoc, SourceLocation LAngleLoc, ArrayRef<NamedDecl *> Params, SourceLocation RAngleLoc, Expr *RequiresClause) : TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc), NumParams(Params.size()), ContainsUnexpandedParameterPack(false), - HasRequiresClause(static_cast<bool>(RequiresClause)) { + HasRequiresClause(RequiresClause != nullptr), + HasConstrainedParameters(false) { for (unsigned Idx = 0; Idx < NumParams; ++Idx) { NamedDecl *P = Params[Idx]; begin()[Idx] = P; - if (!P->isTemplateParameterPack()) { - if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) - if (NTTP->getType()->containsUnexpandedParameterPack()) - ContainsUnexpandedParameterPack = true; - - if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) - if (TTP->getTemplateParameters()->containsUnexpandedParameterPack()) - ContainsUnexpandedParameterPack = true; - - // FIXME: If a default argument contains an unexpanded parameter pack, the - // template parameter list does too. + bool IsPack = P->isTemplateParameterPack(); + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) { + if (!IsPack && NTTP->getType()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + if (NTTP->hasPlaceholderTypeConstraint()) + HasConstrainedParameters = true; + } else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P)) { + if (!IsPack && + TTP->getTemplateParameters()->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + } else if (const TypeConstraint *TC = + cast<TemplateTypeParmDecl>(P)->getTypeConstraint()) { + if (TC->getImmediatelyDeclaredConstraint() + ->containsUnexpandedParameterPack()) + ContainsUnexpandedParameterPack = true; + HasConstrainedParameters = true; } + // FIXME: If a default argument contains an unexpanded parameter pack, the + // template parameter list does too. } - if (RequiresClause) { - *getTrailingObjects<Expr *>() = RequiresClause; + + if (HasRequiresClause) { if (RequiresClause->containsUnexpandedParameterPack()) ContainsUnexpandedParameterPack = true; + *getTrailingObjects<Expr *>() = RequiresClause; } } @@ -83,7 +94,7 @@ TemplateParameterList::Create(const ASTContext &C, SourceLocation TemplateLoc, void *Mem = C.Allocate(totalSizeToAlloc<NamedDecl *, Expr *>( Params.size(), RequiresClause ? 1u : 0u), alignof(TemplateParameterList)); - return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params, + return new (Mem) TemplateParameterList(C, TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause); } @@ -91,11 +102,23 @@ unsigned TemplateParameterList::getMinRequiredArguments() const { unsigned NumRequiredArgs = 0; for (const NamedDecl *P : asArray()) { if (P->isTemplateParameterPack()) { - if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) { if (NTTP->isExpandedParameterPack()) { NumRequiredArgs += NTTP->getNumExpansionTypes(); continue; } + } else if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(P)) { + if (TTP->isExpandedParameterPack()) { + NumRequiredArgs += TTP->getNumExpansionParameters(); + continue; + } + } else { + const auto *TP = cast<TemplateTemplateParmDecl>(P); + if (TP->isExpandedParameterPack()) { + NumRequiredArgs += TP->getNumExpansionTemplateParameters(); + continue; + } + } break; } @@ -140,14 +163,17 @@ static void AdoptTemplateParameterList(TemplateParameterList *Params, void TemplateParameterList:: getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { - // TODO: Concepts: Collect immediately-introduced constraints. + if (HasConstrainedParameters) + for (const NamedDecl *Param : *this) + if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) + if (const auto *TC = TTP->getTypeConstraint()) + AC.push_back(TC->getImmediatelyDeclaredConstraint()); if (HasRequiresClause) AC.push_back(getRequiresClause()); } bool TemplateParameterList::hasAssociatedConstraints() const { - // TODO: Concepts: Regard immediately-introduced constraints. - return HasRequiresClause; + return HasRequiresClause || HasConstrainedParameters; } namespace clang { @@ -171,13 +197,18 @@ void TemplateDecl::anchor() {} void TemplateDecl:: getAssociatedConstraints(llvm::SmallVectorImpl<const Expr *> &AC) const { - // TODO: Concepts: Append function trailing requires clause. TemplateParams->getAssociatedConstraints(AC); + if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl())) + if (const Expr *TRC = FD->getTrailingRequiresClause()) + AC.push_back(TRC); } bool TemplateDecl::hasAssociatedConstraints() const { - // TODO: Concepts: Regard function trailing requires clause. - return TemplateParams->hasAssociatedConstraints(); + if (TemplateParams->hasAssociatedConstraints()) + return true; + if (auto *FD = dyn_cast_or_null<FunctionDecl>(getTemplatedDecl())) + return FD->getTrailingRequiresClause(); + return false; } //===----------------------------------------------------------------------===// @@ -231,15 +262,16 @@ void RedeclarableTemplateDecl::loadLazySpecializationsImpl() const { } } -template<class EntryType> +template<class EntryType, typename... ProfileArguments> typename RedeclarableTemplateDecl::SpecEntryTraits<EntryType>::DeclType * RedeclarableTemplateDecl::findSpecializationImpl( - llvm::FoldingSetVector<EntryType> &Specs, ArrayRef<TemplateArgument> Args, - void *&InsertPos) { + llvm::FoldingSetVector<EntryType> &Specs, void *&InsertPos, + ProfileArguments&&... ProfileArgs) { using SETraits = SpecEntryTraits<EntryType>; llvm::FoldingSetNodeID ID; - EntryType::Profile(ID, Args, getASTContext()); + EntryType::Profile(ID, std::forward<ProfileArguments>(ProfileArgs)..., + getASTContext()); EntryType *Entry = Specs.FindNodeOrInsertPos(ID, InsertPos); return Entry ? SETraits::getDecl(Entry)->getMostRecentDecl() : nullptr; } @@ -254,8 +286,8 @@ void RedeclarableTemplateDecl::addSpecializationImpl( #ifndef NDEBUG void *CorrectInsertPos; assert(!findSpecializationImpl(Specializations, - SETraits::getTemplateArgs(Entry), - CorrectInsertPos) && + CorrectInsertPos, + SETraits::getTemplateArgs(Entry)) && InsertPos == CorrectInsertPos && "given incorrect InsertPos for specialization"); #endif @@ -312,7 +344,7 @@ FunctionTemplateDecl::getSpecializations() const { FunctionDecl * FunctionTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), Args, InsertPos); + return findSpecializationImpl(getSpecializations(), InsertPos, Args); } void FunctionTemplateDecl::addSpecialization( @@ -418,7 +450,7 @@ ClassTemplateDecl::newCommon(ASTContext &C) const { ClassTemplateSpecializationDecl * ClassTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), Args, InsertPos); + return findSpecializationImpl(getSpecializations(), InsertPos, Args); } void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, @@ -427,9 +459,48 @@ void ClassTemplateDecl::AddSpecialization(ClassTemplateSpecializationDecl *D, } ClassTemplatePartialSpecializationDecl * -ClassTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args, - void *&InsertPos) { - return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos); +ClassTemplateDecl::findPartialSpecialization( + ArrayRef<TemplateArgument> Args, + TemplateParameterList *TPL, void *&InsertPos) { + return findSpecializationImpl(getPartialSpecializations(), InsertPos, Args, + TPL); +} + +static void ProfileTemplateParameterList(ASTContext &C, + llvm::FoldingSetNodeID &ID, const TemplateParameterList *TPL) { + const Expr *RC = TPL->getRequiresClause(); + ID.AddBoolean(RC != nullptr); + if (RC) + RC->Profile(ID, C, /*Canonical=*/true); + ID.AddInteger(TPL->size()); + for (NamedDecl *D : *TPL) { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { + ID.AddInteger(0); + ID.AddBoolean(NTTP->isParameterPack()); + NTTP->getType().getCanonicalType().Profile(ID); + continue; + } + if (const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D)) { + ID.AddInteger(1); + ID.AddBoolean(TTP->isParameterPack()); + // TODO: Concepts: profile type-constraints. + continue; + } + const auto *TTP = cast<TemplateTemplateParmDecl>(D); + ID.AddInteger(2); + ID.AddBoolean(TTP->isParameterPack()); + ProfileTemplateParameterList(C, ID, TTP->getTemplateParameters()); + } +} + +void +ClassTemplatePartialSpecializationDecl::Profile(llvm::FoldingSetNodeID &ID, + ArrayRef<TemplateArgument> TemplateArgs, TemplateParameterList *TPL, + ASTContext &Context) { + ID.AddInteger(TemplateArgs.size()); + for (const TemplateArgument &TemplateArg : TemplateArgs) + TemplateArg.Profile(ID, Context); + ProfileTemplateParameterList(Context, ID, TPL); } void ClassTemplateDecl::AddPartialSpecialization( @@ -513,9 +584,14 @@ TemplateTypeParmDecl * TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation KeyLoc, SourceLocation NameLoc, unsigned D, unsigned P, IdentifierInfo *Id, - bool Typename, bool ParameterPack) { + bool Typename, bool ParameterPack, + bool HasTypeConstraint, + Optional<unsigned> NumExpanded) { auto *TTPDecl = - new (C, DC) TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename); + new (C, DC, + additionalSizeToAlloc<TypeConstraint>(HasTypeConstraint ? 1 : 0)) + TemplateTypeParmDecl(DC, KeyLoc, NameLoc, Id, Typename, + HasTypeConstraint, NumExpanded); QualType TTPType = C.getTemplateTypeParmType(D, P, ParameterPack, TTPDecl); TTPDecl->setTypeForDecl(TTPType.getTypePtr()); return TTPDecl; @@ -524,7 +600,17 @@ TemplateTypeParmDecl::Create(const ASTContext &C, DeclContext *DC, TemplateTypeParmDecl * TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, unsigned ID) { return new (C, ID) TemplateTypeParmDecl(nullptr, SourceLocation(), - SourceLocation(), nullptr, false); + SourceLocation(), nullptr, false, + false, None); +} + +TemplateTypeParmDecl * +TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, unsigned ID, + bool HasTypeConstraint) { + return new (C, ID, + additionalSizeToAlloc<TypeConstraint>(HasTypeConstraint ? 1 : 0)) + TemplateTypeParmDecl(nullptr, SourceLocation(), SourceLocation(), + nullptr, false, HasTypeConstraint, None); } SourceLocation TemplateTypeParmDecl::getDefaultArgumentLoc() const { @@ -557,6 +643,20 @@ bool TemplateTypeParmDecl::isParameterPack() const { return getTypeForDecl()->castAs<TemplateTypeParmType>()->isParameterPack(); } +void TemplateTypeParmDecl::setTypeConstraint(NestedNameSpecifierLoc NNS, + DeclarationNameInfo NameInfo, NamedDecl *FoundDecl, ConceptDecl *CD, + const ASTTemplateArgumentListInfo *ArgsAsWritten, + Expr *ImmediatelyDeclaredConstraint) { + assert(HasTypeConstraint && + "HasTypeConstraint=true must be passed at construction in order to " + "call setTypeConstraint"); + assert(!TypeConstraintInitialized && + "TypeConstraint was already initialized!"); + new (getTrailingObjects<TypeConstraint>()) TypeConstraint(NNS, NameInfo, + FoundDecl, CD, ArgsAsWritten, ImmediatelyDeclaredConstraint); + TypeConstraintInitialized = true; +} + //===----------------------------------------------------------------------===// // NonTypeTemplateParmDecl Method Implementations //===----------------------------------------------------------------------===// @@ -1035,7 +1135,7 @@ VarTemplateDecl::newCommon(ASTContext &C) const { VarTemplateSpecializationDecl * VarTemplateDecl::findSpecialization(ArrayRef<TemplateArgument> Args, void *&InsertPos) { - return findSpecializationImpl(getSpecializations(), Args, InsertPos); + return findSpecializationImpl(getSpecializations(), InsertPos, Args); } void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, @@ -1045,8 +1145,19 @@ void VarTemplateDecl::AddSpecialization(VarTemplateSpecializationDecl *D, VarTemplatePartialSpecializationDecl * VarTemplateDecl::findPartialSpecialization(ArrayRef<TemplateArgument> Args, - void *&InsertPos) { - return findSpecializationImpl(getPartialSpecializations(), Args, InsertPos); + TemplateParameterList *TPL, void *&InsertPos) { + return findSpecializationImpl(getPartialSpecializations(), InsertPos, Args, + TPL); +} + +void +VarTemplatePartialSpecializationDecl::Profile(llvm::FoldingSetNodeID &ID, + ArrayRef<TemplateArgument> TemplateArgs, TemplateParameterList *TPL, + ASTContext &Context) { + ID.AddInteger(TemplateArgs.size()); + for (const TemplateArgument &TemplateArg : TemplateArgs) + TemplateArg.Profile(ID, Context); + ProfileTemplateParameterList(Context, ID, TPL); } void VarTemplateDecl::AddPartialSpecialization( @@ -1200,7 +1311,8 @@ createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) { // typename T auto *T = TemplateTypeParmDecl::Create( C, DC, SourceLocation(), SourceLocation(), /*Depth=*/1, /*Position=*/0, - /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false); + /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false, + /*HasTypeConstraint=*/false); T->setImplicit(true); // T ...Ints @@ -1225,7 +1337,8 @@ createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) { // typename T auto *TemplateTypeParm = TemplateTypeParmDecl::Create( C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/1, - /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false); + /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/false, + /*HasTypeConstraint=*/false); TemplateTypeParm->setImplicit(true); // T N @@ -1253,7 +1366,8 @@ createTypePackElementParameterList(const ASTContext &C, DeclContext *DC) { // typename ...T auto *Ts = TemplateTypeParmDecl::Create( C, DC, SourceLocation(), SourceLocation(), /*Depth=*/0, /*Position=*/1, - /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/true); + /*Id=*/nullptr, /*Typename=*/true, /*ParameterPack=*/true, + /*HasTypeConstraint=*/false); Ts->setImplicit(true); // template <std::size_t Index, typename ...T> @@ -1283,3 +1397,15 @@ BuiltinTemplateDecl::BuiltinTemplateDecl(const ASTContext &C, DeclContext *DC, : TemplateDecl(BuiltinTemplate, DC, SourceLocation(), Name, createBuiltinTemplateParameterList(C, DC, BTK)), BTK(BTK) {} + +void TypeConstraint::print(llvm::raw_ostream &OS, PrintingPolicy Policy) const { + if (NestedNameSpec) + NestedNameSpec.getNestedNameSpecifier()->print(OS, Policy); + ConceptName.printName(OS, Policy); + if (hasExplicitTemplateArgs()) { + OS << "<"; + for (auto &ArgLoc : ArgsAsWritten->arguments()) + ArgLoc.getArgument().print(Policy, OS); + OS << ">"; + } +}
\ No newline at end of file diff --git a/clang/lib/AST/DeclarationName.cpp b/clang/lib/AST/DeclarationName.cpp index fe69c71aa3dd..4eb11bc57e52 100644 --- a/clang/lib/AST/DeclarationName.cpp +++ b/clang/lib/AST/DeclarationName.cpp @@ -134,7 +134,8 @@ static void printCXXConstructorDestructorName(QualType ClassType, ClassType.print(OS, Policy); } -void DeclarationName::print(raw_ostream &OS, const PrintingPolicy &Policy) { +void DeclarationName::print(raw_ostream &OS, + const PrintingPolicy &Policy) const { switch (getNameKind()) { case DeclarationName::Identifier: if (const IdentifierInfo *II = getAsIdentifierInfo()) @@ -447,11 +448,17 @@ bool DeclarationNameInfo::isInstantiationDependent() const { std::string DeclarationNameInfo::getAsString() const { std::string Result; llvm::raw_string_ostream OS(Result); - printName(OS); + OS << *this; return OS.str(); } -void DeclarationNameInfo::printName(raw_ostream &OS) const { +raw_ostream &clang::operator<<(raw_ostream &OS, DeclarationNameInfo DNInfo) { + LangOptions LO; + DNInfo.printName(OS, PrintingPolicy(LangOptions())); + return OS; +} + +void DeclarationNameInfo::printName(raw_ostream &OS, PrintingPolicy Policy) const { switch (Name.getNameKind()) { case DeclarationName::Identifier: case DeclarationName::ObjCZeroArgSelector: @@ -461,7 +468,7 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { case DeclarationName::CXXLiteralOperatorName: case DeclarationName::CXXUsingDirective: case DeclarationName::CXXDeductionGuideName: - OS << Name; + Name.print(OS, Policy); return; case DeclarationName::CXXConstructorName: @@ -473,13 +480,11 @@ void DeclarationNameInfo::printName(raw_ostream &OS) const { else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) OS << "operator "; LangOptions LO; - LO.CPlusPlus = true; - LO.Bool = true; - PrintingPolicy PP(LO); - PP.SuppressScope = true; - OS << TInfo->getType().getAsString(PP); + Policy.adjustForCPlusPlus(); + Policy.SuppressScope = true; + OS << TInfo->getType().getAsString(Policy); } else - OS << Name; + Name.print(OS, Policy); return; } llvm_unreachable("Unexpected declaration name kind"); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 3438c3aadc6b..73ddbc62482d 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -49,7 +49,7 @@ const Expr *Expr::getBestDynamicClassTypeExpr() const { // Step into initializer for materialized temporaries. if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) { - E = MTE->GetTemporaryExpr(); + E = MTE->getSubExpr(); continue; } @@ -127,11 +127,7 @@ const Expr *Expr::skipRValueSubobjectAdjustments( return E; } -/// isKnownToHaveBooleanValue - Return true if this is an integer expression -/// that is known to return 0 or 1. This happens for _Bool/bool expressions -/// but also int expressions which are produced by things like comparisons in -/// C. -bool Expr::isKnownToHaveBooleanValue() const { +bool Expr::isKnownToHaveBooleanValue(bool Semantic) const { const Expr *E = IgnoreParens(); // If this value has _Bool type, it is obvious 0/1. @@ -142,7 +138,7 @@ bool Expr::isKnownToHaveBooleanValue() const { if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { switch (UO->getOpcode()) { case UO_Plus: - return UO->getSubExpr()->isKnownToHaveBooleanValue(); + return UO->getSubExpr()->isKnownToHaveBooleanValue(Semantic); case UO_LNot: return true; default: @@ -152,8 +148,9 @@ bool Expr::isKnownToHaveBooleanValue() const { // Only look through implicit casts. If the user writes // '(int) (a && b)' treat it as an arbitrary int. + // FIXME: Should we look through any cast expression in !Semantic mode? if (const ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) - return CE->getSubExpr()->isKnownToHaveBooleanValue(); + return CE->getSubExpr()->isKnownToHaveBooleanValue(Semantic); if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { switch (BO->getOpcode()) { @@ -172,24 +169,30 @@ bool Expr::isKnownToHaveBooleanValue() const { case BO_Xor: // Bitwise XOR operator. case BO_Or: // Bitwise OR operator. // Handle things like (x==2)|(y==12). - return BO->getLHS()->isKnownToHaveBooleanValue() && - BO->getRHS()->isKnownToHaveBooleanValue(); + return BO->getLHS()->isKnownToHaveBooleanValue(Semantic) && + BO->getRHS()->isKnownToHaveBooleanValue(Semantic); case BO_Comma: case BO_Assign: - return BO->getRHS()->isKnownToHaveBooleanValue(); + return BO->getRHS()->isKnownToHaveBooleanValue(Semantic); } } if (const ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) - return CO->getTrueExpr()->isKnownToHaveBooleanValue() && - CO->getFalseExpr()->isKnownToHaveBooleanValue(); + return CO->getTrueExpr()->isKnownToHaveBooleanValue(Semantic) && + CO->getFalseExpr()->isKnownToHaveBooleanValue(Semantic); if (isa<ObjCBoolLiteralExpr>(E)) return true; if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E)) - return OVE->getSourceExpr()->isKnownToHaveBooleanValue(); + return OVE->getSourceExpr()->isKnownToHaveBooleanValue(Semantic); + + if (const FieldDecl *FD = E->getSourceBitField()) + if (!Semantic && FD->getType()->isUnsignedIntegerType() && + !FD->getBitWidth()->isValueDependent() && + FD->getBitWidthValue(FD->getASTContext()) == 1) + return true; return false; } @@ -1675,6 +1678,15 @@ MemberExpr *MemberExpr::Create( MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl, NameInfo, T, VK, OK, NOUR); + if (isa<FieldDecl>(MemberDecl)) { + DeclContext *DC = MemberDecl->getDeclContext(); + // dyn_cast_or_null is used to handle objC variables which do not + // have a declaration context. + CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(DC); + if (RD && RD->isDependentContext() && RD->isCurrentInstantiation(DC)) + E->setTypeDependent(T->isDependentType()); + } + if (HasQualOrFound) { // FIXME: Wrong. We should be looking at the member declaration we found. if (QualifierLoc && QualifierLoc.getNestedNameSpecifier()->isDependent()) { @@ -1811,7 +1823,7 @@ bool CastExpr::CastConsistency() const { auto Ty = getType(); auto SETy = getSubExpr()->getType(); assert(getValueKindForType(Ty) == Expr::getValueKindForType(SETy)); - if (/*isRValue()*/ !Ty->getPointeeType().isNull()) { + if (isRValue()) { Ty = Ty->getPointeeType(); SETy = SETy->getPointeeType(); } @@ -1891,7 +1903,7 @@ namespace { const Expr *skipImplicitTemporary(const Expr *E) { // Skip through reference binding to temporary. if (auto *Materialize = dyn_cast<MaterializeTemporaryExpr>(E)) - E = Materialize->GetTemporaryExpr(); + E = Materialize->getSubExpr(); // Skip any temporary bindings; they're implicit. if (auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E)) @@ -2721,8 +2733,9 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc, case CXXDeleteExprClass: return false; case MaterializeTemporaryExprClass: - return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr() - ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); + return cast<MaterializeTemporaryExpr>(this) + ->getSubExpr() + ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); case CXXBindTemporaryExprClass: return cast<CXXBindTemporaryExpr>(this)->getSubExpr() ->isUnusedResultAWarning(WarnE, Loc, R1, R2, Ctx); @@ -2746,8 +2759,8 @@ bool Expr::isOBJCGCCandidate(ASTContext &Ctx) const { case ImplicitCastExprClass: return cast<ImplicitCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case MaterializeTemporaryExprClass: - return cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr() - ->isOBJCGCCandidate(Ctx); + return cast<MaterializeTemporaryExpr>(E)->getSubExpr()->isOBJCGCCandidate( + Ctx); case CStyleCastExprClass: return cast<CStyleCastExpr>(E)->getSubExpr()->isOBJCGCCandidate(Ctx); case DeclRefExprClass: { @@ -2822,7 +2835,7 @@ static Expr *IgnoreImpCastsExtraSingleStep(Expr *E) { return SubE; if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) - return MTE->GetTemporaryExpr(); + return MTE->getSubExpr(); if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) return NTTP->getReplacement(); @@ -2838,7 +2851,7 @@ static Expr *IgnoreCastsSingleStep(Expr *E) { return FE->getSubExpr(); if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) - return MTE->GetTemporaryExpr(); + return MTE->getSubExpr(); if (auto *NTTP = dyn_cast<SubstNonTypeTemplateParmExpr>(E)) return NTTP->getReplacement(); @@ -2872,7 +2885,7 @@ static Expr *IgnoreImplicitSingleStep(Expr *E) { return SubE; if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) - return MTE->GetTemporaryExpr(); + return MTE->getSubExpr(); if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E)) return BTE->getSubExpr(); @@ -2880,6 +2893,13 @@ static Expr *IgnoreImplicitSingleStep(Expr *E) { return E; } +static Expr *IgnoreImplicitAsWrittenSingleStep(Expr *E) { + if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) + return ICE->getSubExprAsWritten(); + + return IgnoreImplicitSingleStep(E); +} + static Expr *IgnoreParensSingleStep(Expr *E) { if (auto *PE = dyn_cast<ParenExpr>(E)) return PE->getSubExpr(); @@ -2959,6 +2979,10 @@ Expr *Expr::IgnoreImplicit() { return IgnoreExprNodes(this, IgnoreImplicitSingleStep); } +Expr *Expr::IgnoreImplicitAsWritten() { + return IgnoreExprNodes(this, IgnoreImplicitAsWrittenSingleStep); +} + Expr *Expr::IgnoreParens() { return IgnoreExprNodes(this, IgnoreParensSingleStep); } @@ -2996,10 +3020,38 @@ Expr *Expr::IgnoreParenNoopCasts(const ASTContext &Ctx) { }); } +Expr *Expr::IgnoreUnlessSpelledInSource() { + Expr *E = this; + + Expr *LastE = nullptr; + while (E != LastE) { + LastE = E; + E = E->IgnoreParenImpCasts(); + + auto SR = E->getSourceRange(); + + if (auto *C = dyn_cast<CXXConstructExpr>(E)) { + if (C->getNumArgs() == 1) { + Expr *A = C->getArg(0); + if (A->getSourceRange() == SR || !isa<CXXTemporaryObjectExpr>(C)) + E = A; + } + } + + if (auto *C = dyn_cast<CXXMemberCallExpr>(E)) { + Expr *ExprNode = C->getImplicitObjectArgument()->IgnoreParenImpCasts(); + if (ExprNode->getSourceRange() == SR) + E = ExprNode; + } + } + + return E; +} + bool Expr::isDefaultArgument() const { const Expr *E = this; if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E)) - E = M->GetTemporaryExpr(); + E = M->getSubExpr(); while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) E = ICE->getSubExprAsWritten(); @@ -3011,7 +3063,7 @@ bool Expr::isDefaultArgument() const { /// expressions. static const Expr *skipTemporaryBindingsNoOpCastsAndParens(const Expr *E) { if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E)) - E = M->GetTemporaryExpr(); + E = M->getSubExpr(); while (const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { if (ICE->getCastKind() == CK_NoOp) @@ -3106,7 +3158,7 @@ bool Expr::isImplicitCXXThis() const { if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(E)) { - E = M->GetTemporaryExpr(); + E = M->getSubExpr(); continue; } @@ -3283,8 +3335,9 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef, break; } case MaterializeTemporaryExprClass: - return cast<MaterializeTemporaryExpr>(this)->GetTemporaryExpr() - ->isConstantInitializer(Ctx, false, Culprit); + return cast<MaterializeTemporaryExpr>(this) + ->getSubExpr() + ->isConstantInitializer(Ctx, false, Culprit); case SubstNonTypeTemplateParmExprClass: return cast<SubstNonTypeTemplateParmExpr>(this)->getReplacement() @@ -3751,7 +3804,7 @@ Expr::isNullPointerConstant(ASTContext &Ctx, return NPCK_GNUNull; } else if (const MaterializeTemporaryExpr *M = dyn_cast<MaterializeTemporaryExpr>(this)) { - return M->GetTemporaryExpr()->isNullPointerConstant(Ctx, NPC); + return M->getSubExpr()->isNullPointerConstant(Ctx, NPC); } else if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(this)) { if (const Expr *Source = OVE->getSourceExpr()) return Source->isNullPointerConstant(Ctx, NPC); @@ -4460,7 +4513,7 @@ const OpaqueValueExpr *OpaqueValueExpr::findInCopyConstruct(const Expr *e) { if (const ExprWithCleanups *ewc = dyn_cast<ExprWithCleanups>(e)) e = ewc->getSubExpr(); if (const MaterializeTemporaryExpr *m = dyn_cast<MaterializeTemporaryExpr>(e)) - e = m->GetTemporaryExpr(); + e = m->getSubExpr(); e = cast<CXXConstructExpr>(e)->getArg(0); while (const ImplicitCastExpr *ice = dyn_cast<ImplicitCastExpr>(e)) e = ice->getSubExpr(); @@ -4598,6 +4651,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { case AO__c11_atomic_fetch_and: case AO__c11_atomic_fetch_or: case AO__c11_atomic_fetch_xor: + case AO__c11_atomic_fetch_max: + case AO__c11_atomic_fetch_min: case AO__atomic_fetch_add: case AO__atomic_fetch_sub: case AO__atomic_fetch_and: @@ -4610,6 +4665,8 @@ unsigned AtomicExpr::getNumSubExprs(AtomicOp Op) { case AO__atomic_or_fetch: case AO__atomic_xor_fetch: case AO__atomic_nand_fetch: + case AO__atomic_min_fetch: + case AO__atomic_max_fetch: case AO__atomic_fetch_min: case AO__atomic_fetch_max: return 3; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 904928bdf286..422227d787b1 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -107,7 +107,7 @@ CXXRewrittenBinaryOperator::getDecomposedForm() const { return Result; // Otherwise, we expect a <=> to now be on the LHS. - E = Result.LHS->IgnoreImplicit(); + E = Result.LHS->IgnoreImplicitAsWritten(); if (auto *BO = dyn_cast<BinaryOperator>(E)) { assert(BO->getOpcode() == BO_Cmp); Result.LHS = BO->getLHS(); @@ -1653,7 +1653,23 @@ FunctionParmPackExpr::CreateEmpty(const ASTContext &Context, FunctionParmPackExpr(QualType(), nullptr, SourceLocation(), 0, nullptr); } -void MaterializeTemporaryExpr::setExtendingDecl(const ValueDecl *ExtendedBy, +MaterializeTemporaryExpr::MaterializeTemporaryExpr( + QualType T, Expr *Temporary, bool BoundToLvalueReference, + LifetimeExtendedTemporaryDecl *MTD) + : Expr(MaterializeTemporaryExprClass, T, + BoundToLvalueReference ? VK_LValue : VK_XValue, OK_Ordinary, + Temporary->isTypeDependent(), Temporary->isValueDependent(), + Temporary->isInstantiationDependent(), + Temporary->containsUnexpandedParameterPack()) { + if (MTD) { + State = MTD; + MTD->ExprWithTemporary = Temporary; + return; + } + State = Temporary; +} + +void MaterializeTemporaryExpr::setExtendingDecl(ValueDecl *ExtendedBy, unsigned ManglingNumber) { // We only need extra state if we have to remember more than just the Stmt. if (!ExtendedBy) @@ -1661,13 +1677,11 @@ void MaterializeTemporaryExpr::setExtendingDecl(const ValueDecl *ExtendedBy, // We may need to allocate extra storage for the mangling number and the // extended-by ValueDecl. - if (!State.is<ExtraState *>()) { - auto *ES = new (ExtendedBy->getASTContext()) ExtraState; - ES->Temporary = State.get<Stmt *>(); - State = ES; - } + if (!State.is<LifetimeExtendedTemporaryDecl *>()) + State = LifetimeExtendedTemporaryDecl::Create( + cast<Expr>(State.get<Stmt *>()), ExtendedBy, ManglingNumber); - auto ES = State.get<ExtraState *>(); + auto ES = State.get<LifetimeExtendedTemporaryDecl *>(); ES->ExtendingDecl = ExtendedBy; ES->ManglingNumber = ManglingNumber; } @@ -1751,44 +1765,42 @@ CUDAKernelCallExpr *CUDAKernelCallExpr::CreateEmpty(const ASTContext &Ctx, return new (Mem) CUDAKernelCallExpr(NumArgs, Empty); } -ConceptSpecializationExpr::ConceptSpecializationExpr(ASTContext &C, +ConceptSpecializationExpr::ConceptSpecializationExpr(const ASTContext &C, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, - SourceLocation ConceptNameLoc, NamedDecl *FoundDecl, + DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, - ArrayRef<TemplateArgument> ConvertedArgs, Optional<bool> IsSatisfied) + ArrayRef<TemplateArgument> ConvertedArgs, + const ConstraintSatisfaction *Satisfaction) : Expr(ConceptSpecializationExprClass, C.BoolTy, VK_RValue, OK_Ordinary, /*TypeDependent=*/false, // All the flags below are set in setTemplateArguments. - /*ValueDependent=*/!IsSatisfied.hasValue(), - /*InstantiationDependent=*/false, + /*ValueDependent=*/!Satisfaction, /*InstantiationDependent=*/false, /*ContainsUnexpandedParameterPacks=*/false), - NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc), - ConceptNameLoc(ConceptNameLoc), FoundDecl(FoundDecl), - NamedConcept(NamedConcept, IsSatisfied ? *IsSatisfied : true), - NumTemplateArgs(ConvertedArgs.size()) { - - setTemplateArguments(ArgsAsWritten, ConvertedArgs); + ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, + NamedConcept, ArgsAsWritten), + NumTemplateArgs(ConvertedArgs.size()), + Satisfaction(Satisfaction ? + ASTConstraintSatisfaction::Create(C, *Satisfaction) : + nullptr) { + setTemplateArguments(ConvertedArgs); } ConceptSpecializationExpr::ConceptSpecializationExpr(EmptyShell Empty, unsigned NumTemplateArgs) - : Expr(ConceptSpecializationExprClass, Empty), + : Expr(ConceptSpecializationExprClass, Empty), ConceptReference(), NumTemplateArgs(NumTemplateArgs) { } void ConceptSpecializationExpr::setTemplateArguments( - const ASTTemplateArgumentListInfo *ArgsAsWritten, ArrayRef<TemplateArgument> Converted) { assert(Converted.size() == NumTemplateArgs); - assert(!this->ArgsAsWritten && "setTemplateArguments can only be used once"); - this->ArgsAsWritten = ArgsAsWritten; std::uninitialized_copy(Converted.begin(), Converted.end(), getTrailingObjects<TemplateArgument>()); bool IsInstantiationDependent = false; bool ContainsUnexpandedParameterPack = false; - for (const TemplateArgumentLoc& LocInfo : ArgsAsWritten->arguments()) { - if (LocInfo.getArgument().isInstantiationDependent()) + for (const TemplateArgument& Arg : Converted) { + if (Arg.isInstantiationDependent()) IsInstantiationDependent = true; - if (LocInfo.getArgument().containsUnexpandedParameterPack()) + if (Arg.containsUnexpandedParameterPack()) ContainsUnexpandedParameterPack = true; if (ContainsUnexpandedParameterPack && IsInstantiationDependent) break; @@ -1806,20 +1818,21 @@ void ConceptSpecializationExpr::setTemplateArguments( } ConceptSpecializationExpr * -ConceptSpecializationExpr::Create(ASTContext &C, NestedNameSpecifierLoc NNS, +ConceptSpecializationExpr::Create(const ASTContext &C, + NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, - SourceLocation ConceptNameLoc, + DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten, ArrayRef<TemplateArgument> ConvertedArgs, - Optional<bool> IsSatisfied) { + const ConstraintSatisfaction *Satisfaction) { void *Buffer = C.Allocate(totalSizeToAlloc<TemplateArgument>( ConvertedArgs.size())); return new (Buffer) ConceptSpecializationExpr(C, NNS, TemplateKWLoc, - ConceptNameLoc, FoundDecl, + ConceptNameInfo, FoundDecl, NamedConcept, ArgsAsWritten, - ConvertedArgs, IsSatisfied); + ConvertedArgs, Satisfaction); } ConceptSpecializationExpr * diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 42c746e60285..c4b27b5d1daa 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -32,8 +32,6 @@ // //===----------------------------------------------------------------------===// -#include <cstring> -#include <functional> #include "Interp/Context.h" #include "Interp/Frame.h" #include "Interp/State.h" @@ -41,6 +39,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/ASTLambda.h" +#include "clang/AST/Attr.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/CharUnits.h" #include "clang/AST/CurrentSourceLocExprScope.h" @@ -57,6 +56,8 @@ #include "llvm/ADT/SmallBitVector.h" #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" +#include <cstring> +#include <functional> #define DEBUG_TYPE "exprconstant" @@ -107,7 +108,7 @@ namespace { dyn_cast<MaterializeTemporaryExpr>(Base)) { SmallVector<const Expr *, 2> CommaLHSs; SmallVector<SubobjectAdjustment, 2> Adjustments; - const Expr *Temp = MTE->GetTemporaryExpr(); + const Expr *Temp = MTE->getSubExpr(); const Expr *Inner = Temp->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); // Keep any cv-qualifiers from the reference if we generated a temporary @@ -763,11 +764,8 @@ namespace { /// we will evaluate. unsigned StepsLeft; - /// Force the use of the experimental new constant interpreter, bailing out - /// with an error if a feature is not supported. - bool ForceNewConstInterp; - - /// Enable the experimental new constant interpreter. + /// Enable the experimental new constant interpreter. If an expression is + /// not supported by the interpreter, an error is triggered. bool EnableNewConstInterp; /// BottomFrame - The frame in which evaluation started. This must be @@ -921,10 +919,8 @@ namespace { EvalInfo(const ASTContext &C, Expr::EvalStatus &S, EvaluationMode Mode) : Ctx(const_cast<ASTContext &>(C)), EvalStatus(S), CurrentCall(nullptr), CallStackDepth(0), NextCallIndex(1), - StepsLeft(getLangOpts().ConstexprStepLimit), - ForceNewConstInterp(getLangOpts().ForceNewConstInterp), - EnableNewConstInterp(ForceNewConstInterp || - getLangOpts().EnableNewConstInterp), + StepsLeft(C.getLangOpts().ConstexprStepLimit), + EnableNewConstInterp(C.getLangOpts().EnableNewConstInterp), BottomFrame(*this, SourceLocation(), nullptr, nullptr, nullptr), EvaluatingDecl((const ValueDecl *)nullptr), EvaluatingDeclValue(nullptr), HasActiveDiagnostic(false), @@ -1039,10 +1035,13 @@ namespace { /// cleanups would have had a side-effect, note that as an unmodeled /// side-effect and return false. Otherwise, return true. bool discardCleanups() { - for (Cleanup &C : CleanupStack) - if (C.hasSideEffect()) - if (!noteSideEffect()) - return false; + for (Cleanup &C : CleanupStack) { + if (C.hasSideEffect() && !noteSideEffect()) { + CleanupStack.clear(); + return false; + } + } + CleanupStack.clear(); return true; } @@ -2072,7 +2071,7 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc, return false; } - APValue *V = Info.Ctx.getMaterializedTemporaryValue(MTE, false); + APValue *V = MTE->getOrCreateValue(false); assert(V && "evasluation result refers to uninitialised temporary"); if (!CheckEvaluationResult(CheckEvaluationResultKind::ConstantExpression, Info, MTE->getExprLoc(), TempType, *V, @@ -3676,7 +3675,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E, return CompleteObject(); } - BaseVal = Info.Ctx.getMaterializedTemporaryValue(MTE, false); + BaseVal = MTE->getOrCreateValue(false); assert(BaseVal && "got reference to unevaluated temporary"); } else { if (!IsAccess) @@ -5333,9 +5332,16 @@ static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr, if (!FD || FD->getType()->isReferenceType()) break; - // ... and also contains A.B if B names a union member - if (FD->getParent()->isUnion()) - UnionPathLengths.push_back({PathLength - 1, FD}); + // ... and also contains A.B if B names a union member ... + if (FD->getParent()->isUnion()) { + // ... of a non-class, non-array type, or of a class type with a + // trivial default constructor that is not deleted, or an array of + // such types. + auto *RD = + FD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + if (!RD || RD->hasTrivialDefaultConstructor()) + UnionPathLengths.push_back({PathLength - 1, FD}); + } E = ME->getBase(); --PathLength; @@ -6824,6 +6830,36 @@ public: return StmtVisitorTy::Visit(Source); } + bool VisitPseudoObjectExpr(const PseudoObjectExpr *E) { + for (const Expr *SemE : E->semantics()) { + if (auto *OVE = dyn_cast<OpaqueValueExpr>(SemE)) { + // FIXME: We can't handle the case where an OpaqueValueExpr is also the + // result expression: there could be two different LValues that would + // refer to the same object in that case, and we can't model that. + if (SemE == E->getResultExpr()) + return Error(E); + + // Unique OVEs get evaluated if and when we encounter them when + // emitting the rest of the semantic form, rather than eagerly. + if (OVE->isUnique()) + continue; + + LValue LV; + if (!Evaluate(Info.CurrentCall->createTemporary( + OVE, getStorageType(Info.Ctx, OVE), false, LV), + Info, OVE->getSourceExpr())) + return false; + } else if (SemE == E->getResultExpr()) { + if (!StmtVisitorTy::Visit(SemE)) + return false; + } else { + if (!EvaluateIgnoredValue(Info, SemE)) + return false; + } + } + return true; + } + bool VisitCallExpr(const CallExpr *E) { APValue Result; if (!handleCallExpr(E, Result, nullptr)) @@ -7044,6 +7080,31 @@ public: DerivedSuccess(Result, E); } + bool VisitExtVectorElementExpr(const ExtVectorElementExpr *E) { + APValue Val; + if (!Evaluate(Val, Info, E->getBase())) + return false; + + if (Val.isVector()) { + SmallVector<uint32_t, 4> Indices; + E->getEncodedElementAccess(Indices); + if (Indices.size() == 1) { + // Return scalar. + return DerivedSuccess(Val.getVectorElt(Indices[0]), E); + } else { + // Construct new APValue vector. + SmallVector<APValue, 4> Elts; + for (unsigned I = 0; I < Indices.size(); ++I) { + Elts.push_back(Val.getVectorElt(Indices[I])); + } + APValue VecResult(Elts.data(), Indices.size()); + return DerivedSuccess(VecResult, E); + } + } + + return false; + } + bool VisitCastExpr(const CastExpr *E) { switch (E->getCastKind()) { default: @@ -7082,6 +7143,13 @@ public: return false; return DerivedSuccess(DestValue, E); } + + case CK_AddressSpaceConversion: { + APValue Value; + if (!Evaluate(Value, Info, E->getSubExpr())) + return false; + return DerivedSuccess(Value, E); + } } return Error(E); @@ -7460,8 +7528,8 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( // Walk through the expression to find the materialized temporary itself. SmallVector<const Expr *, 2> CommaLHSs; SmallVector<SubobjectAdjustment, 2> Adjustments; - const Expr *Inner = E->GetTemporaryExpr()-> - skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); + const Expr *Inner = + E->getSubExpr()->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); // If we passed any comma operators, evaluate their LHSs. for (unsigned I = 0, N = CommaLHSs.size(); I != N; ++I) @@ -7473,7 +7541,7 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr( // value for use outside this evaluation. APValue *Value; if (E->getStorageDuration() == SD_Static) { - Value = Info.Ctx.getMaterializedTemporaryValue(E, true); + Value = E->getOrCreateValue(true); *Value = APValue(); Result.set(E); } else { @@ -7856,6 +7924,11 @@ public: // either copied into the closure object's field that represents the '*this' // or refers to '*this'. if (isLambdaCallOperator(Info.CurrentCall->Callee)) { + // Ensure we actually have captured 'this'. (an error will have + // been previously reported if not). + if (!Info.CurrentCall->LambdaThisCaptureField) + return false; + // Update 'Result' to refer to the data member/field of the closure object // that represents the '*this' capture. if (!HandleLValueMember(Info, E, Result, @@ -8102,6 +8175,42 @@ static CharUnits GetAlignOfExpr(EvalInfo &Info, const Expr *E, return GetAlignOfType(Info, E->getType(), ExprKind); } +static CharUnits getBaseAlignment(EvalInfo &Info, const LValue &Value) { + if (const auto *VD = Value.Base.dyn_cast<const ValueDecl *>()) + return Info.Ctx.getDeclAlign(VD); + if (const auto *E = Value.Base.dyn_cast<const Expr *>()) + return GetAlignOfExpr(Info, E, UETT_AlignOf); + return GetAlignOfType(Info, Value.Base.getTypeInfoType(), UETT_AlignOf); +} + +/// Evaluate the value of the alignment argument to __builtin_align_{up,down}, +/// __builtin_is_aligned and __builtin_assume_aligned. +static bool getAlignmentArgument(const Expr *E, QualType ForType, + EvalInfo &Info, APSInt &Alignment) { + if (!EvaluateInteger(E, Alignment, Info)) + return false; + if (Alignment < 0 || !Alignment.isPowerOf2()) { + Info.FFDiag(E, diag::note_constexpr_invalid_alignment) << Alignment; + return false; + } + unsigned SrcWidth = Info.Ctx.getIntWidth(ForType); + APSInt MaxValue(APInt::getOneBitSet(SrcWidth, SrcWidth - 1)); + if (APSInt::compareValues(Alignment, MaxValue) > 0) { + Info.FFDiag(E, diag::note_constexpr_alignment_too_big) + << MaxValue << ForType << Alignment; + return false; + } + // Ensure both alignment and source value have the same bit width so that we + // don't assert when computing the resulting value. + APSInt ExtAlignment = + APSInt(Alignment.zextOrTrunc(SrcWidth), /*isUnsigned=*/true); + assert(APSInt::compareValues(Alignment, ExtAlignment) == 0 && + "Alignment should not be changed by ext/trunc"); + Alignment = ExtAlignment; + assert(Alignment.getBitWidth() == SrcWidth); + return true; +} + // To be clear: this happily visits unsupported builtins. Better name welcomed. bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) { if (ExprEvaluatorBaseTy::VisitCallExpr(E)) @@ -8140,7 +8249,8 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, LValue OffsetResult(Result); APSInt Alignment; - if (!EvaluateInteger(E->getArg(1), Alignment, Info)) + if (!getAlignmentArgument(E->getArg(1), E->getArg(0)->getType(), Info, + Alignment)) return false; CharUnits Align = CharUnits::fromQuantity(Alignment.getZExtValue()); @@ -8155,16 +8265,7 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, // If there is a base object, then it must have the correct alignment. if (OffsetResult.Base) { - CharUnits BaseAlignment; - if (const ValueDecl *VD = - OffsetResult.Base.dyn_cast<const ValueDecl*>()) { - BaseAlignment = Info.Ctx.getDeclAlign(VD); - } else if (const Expr *E = OffsetResult.Base.dyn_cast<const Expr *>()) { - BaseAlignment = GetAlignOfExpr(Info, E, UETT_AlignOf); - } else { - BaseAlignment = GetAlignOfType( - Info, OffsetResult.Base.getTypeInfoType(), UETT_AlignOf); - } + CharUnits BaseAlignment = getBaseAlignment(Info, OffsetResult); if (BaseAlignment < Align) { Result.Designator.setInvalid(); @@ -8193,6 +8294,43 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return true; } + case Builtin::BI__builtin_align_up: + case Builtin::BI__builtin_align_down: { + if (!evaluatePointer(E->getArg(0), Result)) + return false; + APSInt Alignment; + if (!getAlignmentArgument(E->getArg(1), E->getArg(0)->getType(), Info, + Alignment)) + return false; + CharUnits BaseAlignment = getBaseAlignment(Info, Result); + CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Result.Offset); + // For align_up/align_down, we can return the same value if the alignment + // is known to be greater or equal to the requested value. + if (PtrAlign.getQuantity() >= Alignment) + return true; + + // The alignment could be greater than the minimum at run-time, so we cannot + // infer much about the resulting pointer value. One case is possible: + // For `_Alignas(32) char buf[N]; __builtin_align_down(&buf[idx], 32)` we + // can infer the correct index if the requested alignment is smaller than + // the base alignment so we can perform the computation on the offset. + if (BaseAlignment.getQuantity() >= Alignment) { + assert(Alignment.getBitWidth() <= 64 && + "Cannot handle > 64-bit address-space"); + uint64_t Alignment64 = Alignment.getZExtValue(); + CharUnits NewOffset = CharUnits::fromQuantity( + BuiltinOp == Builtin::BI__builtin_align_down + ? llvm::alignDown(Result.Offset.getQuantity(), Alignment64) + : llvm::alignTo(Result.Offset.getQuantity(), Alignment64)); + Result.adjustOffset(NewOffset - Result.Offset); + // TODO: diagnose out-of-bounds values/only allow for arrays? + return true; + } + // Otherwise, we cannot constant-evaluate the result. + Info.FFDiag(E->getArg(0), diag::note_constexpr_alignment_adjust) + << Alignment; + return false; + } case Builtin::BI__builtin_operator_new: return HandleOperatorNewCall(Info, E, Result); case Builtin::BI__builtin_launder: @@ -9021,7 +9159,7 @@ bool RecordExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, if (E->isElidable() && !ZeroInit) if (const MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(E->getArg(0))) - return Visit(ME->GetTemporaryExpr()); + return Visit(ME->getSubExpr()); if (ZeroInit && !ZeroInitialization(E, T)) return false; @@ -9240,6 +9378,7 @@ namespace { bool VisitUnaryImag(const UnaryOperator *E); // FIXME: Missing: unary -, unary ~, binary add/sub/mul/div, // binary comparisons, binary and/or/xor, + // conditional operator (for GNU conditional select), // shufflevector, ExtVectorElementExpr }; } // end anonymous namespace @@ -10170,7 +10309,7 @@ static QualType getObjectType(APValue::LValueBase B) { if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>()) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) return VD->getType(); - } else if (const Expr *E = B.get<const Expr*>()) { + } else if (const Expr *E = B.dyn_cast<const Expr*>()) { if (isa<CompoundLiteralExpr>(E)) return E->getType(); } else if (B.is<TypeInfoLValue>()) { @@ -10491,6 +10630,33 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { return ExprEvaluatorBaseTy::VisitCallExpr(E); } +static bool getBuiltinAlignArguments(const CallExpr *E, EvalInfo &Info, + APValue &Val, APSInt &Alignment) { + QualType SrcTy = E->getArg(0)->getType(); + if (!getAlignmentArgument(E->getArg(1), SrcTy, Info, Alignment)) + return false; + // Even though we are evaluating integer expressions we could get a pointer + // argument for the __builtin_is_aligned() case. + if (SrcTy->isPointerType()) { + LValue Ptr; + if (!EvaluatePointer(E->getArg(0), Ptr, Info)) + return false; + Ptr.moveInto(Val); + } else if (!SrcTy->isIntegralOrEnumerationType()) { + Info.FFDiag(E->getArg(0)); + return false; + } else { + APSInt SrcInt; + if (!EvaluateInteger(E->getArg(0), SrcInt, Info)) + return false; + assert(SrcInt.getBitWidth() >= Alignment.getBitWidth() && + "Bit widths must be the same"); + Val = APValue(SrcInt); + } + assert(Val.hasValue()); + return true; +} + bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, unsigned BuiltinOp) { switch (unsigned BuiltinOp = E->getBuiltinCallee()) { @@ -10533,6 +10699,66 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return Success(Layout.size().getQuantity(), E); } + case Builtin::BI__builtin_is_aligned: { + APValue Src; + APSInt Alignment; + if (!getBuiltinAlignArguments(E, Info, Src, Alignment)) + return false; + if (Src.isLValue()) { + // If we evaluated a pointer, check the minimum known alignment. + LValue Ptr; + Ptr.setFrom(Info.Ctx, Src); + CharUnits BaseAlignment = getBaseAlignment(Info, Ptr); + CharUnits PtrAlign = BaseAlignment.alignmentAtOffset(Ptr.Offset); + // We can return true if the known alignment at the computed offset is + // greater than the requested alignment. + assert(PtrAlign.isPowerOfTwo()); + assert(Alignment.isPowerOf2()); + if (PtrAlign.getQuantity() >= Alignment) + return Success(1, E); + // If the alignment is not known to be sufficient, some cases could still + // be aligned at run time. However, if the requested alignment is less or + // equal to the base alignment and the offset is not aligned, we know that + // the run-time value can never be aligned. + if (BaseAlignment.getQuantity() >= Alignment && + PtrAlign.getQuantity() < Alignment) + return Success(0, E); + // Otherwise we can't infer whether the value is sufficiently aligned. + // TODO: __builtin_is_aligned(__builtin_align_{down,up{(expr, N), N) + // in cases where we can't fully evaluate the pointer. + Info.FFDiag(E->getArg(0), diag::note_constexpr_alignment_compute) + << Alignment; + return false; + } + assert(Src.isInt()); + return Success((Src.getInt() & (Alignment - 1)) == 0 ? 1 : 0, E); + } + case Builtin::BI__builtin_align_up: { + APValue Src; + APSInt Alignment; + if (!getBuiltinAlignArguments(E, Info, Src, Alignment)) + return false; + if (!Src.isInt()) + return Error(E); + APSInt AlignedVal = + APSInt((Src.getInt() + (Alignment - 1)) & ~(Alignment - 1), + Src.getInt().isUnsigned()); + assert(AlignedVal.getBitWidth() == Src.getInt().getBitWidth()); + return Success(AlignedVal, E); + } + case Builtin::BI__builtin_align_down: { + APValue Src; + APSInt Alignment; + if (!getBuiltinAlignArguments(E, Info, Src, Alignment)) + return false; + if (!Src.isInt()) + return Error(E); + APSInt AlignedVal = + APSInt(Src.getInt() & ~(Alignment - 1), Src.getInt().isUnsigned()); + assert(AlignedVal.getBitWidth() == Src.getInt().getBitWidth()); + return Success(AlignedVal, E); + } + case Builtin::BI__builtin_bswap16: case Builtin::BI__builtin_bswap32: case Builtin::BI__builtin_bswap64: { @@ -10583,8 +10809,24 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return false; } - case Builtin::BI__builtin_is_constant_evaluated: + case Builtin::BI__builtin_is_constant_evaluated: { + const auto *Callee = Info.CurrentCall->getCallee(); + if (Info.InConstantContext && !Info.CheckingPotentialConstantExpression && + (Info.CallStackDepth == 1 || + (Info.CallStackDepth == 2 && Callee->isInStdNamespace() && + Callee->getIdentifier() && + Callee->getIdentifier()->isStr("is_constant_evaluated")))) { + // FIXME: Find a better way to avoid duplicated diagnostics. + if (Info.EvalStatus.Diag) + Info.report((Info.CallStackDepth == 1) ? E->getExprLoc() + : Info.CurrentCall->CallLoc, + diag::warn_is_constant_evaluated_always_true_constexpr) + << (Info.CallStackDepth == 1 ? "__builtin_is_constant_evaluated" + : "std::is_constant_evaluated"); + } + return Success(Info.InConstantContext, E); + } case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: @@ -11417,6 +11659,14 @@ public: } } }; + +enum class CmpResult { + Unequal, + Less, + Equal, + Greater, + Unordered, +}; } template <class SuccessCB, class AfterCB> @@ -11432,15 +11682,8 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, return false; }; - using CCR = ComparisonCategoryResult; - bool IsRelational = E->isRelationalOp(); + bool IsRelational = E->isRelationalOp() || E->getOpcode() == BO_Cmp; bool IsEquality = E->isEqualityOp(); - if (E->getOpcode() == BO_Cmp) { - const ComparisonCategoryInfo &CmpInfo = - Info.Ctx.CompCategories.getInfoForType(E->getType()); - IsRelational = CmpInfo.isOrdered(); - IsEquality = CmpInfo.isEquality(); - } QualType LHSTy = E->getLHS()->getType(); QualType RHSTy = E->getRHS()->getType(); @@ -11454,10 +11697,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, if (!EvaluateInteger(E->getRHS(), RHS, Info) || !LHSOK) return false; if (LHS < RHS) - return Success(CCR::Less, E); + return Success(CmpResult::Less, E); if (LHS > RHS) - return Success(CCR::Greater, E); - return Success(CCR::Equal, E); + return Success(CmpResult::Greater, E); + return Success(CmpResult::Equal, E); } if (LHSTy->isFixedPointType() || RHSTy->isFixedPointType()) { @@ -11470,10 +11713,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, if (!EvaluateFixedPointOrInteger(E->getRHS(), RHSFX, Info) || !LHSOK) return false; if (LHSFX < RHSFX) - return Success(CCR::Less, E); + return Success(CmpResult::Less, E); if (LHSFX > RHSFX) - return Success(CCR::Greater, E); - return Success(CCR::Equal, E); + return Success(CmpResult::Greater, E); + return Success(CmpResult::Equal, E); } if (LHSTy->isAnyComplexType() || RHSTy->isAnyComplexType()) { @@ -11509,12 +11752,12 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, APFloat::cmpResult CR_i = LHS.getComplexFloatImag().compare(RHS.getComplexFloatImag()); bool IsEqual = CR_r == APFloat::cmpEqual && CR_i == APFloat::cmpEqual; - return Success(IsEqual ? CCR::Equal : CCR::Nonequal, E); + return Success(IsEqual ? CmpResult::Equal : CmpResult::Unequal, E); } else { assert(IsEquality && "invalid complex comparison"); bool IsEqual = LHS.getComplexIntReal() == RHS.getComplexIntReal() && LHS.getComplexIntImag() == RHS.getComplexIntImag(); - return Success(IsEqual ? CCR::Equal : CCR::Nonequal, E); + return Success(IsEqual ? CmpResult::Equal : CmpResult::Unequal, E); } } @@ -11533,13 +11776,13 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, auto GetCmpRes = [&]() { switch (LHS.compare(RHS)) { case APFloat::cmpEqual: - return CCR::Equal; + return CmpResult::Equal; case APFloat::cmpLessThan: - return CCR::Less; + return CmpResult::Less; case APFloat::cmpGreaterThan: - return CCR::Greater; + return CmpResult::Greater; case APFloat::cmpUnordered: - return CCR::Unordered; + return CmpResult::Unordered; } llvm_unreachable("Unrecognised APFloat::cmpResult enum"); }; @@ -11561,8 +11804,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, if (!HasSameBase(LHSValue, RHSValue)) { // Inequalities and subtractions between unrelated pointers have // unspecified or undefined behavior. - if (!IsEquality) - return Error(E); + if (!IsEquality) { + Info.FFDiag(E, diag::note_constexpr_pointer_comparison_unspecified); + return false; + } // A constant address may compare equal to the address of a symbol. // The one exception is that address of an object cannot compare equal // to a null pointer constant. @@ -11592,7 +11837,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, if ((RHSValue.Base && isZeroSized(LHSValue)) || (LHSValue.Base && isZeroSized(RHSValue))) return Error(E); - return Success(CCR::Nonequal, E); + return Success(CmpResult::Unequal, E); } const CharUnits &LHSOffset = LHSValue.getLValueOffset(); @@ -11676,10 +11921,10 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, } if (CompareLHS < CompareRHS) - return Success(CCR::Less, E); + return Success(CmpResult::Less, E); if (CompareLHS > CompareRHS) - return Success(CCR::Greater, E); - return Success(CCR::Equal, E); + return Success(CmpResult::Greater, E); + return Success(CmpResult::Equal, E); } if (LHSTy->isMemberPointerType()) { @@ -11700,7 +11945,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, // null, they compare unequal. if (!LHSValue.getDecl() || !RHSValue.getDecl()) { bool Equal = !LHSValue.getDecl() && !RHSValue.getDecl(); - return Success(Equal ? CCR::Equal : CCR::Nonequal, E); + return Success(Equal ? CmpResult::Equal : CmpResult::Unequal, E); } // Otherwise if either is a pointer to a virtual member function, the @@ -11717,7 +11962,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, // they were dereferenced with a hypothetical object of the associated // class type. bool Equal = LHSValue == RHSValue; - return Success(Equal ? CCR::Equal : CCR::Nonequal, E); + return Success(Equal ? CmpResult::Equal : CmpResult::Unequal, E); } if (LHSTy->isNullPtrType()) { @@ -11726,7 +11971,7 @@ EvaluateComparisonBinaryOperator(EvalInfo &Info, const BinaryOperator *E, // C++11 [expr.rel]p4, [expr.eq]p3: If two operands of type std::nullptr_t // are compared, the result is true of the operator is <=, >= or ==, and // false otherwise. - return Success(CCR::Equal, E); + return Success(CmpResult::Equal, E); } return DoAfter(); @@ -11736,14 +11981,29 @@ bool RecordExprEvaluator::VisitBinCmp(const BinaryOperator *E) { if (!CheckLiteralType(Info, E)) return false; - auto OnSuccess = [&](ComparisonCategoryResult ResKind, - const BinaryOperator *E) { + auto OnSuccess = [&](CmpResult CR, const BinaryOperator *E) { + ComparisonCategoryResult CCR; + switch (CR) { + case CmpResult::Unequal: + llvm_unreachable("should never produce Unequal for three-way comparison"); + case CmpResult::Less: + CCR = ComparisonCategoryResult::Less; + break; + case CmpResult::Equal: + CCR = ComparisonCategoryResult::Equal; + break; + case CmpResult::Greater: + CCR = ComparisonCategoryResult::Greater; + break; + case CmpResult::Unordered: + CCR = ComparisonCategoryResult::Unordered; + break; + } // Evaluation succeeded. Lookup the information for the comparison category // type and fetch the VarDecl for the result. const ComparisonCategoryInfo &CmpInfo = Info.Ctx.CompCategories.getInfoForType(E->getType()); - const VarDecl *VD = - CmpInfo.getValueInfo(CmpInfo.makeWeakResult(ResKind))->VD; + const VarDecl *VD = CmpInfo.getValueInfo(CmpInfo.makeWeakResult(CCR))->VD; // Check and evaluate the result as a constant expression. LValue LV; LV.set(VD); @@ -11771,14 +12031,14 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { "DataRecursiveIntBinOpEvaluator should have handled integral types"); if (E->isComparisonOp()) { - // Evaluate builtin binary comparisons by evaluating them as C++2a three-way + // Evaluate builtin binary comparisons by evaluating them as three-way // comparisons and then translating the result. - auto OnSuccess = [&](ComparisonCategoryResult ResKind, - const BinaryOperator *E) { - using CCR = ComparisonCategoryResult; - bool IsEqual = ResKind == CCR::Equal, - IsLess = ResKind == CCR::Less, - IsGreater = ResKind == CCR::Greater; + auto OnSuccess = [&](CmpResult CR, const BinaryOperator *E) { + assert((CR != CmpResult::Unequal || E->isEqualityOp()) && + "should only produce Unequal for equality comparisons"); + bool IsEqual = CR == CmpResult::Equal, + IsLess = CR == CmpResult::Less, + IsGreater = CR == CmpResult::Greater; auto Op = E->getOpcode(); switch (Op) { default: @@ -11786,10 +12046,14 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { case BO_EQ: case BO_NE: return Success(IsEqual == (Op == BO_EQ), E); - case BO_LT: return Success(IsLess, E); - case BO_GT: return Success(IsGreater, E); - case BO_LE: return Success(IsEqual || IsLess, E); - case BO_GE: return Success(IsEqual || IsGreater, E); + case BO_LT: + return Success(IsLess, E); + case BO_GT: + return Success(IsGreater, E); + case BO_LE: + return Success(IsEqual || IsLess, E); + case BO_GE: + return Success(IsEqual || IsGreater, E); } }; return EvaluateComparisonBinaryOperator(Info, E, OnSuccess, [&]() { @@ -13374,32 +13638,25 @@ static bool EvaluateInPlace(APValue &Result, EvalInfo &Info, const LValue &This, /// EvaluateAsRValue - Try to evaluate this expression, performing an implicit /// lvalue-to-rvalue cast if it is an lvalue. static bool EvaluateAsRValue(EvalInfo &Info, const Expr *E, APValue &Result) { - if (Info.EnableNewConstInterp) { - auto &InterpCtx = Info.Ctx.getInterpContext(); - switch (InterpCtx.evaluateAsRValue(Info, E, Result)) { - case interp::InterpResult::Success: - return true; - case interp::InterpResult::Fail: + if (Info.EnableNewConstInterp) { + if (!Info.Ctx.getInterpContext().evaluateAsRValue(Info, E, Result)) + return false; + } else { + if (E->getType().isNull()) return false; - case interp::InterpResult::Bail: - break; - } - } - - if (E->getType().isNull()) - return false; - - if (!CheckLiteralType(Info, E)) - return false; - if (!::Evaluate(Result, Info, E)) - return false; + if (!CheckLiteralType(Info, E)) + return false; - if (E->isGLValue()) { - LValue LV; - LV.setFrom(Info.Ctx, Result); - if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) + if (!::Evaluate(Result, Info, E)) return false; + + if (E->isGLValue()) { + LValue LV; + LV.setFrom(Info.Ctx, Result); + if (!handleLValueToRValueConversion(Info, E, E->getType(), LV, Result)) + return false; + } } // Check this core constant expression is a constant expression. @@ -13611,46 +13868,36 @@ bool Expr::EvaluateAsInitializer(APValue &Value, const ASTContext &Ctx, if (Info.EnableNewConstInterp) { auto &InterpCtx = const_cast<ASTContext &>(Ctx).getInterpContext(); - switch (InterpCtx.evaluateAsInitializer(Info, VD, Value)) { - case interp::InterpResult::Fail: - // Bail out if an error was encountered. + if (!InterpCtx.evaluateAsInitializer(Info, VD, Value)) return false; - case interp::InterpResult::Success: - // Evaluation succeeded and value was set. - return CheckConstantExpression(Info, DeclLoc, DeclTy, Value); - case interp::InterpResult::Bail: - // Evaluate the value again for the tree evaluator to use. - break; - } - } + } else { + LValue LVal; + LVal.set(VD); - LValue LVal; - LVal.set(VD); + // C++11 [basic.start.init]p2: + // Variables with static storage duration or thread storage duration shall + // be zero-initialized before any other initialization takes place. + // This behavior is not present in C. + if (Ctx.getLangOpts().CPlusPlus && !VD->hasLocalStorage() && + !DeclTy->isReferenceType()) { + ImplicitValueInitExpr VIE(DeclTy); + if (!EvaluateInPlace(Value, Info, LVal, &VIE, + /*AllowNonLiteralTypes=*/true)) + return false; + } - // C++11 [basic.start.init]p2: - // Variables with static storage duration or thread storage duration shall be - // zero-initialized before any other initialization takes place. - // This behavior is not present in C. - if (Ctx.getLangOpts().CPlusPlus && !VD->hasLocalStorage() && - !DeclTy->isReferenceType()) { - ImplicitValueInitExpr VIE(DeclTy); - if (!EvaluateInPlace(Value, Info, LVal, &VIE, - /*AllowNonLiteralTypes=*/true)) + if (!EvaluateInPlace(Value, Info, LVal, this, + /*AllowNonLiteralTypes=*/true) || + EStatus.HasSideEffects) return false; - } - if (!EvaluateInPlace(Value, Info, LVal, this, - /*AllowNonLiteralTypes=*/true) || - EStatus.HasSideEffects) - return false; - - // At this point, any lifetime-extended temporaries are completely - // initialized. - Info.performLifetimeExtension(); - - if (!Info.discardCleanups()) - llvm_unreachable("Unhandled cleanup; missing full expression marker?"); + // At this point, any lifetime-extended temporaries are completely + // initialized. + Info.performLifetimeExtension(); + if (!Info.discardCleanups()) + llvm_unreachable("Unhandled cleanup; missing full expression marker?"); + } return CheckConstantExpression(Info, DeclLoc, DeclTy, Value) && CheckMemoryLeaks(Info); } @@ -14333,27 +14580,41 @@ bool Expr::EvaluateWithSubstitution(APValue &Value, ASTContext &Ctx, assert(MD && "Don't provide `this` for non-methods."); assert(!MD->isStatic() && "Don't provide `this` for static methods."); #endif - if (EvaluateObjectArgument(Info, This, ThisVal)) + if (!This->isValueDependent() && + EvaluateObjectArgument(Info, This, ThisVal) && + !Info.EvalStatus.HasSideEffects) ThisPtr = &ThisVal; - if (Info.EvalStatus.HasSideEffects) - return false; + + // Ignore any side-effects from a failed evaluation. This is safe because + // they can't interfere with any other argument evaluation. + Info.EvalStatus.HasSideEffects = false; } ArgVector ArgValues(Args.size()); for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end(); I != E; ++I) { if ((*I)->isValueDependent() || - !Evaluate(ArgValues[I - Args.begin()], Info, *I)) + !Evaluate(ArgValues[I - Args.begin()], Info, *I) || + Info.EvalStatus.HasSideEffects) // If evaluation fails, throw away the argument entirely. ArgValues[I - Args.begin()] = APValue(); - if (Info.EvalStatus.HasSideEffects) - return false; + + // Ignore any side-effects from a failed evaluation. This is safe because + // they can't interfere with any other argument evaluation. + Info.EvalStatus.HasSideEffects = false; } + // Parameter cleanups happen in the caller and are not part of this + // evaluation. + Info.discardCleanups(); + Info.EvalStatus.HasSideEffects = false; + // Build fake call to Callee. CallStackFrame Frame(Info, Callee->getLocation(), Callee, ThisPtr, ArgValues.data()); - return Evaluate(Value, Info, this) && Info.discardCleanups() && + // FIXME: Missing ExprWithCleanups in enable_if conditions? + FullExpressionRAII Scope(Info); + return Evaluate(Value, Info, this) && Scope.destroy() && !Info.EvalStatus.HasSideEffects; } @@ -14375,14 +14636,8 @@ bool Expr::isPotentialConstantExpr(const FunctionDecl *FD, // The constexpr VM attempts to compile all methods to bytecode here. if (Info.EnableNewConstInterp) { - auto &InterpCtx = Info.Ctx.getInterpContext(); - switch (InterpCtx.isPotentialConstantExpr(Info, FD)) { - case interp::InterpResult::Success: - case interp::InterpResult::Fail: - return Diags.empty(); - case interp::InterpResult::Bail: - break; - } + Info.Ctx.getInterpContext().isPotentialConstantExpr(Info, FD); + return Diags.empty(); } const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD); diff --git a/clang/lib/AST/ExternalASTMerger.cpp b/clang/lib/AST/ExternalASTMerger.cpp index f678c2dd3b59..88bbe90a4e90 100644 --- a/clang/lib/AST/ExternalASTMerger.cpp +++ b/clang/lib/AST/ExternalASTMerger.cpp @@ -510,9 +510,7 @@ bool ExternalASTMerger::FindExternalVisibleDeclsByName(const DeclContext *DC, Decl *LookupRes = C.first.get(); ASTImporter *Importer = C.second; auto NDOrErr = Importer->Import(LookupRes); - assert(NDOrErr); - (void)static_cast<bool>(NDOrErr); - NamedDecl *ND = cast_or_null<NamedDecl>(*NDOrErr); + NamedDecl *ND = cast<NamedDecl>(llvm::cantFail(std::move(NDOrErr))); assert(ND); // If we don't import specialization, they are not available via lookup // because the lookup result is imported TemplateDecl and it does not diff --git a/clang/lib/AST/ExternalASTSource.cpp b/clang/lib/AST/ExternalASTSource.cpp index 730102757440..837be5527fce 100644 --- a/clang/lib/AST/ExternalASTSource.cpp +++ b/clang/lib/AST/ExternalASTSource.cpp @@ -24,6 +24,8 @@ using namespace clang; +char ExternalASTSource::ID; + ExternalASTSource::~ExternalASTSource() = default; llvm::Optional<ExternalASTSource::ASTSourceDescriptor> diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index c71301598bde..5b47489e65e0 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -14,13 +14,11 @@ #include "PrimType.h" #include "Program.h" #include "State.h" +#include "clang/Basic/LLVM.h" using namespace clang; using namespace clang::interp; -template <typename T> using Expected = llvm::Expected<T>; -template <typename T> using Optional = llvm::Optional<T>; - namespace clang { namespace interp { diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index 4f8f7b96e7c3..e7f9ba0f010a 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -21,44 +21,37 @@ using namespace clang; using namespace clang::interp; -Context::Context(ASTContext &Ctx) - : Ctx(Ctx), ForceInterp(getLangOpts().ForceNewConstInterp), - P(new Program(*this)) {} +Context::Context(ASTContext &Ctx) : Ctx(Ctx), P(new Program(*this)) {} Context::~Context() {} -InterpResult Context::isPotentialConstantExpr(State &Parent, - const FunctionDecl *FD) { +bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) { Function *Func = P->getFunction(FD); if (!Func) { if (auto R = ByteCodeStmtGen<ByteCodeEmitter>(*this, *P).compileFunc(FD)) { Func = *R; - } else if (ForceInterp) { + } else { handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) { Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed); }); - return InterpResult::Fail; - } else { - consumeError(R.takeError()); - return InterpResult::Bail; + return false; } } if (!Func->isConstexpr()) - return InterpResult::Fail; + return false; APValue Dummy; return Run(Parent, Func, Dummy); } -InterpResult Context::evaluateAsRValue(State &Parent, const Expr *E, - APValue &Result) { +bool Context::evaluateAsRValue(State &Parent, const Expr *E, APValue &Result) { ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result); return Check(Parent, C.interpretExpr(E)); } -InterpResult Context::evaluateAsInitializer(State &Parent, const VarDecl *VD, - APValue &Result) { +bool Context::evaluateAsInitializer(State &Parent, const VarDecl *VD, + APValue &Result) { ByteCodeExprGen<EvalEmitter> C(*this, *P, Parent, Stk, Result); return Check(Parent, C.interpretDecl(VD)); } @@ -116,33 +109,20 @@ unsigned Context::getCharBit() const { return Ctx.getTargetInfo().getCharWidth(); } -InterpResult Context::Run(State &Parent, Function *Func, APValue &Result) { - InterpResult Flag; - { - InterpState State(Parent, *P, Stk, *this); - State.Current = new InterpFrame(State, Func, nullptr, {}, {}); - if (Interpret(State, Result)) { - Flag = InterpResult::Success; - } else { - Flag = InterpResult::Fail; - } - } - - if (Flag != InterpResult::Success) - Stk.clear(); - return Flag; +bool Context::Run(State &Parent, Function *Func, APValue &Result) { + InterpState State(Parent, *P, Stk, *this); + State.Current = new InterpFrame(State, Func, nullptr, {}, {}); + if (Interpret(State, Result)) + return true; + Stk.clear(); + return false; } -InterpResult Context::Check(State &Parent, llvm::Expected<bool> &&R) { - if (R) { - return *R ? InterpResult::Success : InterpResult::Fail; - } else if (ForceInterp) { - handleAllErrors(R.takeError(), [&Parent](ByteCodeGenError &Err) { - Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed); - }); - return InterpResult::Fail; - } else { - consumeError(R.takeError()); - return InterpResult::Bail; - } +bool Context::Check(State &Parent, llvm::Expected<bool> &&Flag) { + if (Flag) + return *Flag; + handleAllErrors(Flag.takeError(), [&Parent](ByteCodeGenError &Err) { + Parent.FFDiag(Err.getLoc(), diag::err_experimental_clang_interp_failed); + }); + return false; } diff --git a/clang/lib/AST/Interp/Context.h b/clang/lib/AST/Interp/Context.h index 96368b6e5f02..e4d831cbb991 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -34,16 +34,6 @@ class Program; class State; enum PrimType : unsigned; -/// Wrapper around interpreter termination results. -enum class InterpResult { - /// Interpreter successfully computed a value. - Success, - /// Interpreter encountered an error and quit. - Fail, - /// Interpreter encountered an unimplemented feature, AST fallback. - Bail, -}; - /// Holds all information required to evaluate constexpr code in a module. class Context { public: @@ -54,15 +44,13 @@ public: ~Context(); /// Checks if a function is a potential constant expression. - InterpResult isPotentialConstantExpr(State &Parent, - const FunctionDecl *FnDecl); + bool isPotentialConstantExpr(State &Parent, const FunctionDecl *FnDecl); /// Evaluates a toplevel expression as an rvalue. - InterpResult evaluateAsRValue(State &Parent, const Expr *E, APValue &Result); + bool evaluateAsRValue(State &Parent, const Expr *E, APValue &Result); /// Evaluates a toplevel initializer. - InterpResult evaluateAsInitializer(State &Parent, const VarDecl *VD, - APValue &Result); + bool evaluateAsInitializer(State &Parent, const VarDecl *VD, APValue &Result); /// Returns the AST context. ASTContext &getASTContext() const { return Ctx; } @@ -78,16 +66,14 @@ public: private: /// Runs a function. - InterpResult Run(State &Parent, Function *Func, APValue &Result); + bool Run(State &Parent, Function *Func, APValue &Result); /// Checks a result fromt the interpreter. - InterpResult Check(State &Parent, llvm::Expected<bool> &&R); + bool Check(State &Parent, llvm::Expected<bool> &&R); private: /// Current compilation context. ASTContext &Ctx; - /// Flag to indicate if the use of the interpreter is mandatory. - bool ForceInterp; /// Interpreter stack, shared across invocations. InterpStack Stk; /// Constexpr program. diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 8934efa13b9c..c12caa639da7 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -196,11 +196,8 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { const Pointer &RHS = S.Stk.pop<Pointer>(); const Pointer &LHS = S.Stk.pop<Pointer>(); - if (LHS.isZero() || RHS.isZero()) { - if (LHS.isZero() && RHS.isZero()) - S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal))); - else - S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Nonequal))); + if (LHS.isZero() && RHS.isZero()) { + S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal))); return true; } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index c55a90137578..0d567edac521 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2301,6 +2301,16 @@ void CXXNameMangler::mangleQualifiers(Qualifiers Quals, const DependentAddressSp case LangAS::cuda_device: ASString = "CUdevice"; break; case LangAS::cuda_constant: ASString = "CUconstant"; break; case LangAS::cuda_shared: ASString = "CUshared"; break; + // <ptrsize-addrspace> ::= [ "ptr32_sptr" | "ptr32_uptr" | "ptr64" ] + case LangAS::ptr32_sptr: + ASString = "ptr32_sptr"; + break; + case LangAS::ptr32_uptr: + ASString = "ptr32_uptr"; + break; + case LangAS::ptr64: + ASString = "ptr64"; + break; } } if (!ASString.empty()) @@ -4338,7 +4348,7 @@ recurse: } case Expr::MaterializeTemporaryExprClass: { - mangleExpression(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr()); + mangleExpression(cast<MaterializeTemporaryExpr>(E)->getSubExpr()); break; } diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index f60d761c996c..c30b07137edc 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -202,14 +202,20 @@ void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc, PresumedLoc Presumed = SM.getPresumedLoc(Loc); unsigned ActualLine = IsSpelling ? SM.getSpellingLineNumber(Loc) : SM.getExpansionLineNumber(Loc); + StringRef ActualFile = SM.getBufferName(Loc); + if (Presumed.isValid()) { JOS.attribute("offset", SM.getDecomposedLoc(Loc).second); - if (LastLocFilename != Presumed.getFilename()) { - JOS.attribute("file", Presumed.getFilename()); + if (LastLocFilename != ActualFile) { + JOS.attribute("file", ActualFile); JOS.attribute("line", ActualLine); } else if (LastLocLine != ActualLine) JOS.attribute("line", ActualLine); + StringRef PresumedFile = Presumed.getFilename(); + if (PresumedFile != ActualFile && LastLocPresumedFilename != PresumedFile) + JOS.attribute("presumedFile", PresumedFile); + unsigned PresumedLine = Presumed.getLine(); if (ActualLine != PresumedLine && LastLocPresumedLine != PresumedLine) JOS.attribute("presumedLine", PresumedLine); @@ -217,7 +223,8 @@ void JSONNodeDumper::writeBareSourceLocation(SourceLocation Loc, JOS.attribute("col", Presumed.getColumn()); JOS.attribute("tokLen", Lexer::MeasureTokenLength(Loc, SM, Ctx.getLangOpts())); - LastLocFilename = Presumed.getFilename(); + LastLocFilename = ActualFile; + LastLocPresumedFilename = PresumedFile; LastLocPresumedLine = PresumedLine; LastLocLine = ActualLine; @@ -688,8 +695,12 @@ void JSONNodeDumper::VisitMemberPointerType(const MemberPointerType *MPT) { } void JSONNodeDumper::VisitNamedDecl(const NamedDecl *ND) { - if (ND && ND->getDeclName()) + if (ND && ND->getDeclName()) { JOS.attribute("name", ND->getNameAsString()); + std::string MangledName = ASTNameGen.getName(ND); + if (!MangledName.empty()) + JOS.attribute("mangledName", MangledName); + } } void JSONNodeDumper::VisitTypedefDecl(const TypedefDecl *TD) { @@ -874,12 +885,6 @@ void JSONNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *LSD) { switch (LSD->getLanguage()) { case LinkageSpecDecl::lang_c: Lang = "C"; break; case LinkageSpecDecl::lang_cxx: Lang = "C++"; break; - case LinkageSpecDecl::lang_cxx_11: - Lang = "C++11"; - break; - case LinkageSpecDecl::lang_cxx_14: - Lang = "C++14"; - break; } JOS.attribute("language", Lang); attributeOnlyIfTrue("hasBraces", LSD->hasBraces()); @@ -1013,6 +1018,7 @@ void JSONNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { attributeOnlyIfTrue("unsafe_unretained", Attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained); attributeOnlyIfTrue("class", Attrs & ObjCPropertyDecl::OBJC_PR_class); + attributeOnlyIfTrue("direct", Attrs & ObjCPropertyDecl::OBJC_PR_direct); attributeOnlyIfTrue("nullability", Attrs & ObjCPropertyDecl::OBJC_PR_nullability); attributeOnlyIfTrue("null_resettable", @@ -1512,6 +1518,9 @@ void JSONNodeDumper::visitInlineCommandComment( case comments::InlineCommandComment::RenderMonospaced: JOS.attribute("renderKind", "monospaced"); break; + case comments::InlineCommandComment::RenderAnchor: + JOS.attribute("renderKind", "anchor"); + break; } llvm::json::Array Args; diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index 32d466cb5718..e106b31f59f0 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -63,9 +63,7 @@ static CCMangling getCallingConvMangling(const ASTContext &Context, const NamedDecl *ND) { const TargetInfo &TI = Context.getTargetInfo(); const llvm::Triple &Triple = TI.getTriple(); - if (!Triple.isOSWindows() || - !(Triple.getArch() == llvm::Triple::x86 || - Triple.getArch() == llvm::Triple::x86_64)) + if (!Triple.isOSWindows() || !Triple.isX86()) return CCM_Other; if (Context.getLangOpts().CPlusPlus && !isExternC(ND) && diff --git a/clang/lib/AST/MicrosoftCXXABI.cpp b/clang/lib/AST/MicrosoftCXXABI.cpp index 074abba3d458..f9f9fe985b6f 100644 --- a/clang/lib/AST/MicrosoftCXXABI.cpp +++ b/clang/lib/AST/MicrosoftCXXABI.cpp @@ -14,6 +14,7 @@ #include "CXXABI.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/MangleNumberingContext.h" #include "clang/AST/RecordLayout.h" @@ -154,27 +155,32 @@ static bool usesMultipleInheritanceModel(const CXXRecordDecl *RD) { return false; } -MSInheritanceAttr::Spelling CXXRecordDecl::calculateInheritanceModel() const { +MSInheritanceModel CXXRecordDecl::calculateInheritanceModel() const { if (!hasDefinition() || isParsingBaseSpecifiers()) - return MSInheritanceAttr::Keyword_unspecified_inheritance; + return MSInheritanceModel::Unspecified; if (getNumVBases() > 0) - return MSInheritanceAttr::Keyword_virtual_inheritance; + return MSInheritanceModel::Virtual; if (usesMultipleInheritanceModel(this)) - return MSInheritanceAttr::Keyword_multiple_inheritance; - return MSInheritanceAttr::Keyword_single_inheritance; + return MSInheritanceModel::Multiple; + return MSInheritanceModel::Single; } -MSInheritanceAttr::Spelling -CXXRecordDecl::getMSInheritanceModel() const { +MSInheritanceModel CXXRecordDecl::getMSInheritanceModel() const { MSInheritanceAttr *IA = getAttr<MSInheritanceAttr>(); assert(IA && "Expected MSInheritanceAttr on the CXXRecordDecl!"); - return IA->getSemanticSpelling(); + return IA->getInheritanceModel(); } -MSVtorDispAttr::Mode CXXRecordDecl::getMSVtorDispMode() const { +bool CXXRecordDecl::nullFieldOffsetIsZero() const { + return !inheritanceModelHasOnlyOneField(/*IsMemberFunction=*/false, + getMSInheritanceModel()) || + (hasDefinition() && isPolymorphic()); +} + +MSVtorDispMode CXXRecordDecl::getMSVtorDispMode() const { if (MSVtorDispAttr *VDA = getAttr<MSVtorDispAttr>()) return VDA->getVtorDispMode(); - return MSVtorDispAttr::Mode(getASTContext().getLangOpts().VtorDispMode); + return getASTContext().getLangOpts().getVtorDispMode(); } // Returns the number of pointer and integer slots used to represent a member @@ -209,19 +215,19 @@ MSVtorDispAttr::Mode CXXRecordDecl::getMSVtorDispMode() const { static std::pair<unsigned, unsigned> getMSMemberPointerSlots(const MemberPointerType *MPT) { const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); - MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); unsigned Ptrs = 0; unsigned Ints = 0; if (MPT->isMemberFunctionPointer()) Ptrs = 1; else Ints = 1; - if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(), + if (inheritanceModelHasNVOffsetField(MPT->isMemberFunctionPointer(), Inheritance)) Ints++; - if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) + if (inheritanceModelHasVBPtrOffsetField(Inheritance)) Ints++; - if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) + if (inheritanceModelHasVBTableOffsetField(Inheritance)) Ints++; return std::make_pair(Ptrs, Ints); } diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index f871a1b99900..a286c5335584 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -279,8 +279,6 @@ class MicrosoftCXXNameMangler { ASTContext &getASTContext() const { return Context.getASTContext(); } - // FIXME: If we add support for __ptr32/64 qualifiers, then we should push - // this check into mangleQualifiers(). const bool PointersAre64Bit; public: @@ -335,6 +333,13 @@ private: return ND == Structor || getStructor(ND) == Structor; } + bool is64BitPointer(Qualifiers Quals) const { + LangAS AddrSpace = Quals.getAddressSpace(); + return AddrSpace == LangAS::ptr64 || + (PointersAre64Bit && !(AddrSpace == LangAS::ptr32_sptr || + AddrSpace == LangAS::ptr32_uptr)); + } + void mangleUnqualifiedName(const NamedDecl *ND) { mangleUnqualifiedName(ND, ND->getDeclName()); } @@ -592,7 +597,7 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD, int64_t FieldOffset; int64_t VBTableOffset; - MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel(); + MSInheritanceModel IM = RD->getMSInheritanceModel(); if (VD) { FieldOffset = getASTContext().getFieldOffset(VD); assert(FieldOffset % getASTContext().getCharWidth() == 0 && @@ -601,7 +606,7 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD, VBTableOffset = 0; - if (IM == MSInheritanceAttr::Keyword_virtual_inheritance) + if (IM == MSInheritanceModel::Virtual) FieldOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity(); } else { FieldOffset = RD->nullFieldOffsetIsZero() ? 0 : -1; @@ -611,12 +616,10 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD, char Code = '\0'; switch (IM) { - case MSInheritanceAttr::Keyword_single_inheritance: Code = '0'; break; - case MSInheritanceAttr::Keyword_multiple_inheritance: Code = '0'; break; - case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'F'; break; - case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'G'; break; - case MSInheritanceAttr::SpellingNotCalculated: - llvm_unreachable("not reachable"); + case MSInheritanceModel::Single: Code = '0'; break; + case MSInheritanceModel::Multiple: Code = '0'; break; + case MSInheritanceModel::Virtual: Code = 'F'; break; + case MSInheritanceModel::Unspecified: Code = 'G'; break; } Out << '$' << Code; @@ -626,9 +629,9 @@ void MicrosoftCXXNameMangler::mangleMemberDataPointer(const CXXRecordDecl *RD, // The C++ standard doesn't allow base-to-derived member pointer conversions // in template parameter contexts, so the vbptr offset of data member pointers // is always zero. - if (MSInheritanceAttr::hasVBPtrOffsetField(IM)) + if (inheritanceModelHasVBPtrOffsetField(IM)) mangleNumber(0); - if (MSInheritanceAttr::hasVBTableOffsetField(IM)) + if (inheritanceModelHasVBTableOffsetField(IM)) mangleNumber(VBTableOffset); } @@ -640,16 +643,14 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD, // ::= $I? <name> <number> <number> // ::= $J? <name> <number> <number> <number> - MSInheritanceAttr::Spelling IM = RD->getMSInheritanceModel(); + MSInheritanceModel IM = RD->getMSInheritanceModel(); char Code = '\0'; switch (IM) { - case MSInheritanceAttr::Keyword_single_inheritance: Code = '1'; break; - case MSInheritanceAttr::Keyword_multiple_inheritance: Code = 'H'; break; - case MSInheritanceAttr::Keyword_virtual_inheritance: Code = 'I'; break; - case MSInheritanceAttr::Keyword_unspecified_inheritance: Code = 'J'; break; - case MSInheritanceAttr::SpellingNotCalculated: - llvm_unreachable("not reachable"); + case MSInheritanceModel::Single: Code = '1'; break; + case MSInheritanceModel::Multiple: Code = 'H'; break; + case MSInheritanceModel::Virtual: Code = 'I'; break; + case MSInheritanceModel::Unspecified: Code = 'J'; break; } // If non-virtual, mangle the name. If virtual, mangle as a virtual memptr @@ -676,25 +677,24 @@ MicrosoftCXXNameMangler::mangleMemberFunctionPointer(const CXXRecordDecl *RD, mangleFunctionEncoding(MD, /*ShouldMangle=*/true); } - if (VBTableOffset == 0 && - IM == MSInheritanceAttr::Keyword_virtual_inheritance) + if (VBTableOffset == 0 && IM == MSInheritanceModel::Virtual) NVOffset -= getASTContext().getOffsetOfBaseWithVBPtr(RD).getQuantity(); } else { // Null single inheritance member functions are encoded as a simple nullptr. - if (IM == MSInheritanceAttr::Keyword_single_inheritance) { + if (IM == MSInheritanceModel::Single) { Out << "$0A@"; return; } - if (IM == MSInheritanceAttr::Keyword_unspecified_inheritance) + if (IM == MSInheritanceModel::Unspecified) VBTableOffset = -1; Out << '$' << Code; } - if (MSInheritanceAttr::hasNVOffsetField(/*IsMemberFunction=*/true, IM)) + if (inheritanceModelHasNVOffsetField(/*IsMemberFunction=*/true, IM)) mangleNumber(static_cast<uint32_t>(NVOffset)); - if (MSInheritanceAttr::hasVBPtrOffsetField(IM)) + if (inheritanceModelHasVBPtrOffsetField(IM)) mangleNumber(VBPtrOffset); - if (MSInheritanceAttr::hasVBTableOffsetField(IM)) + if (inheritanceModelHasVBTableOffsetField(IM)) mangleNumber(VBTableOffset); } @@ -710,7 +710,7 @@ void MicrosoftCXXNameMangler::mangleVirtualMemPtrThunk( Out << "$B"; mangleNumber(OffsetInVFTable); Out << 'A'; - mangleCallingConvention(MD->getType()->getAs<FunctionProtoType>()); + mangleCallingConvention(MD->getType()->castAs<FunctionProtoType>()); } void MicrosoftCXXNameMangler::mangleName(const NamedDecl *ND) { @@ -1708,8 +1708,10 @@ MicrosoftCXXNameMangler::mangleRefQualifier(RefQualifierKind RefQualifier) { void MicrosoftCXXNameMangler::manglePointerExtQualifiers(Qualifiers Quals, QualType PointeeType) { - if (PointersAre64Bit && - (PointeeType.isNull() || !PointeeType->isFunctionType())) + // Check if this is a default 64-bit pointer or has __ptr64 qualifier. + bool is64Bit = PointeeType.isNull() ? PointersAre64Bit : + is64BitPointer(PointeeType.getQualifiers()); + if (is64Bit && (PointeeType.isNull() || !PointeeType->isFunctionType())) Out << 'E'; if (Quals.hasRestrict()) @@ -1869,6 +1871,10 @@ void MicrosoftCXXNameMangler::mangleAddressSpaceType(QualType T, case LangAS::cuda_shared: Extra.mangleSourceName("_ASCUshared"); break; + case LangAS::ptr32_sptr: + case LangAS::ptr32_uptr: + case LangAS::ptr64: + llvm_unreachable("don't mangle ptr address spaces with _AS"); } } @@ -2602,10 +2608,13 @@ void MicrosoftCXXNameMangler::mangleType(const PointerType *T, Qualifiers Quals, manglePointerCVQualifiers(Quals); manglePointerExtQualifiers(Quals, PointeeType); - if (PointeeType.getQualifiers().hasAddressSpace()) - mangleAddressSpaceType(PointeeType, PointeeType.getQualifiers(), Range); - else + // For pointer size address spaces, go down the same type mangling path as + // non address space types. + LangAS AddrSpace = PointeeType.getQualifiers().getAddressSpace(); + if (isPtrSizeAddressSpace(AddrSpace) || AddrSpace == LangAS::Default) mangleType(PointeeType, Range); + else + mangleAddressSpaceType(PointeeType, PointeeType.getQualifiers(), Range); } void MicrosoftCXXNameMangler::mangleType(const ObjCObjectPointerType *T, @@ -2692,9 +2701,7 @@ void MicrosoftCXXNameMangler::mangleType(const VectorType *T, Qualifiers Quals, // doesn't match the Intel types uses a custom mangling below. size_t OutSizeBefore = Out.tell(); if (!isa<ExtVectorType>(T)) { - llvm::Triple::ArchType AT = - getASTContext().getTargetInfo().getTriple().getArch(); - if (AT == llvm::Triple::x86 || AT == llvm::Triple::x86_64) { + if (getASTContext().getTargetInfo().getTriple().isX86()) { if (Width == 64 && ET->getKind() == BuiltinType::LongLong) { mangleArtificialTagType(TTK_Union, "__m64"); } else if (Width >= 128) { diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp index 09d85102585b..137953fa8203 100644 --- a/clang/lib/AST/NestedNameSpecifier.cpp +++ b/clang/lib/AST/NestedNameSpecifier.cpp @@ -472,7 +472,7 @@ TypeLoc NestedNameSpecifierLoc::getTypeLoc() const { } static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, - unsigned &BufferCapacity) { + unsigned &BufferCapacity) { if (Start == End) return; @@ -489,9 +489,9 @@ static void Append(char *Start, char *End, char *&Buffer, unsigned &BufferSize, Buffer = NewBuffer; BufferCapacity = NewCapacity; } - + assert(Buffer && Start && End && End > Start && "Illegal memory buffer copy"); memcpy(Buffer + BufferSize, Start, End - Start); - BufferSize += End-Start; + BufferSize += End - Start; } /// Save a source location to the given buffer. diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 3b89c630b451..27fdca1c4b9c 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -380,6 +380,11 @@ public: } Hash.AddBoolean(D->isParameterPack()); + const TypeConstraint *TC = D->getTypeConstraint(); + Hash.AddBoolean(TC != nullptr); + if (TC) + AddStmt(TC->getImmediatelyDeclaredConstraint()); + Inherited::VisitTemplateTypeParmDecl(D); } diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index fe1334469d48..5ef82648c89d 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -15,6 +15,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclOpenMP.h" #include "clang/Basic/LLVM.h" +#include "clang/Basic/OpenMPKinds.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" @@ -135,6 +136,7 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) { case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + case OMPC_nontemporal: break; } @@ -213,6 +215,7 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C) case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + case OMPC_nontemporal: break; } @@ -402,11 +405,12 @@ void OMPLastprivateClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) { OMPLastprivateClause *OMPLastprivateClause::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs, - ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps, Stmt *PreInit, - Expr *PostUpdate) { + ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps, + OpenMPLastprivateModifier LPKind, SourceLocation LPKindLoc, + SourceLocation ColonLoc, Stmt *PreInit, Expr *PostUpdate) { void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(5 * VL.size())); - OMPLastprivateClause *Clause = - new (Mem) OMPLastprivateClause(StartLoc, LParenLoc, EndLoc, VL.size()); + OMPLastprivateClause *Clause = new (Mem) OMPLastprivateClause( + StartLoc, LParenLoc, EndLoc, LPKind, LPKindLoc, ColonLoc, VL.size()); Clause->setVarRefs(VL); Clause->setSourceExprs(SrcExprs); Clause->setDestinationExprs(DstExprs); @@ -1155,13 +1159,38 @@ OMPIsDevicePtrClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPIsDevicePtrClause(Sizes); } +OMPNontemporalClause *OMPNontemporalClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef<Expr *> VL) { + // Allocate space for nontemporal variables + private references. + void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * VL.size())); + auto *Clause = + new (Mem) OMPNontemporalClause(StartLoc, LParenLoc, EndLoc, VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPNontemporalClause *OMPNontemporalClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(2 * N)); + return new (Mem) OMPNontemporalClause(N); +} + +void OMPNontemporalClause::setPrivateRefs(ArrayRef<Expr *> VL) { + assert(VL.size() == varlist_size() && "Number of private references is not " + "the same as the preallocated buffer"); + std::copy(VL.begin(), VL.end(), varlist_end()); +} + //===----------------------------------------------------------------------===// // OpenMP clauses printing methods //===----------------------------------------------------------------------===// void OMPClausePrinter::VisitOMPIfClause(OMPIfClause *Node) { OS << "if("; - if (Node->getNameModifier() != OMPD_unknown) + if (Node->getNameModifier() != llvm::omp::OMPD_unknown) OS << getOpenMPDirectiveName(Node->getNameModifier()) << ": "; Node->getCondition()->printPretty(OS, nullptr, Policy, 0); OS << ")"; @@ -1211,7 +1240,8 @@ void OMPClausePrinter::VisitOMPDefaultClause(OMPDefaultClause *Node) { void OMPClausePrinter::VisitOMPProcBindClause(OMPProcBindClause *Node) { OS << "proc_bind(" - << getOpenMPSimpleClauseTypeName(OMPC_proc_bind, Node->getProcBindKind()) + << getOpenMPSimpleClauseTypeName(OMPC_proc_bind, + unsigned(Node->getProcBindKind())) << ")"; } @@ -1401,7 +1431,13 @@ void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) { void OMPClausePrinter::VisitOMPLastprivateClause(OMPLastprivateClause *Node) { if (!Node->varlist_empty()) { OS << "lastprivate"; - VisitOMPClauseList(Node, '('); + OpenMPLastprivateModifier LPKind = Node->getKind(); + if (LPKind != OMPC_LASTPRIVATE_unknown) { + OS << "(" + << getOpenMPSimpleClauseTypeName(OMPC_lastprivate, Node->getKind()) + << ":"; + } + VisitOMPClauseList(Node, LPKind == OMPC_LASTPRIVATE_unknown ? '(' : ' '); OS << ")"; } } @@ -1648,3 +1684,10 @@ void OMPClausePrinter::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *Node) { } } +void OMPClausePrinter::VisitOMPNontemporalClause(OMPNontemporalClause *Node) { + if (!Node->varlist_empty()) { + OS << "nontemporal"; + VisitOMPClauseList(Node, '('); + OS << ")"; + } +} diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index f28f00171cce..73a33a208233 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -192,7 +192,7 @@ static NestedNameSpecifier *createOuterNNS(const ASTContext &Ctx, const Decl *D, // Ignore inline namespace; NS = dyn_cast<NamespaceDecl>(NS->getDeclContext()); } - if (NS->getDeclName()) { + if (NS && NS->getDeclName()) { return createNestedNameSpecifier(Ctx, NS, WithGlobalNsPrefix); } return nullptr; // no starting '::', no anonymous diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 2a3419a0cec3..9a21732b63e3 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2956,7 +2956,7 @@ void MicrosoftRecordLayoutBuilder::computeVtorDispSet( const CXXRecordDecl *RD) const { // /vd2 or #pragma vtordisp(2): Always use vtordisps for virtual bases with // vftables. - if (RD->getMSVtorDispMode() == MSVtorDispAttr::ForVFTable) { + if (RD->getMSVtorDispMode() == MSVtorDispMode::ForVFTable) { for (const CXXBaseSpecifier &Base : RD->vbases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); const ASTRecordLayout &Layout = Context.getASTRecordLayout(BaseDecl); @@ -2979,12 +2979,12 @@ void MicrosoftRecordLayoutBuilder::computeVtorDispSet( // * A user declared constructor or destructor aren't declared. // * #pragma vtordisp(0) or the /vd0 flag are in use. if ((!RD->hasUserDeclaredConstructor() && !RD->hasUserDeclaredDestructor()) || - RD->getMSVtorDispMode() == MSVtorDispAttr::Never) + RD->getMSVtorDispMode() == MSVtorDispMode::Never) return; // /vd1 or #pragma vtordisp(1): Try to guess based on whether we think it's // possible for a partially constructed object with virtual base overrides to // escape a non-trivial constructor. - assert(RD->getMSVtorDispMode() == MSVtorDispAttr::ForVBaseOverride); + assert(RD->getMSVtorDispMode() == MSVtorDispMode::ForVBaseOverride); // Compute a set of base classes which define methods we override. A virtual // base in this set will require a vtordisp. A virtual base that transitively // contains one of these bases as a non-virtual base will also require a diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 80a1451ac789..b6e4d8aff21e 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -908,6 +908,12 @@ bool IfStmt::isObjCAvailabilityCheck() const { return isa<ObjCAvailabilityCheckExpr>(getCond()); } +Optional<const Stmt*> IfStmt::getNondiscardedCase(const ASTContext &Ctx) const { + if (!isConstexpr() || getCond()->isValueDependent()) + return None; + return !getCond()->EvaluateKnownConstInt(Ctx) ? getElse() : getThen(); +} + ForStmt::ForStmt(const ASTContext &C, Stmt *Init, Expr *Cond, VarDecl *condVar, Expr *Inc, Stmt *Body, SourceLocation FL, SourceLocation LP, SourceLocation RP) diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index da1364ebffc4..da6d308ad15b 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTContext.h" using namespace clang; +using namespace llvm::omp; void OMPExecutableDirective::setClauses(ArrayRef<OMPClause *> Clauses) { assert(Clauses.size() == getNumClauses() && @@ -41,6 +42,74 @@ const Stmt *OMPExecutableDirective::getStructuredBlock() const { return getInnermostCapturedStmt()->getCapturedStmt(); } +Stmt *OMPLoopDirective::tryToFindNextInnerLoop(Stmt *CurStmt, + bool TryImperfectlyNestedLoops) { + Stmt *OrigStmt = CurStmt; + CurStmt = CurStmt->IgnoreContainers(); + // Additional work for imperfectly nested loops, introduced in OpenMP 5.0. + if (TryImperfectlyNestedLoops) { + if (auto *CS = dyn_cast<CompoundStmt>(CurStmt)) { + CurStmt = nullptr; + SmallVector<CompoundStmt *, 4> Statements(1, CS); + SmallVector<CompoundStmt *, 4> NextStatements; + while (!Statements.empty()) { + CS = Statements.pop_back_val(); + if (!CS) + continue; + for (Stmt *S : CS->body()) { + if (!S) + continue; + if (isa<ForStmt>(S) || isa<CXXForRangeStmt>(S)) { + // Only single loop construct is allowed. + if (CurStmt) { + CurStmt = OrigStmt; + break; + } + CurStmt = S; + continue; + } + S = S->IgnoreContainers(); + if (auto *InnerCS = dyn_cast_or_null<CompoundStmt>(S)) + NextStatements.push_back(InnerCS); + } + if (Statements.empty()) { + // Found single inner loop or multiple loops - exit. + if (CurStmt) + break; + Statements.swap(NextStatements); + } + } + if (!CurStmt) + CurStmt = OrigStmt; + } + } + return CurStmt; +} + +Stmt *OMPLoopDirective::getBody() { + // This relies on the loop form is already checked by Sema. + Stmt *Body = + getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers(); + if (auto *For = dyn_cast<ForStmt>(Body)) { + Body = For->getBody(); + } else { + assert(isa<CXXForRangeStmt>(Body) && + "Expected canonical for loop or range-based for loop."); + Body = cast<CXXForRangeStmt>(Body)->getBody(); + } + for (unsigned Cnt = 1; Cnt < CollapsedNum; ++Cnt) { + Body = tryToFindNextInnerLoop(Body, /*TryImperfectlyNestedLoops=*/true); + if (auto *For = dyn_cast<ForStmt>(Body)) { + Body = For->getBody(); + } else { + assert(isa<CXXForRangeStmt>(Body) && + "Expected canonical for loop or range-based for loop."); + Body = cast<CXXForRangeStmt>(Body)->getBody(); + } + } + return Body; +} + void OMPLoopDirective::setCounters(ArrayRef<Expr *> A) { assert(A.size() == getCollapsedNumber() && "Number of loop counters is not the same as the collapsed number"); @@ -482,6 +551,30 @@ OMPParallelForSimdDirective::CreateEmpty(const ASTContext &C, return new (Mem) OMPParallelForSimdDirective(CollapsedNum, NumClauses); } +OMPParallelMasterDirective *OMPParallelMasterDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt) { + unsigned Size = + llvm::alignTo(sizeof(OMPParallelMasterDirective), alignof(OMPClause *)); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * Clauses.size() + sizeof(Stmt *)); + auto *Dir = + new (Mem) OMPParallelMasterDirective(StartLoc, EndLoc, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + return Dir; +} + +OMPParallelMasterDirective *OMPParallelMasterDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + EmptyShell) { + unsigned Size = + llvm::alignTo(sizeof(OMPParallelMasterDirective), alignof(OMPClause *)); + void *Mem = + C.Allocate(Size + sizeof(OMPClause *) * NumClauses + sizeof(Stmt *)); + return new (Mem) OMPParallelMasterDirective(NumClauses); +} + OMPParallelSectionsDirective *OMPParallelSectionsDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, bool HasCancel) { @@ -1182,6 +1275,63 @@ OMPParallelMasterTaskLoopDirective::CreateEmpty(const ASTContext &C, return new (Mem) OMPParallelMasterTaskLoopDirective(CollapsedNum, NumClauses); } +OMPParallelMasterTaskLoopSimdDirective * +OMPParallelMasterTaskLoopSimdDirective::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, + unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, + const HelperExprs &Exprs) { + unsigned Size = llvm::alignTo(sizeof(OMPParallelMasterTaskLoopSimdDirective), + alignof(OMPClause *)); + void *Mem = C.Allocate( + Size + sizeof(OMPClause *) * Clauses.size() + + sizeof(Stmt *) * + numLoopChildren(CollapsedNum, OMPD_parallel_master_taskloop_simd)); + auto *Dir = new (Mem) OMPParallelMasterTaskLoopSimdDirective( + StartLoc, EndLoc, CollapsedNum, Clauses.size()); + Dir->setClauses(Clauses); + Dir->setAssociatedStmt(AssociatedStmt); + Dir->setIterationVariable(Exprs.IterationVarRef); + Dir->setLastIteration(Exprs.LastIteration); + Dir->setCalcLastIteration(Exprs.CalcLastIteration); + Dir->setPreCond(Exprs.PreCond); + Dir->setCond(Exprs.Cond); + Dir->setInit(Exprs.Init); + Dir->setInc(Exprs.Inc); + Dir->setIsLastIterVariable(Exprs.IL); + Dir->setLowerBoundVariable(Exprs.LB); + Dir->setUpperBoundVariable(Exprs.UB); + Dir->setStrideVariable(Exprs.ST); + Dir->setEnsureUpperBound(Exprs.EUB); + Dir->setNextLowerBound(Exprs.NLB); + Dir->setNextUpperBound(Exprs.NUB); + Dir->setNumIterations(Exprs.NumIterations); + Dir->setCounters(Exprs.Counters); + Dir->setPrivateCounters(Exprs.PrivateCounters); + Dir->setInits(Exprs.Inits); + Dir->setUpdates(Exprs.Updates); + Dir->setFinals(Exprs.Finals); + Dir->setDependentCounters(Exprs.DependentCounters); + Dir->setDependentInits(Exprs.DependentInits); + Dir->setFinalsConditions(Exprs.FinalsConditions); + Dir->setPreInits(Exprs.PreInits); + return Dir; +} + +OMPParallelMasterTaskLoopSimdDirective * +OMPParallelMasterTaskLoopSimdDirective::CreateEmpty(const ASTContext &C, + unsigned NumClauses, + unsigned CollapsedNum, + EmptyShell) { + unsigned Size = llvm::alignTo(sizeof(OMPParallelMasterTaskLoopSimdDirective), + alignof(OMPClause *)); + void *Mem = C.Allocate( + Size + sizeof(OMPClause *) * NumClauses + + sizeof(Stmt *) * + numLoopChildren(CollapsedNum, OMPD_parallel_master_taskloop_simd)); + return new (Mem) + OMPParallelMasterTaskLoopSimdDirective(CollapsedNum, NumClauses); +} + OMPDistributeDirective *OMPDistributeDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 7759ff6c1389..c14bb886bb11 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -697,7 +697,7 @@ void StmtPrinter::VisitOMPCriticalDirective(OMPCriticalDirective *Node) { Indent() << "#pragma omp critical"; if (Node->getDirectiveName().getName()) { OS << " ("; - Node->getDirectiveName().printName(OS); + Node->getDirectiveName().printName(OS, Policy); OS << ")"; } PrintOMPExecutableDirective(Node); @@ -714,6 +714,12 @@ void StmtPrinter::VisitOMPParallelForSimdDirective( PrintOMPExecutableDirective(Node); } +void StmtPrinter::VisitOMPParallelMasterDirective( + OMPParallelMasterDirective *Node) { + Indent() << "#pragma omp parallel master"; + PrintOMPExecutableDirective(Node); +} + void StmtPrinter::VisitOMPParallelSectionsDirective( OMPParallelSectionsDirective *Node) { Indent() << "#pragma omp parallel sections"; @@ -841,6 +847,12 @@ void StmtPrinter::VisitOMPParallelMasterTaskLoopDirective( PrintOMPExecutableDirective(Node); } +void StmtPrinter::VisitOMPParallelMasterTaskLoopSimdDirective( + OMPParallelMasterTaskLoopSimdDirective *Node) { + Indent() << "#pragma omp parallel master taskloop simd"; + PrintOMPExecutableDirective(Node); +} + void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) { Indent() << "#pragma omp distribute"; PrintOMPExecutableDirective(Node); @@ -1298,7 +1310,7 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){ void StmtPrinter::VisitGenericSelectionExpr(GenericSelectionExpr *Node) { OS << "_Generic("; PrintExpr(Node->getControllingExpr()); - for (const GenericSelectionExpr::Association &Assoc : Node->associations()) { + for (const GenericSelectionExpr::Association Assoc : Node->associations()) { OS << ", "; QualType T = Assoc.getType(); if (T.isNull()) @@ -2229,7 +2241,7 @@ void StmtPrinter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { } void StmtPrinter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *Node){ - PrintExpr(Node->GetTemporaryExpr()); + PrintExpr(Node->getSubExpr()); } void StmtPrinter::VisitCXXFoldExpr(CXXFoldExpr *E) { diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index d1e856538932..2aa5106e90fa 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -769,7 +769,13 @@ void OMPClauseProfiler::VisitOMPIsDevicePtrClause( const OMPIsDevicePtrClause *C) { VisitOMPClauseList(C); } +void OMPClauseProfiler::VisitOMPNontemporalClause( + const OMPNontemporalClause *C) { + VisitOMPClauseList(C); + for (auto *E : C->private_refs()) + Profiler->VisitStmt(E); } +} // namespace void StmtProfiler::VisitOMPExecutableDirective(const OMPExecutableDirective *S) { @@ -833,6 +839,11 @@ void StmtProfiler::VisitOMPParallelForSimdDirective( VisitOMPLoopDirective(S); } +void StmtProfiler::VisitOMPParallelMasterDirective( + const OMPParallelMasterDirective *S) { + VisitOMPExecutableDirective(S); +} + void StmtProfiler::VisitOMPParallelSectionsDirective( const OMPParallelSectionsDirective *S) { VisitOMPExecutableDirective(S); @@ -937,6 +948,11 @@ void StmtProfiler::VisitOMPParallelMasterTaskLoopDirective( VisitOMPLoopDirective(S); } +void StmtProfiler::VisitOMPParallelMasterTaskLoopSimdDirective( + const OMPParallelMasterTaskLoopSimdDirective *S) { + VisitOMPLoopDirective(S); +} + void StmtProfiler::VisitOMPDistributeDirective( const OMPDistributeDirective *S) { VisitOMPLoopDirective(S); @@ -1291,7 +1307,7 @@ void StmtProfiler::VisitBlockExpr(const BlockExpr *S) { void StmtProfiler::VisitGenericSelectionExpr(const GenericSelectionExpr *S) { VisitExpr(S); - for (const GenericSelectionExpr::ConstAssociation &Assoc : + for (const GenericSelectionExpr::ConstAssociation Assoc : S->associations()) { QualType T = Assoc.getType(); if (T.isNull()) diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 63a6510324f7..965ad17fcfa5 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -489,6 +489,9 @@ void TextNodeDumper::visitInlineCommandComment( case comments::InlineCommandComment::RenderEmphasized: OS << " RenderEmphasized"; break; + case comments::InlineCommandComment::RenderAnchor: + OS << " RenderAnchor"; + break; } for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i) @@ -1338,6 +1341,17 @@ void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) { OS << " <<<NULL params x " << D->getNumParams() << ">>>"; } +void TextNodeDumper::VisitLifetimeExtendedTemporaryDecl( + const LifetimeExtendedTemporaryDecl *D) { + OS << " extended by "; + dumpBareDeclRef(D->getExtendingDecl()); + OS << " mangling "; + { + ColorScope Color(OS, ShowColors, ValueColor); + OS << D->getManglingNumber(); + } +} + void TextNodeDumper::VisitFieldDecl(const FieldDecl *D) { dumpName(D); dumpType(D->getType()); @@ -1680,7 +1694,16 @@ void TextNodeDumper::VisitBuiltinTemplateDecl(const BuiltinTemplateDecl *D) { } void TextNodeDumper::VisitTemplateTypeParmDecl(const TemplateTypeParmDecl *D) { - if (D->wasDeclaredWithTypename()) + if (const auto *TC = D->getTypeConstraint()) { + OS << " "; + dumpBareDeclRef(TC->getNamedConcept()); + if (TC->getNamedConcept() != TC->getFoundDecl()) { + OS << " ("; + dumpBareDeclRef(TC->getFoundDecl()); + OS << ")"; + } + Visit(TC->getImmediatelyDeclaredConstraint()); + } else if (D->wasDeclaredWithTypename()) OS << " typename"; else OS << " class"; @@ -1769,12 +1792,6 @@ void TextNodeDumper::VisitLinkageSpecDecl(const LinkageSpecDecl *D) { case LinkageSpecDecl::lang_cxx: OS << " C++"; break; - case LinkageSpecDecl::lang_cxx_11: - OS << " C++11"; - break; - case LinkageSpecDecl::lang_cxx_14: - OS << " C++14"; - break; } } @@ -1921,6 +1938,8 @@ void TextNodeDumper::VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { OS << " unsafe_unretained"; if (Attrs & ObjCPropertyDecl::OBJC_PR_class) OS << " class"; + if (Attrs & ObjCPropertyDecl::OBJC_PR_direct) + OS << " direct"; if (Attrs & ObjCPropertyDecl::OBJC_PR_getter) dumpDeclRef(D->getGetterMethodDecl(), "getter"); if (Attrs & ObjCPropertyDecl::OBJC_PR_setter) diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 4d54ea1061ed..c5ad711d872e 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -663,10 +663,6 @@ ObjCTypeParamType::ObjCTypeParamType(const ObjCTypeParamDecl *D, initialize(protocols); } -QualType ObjCTypeParamType::desugar() const { - return getDecl()->getUnderlyingType(); -} - ObjCObjectType::ObjCObjectType(QualType Canonical, QualType Base, ArrayRef<QualType> typeArgs, ArrayRef<ObjCProtocolDecl *> protocols, @@ -1860,13 +1856,12 @@ bool Type::isIntegralOrUnscopedEnumerationType() const { if (const auto *BT = dyn_cast<BuiltinType>(CanonicalType)) return BT->getKind() >= BuiltinType::Bool && BT->getKind() <= BuiltinType::Int128; + return isUnscopedEnumerationType(); +} - // Check for a complete enum type; incomplete enum types are not properly an - // enumeration type in the sense required here. - // C++0x: However, if the underlying type of the enum is fixed, it is - // considered complete. +bool Type::isUnscopedEnumerationType() const { if (const auto *ET = dyn_cast<EnumType>(CanonicalType)) - return ET->getDecl()->isComplete() && !ET->getDecl()->isScoped(); + return !ET->getDecl()->isScoped(); return false; } @@ -3069,6 +3064,12 @@ FunctionProtoType::FunctionProtoType(QualType result, ArrayRef<QualType> params, } else { FunctionTypeBits.HasExtQuals = 0; } + + // Fill in the Ellipsis location info if present. + if (epi.Variadic) { + auto &EllipsisLoc = *getTrailingObjects<SourceLocation>(); + EllipsisLoc = epi.EllipsisLoc; + } } bool FunctionProtoType::hasDependentExceptionSpec() const { diff --git a/clang/lib/AST/TypeLoc.cpp b/clang/lib/AST/TypeLoc.cpp index e4788f32b265..6e67ca8e0af7 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -12,6 +12,7 @@ #include "clang/AST/TypeLoc.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" @@ -293,6 +294,12 @@ bool TypeSpecTypeLoc::isKind(const TypeLoc &TL) { return TSTChecker().Visit(TL); } +bool TagTypeLoc::isDefinition() const { + TagDecl *D = getDecl(); + return D->isCompleteDefinition() && + (D->getIdentifier() == nullptr || D->getLocation() == getNameLoc()); +} + // Reimplemented to account for GNU/C++ extension // typeof unary-expression // where there are no parentheses. @@ -467,6 +474,19 @@ void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context, setProtocolLoc(i, Loc); } +SourceRange AttributedTypeLoc::getLocalSourceRange() const { + // Note that this does *not* include the range of the attribute + // enclosure, e.g.: + // __attribute__((foo(bar))) + // ^~~~~~~~~~~~~~~ ~~ + // or + // [[foo(bar)]] + // ^~ ~~ + // That enclosure doesn't necessarily belong to a single attribute + // anyway. + return getAttr() ? getAttr()->getRange() : SourceRange(); +} + void TypeOfTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { TypeofLikeTypeLoc<TypeOfTypeLoc, TypeOfType, TypeOfTypeLocInfo> diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index dacbf9a96d81..c2f4baec989e 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1189,8 +1189,8 @@ void TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { if (PLoc.isValid()) { OS << " at "; StringRef File = PLoc.getFilename(); - if (Policy.RemapFilePaths) - OS << Policy.remapPath(File); + if (auto *Callbacks = Policy.Callbacks) + OS << Callbacks->remapPath(File); else OS << File; OS << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); @@ -1555,6 +1555,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::NoDeref: OS << "noderef"; break; + case attr::AcquireHandle: + OS << "acquire_handle"; + break; } OS << "))"; } @@ -1772,6 +1775,37 @@ bool Qualifiers::isEmptyWhenPrinted(const PrintingPolicy &Policy) const { return true; } +std::string Qualifiers::getAddrSpaceAsString(LangAS AS) { + switch (AS) { + case LangAS::Default: + return ""; + case LangAS::opencl_global: + return "__global"; + case LangAS::opencl_local: + return "__local"; + case LangAS::opencl_private: + return "__private"; + case LangAS::opencl_constant: + return "__constant"; + case LangAS::opencl_generic: + return "__generic"; + case LangAS::cuda_device: + return "__device__"; + case LangAS::cuda_constant: + return "__constant__"; + case LangAS::cuda_shared: + return "__shared__"; + case LangAS::ptr32_sptr: + return "__sptr __ptr32"; + case LangAS::ptr32_uptr: + return "__uptr __ptr32"; + case LangAS::ptr64: + return "__ptr64"; + default: + return std::to_string(toTargetAddressSpace(AS)); + } +} + // Appends qualifiers to the given string, separated by spaces. Will // prefix a space if the string is non-empty. Will not append a final // space. @@ -1790,43 +1824,18 @@ void Qualifiers::print(raw_ostream &OS, const PrintingPolicy& Policy, OS << "__unaligned"; addSpace = true; } - LangAS addrspace = getAddressSpace(); - if (addrspace != LangAS::Default) { - if (addrspace != LangAS::opencl_private) { - if (addSpace) - OS << ' '; - addSpace = true; - switch (addrspace) { - case LangAS::opencl_global: - OS << "__global"; - break; - case LangAS::opencl_local: - OS << "__local"; - break; - case LangAS::opencl_private: - break; - case LangAS::opencl_constant: - OS << "__constant"; - break; - case LangAS::opencl_generic: - OS << "__generic"; - break; - case LangAS::cuda_device: - OS << "__device__"; - break; - case LangAS::cuda_constant: - OS << "__constant__"; - break; - case LangAS::cuda_shared: - OS << "__shared__"; - break; - default: - OS << "__attribute__((address_space("; - OS << toTargetAddressSpace(addrspace); - OS << ")))"; - } - } + auto ASStr = getAddrSpaceAsString(getAddressSpace()); + if (!ASStr.empty()) { + if (addSpace) + OS << ' '; + addSpace = true; + // Wrap target address space into an attribute syntax + if (isTargetAddressSpace(getAddressSpace())) + OS << "__attribute__((address_space(" << ASStr << ")))"; + else + OS << ASStr; } + if (Qualifiers::GC gc = getObjCGCAttr()) { if (addSpace) OS << ' '; diff --git a/clang/lib/AST/VTableBuilder.cpp b/clang/lib/AST/VTableBuilder.cpp index 5688042dadd9..2b5b74be5961 100644 --- a/clang/lib/AST/VTableBuilder.cpp +++ b/clang/lib/AST/VTableBuilder.cpp @@ -270,8 +270,8 @@ static BaseOffset ComputeReturnAdjustmentBaseOffset(ASTContext &Context, const CXXMethodDecl *DerivedMD, const CXXMethodDecl *BaseMD) { - const FunctionType *BaseFT = BaseMD->getType()->getAs<FunctionType>(); - const FunctionType *DerivedFT = DerivedMD->getType()->getAs<FunctionType>(); + const auto *BaseFT = BaseMD->getType()->castAs<FunctionType>(); + const auto *DerivedFT = DerivedMD->getType()->castAs<FunctionType>(); // Canonicalize the return types. CanQualType CanDerivedReturnType = diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index c51fd630e64b..0d1f713db8d3 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -59,10 +59,12 @@ struct MatchKey { DynTypedMatcher::MatcherIDType MatcherID; ast_type_traits::DynTypedNode Node; BoundNodesTreeBuilder BoundNodes; + ast_type_traits::TraversalKind Traversal = ast_type_traits::TK_AsIs; bool operator<(const MatchKey &Other) const { - return std::tie(MatcherID, Node, BoundNodes) < - std::tie(Other.MatcherID, Other.Node, Other.BoundNodes); + return std::tie(MatcherID, Node, BoundNodes, Traversal) < + std::tie(Other.MatcherID, Other.Node, Other.BoundNodes, + Other.Traversal); } }; @@ -136,18 +138,32 @@ public: ScopedIncrement ScopedDepth(&CurrentDepth); return (DeclNode == nullptr) || traverse(*DeclNode); } - bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) { - // If we need to keep track of the depth, we can't perform data recursion. - if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX)) - Queue = nullptr; - ScopedIncrement ScopedDepth(&CurrentDepth); + Stmt *getStmtToTraverse(Stmt *StmtNode) { Stmt *StmtToTraverse = StmtNode; + if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) { + auto *LambdaNode = dyn_cast_or_null<LambdaExpr>(StmtNode); + if (LambdaNode && Finder->getASTContext().getTraversalKind() == + ast_type_traits::TK_IgnoreUnlessSpelledInSource) + StmtToTraverse = LambdaNode; + else + StmtToTraverse = Finder->getASTContext().traverseIgnored(ExprNode); + } if (Traversal == ast_type_traits::TraversalKind::TK_IgnoreImplicitCastsAndParentheses) { if (Expr *ExprNode = dyn_cast_or_null<Expr>(StmtNode)) StmtToTraverse = ExprNode->IgnoreParenImpCasts(); } + return StmtToTraverse; + } + + bool TraverseStmt(Stmt *StmtNode, DataRecursionQueue *Queue = nullptr) { + // If we need to keep track of the depth, we can't perform data recursion. + if (CurrentDepth == 0 || (CurrentDepth <= MaxDepth && MaxDepth < INT_MAX)) + Queue = nullptr; + + ScopedIncrement ScopedDepth(&CurrentDepth); + Stmt *StmtToTraverse = getStmtToTraverse(StmtNode); if (!StmtToTraverse) return true; if (!match(*StmtToTraverse)) @@ -199,6 +215,41 @@ public: ScopedIncrement ScopedDepth(&CurrentDepth); return traverse(*CtorInit); } + bool TraverseLambdaExpr(LambdaExpr *Node) { + if (Finder->getASTContext().getTraversalKind() != + ast_type_traits::TK_IgnoreUnlessSpelledInSource) + return VisitorBase::TraverseLambdaExpr(Node); + if (!Node) + return true; + ScopedIncrement ScopedDepth(&CurrentDepth); + + for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) { + const auto *C = Node->capture_begin() + I; + if (!C->isExplicit()) + continue; + if (Node->isInitCapture(C) && !match(*C->getCapturedVar())) + return false; + if (!match(*Node->capture_init_begin()[I])) + return false; + } + + if (const auto *TPL = Node->getTemplateParameterList()) { + for (const auto *TP : *TPL) { + if (!match(*TP)) + return false; + } + } + + for (const auto *P : Node->getCallOperator()->parameters()) { + if (!match(*P)) + return false; + } + + if (!match(*Node->getBody())) + return false; + + return true; + } bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { return true; } @@ -390,6 +441,7 @@ public: // Matches children or descendants of 'Node' with 'BaseMatcher'. bool memoizedMatchesRecursively(const ast_type_traits::DynTypedNode &Node, + ASTContext &Ctx, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, int MaxDepth, ast_type_traits::TraversalKind Traversal, @@ -404,6 +456,7 @@ public: Key.Node = Node; // Note that we key on the bindings *before* the match. Key.BoundNodes = *Builder; + Key.Traversal = Ctx.getTraversalKind(); MemoizationMap::iterator I = ResultCache.find(Key); if (I != ResultCache.end()) { @@ -446,36 +499,36 @@ public: // Implements ASTMatchFinder::matchesChildOf. bool matchesChildOf(const ast_type_traits::DynTypedNode &Node, - const DynTypedMatcher &Matcher, + ASTContext &Ctx, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, ast_type_traits::TraversalKind Traversal, BindKind Bind) override { if (ResultCache.size() > MaxMemoizationEntries) ResultCache.clear(); - return memoizedMatchesRecursively(Node, Matcher, Builder, 1, Traversal, + return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, 1, Traversal, Bind); } // Implements ASTMatchFinder::matchesDescendantOf. bool matchesDescendantOf(const ast_type_traits::DynTypedNode &Node, - const DynTypedMatcher &Matcher, + ASTContext &Ctx, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, BindKind Bind) override { if (ResultCache.size() > MaxMemoizationEntries) ResultCache.clear(); - return memoizedMatchesRecursively(Node, Matcher, Builder, INT_MAX, + return memoizedMatchesRecursively(Node, Ctx, Matcher, Builder, INT_MAX, ast_type_traits::TraversalKind::TK_AsIs, Bind); } // Implements ASTMatchFinder::matchesAncestorOf. bool matchesAncestorOf(const ast_type_traits::DynTypedNode &Node, - const DynTypedMatcher &Matcher, + ASTContext &Ctx, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) override { // Reset the cache outside of the recursive call to make sure we // don't invalidate any iterators. if (ResultCache.size() > MaxMemoizationEntries) ResultCache.clear(); - return memoizedMatchesAncestorOfRecursively(Node, Matcher, Builder, + return memoizedMatchesAncestorOfRecursively(Node, Ctx, Matcher, Builder, MatchMode); } @@ -576,7 +629,7 @@ private: if (EnableCheckProfiling) Timer.setBucket(&TimeByBucket[MP.second->getID()]); BoundNodesTreeBuilder Builder; - if (MP.first.matchesNoKindCheck(DynNode, this, &Builder)) { + if (MP.first.matches(DynNode, this, &Builder)) { MatchVisitor Visitor(ActiveASTContext, MP.second); Builder.visitMatches(&Visitor); } @@ -640,16 +693,19 @@ private: // allow simple memoization on the ancestors. Thus, we only memoize as long // as there is a single parent. bool memoizedMatchesAncestorOfRecursively( - const ast_type_traits::DynTypedNode &Node, const DynTypedMatcher &Matcher, - BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) { + const ast_type_traits::DynTypedNode &Node, ASTContext &Ctx, + const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, + AncestorMatchMode MatchMode) { // For AST-nodes that don't have an identity, we can't memoize. if (!Builder->isComparable()) - return matchesAncestorOfRecursively(Node, Matcher, Builder, MatchMode); + return matchesAncestorOfRecursively(Node, Ctx, Matcher, Builder, + MatchMode); MatchKey Key; Key.MatcherID = Matcher.getID(); Key.Node = Node; Key.BoundNodes = *Builder; + Key.Traversal = Ctx.getTraversalKind(); // Note that we cannot use insert and reuse the iterator, as recursive // calls to match might invalidate the result cache iterators. @@ -661,8 +717,8 @@ private: MemoizedMatchResult Result; Result.Nodes = *Builder; - Result.ResultOfMatch = - matchesAncestorOfRecursively(Node, Matcher, &Result.Nodes, MatchMode); + Result.ResultOfMatch = matchesAncestorOfRecursively( + Node, Ctx, Matcher, &Result.Nodes, MatchMode); MemoizedMatchResult &CachedResult = ResultCache[Key]; CachedResult = std::move(Result); @@ -672,6 +728,7 @@ private: } bool matchesAncestorOfRecursively(const ast_type_traits::DynTypedNode &Node, + ASTContext &Ctx, const DynTypedMatcher &Matcher, BoundNodesTreeBuilder *Builder, AncestorMatchMode MatchMode) { @@ -705,8 +762,8 @@ private: return true; } if (MatchMode != ASTMatchFinder::AMM_ParentOnly) { - return memoizedMatchesAncestorOfRecursively(Parent, Matcher, Builder, - MatchMode); + return memoizedMatchesAncestorOfRecursively(Parent, Ctx, Matcher, + Builder, MatchMode); // Once we get back from the recursive call, the result will be the // same as the parent's result. } @@ -804,8 +861,6 @@ private: /// kind (and derived kinds) so it is a waste to try every matcher on every /// node. /// We precalculate a list of matchers that pass the toplevel restrict check. - /// This also allows us to skip the restrict check at matching time. See - /// use \c matchesNoKindCheck() above. llvm::DenseMap<ast_type_traits::ASTNodeKind, std::vector<unsigned short>> MatcherFiltersMap; @@ -904,8 +959,9 @@ bool MatchASTVisitor::objcClassIsDerivedFrom( if (Base.matches(*ClassDecl, this, Builder)) return true; + // Not `return false` as a temporary workaround for PR43879. if (Directly) - return false; + break; } return false; diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 4ee32fbe94b1..199a6d839e2e 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -68,6 +68,11 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, BoundNodesTreeBuilder *Builder, ArrayRef<DynTypedMatcher> InnerMatchers); +bool OptionallyVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers); + void BoundNodesTreeBuilder::visitMatches(Visitor *ResultVisitor) { if (Bindings.empty()) Bindings.push_back(BoundNodesMap()); @@ -112,6 +117,11 @@ public: return Result; } + llvm::Optional<ast_type_traits::TraversalKind> + TraversalKind() const override { + return InnerMatcher->TraversalKind(); + } + private: const std::string ID; const IntrusiveRefCntPtr<DynMatcherInterface> InnerMatcher; @@ -179,6 +189,11 @@ DynTypedMatcher DynTypedMatcher::constructVariadic( SupportedKind, RestrictKind, new VariadicMatcher<EachOfVariadicOperator>(std::move(InnerMatchers))); + case VO_Optionally: + return DynTypedMatcher(SupportedKind, RestrictKind, + new VariadicMatcher<OptionallyVariadicOperator>( + std::move(InnerMatchers))); + case VO_UnaryNot: // FIXME: Implement the Not operator to take a single matcher instead of a // vector. @@ -189,6 +204,14 @@ DynTypedMatcher DynTypedMatcher::constructVariadic( llvm_unreachable("Invalid Op value."); } +DynTypedMatcher DynTypedMatcher::constructRestrictedWrapper( + const DynTypedMatcher &InnerMatcher, + ast_type_traits::ASTNodeKind RestrictKind) { + DynTypedMatcher Copy = InnerMatcher; + Copy.RestrictKind = RestrictKind; + return Copy; +} + DynTypedMatcher DynTypedMatcher::trueMatcher( ast_type_traits::ASTNodeKind NodeKind) { return DynTypedMatcher(NodeKind, NodeKind, &*TrueMatcherInstance); @@ -211,8 +234,13 @@ DynTypedMatcher DynTypedMatcher::dynCastTo( bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - if (RestrictKind.isBaseOf(DynNode.getNodeKind()) && - Implementation->dynMatches(DynNode, Finder, Builder)) { + TraversalKindScope RAII(Finder->getASTContext(), + Implementation->TraversalKind()); + + auto N = Finder->getASTContext().traverseIgnored(DynNode); + + if (RestrictKind.isBaseOf(N.getNodeKind()) && + Implementation->dynMatches(N, Finder, Builder)) { return true; } // Delete all bindings when a matcher does not match. @@ -225,8 +253,13 @@ bool DynTypedMatcher::matches(const ast_type_traits::DynTypedNode &DynNode, bool DynTypedMatcher::matchesNoKindCheck( const ast_type_traits::DynTypedNode &DynNode, ASTMatchFinder *Finder, BoundNodesTreeBuilder *Builder) const { - assert(RestrictKind.isBaseOf(DynNode.getNodeKind())); - if (Implementation->dynMatches(DynNode, Finder, Builder)) { + TraversalKindScope raii(Finder->getASTContext(), + Implementation->TraversalKind()); + + auto N = Finder->getASTContext().traverseIgnored(DynNode); + + assert(RestrictKind.isBaseOf(N.getNodeKind())); + if (Implementation->dynMatches(N, Finder, Builder)) { return true; } // Delete all bindings when a matcher does not match. @@ -324,6 +357,20 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, return false; } +bool OptionallyVariadicOperator(const ast_type_traits::DynTypedNode &DynNode, + ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder, + ArrayRef<DynTypedMatcher> InnerMatchers) { + BoundNodesTreeBuilder Result; + for (const DynTypedMatcher &InnerMatcher : InnerMatchers) { + BoundNodesTreeBuilder BuilderInner(*Builder); + if (InnerMatcher.matches(DynNode, Finder, &BuilderInner)) + Result.addMatch(BuilderInner); + } + *Builder = std::move(Result); + return true; +} + inline static std::vector<std::string> vectorFromRefs(ArrayRef<const StringRef *> NameRefs) { std::vector<std::string> Names; @@ -774,6 +821,9 @@ const internal::VariadicOperatorMatcherFunc< const internal::VariadicOperatorMatcherFunc< 2, std::numeric_limits<unsigned>::max()> allOf = {internal::DynTypedMatcher::VO_AllOf}; +const internal::VariadicOperatorMatcherFunc< + 1, std::numeric_limits<unsigned>::max()> + optionally = {internal::DynTypedMatcher::VO_Optionally}; const internal::VariadicFunction<internal::Matcher<NamedDecl>, StringRef, internal::hasAnyNameFunc> hasAnyName = {}; diff --git a/clang/lib/ASTMatchers/Dynamic/Parser.cpp b/clang/lib/ASTMatchers/Dynamic/Parser.cpp index e3b00b46832c..a0037549ca61 100644 --- a/clang/lib/ASTMatchers/Dynamic/Parser.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Parser.cpp @@ -38,6 +38,7 @@ struct Parser::TokenInfo { /// Different possible tokens. enum TokenKind { TK_Eof, + TK_NewLine, TK_OpenParen, TK_CloseParen, TK_Comma, @@ -65,12 +66,12 @@ const char* const Parser::TokenInfo::ID_Bind = "bind"; /// Simple tokenizer for the parser. class Parser::CodeTokenizer { public: - explicit CodeTokenizer(StringRef MatcherCode, Diagnostics *Error) + explicit CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error) : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error) { NextToken = getNextToken(); } - CodeTokenizer(StringRef MatcherCode, Diagnostics *Error, + CodeTokenizer(StringRef &MatcherCode, Diagnostics *Error, unsigned CodeCompletionOffset) : Code(MatcherCode), StartOfLine(MatcherCode), Error(Error), CodeCompletionLocation(MatcherCode.data() + CodeCompletionOffset) { @@ -87,6 +88,19 @@ public: return ThisToken; } + TokenInfo SkipNewlines() { + while (NextToken.Kind == TokenInfo::TK_NewLine) + NextToken = getNextToken(); + return NextToken; + } + + TokenInfo consumeNextTokenIgnoreNewlines() { + SkipNewlines(); + if (NextToken.Kind == TokenInfo::TK_Eof) + return NextToken; + return consumeNextToken(); + } + TokenInfo::TokenKind nextTokenKind() const { return NextToken.Kind; } private: @@ -110,9 +124,8 @@ private: switch (Code[0]) { case '#': - Result.Kind = TokenInfo::TK_Eof; - Result.Text = ""; - return Result; + Code = Code.drop_until([](char c) { return c == '\n'; }); + return getNextToken(); case ',': Result.Kind = TokenInfo::TK_Comma; Result.Text = Code.substr(0, 1); @@ -123,6 +136,13 @@ private: Result.Text = Code.substr(0, 1); Code = Code.drop_front(); break; + case '\n': + ++Line; + StartOfLine = Code.drop_front(); + Result.Kind = TokenInfo::TK_NewLine; + Result.Text = Code.substr(0, 1); + Code = Code.drop_front(); + break; case '(': Result.Kind = TokenInfo::TK_OpenParen; Result.Text = Code.substr(0, 1); @@ -277,13 +297,10 @@ private: /// Consume all leading whitespace from \c Code. void consumeWhitespace() { - while (!Code.empty() && isWhitespace(Code[0])) { - if (Code[0] == '\n') { - ++Line; - StartOfLine = Code.drop_front(); - } - Code = Code.drop_front(); - } + Code = Code.drop_while([](char c) { + // Don't trim newlines. + return StringRef(" \t\v\f\r").contains(c); + }); } SourceLocation currentLocation() { @@ -293,7 +310,7 @@ private: return Location; } - StringRef Code; + StringRef &Code; StringRef StartOfLine; unsigned Line = 1; Diagnostics *Error; @@ -364,10 +381,19 @@ bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) { } return false; } + + if (Tokenizer->nextTokenKind() == TokenInfo::TK_NewLine) { + Error->addError(Tokenizer->peekNextToken().Range, + Error->ET_ParserNoOpenParen) + << "NewLine"; + return false; + } + // If the syntax is correct and the name is not a matcher either, report // unknown named value. if ((Tokenizer->nextTokenKind() == TokenInfo::TK_Comma || Tokenizer->nextTokenKind() == TokenInfo::TK_CloseParen || + Tokenizer->nextTokenKind() == TokenInfo::TK_NewLine || Tokenizer->nextTokenKind() == TokenInfo::TK_Eof) && !S->lookupMatcherCtor(NameToken.Text)) { Error->addError(NameToken.Range, Error->ET_RegistryValueNotFound) @@ -377,6 +403,8 @@ bool Parser::parseIdentifierPrefixImpl(VariantValue *Value) { // Otherwise, fallback to the matcher parser. } + Tokenizer->SkipNewlines(); + // Parse as a matcher expression. return parseMatcherExpressionImpl(NameToken, Value); } @@ -392,8 +420,8 @@ bool Parser::parseBindID(std::string &BindID) { } const TokenInfo OpenToken = Tokenizer->consumeNextToken(); - const TokenInfo IDToken = Tokenizer->consumeNextToken(); - const TokenInfo CloseToken = Tokenizer->consumeNextToken(); + const TokenInfo IDToken = Tokenizer->consumeNextTokenIgnoreNewlines(); + const TokenInfo CloseToken = Tokenizer->consumeNextTokenIgnoreNewlines(); // TODO: We could use different error codes for each/some to be more // explicit about the syntax error. @@ -443,6 +471,8 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken, std::vector<ParserValue> Args; TokenInfo EndToken; + Tokenizer->SkipNewlines(); + { ScopedContextEntry SCE(this, Ctor ? *Ctor : nullptr); @@ -466,12 +496,14 @@ bool Parser::parseMatcherExpressionImpl(const TokenInfo &NameToken, NameToken.Text, NameToken.Range, Args.size() + 1); ParserValue ArgValue; + Tokenizer->SkipNewlines(); ArgValue.Text = Tokenizer->peekNextToken().Text; ArgValue.Range = Tokenizer->peekNextToken().Range; if (!parseExpressionImpl(&ArgValue.Value)) { return false; } + Tokenizer->SkipNewlines(); Args.push_back(ArgValue); SCE.nextArg(); } @@ -531,7 +563,7 @@ std::vector<MatcherCompletion> Parser::getNamedValueCompletions( } void Parser::addExpressionCompletions() { - const TokenInfo CompToken = Tokenizer->consumeNextToken(); + const TokenInfo CompToken = Tokenizer->consumeNextTokenIgnoreNewlines(); assert(CompToken.Kind == TokenInfo::TK_CodeCompletion); // We cannot complete code if there is an invalid element on the context @@ -575,14 +607,15 @@ bool Parser::parseExpressionImpl(VariantValue *Value) { case TokenInfo::TK_Error: // This error was already reported by the tokenizer. return false; - + case TokenInfo::TK_NewLine: case TokenInfo::TK_OpenParen: case TokenInfo::TK_CloseParen: case TokenInfo::TK_Comma: case TokenInfo::TK_Period: case TokenInfo::TK_InvalidChar: const TokenInfo Token = Tokenizer->consumeNextToken(); - Error->addError(Token.Range, Error->ET_ParserInvalidToken) << Token.Text; + Error->addError(Token.Range, Error->ET_ParserInvalidToken) + << (Token.Kind == TokenInfo::TK_NewLine ? "NewLine" : Token.Text); return false; } @@ -624,13 +657,14 @@ std::vector<MatcherCompletion> Parser::RegistrySema::getMatcherCompletions( return Registry::getMatcherCompletions(AcceptedTypes); } -bool Parser::parseExpression(StringRef Code, Sema *S, +bool Parser::parseExpression(StringRef &Code, Sema *S, const NamedValueMap *NamedValues, VariantValue *Value, Diagnostics *Error) { CodeTokenizer Tokenizer(Code, Error); if (!Parser(&Tokenizer, S, NamedValues, Error).parseExpressionImpl(Value)) return false; - if (Tokenizer.peekNextToken().Kind != TokenInfo::TK_Eof) { + auto NT = Tokenizer.peekNextToken(); + if (NT.Kind != TokenInfo::TK_Eof && NT.Kind != TokenInfo::TK_NewLine) { Error->addError(Tokenizer.peekNextToken().Range, Error->ET_ParserTrailingCode); return false; @@ -639,7 +673,7 @@ bool Parser::parseExpression(StringRef Code, Sema *S, } std::vector<MatcherCompletion> -Parser::completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S, +Parser::completeExpression(StringRef &Code, unsigned CompletionOffset, Sema *S, const NamedValueMap *NamedValues) { Diagnostics Error; CodeTokenizer Tokenizer(Code, &Error, CompletionOffset); @@ -659,7 +693,7 @@ Parser::completeExpression(StringRef Code, unsigned CompletionOffset, Sema *S, } llvm::Optional<DynTypedMatcher> -Parser::parseMatcherExpression(StringRef Code, Sema *S, +Parser::parseMatcherExpression(StringRef &Code, Sema *S, const NamedValueMap *NamedValues, Diagnostics *Error) { VariantValue Value; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 8c11e069cb05..1c0930c5983a 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -41,7 +41,8 @@ namespace { using internal::MatcherDescriptor; -using ConstructorMap = llvm::StringMap<std::unique_ptr<const MatcherDescriptor>>; +using ConstructorMap = + llvm::StringMap<std::unique_ptr<const MatcherDescriptor>>; class RegistryMaps { public: @@ -104,6 +105,7 @@ RegistryMaps::RegistryMaps() { // equalsNode REGISTER_OVERLOADED_2(callee); + REGISTER_OVERLOADED_2(hasAnyCapture); REGISTER_OVERLOADED_2(hasPrefix); REGISTER_OVERLOADED_2(hasType); REGISTER_OVERLOADED_2(ignoringParens); @@ -279,6 +281,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasIndex); REGISTER_MATCHER(hasInit); REGISTER_MATCHER(hasInitializer); + REGISTER_MATCHER(hasInitStatement); REGISTER_MATCHER(hasKeywordSelector); REGISTER_MATCHER(hasLHS); REGISTER_MATCHER(hasLocalQualifiers); @@ -454,6 +457,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(on); REGISTER_MATCHER(onImplicitObjectArgument); REGISTER_MATCHER(opaqueValueExpr); + REGISTER_MATCHER(optionally); REGISTER_MATCHER(parameterCountIs); REGISTER_MATCHER(parenExpr); REGISTER_MATCHER(parenListExpr); diff --git a/clang/lib/Analysis/BodyFarm.cpp b/clang/lib/Analysis/BodyFarm.cpp index 43f9e715b3de..1a7891550542 100644 --- a/clang/lib/Analysis/BodyFarm.cpp +++ b/clang/lib/Analysis/BodyFarm.cpp @@ -737,50 +737,69 @@ static const ObjCIvarDecl *findBackingIvar(const ObjCPropertyDecl *Prop) { } static Stmt *createObjCPropertyGetter(ASTContext &Ctx, - const ObjCPropertyDecl *Prop) { - // First, find the backing ivar. - const ObjCIvarDecl *IVar = findBackingIvar(Prop); - if (!IVar) - return nullptr; + const ObjCMethodDecl *MD) { + // First, find the backing ivar. + const ObjCIvarDecl *IVar = nullptr; - // Ignore weak variables, which have special behavior. - if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) - return nullptr; + // Property accessor stubs sometimes do not correspond to any property decl + // in the current interface (but in a superclass). They still have a + // corresponding property impl decl in this case. + if (MD->isSynthesizedAccessorStub()) { + const ObjCInterfaceDecl *IntD = MD->getClassInterface(); + const ObjCImplementationDecl *ImpD = IntD->getImplementation(); + for (const auto *PI: ImpD->property_impls()) { + if (const ObjCPropertyDecl *P = PI->getPropertyDecl()) { + if (P->getGetterName() == MD->getSelector()) + IVar = P->getPropertyIvarDecl(); + } + } + } - // Look to see if Sema has synthesized a body for us. This happens in - // Objective-C++ because the return value may be a C++ class type with a - // non-trivial copy constructor. We can only do this if we can find the - // @synthesize for this property, though (or if we know it's been auto- - // synthesized). - const ObjCImplementationDecl *ImplDecl = - IVar->getContainingInterface()->getImplementation(); - if (ImplDecl) { - for (const auto *I : ImplDecl->property_impls()) { - if (I->getPropertyDecl() != Prop) - continue; + if (!IVar) { + const ObjCPropertyDecl *Prop = MD->findPropertyDecl(); + IVar = findBackingIvar(Prop); + if (!IVar) + return nullptr; + + // Ignore weak variables, which have special behavior. + if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) + return nullptr; - if (I->getGetterCXXConstructor()) { - ASTMaker M(Ctx); - return M.makeReturn(I->getGetterCXXConstructor()); + // Look to see if Sema has synthesized a body for us. This happens in + // Objective-C++ because the return value may be a C++ class type with a + // non-trivial copy constructor. We can only do this if we can find the + // @synthesize for this property, though (or if we know it's been auto- + // synthesized). + const ObjCImplementationDecl *ImplDecl = + IVar->getContainingInterface()->getImplementation(); + if (ImplDecl) { + for (const auto *I : ImplDecl->property_impls()) { + if (I->getPropertyDecl() != Prop) + continue; + + if (I->getGetterCXXConstructor()) { + ASTMaker M(Ctx); + return M.makeReturn(I->getGetterCXXConstructor()); + } } } - } - // Sanity check that the property is the same type as the ivar, or a - // reference to it, and that it is either an object pointer or trivially - // copyable. - if (!Ctx.hasSameUnqualifiedType(IVar->getType(), - Prop->getType().getNonReferenceType())) - return nullptr; - if (!IVar->getType()->isObjCLifetimeType() && - !IVar->getType().isTriviallyCopyableType(Ctx)) - return nullptr; + // Sanity check that the property is the same type as the ivar, or a + // reference to it, and that it is either an object pointer or trivially + // copyable. + if (!Ctx.hasSameUnqualifiedType(IVar->getType(), + Prop->getType().getNonReferenceType())) + return nullptr; + if (!IVar->getType()->isObjCLifetimeType() && + !IVar->getType().isTriviallyCopyableType(Ctx)) + return nullptr; + } // Generate our body: // return self->_ivar; ASTMaker M(Ctx); - const VarDecl *selfVar = Prop->getGetterMethodDecl()->getSelfDecl(); + const VarDecl *selfVar = MD->getSelfDecl(); if (!selfVar) return nullptr; @@ -791,7 +810,7 @@ static Stmt *createObjCPropertyGetter(ASTContext &Ctx, selfVar->getType()), IVar); - if (!Prop->getType()->isReferenceType()) + if (!MD->getReturnType()->isReferenceType()) loadedIVar = M.makeLvalueToRvalue(loadedIVar, IVar->getType()); return M.makeReturn(loadedIVar); @@ -814,10 +833,6 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) { return Val.getValue(); Val = nullptr; - const ObjCPropertyDecl *Prop = D->findPropertyDecl(); - if (!Prop) - return nullptr; - // For now, we only synthesize getters. // Synthesizing setters would cause false negatives in the // RetainCountChecker because the method body would bind the parameter @@ -830,7 +845,17 @@ Stmt *BodyFarm::getBody(const ObjCMethodDecl *D) { if (D->param_size() != 0) return nullptr; - Val = createObjCPropertyGetter(C, Prop); + // If the property was defined in an extension, search the extensions for + // overrides. + const ObjCInterfaceDecl *OID = D->getClassInterface(); + if (dyn_cast<ObjCInterfaceDecl>(D->getParent()) != OID) + for (auto *Ext : OID->known_extensions()) { + auto *OMD = Ext->getInstanceMethod(D->getSelector()); + if (OMD && !OMD->isImplicit()) + return nullptr; + } + + Val = createObjCPropertyGetter(C, D); return Val.getValue(); } diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index a533a8d97b84..4c1ea8995f9f 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -542,6 +542,7 @@ public: private: // Visitors to walk an AST and construct the CFG. + CFGBlock *VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc); CFGBlock *VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc); CFGBlock *VisitBinaryOperator(BinaryOperator *B, AddStmtChoice asc); CFGBlock *VisitBreakStmt(BreakStmt *B); @@ -1428,7 +1429,7 @@ void CFGBuilder::findConstructionContexts( if (Layer->getItem().getKind() == ConstructionContextItem::ElidableConstructorKind) { auto *MTE = cast<MaterializeTemporaryExpr>(Child); - findConstructionContexts(withExtraLayer(MTE), MTE->GetTemporaryExpr()); + findConstructionContexts(withExtraLayer(MTE), MTE->getSubExpr()); } break; } @@ -1694,7 +1695,7 @@ static QualType getReferenceInitTemporaryType(const Expr *Init, // Skip through the temporary-materialization expression. if (const MaterializeTemporaryExpr *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) { - Init = MTE->GetTemporaryExpr(); + Init = MTE->getSubExpr(); if (FoundMTE) *FoundMTE = true; continue; @@ -2135,6 +2136,14 @@ CFGBlock *CFGBuilder::Visit(Stmt * S, AddStmtChoice asc, default: return VisitStmt(S, asc); + case Stmt::ImplicitValueInitExprClass: + if (BuildOpts.OmitImplicitValueInitializers) + return Block; + return VisitStmt(S, asc); + + case Stmt::InitListExprClass: + return VisitInitListExpr(cast<InitListExpr>(S), asc); + case Stmt::AddrLabelExprClass: return VisitAddrLabelExpr(cast<AddrLabelExpr>(S), asc); @@ -2341,15 +2350,37 @@ CFGBlock *CFGBuilder::VisitChildren(Stmt *S) { // Visit the children in their reverse order so that they appear in // left-to-right (natural) order in the CFG. reverse_children RChildren(S); - for (reverse_children::iterator I = RChildren.begin(), E = RChildren.end(); - I != E; ++I) { - if (Stmt *Child = *I) + for (Stmt *Child : RChildren) { + if (Child) if (CFGBlock *R = Visit(Child)) B = R; } return B; } +CFGBlock *CFGBuilder::VisitInitListExpr(InitListExpr *ILE, AddStmtChoice asc) { + if (asc.alwaysAdd(*this, ILE)) { + autoCreateBlock(); + appendStmt(Block, ILE); + } + CFGBlock *B = Block; + + reverse_children RChildren(ILE); + for (Stmt *Child : RChildren) { + if (!Child) + continue; + if (CFGBlock *R = Visit(Child)) + B = R; + if (BuildOpts.AddCXXDefaultInitExprInAggregates) { + if (auto *DIE = dyn_cast<CXXDefaultInitExpr>(Child)) + if (Stmt *Child = DIE->getExpr()) + if (CFGBlock *R = Visit(Child)) + B = R; + } + } + return B; +} + CFGBlock *CFGBuilder::VisitAddrLabelExpr(AddrLabelExpr *A, AddStmtChoice asc) { AddressTakenLabels.insert(A->getLabel()); @@ -3462,7 +3493,7 @@ CFGBuilder::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE, AddStmtChoice asc) { findConstructionContexts( ConstructionContextLayer::create(cfg->getBumpVectorContext(), MTE), - MTE->getTemporary()); + MTE->getSubExpr()); return VisitStmt(MTE, asc); } @@ -4649,7 +4680,7 @@ tryAgain: // Find the expression whose lifetime needs to be extended. E = const_cast<Expr *>( cast<MaterializeTemporaryExpr>(E) - ->GetTemporaryExpr() + ->getSubExpr() ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments)); // Visit the skipped comma operator left-hand sides for other temporaries. for (const Expr *CommaLHS : CommaLHSs) { @@ -5879,12 +5910,16 @@ const Expr *CFGBlock::getLastCondition() const { if (succ_size() < 2) return nullptr; + // FIXME: Is there a better condition expression we can return in this case? + if (size() == 0) + return nullptr; + auto StmtElem = rbegin()->getAs<CFGStmt>(); if (!StmtElem) return nullptr; const Stmt *Cond = StmtElem->getStmt(); - if (isa<ObjCForCollectionStmt>(Cond)) + if (isa<ObjCForCollectionStmt>(Cond) || isa<DeclStmt>(Cond)) return nullptr; // Only ObjCForCollectionStmt is known not to be a non-Expr terminator, hence diff --git a/clang/lib/Analysis/CloneDetection.cpp b/clang/lib/Analysis/CloneDetection.cpp index 30d104165cc5..5fb5840ce293 100644 --- a/clang/lib/Analysis/CloneDetection.cpp +++ b/clang/lib/Analysis/CloneDetection.cpp @@ -11,7 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/CloneDetection.h" - +#include "clang/AST/Attr.h" #include "clang/AST/DataCollection.h" #include "clang/AST/DeclTemplate.h" #include "llvm/Support/MD5.h" diff --git a/clang/lib/Analysis/Consumed.cpp b/clang/lib/Analysis/Consumed.cpp index cde753e8ec57..9560248b173f 100644 --- a/clang/lib/Analysis/Consumed.cpp +++ b/clang/lib/Analysis/Consumed.cpp @@ -847,7 +847,7 @@ void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) { void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr( const MaterializeTemporaryExpr *Temp) { - forwardInfo(Temp->GetTemporaryExpr(), Temp); + forwardInfo(Temp->getSubExpr(), Temp); } void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) { diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp index 1dab8e309f59..369879ad65f5 100644 --- a/clang/lib/Analysis/ReachableCode.cpp +++ b/clang/lib/Analysis/ReachableCode.cpp @@ -19,6 +19,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/Analysis/AnalysisDeclContext.h" #include "clang/Analysis/CFG.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" #include "llvm/ADT/BitVector.h" diff --git a/clang/lib/Analysis/ThreadSafety.cpp b/clang/lib/Analysis/ThreadSafety.cpp index c60954374ce3..48f4106b6bae 100644 --- a/clang/lib/Analysis/ThreadSafety.cpp +++ b/clang/lib/Analysis/ThreadSafety.cpp @@ -2142,6 +2142,9 @@ void BuildLockset::VisitDeclStmt(const DeclStmt *S) { // handle constructors that involve temporaries if (auto *EWC = dyn_cast<ExprWithCleanups>(E)) E = EWC->getSubExpr(); + if (auto *ICE = dyn_cast<ImplicitCastExpr>(E)) + if (ICE->getCastKind() == CK_NoOp) + E = ICE->getSubExpr(); if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(E)) E = BTE->getSubExpr(); diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp index 373dfc77fa9b..1b8c55e56d47 100644 --- a/clang/lib/Analysis/ThreadSafetyCommon.cpp +++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp @@ -244,8 +244,7 @@ til::SExpr *SExprBuilder::translate(const Stmt *S, CallingContext *Ctx) { case Stmt::CXXBindTemporaryExprClass: return translate(cast<CXXBindTemporaryExpr>(S)->getSubExpr(), Ctx); case Stmt::MaterializeTemporaryExprClass: - return translate(cast<MaterializeTemporaryExpr>(S)->GetTemporaryExpr(), - Ctx); + return translate(cast<MaterializeTemporaryExpr>(S)->getSubExpr(), Ctx); // Collect all literals case Stmt::CharacterLiteralClass: diff --git a/clang/lib/Basic/Builtins.cpp b/clang/lib/Basic/Builtins.cpp index d23c280d4758..0cd89df41b67 100644 --- a/clang/lib/Basic/Builtins.cpp +++ b/clang/lib/Basic/Builtins.cpp @@ -47,8 +47,7 @@ void Builtin::Context::InitializeTarget(const TargetInfo &Target, AuxTSRecords = AuxTarget->getTargetBuiltins(); } -bool Builtin::Context::isBuiltinFunc(const char *Name) { - StringRef FuncName(Name); +bool Builtin::Context::isBuiltinFunc(llvm::StringRef FuncName) { for (unsigned i = Builtin::NotBuiltin + 1; i != Builtin::FirstTSBuiltin; ++i) if (FuncName.equals(BuiltinInfo[i].Name)) return strchr(BuiltinInfo[i].Attributes, 'f') != nullptr; diff --git a/clang/lib/Basic/Diagnostic.cpp b/clang/lib/Basic/Diagnostic.cpp index c82f74413ec1..f258b37f2fa6 100644 --- a/clang/lib/Basic/Diagnostic.cpp +++ b/clang/lib/Basic/Diagnostic.cpp @@ -145,19 +145,20 @@ void DiagnosticsEngine::Reset() { } void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1, - StringRef Arg2) { + StringRef Arg2, StringRef Arg3) { if (DelayedDiagID) return; DelayedDiagID = DiagID; DelayedDiagArg1 = Arg1.str(); DelayedDiagArg2 = Arg2.str(); + DelayedDiagArg3 = Arg3.str(); } void DiagnosticsEngine::ReportDelayed() { unsigned ID = DelayedDiagID; DelayedDiagID = 0; - Report(ID) << DelayedDiagArg1 << DelayedDiagArg2; + Report(ID) << DelayedDiagArg1 << DelayedDiagArg2 << DelayedDiagArg3; } void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState *State) { @@ -981,6 +982,7 @@ FormatDiagnostic(const char *DiagStr, const char *DiagEnd, llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\''; break; } + case DiagnosticsEngine::ak_addrspace: case DiagnosticsEngine::ak_qual: case DiagnosticsEngine::ak_qualtype: case DiagnosticsEngine::ak_declarationname: diff --git a/clang/lib/Basic/FileManager.cpp b/clang/lib/Basic/FileManager.cpp index 88a7a1250837..079a4bbfc82f 100644 --- a/clang/lib/Basic/FileManager.cpp +++ b/clang/lib/Basic/FileManager.cpp @@ -221,12 +221,12 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { // We've not seen this before. Fill it in. ++NumFileCacheMisses; - auto &NamedFileEnt = *SeenFileInsertResult.first; - assert(!NamedFileEnt.second && "should be newly-created"); + auto *NamedFileEnt = &*SeenFileInsertResult.first; + assert(!NamedFileEnt->second && "should be newly-created"); // Get the null-terminated file name as stored as the key of the // SeenFileEntries map. - StringRef InterndFileName = NamedFileEnt.first(); + StringRef InterndFileName = NamedFileEnt->first(); // Look up the directory for the file. When looking up something like // sys/foo.h we'll discover all of the search directories that have a 'sys' @@ -236,7 +236,7 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { auto DirInfoOrErr = getDirectoryFromFile(*this, Filename, CacheFailure); if (!DirInfoOrErr) { // Directory doesn't exist, file can't exist. if (CacheFailure) - NamedFileEnt.second = DirInfoOrErr.getError(); + NamedFileEnt->second = DirInfoOrErr.getError(); else SeenFileEntries.erase(Filename); @@ -255,7 +255,7 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { if (statError) { // There's no real file at the given path. if (CacheFailure) - NamedFileEnt.second = statError; + NamedFileEnt->second = statError; else SeenFileEntries.erase(Filename); @@ -268,7 +268,7 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { // This occurs when one dir is symlinked to another, for example. FileEntry &UFE = UniqueRealFiles[Status.getUniqueID()]; - NamedFileEnt.second = &UFE; + NamedFileEnt->second = &UFE; // If the name returned by getStatValue is different than Filename, re-intern // the name. @@ -281,7 +281,11 @@ FileManager::getFileRef(StringRef Filename, bool openFile, bool CacheFailure) { // In addition to re-interning the name, construct a redirecting seen file // entry, that will point to the name the filesystem actually wants to use. StringRef *Redirect = new (CanonicalNameStorage) StringRef(InterndFileName); - NamedFileEnt.second = Redirect; + auto SeenFileInsertResultIt = SeenFileEntries.find(Filename); + assert(SeenFileInsertResultIt != SeenFileEntries.end() && + "unexpected SeenFileEntries cache miss"); + SeenFileInsertResultIt->second = Redirect; + NamedFileEnt = &*SeenFileInsertResultIt; } if (UFE.isValid()) { // Already have an entry with this inode, return it. @@ -544,10 +548,9 @@ void FileManager::GetUniqueIDMapping( } StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) { - // FIXME: use llvm::sys::fs::canonical() when it gets implemented - llvm::DenseMap<const DirectoryEntry *, llvm::StringRef>::iterator Known - = CanonicalDirNames.find(Dir); - if (Known != CanonicalDirNames.end()) + llvm::DenseMap<const void *, llvm::StringRef>::iterator Known + = CanonicalNames.find(Dir); + if (Known != CanonicalNames.end()) return Known->second; StringRef CanonicalName(Dir->getName()); @@ -556,7 +559,23 @@ StringRef FileManager::getCanonicalName(const DirectoryEntry *Dir) { if (!FS->getRealPath(Dir->getName(), CanonicalNameBuf)) CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage); - CanonicalDirNames.insert({Dir, CanonicalName}); + CanonicalNames.insert({Dir, CanonicalName}); + return CanonicalName; +} + +StringRef FileManager::getCanonicalName(const FileEntry *File) { + llvm::DenseMap<const void *, llvm::StringRef>::iterator Known + = CanonicalNames.find(File); + if (Known != CanonicalNames.end()) + return Known->second; + + StringRef CanonicalName(File->getName()); + + SmallString<4096> CanonicalNameBuf; + if (!FS->getRealPath(File->getName(), CanonicalNameBuf)) + CanonicalName = StringRef(CanonicalNameBuf).copy(CanonicalNameStorage); + + CanonicalNames.insert({File, CanonicalName}); return CanonicalName; } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index a52ed8caa121..414ebb52c0c7 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -18,30 +18,49 @@ #include <cassert> using namespace clang; +using namespace llvm::omp; -OpenMPDirectiveKind clang::getOpenMPDirectiveKind(StringRef Str) { - return llvm::StringSwitch<OpenMPDirectiveKind>(Str) -#define OPENMP_DIRECTIVE(Name) .Case(#Name, OMPD_##Name) -#define OPENMP_DIRECTIVE_EXT(Name, Str) .Case(Str, OMPD_##Name) +OpenMPContextSelectorSetKind +clang::getOpenMPContextSelectorSet(llvm::StringRef Str) { + return llvm::StringSwitch<OpenMPContextSelectorSetKind>(Str) +#define OPENMP_CONTEXT_SELECTOR_SET(Name) .Case(#Name, OMP_CTX_SET_##Name) #include "clang/Basic/OpenMPKinds.def" - .Default(OMPD_unknown); + .Default(OMP_CTX_SET_unknown); } -const char *clang::getOpenMPDirectiveName(OpenMPDirectiveKind Kind) { - assert(Kind <= OMPD_unknown); +llvm::StringRef +clang::getOpenMPContextSelectorSetName(OpenMPContextSelectorSetKind Kind) { switch (Kind) { - case OMPD_unknown: + case OMP_CTX_SET_unknown: + return "unknown"; +#define OPENMP_CONTEXT_SELECTOR_SET(Name) \ + case OMP_CTX_SET_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + break; + } + llvm_unreachable("Invalid OpenMP context selector set kind"); +} + +OpenMPContextSelectorKind clang::getOpenMPContextSelector(llvm::StringRef Str) { + return llvm::StringSwitch<OpenMPContextSelectorKind>(Str) +#define OPENMP_CONTEXT_SELECTOR(Name) .Case(#Name, OMP_CTX_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMP_CTX_unknown); +} + +llvm::StringRef +clang::getOpenMPContextSelectorName(OpenMPContextSelectorKind Kind) { + switch (Kind) { + case OMP_CTX_unknown: return "unknown"; -#define OPENMP_DIRECTIVE(Name) \ - case OMPD_##Name: \ +#define OPENMP_CONTEXT_SELECTOR(Name) \ + case OMP_CTX_##Name: \ return #Name; -#define OPENMP_DIRECTIVE_EXT(Name, Str) \ - case OMPD_##Name: \ - return Str; #include "clang/Basic/OpenMPKinds.def" break; } - llvm_unreachable("Invalid OpenMP directive kind"); + llvm_unreachable("Invalid OpenMP context selector kind"); } OpenMPClauseKind clang::getOpenMPClauseKind(StringRef Str) { @@ -90,10 +109,10 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_DEFAULT_unknown); case OMPC_proc_bind: - return llvm::StringSwitch<OpenMPProcBindClauseKind>(Str) -#define OPENMP_PROC_BIND_KIND(Name) .Case(#Name, OMPC_PROC_BIND_##Name) -#include "clang/Basic/OpenMPKinds.def" - .Default(OMPC_PROC_BIND_unknown); + return llvm::StringSwitch<unsigned>(Str) +#define OMP_PROC_BIND_KIND(Enum, Name, Value) .Case(Name, Value) +#include "llvm/Frontend/OpenMP/OMPKinds.def" + .Default(unsigned(llvm::omp::OMP_PROC_BIND_unknown)); case OMPC_schedule: return llvm::StringSwitch<unsigned>(Str) #define OPENMP_SCHEDULE_KIND(Name) \ @@ -156,6 +175,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, #define OPENMP_DEVICE_TYPE_KIND(Name) .Case(#Name, OMPC_DEVICE_TYPE_##Name) #include "clang/Basic/OpenMPKinds.def" .Default(OMPC_DEVICE_TYPE_unknown); + case OMPC_lastprivate: + return llvm::StringSwitch<OpenMPLastprivateModifier>(Str) +#define OPENMP_LASTPRIVATE_KIND(Name) .Case(#Name, OMPC_LASTPRIVATE_##Name) +#include "clang/Basic/OpenMPKinds.def" + .Default(OMPC_LASTPRIVATE_unknown); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -168,7 +192,6 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_collapse: case OMPC_private: case OMPC_firstprivate: - case OMPC_lastprivate: case OMPC_shared: case OMPC_reduction: case OMPC_task_reduction: @@ -204,6 +227,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_match: + case OMPC_nontemporal: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); @@ -224,12 +248,10 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, llvm_unreachable("Invalid OpenMP 'default' clause type"); case OMPC_proc_bind: switch (Type) { - case OMPC_PROC_BIND_unknown: - return "unknown"; -#define OPENMP_PROC_BIND_KIND(Name) \ - case OMPC_PROC_BIND_##Name: \ - return #Name; -#include "clang/Basic/OpenMPKinds.def" +#define OMP_PROC_BIND_KIND(Enum, Name, Value) \ + case Value: \ + return Name; +#include "llvm/Frontend/OpenMP/OMPKinds.def" } llvm_unreachable("Invalid OpenMP 'proc_bind' clause type"); case OMPC_schedule: @@ -350,6 +372,16 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, #include "clang/Basic/OpenMPKinds.def" } llvm_unreachable("Invalid OpenMP 'device_type' clause type"); + case OMPC_lastprivate: + switch (Type) { + case OMPC_LASTPRIVATE_unknown: + return "unknown"; +#define OPENMP_LASTPRIVATE_KIND(Name) \ + case OMPC_LASTPRIVATE_##Name: \ + return #Name; +#include "clang/Basic/OpenMPKinds.def" + } + llvm_unreachable("Invalid OpenMP 'lastprivate' clause type"); case OMPC_unknown: case OMPC_threadprivate: case OMPC_if: @@ -362,7 +394,6 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_collapse: case OMPC_private: case OMPC_firstprivate: - case OMPC_lastprivate: case OMPC_shared: case OMPC_reduction: case OMPC_task_reduction: @@ -398,15 +429,20 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_reverse_offload: case OMPC_dynamic_allocators: case OMPC_match: + case OMPC_nontemporal: break; } llvm_unreachable("Invalid OpenMP simple clause kind"); } bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, - OpenMPClauseKind CKind) { - assert(DKind <= OMPD_unknown); + OpenMPClauseKind CKind, + unsigned OpenMPVersion) { + assert(unsigned(DKind) <= unsigned(OMPD_unknown)); assert(CKind <= OMPC_unknown); + // Nontemporal clause is not supported in OpenMP < 5.0. + if (OpenMPVersion < 50 && CKind == OMPC_nontemporal) + return false; switch (DKind) { case OMPD_parallel: switch (CKind) { @@ -419,6 +455,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, } break; case OMPD_simd: + if (OpenMPVersion < 50 && CKind == OMPC_if) + return false; switch (CKind) { #define OPENMP_SIMD_CLAUSE(Name) \ case OMPC_##Name: \ @@ -439,6 +477,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, } break; case OMPD_for_simd: + if (OpenMPVersion < 50 && CKind == OMPC_if) + return false; switch (CKind) { #define OPENMP_FOR_SIMD_CLAUSE(Name) \ case OMPC_##Name: \ @@ -488,6 +528,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, break; } break; + case OMPD_parallel_master: + switch (CKind) { +#define OPENMP_PARALLEL_MASTER_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; case OMPD_parallel_sections: switch (CKind) { #define OPENMP_PARALLEL_SECTIONS_CLAUSE(Name) \ @@ -681,6 +731,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, break; } break; + case OMPD_parallel_master_taskloop_simd: + switch (CKind) { +#define OPENMP_PARALLEL_MASTER_TASKLOOP_SIMD_CLAUSE(Name) \ + case OMPC_##Name: \ + return true; +#include "clang/Basic/OpenMPKinds.def" + default: + break; + } + break; case OMPD_critical: switch (CKind) { #define OPENMP_CRITICAL_CLAUSE(Name) \ @@ -722,6 +782,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, } break; case OMPD_distribute_simd: + if (OpenMPVersion < 50 && CKind == OMPC_if) + return false; switch (CKind) { #define OPENMP_DISTRIBUTE_SIMD_CLAUSE(Name) \ case OMPC_##Name: \ @@ -762,6 +824,8 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, } break; case OMPD_teams_distribute_simd: + if (OpenMPVersion < 50 && CKind == OMPC_if) + return false; switch (CKind) { #define OPENMP_TEAMS_DISTRIBUTE_SIMD_CLAUSE(Name) \ case OMPC_##Name: \ @@ -903,8 +967,9 @@ bool clang::isOpenMPLoopDirective(OpenMPDirectiveKind DKind) { DKind == OMPD_parallel_for || DKind == OMPD_parallel_for_simd || DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd || DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd || - DKind == OMPD_parallel_master_taskloop || DKind == OMPD_distribute || - DKind == OMPD_target_parallel_for || + DKind == OMPD_parallel_master_taskloop || + DKind == OMPD_parallel_master_taskloop_simd || + DKind == OMPD_distribute || DKind == OMPD_target_parallel_for || DKind == OMPD_distribute_parallel_for || DKind == OMPD_distribute_parallel_for_simd || DKind == OMPD_distribute_simd || @@ -937,7 +1002,8 @@ bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) { bool clang::isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind) { return DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd || DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd || - DKind == OMPD_parallel_master_taskloop; + DKind == OMPD_parallel_master_taskloop || + DKind == OMPD_parallel_master_taskloop_simd; } bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) { @@ -951,7 +1017,9 @@ bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) { DKind == OMPD_teams_distribute_parallel_for_simd || DKind == OMPD_target_teams_distribute_parallel_for || DKind == OMPD_target_teams_distribute_parallel_for_simd || - DKind == OMPD_parallel_master_taskloop; + DKind == OMPD_parallel_master || + DKind == OMPD_parallel_master_taskloop || + DKind == OMPD_parallel_master_taskloop_simd; } bool clang::isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind) { @@ -988,6 +1056,7 @@ bool clang::isOpenMPSimdDirective(OpenMPDirectiveKind DKind) { return DKind == OMPD_simd || DKind == OMPD_for_simd || DKind == OMPD_parallel_for_simd || DKind == OMPD_taskloop_simd || DKind == OMPD_master_taskloop_simd || + DKind == OMPD_parallel_master_taskloop_simd || DKind == OMPD_distribute_parallel_for_simd || DKind == OMPD_distribute_simd || DKind == OMPD_target_simd || DKind == OMPD_teams_distribute_simd || @@ -1047,6 +1116,7 @@ void clang::getOpenMPCaptureRegions( case OMPD_parallel: case OMPD_parallel_for: case OMPD_parallel_for_simd: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: @@ -1094,6 +1164,7 @@ void clang::getOpenMPCaptureRegions( CaptureRegions.push_back(OMPD_taskloop); break; case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: CaptureRegions.push_back(OMPD_parallel); CaptureRegions.push_back(OMPD_taskloop); break; diff --git a/clang/lib/Basic/SanitizerBlacklist.cpp b/clang/lib/Basic/SanitizerBlacklist.cpp index aec35c7d9864..4f71349350fd 100644 --- a/clang/lib/Basic/SanitizerBlacklist.cpp +++ b/clang/lib/Basic/SanitizerBlacklist.cpp @@ -16,7 +16,9 @@ using namespace clang; SanitizerBlacklist::SanitizerBlacklist( const std::vector<std::string> &BlacklistPaths, SourceManager &SM) - : SSCL(SanitizerSpecialCaseList::createOrDie(BlacklistPaths)), SM(SM) {} + : SSCL(SanitizerSpecialCaseList::createOrDie( + BlacklistPaths, SM.getFileManager().getVirtualFileSystem())), + SM(SM) {} bool SanitizerBlacklist::isBlacklistedGlobal(SanitizerMask Mask, StringRef GlobalName, diff --git a/clang/lib/Basic/SanitizerSpecialCaseList.cpp b/clang/lib/Basic/SanitizerSpecialCaseList.cpp index 5fb0f9660b15..5bf8d39ffd95 100644 --- a/clang/lib/Basic/SanitizerSpecialCaseList.cpp +++ b/clang/lib/Basic/SanitizerSpecialCaseList.cpp @@ -16,10 +16,11 @@ using namespace clang; std::unique_ptr<SanitizerSpecialCaseList> SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths, + llvm::vfs::FileSystem &VFS, std::string &Error) { std::unique_ptr<clang::SanitizerSpecialCaseList> SSCL( new SanitizerSpecialCaseList()); - if (SSCL->createInternal(Paths, Error)) { + if (SSCL->createInternal(Paths, VFS, Error)) { SSCL->createSanitizerSections(); return SSCL; } @@ -27,9 +28,10 @@ SanitizerSpecialCaseList::create(const std::vector<std::string> &Paths, } std::unique_ptr<SanitizerSpecialCaseList> -SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths) { +SanitizerSpecialCaseList::createOrDie(const std::vector<std::string> &Paths, + llvm::vfs::FileSystem &VFS) { std::string Error; - if (auto SSCL = create(Paths, Error)) + if (auto SSCL = create(Paths, VFS, Error)) return SSCL; llvm::report_fatal_error(Error); } diff --git a/clang/lib/Basic/SourceManager.cpp b/clang/lib/Basic/SourceManager.cpp index 58b95289eaf2..73f2ae96d4a3 100644 --- a/clang/lib/Basic/SourceManager.cpp +++ b/clang/lib/Basic/SourceManager.cpp @@ -95,6 +95,29 @@ void ContentCache::replaceBuffer(const llvm::MemoryBuffer *B, bool DoNotFree) { Buffer.setInt((B && DoNotFree) ? DoNotFreeFlag : 0); } +const char *ContentCache::getInvalidBOM(StringRef BufStr) { + // If the buffer is valid, check to see if it has a UTF Byte Order Mark + // (BOM). We only support UTF-8 with and without a BOM right now. See + // http://en.wikipedia.org/wiki/Byte_order_mark for more information. + const char *InvalidBOM = + llvm::StringSwitch<const char *>(BufStr) + .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"), + "UTF-32 (BE)") + .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"), + "UTF-32 (LE)") + .StartsWith("\xFE\xFF", "UTF-16 (BE)") + .StartsWith("\xFF\xFE", "UTF-16 (LE)") + .StartsWith("\x2B\x2F\x76", "UTF-7") + .StartsWith("\xF7\x64\x4C", "UTF-1") + .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC") + .StartsWith("\x0E\xFE\xFF", "SCSU") + .StartsWith("\xFB\xEE\x28", "BOCU-1") + .StartsWith("\x84\x31\x95\x33", "GB-18030") + .Default(nullptr); + + return InvalidBOM; +} + const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag, FileManager &FM, SourceLocation Loc, @@ -190,20 +213,7 @@ const llvm::MemoryBuffer *ContentCache::getBuffer(DiagnosticsEngine &Diag, // (BOM). We only support UTF-8 with and without a BOM right now. See // http://en.wikipedia.org/wiki/Byte_order_mark for more information. StringRef BufStr = Buffer.getPointer()->getBuffer(); - const char *InvalidBOM = llvm::StringSwitch<const char *>(BufStr) - .StartsWith(llvm::StringLiteral::withInnerNUL("\x00\x00\xFE\xFF"), - "UTF-32 (BE)") - .StartsWith(llvm::StringLiteral::withInnerNUL("\xFF\xFE\x00\x00"), - "UTF-32 (LE)") - .StartsWith("\xFE\xFF", "UTF-16 (BE)") - .StartsWith("\xFF\xFE", "UTF-16 (LE)") - .StartsWith("\x2B\x2F\x76", "UTF-7") - .StartsWith("\xF7\x64\x4C", "UTF-1") - .StartsWith("\xDD\x73\x66\x73", "UTF-EBCDIC") - .StartsWith("\x0E\xFE\xFF", "SCSU") - .StartsWith("\xFB\xEE\x28", "BOCU-1") - .StartsWith("\x84\x31\x95\x33", "GB-18030") - .Default(nullptr); + const char *InvalidBOM = getInvalidBOM(BufStr); if (InvalidBOM) { Diag.Report(Loc, diag::err_unsupported_bom) @@ -1240,23 +1250,18 @@ static void ComputeLineNumbers(DiagnosticsEngine &Diag, ContentCache *FI, const unsigned char *Buf = (const unsigned char *)Buffer->getBufferStart(); const unsigned char *End = (const unsigned char *)Buffer->getBufferEnd(); + const std::size_t BufLen = End - Buf; unsigned I = 0; - while (true) { - // Skip over the contents of the line. - while (Buf[I] != '\n' && Buf[I] != '\r' && Buf[I] != '\0') - ++I; - - if (Buf[I] == '\n' || Buf[I] == '\r') { + while (I < BufLen) { + if (Buf[I] == '\n') { + LineOffsets.push_back(I + 1); + } else if (Buf[I] == '\r') { // If this is \r\n, skip both characters. - if (Buf[I] == '\r' && Buf[I+1] == '\n') + if (I + 1 < BufLen && Buf[I + 1] == '\n') ++I; - ++I; - LineOffsets.push_back(I); - } else { - // Otherwise, this is a NUL. If end of file, exit. - if (Buf+I == End) break; - ++I; + LineOffsets.push_back(I + 1); } + ++I; } // Copy the offsets into the FileInfo structure. diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 63a64ed2931a..c063f8ca4472 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -122,6 +122,11 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, case llvm::Triple::lanai: return new LanaiTargetInfo(Triple, Opts); + case llvm::Triple::aarch64_32: + if (Triple.isOSDarwin()) + return new DarwinAArch64TargetInfo(Triple, Opts); + + return nullptr; case llvm::Triple::aarch64: if (Triple.isOSDarwin()) return new DarwinAArch64TargetInfo(Triple, Opts); @@ -378,6 +383,8 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple, switch (os) { case llvm::Triple::FreeBSD: return new FreeBSDTargetInfo<RISCV64TargetInfo>(Triple, Opts); + case llvm::Triple::Fuchsia: + return new FuchsiaTargetInfo<RISCV64TargetInfo>(Triple, Opts); case llvm::Triple::Linux: return new LinuxTargetInfo<RISCV64TargetInfo>(Triple, Opts); default: diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index c86cc63e3d84..cba3e3ada7ea 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -15,6 +15,8 @@ #include "clang/Basic/TargetInfo.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/AArch64TargetParser.h" using namespace clang; using namespace clang::targets; @@ -51,7 +53,11 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple, HasLegalHalfType = true; HasFloat16 = true; - LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + if (Triple.isArch64Bit()) + LongWidth = LongAlign = PointerWidth = PointerAlign = 64; + else + LongWidth = LongAlign = PointerWidth = PointerAlign = 32; + MaxVectorAlign = 128; MaxAtomicInlineWidth = 128; MaxAtomicPromoteWidth = 128; @@ -103,6 +109,28 @@ bool AArch64TargetInfo::setABI(const std::string &Name) { return true; } +bool AArch64TargetInfo::validateBranchProtection(StringRef Spec, + BranchProtectionInfo &BPI, + StringRef &Err) const { + llvm::AArch64::ParsedBranchProtection PBP; + if (!llvm::AArch64::parseBranchProtection(Spec, PBP, Err)) + return false; + + BPI.SignReturnAddr = + llvm::StringSwitch<CodeGenOptions::SignReturnAddressScope>(PBP.Scope) + .Case("non-leaf", CodeGenOptions::SignReturnAddressScope::NonLeaf) + .Case("all", CodeGenOptions::SignReturnAddressScope::All) + .Default(CodeGenOptions::SignReturnAddressScope::None); + + if (PBP.Key == "a_key") + BPI.SignKey = CodeGenOptions::SignReturnAddressKeyValue::AKey; + else + BPI.SignKey = CodeGenOptions::SignReturnAddressKeyValue::BKey; + + BPI.BranchTargetEnforcement = PBP.BranchTargetEnforcement; + return true; +} + bool AArch64TargetInfo::isValidCPUName(StringRef Name) const { return Name == "generic" || llvm::AArch64::parseCPUArch(Name) != llvm::AArch64::ArchKind::INVALID; @@ -130,6 +158,7 @@ void AArch64TargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts, void AArch64TargetInfo::getTargetDefinesARMV83A(const LangOptions &Opts, MacroBuilder &Builder) const { + Builder.defineMacro("__ARM_FEATURE_COMPLEX", "1"); Builder.defineMacro("__ARM_FEATURE_JCVT", "1"); // Also include the Armv8.2 defines getTargetDefinesARMV82A(Opts, Builder); @@ -160,7 +189,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__ELF__"); // Target properties. - if (!getTriple().isOSWindows()) { + if (!getTriple().isOSWindows() && getTriple().isArch64Bit()) { Builder.defineMacro("_LP64"); Builder.defineMacro("__LP64__"); } @@ -506,14 +535,19 @@ int AArch64TargetInfo::getEHDataRegisterNumber(unsigned RegNo) const { return -1; } +bool AArch64TargetInfo::hasInt128Type() const { return true; } + AArch64leTargetInfo::AArch64leTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : AArch64TargetInfo(Triple, Opts) {} void AArch64leTargetInfo::setDataLayout() { - if (getTriple().isOSBinFormatMachO()) - resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128"); - else + if (getTriple().isOSBinFormatMachO()) { + if(getTriple().isArch32Bit()) + resetDataLayout("e-m:o-p:32:32-i64:64-i128:128-n32:64-S128"); + else + resetDataLayout("e-m:o-i64:64-i128:128-n32:64-S128"); + } else resetDataLayout("e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"); } @@ -631,19 +665,34 @@ DarwinAArch64TargetInfo::DarwinAArch64TargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : DarwinTargetInfo<AArch64leTargetInfo>(Triple, Opts) { Int64Type = SignedLongLong; + if (getTriple().isArch32Bit()) + IntMaxType = SignedLongLong; + + WCharType = SignedInt; UseSignedCharForObjCBool = false; LongDoubleWidth = LongDoubleAlign = SuitableAlign = 64; LongDoubleFormat = &llvm::APFloat::IEEEdouble(); - TheCXXABI.set(TargetCXXABI::iOS64); + UseZeroLengthBitfieldAlignment = false; + + if (getTriple().isArch32Bit()) { + UseBitFieldTypeAlignment = false; + ZeroLengthBitfieldBoundary = 32; + UseZeroLengthBitfieldAlignment = true; + TheCXXABI.set(TargetCXXABI::WatchOS); + } else + TheCXXABI.set(TargetCXXABI::iOS64); } void DarwinAArch64TargetInfo::getOSDefines(const LangOptions &Opts, const llvm::Triple &Triple, MacroBuilder &Builder) const { Builder.defineMacro("__AARCH64_SIMD__"); - Builder.defineMacro("__ARM64_ARCH_8__"); + if (Triple.isArch32Bit()) + Builder.defineMacro("__ARM64_ARCH_8_32__"); + else + Builder.defineMacro("__ARM64_ARCH_8__"); Builder.defineMacro("__ARM_NEON__"); Builder.defineMacro("__LITTLE_ENDIAN__"); Builder.defineMacro("__REGISTER_PREFIX__", ""); diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index b6aa07780edd..5e78237743c9 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -49,6 +49,9 @@ public: StringRef getABI() const override; bool setABI(const std::string &Name) override; + bool validateBranchProtection(StringRef, BranchProtectionInfo &, + StringRef &) const override; + bool isValidCPUName(StringRef Name) const override; void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; bool setCPU(const std::string &Name) override; @@ -97,6 +100,8 @@ public: } int getEHDataRegisterNumber(unsigned RegNo) const override; + + bool hasInt128Type() const override; }; class LLVM_LIBRARY_VISIBILITY AArch64leTargetInfo : public AArch64TargetInfo { diff --git a/clang/lib/Basic/Targets/AMDGPU.cpp b/clang/lib/Basic/Targets/AMDGPU.cpp index 481630c0fa45..135ad3f97ce1 100644 --- a/clang/lib/Basic/Targets/AMDGPU.cpp +++ b/clang/lib/Basic/Targets/AMDGPU.cpp @@ -47,7 +47,10 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsGenMap = { Generic, // opencl_generic Global, // cuda_device Constant, // cuda_constant - Local // cuda_shared + Local, // cuda_shared + Generic, // ptr32_sptr + Generic, // ptr32_uptr + Generic // ptr64 }; const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = { @@ -59,7 +62,11 @@ const LangASMap AMDGPUTargetInfo::AMDGPUDefIsPrivMap = { Generic, // opencl_generic Global, // cuda_device Constant, // cuda_constant - Local // cuda_shared + Local, // cuda_shared + Generic, // ptr32_sptr + Generic, // ptr32_uptr + Generic // ptr64 + }; } // namespace targets } // namespace clang diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index 437a77afdc99..be088e81cffe 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -580,6 +580,13 @@ void ARMTargetInfo::getTargetDefinesARMV82A(const LangOptions &Opts, getTargetDefinesARMV81A(Opts, Builder); } +void ARMTargetInfo::getTargetDefinesARMV83A(const LangOptions &Opts, + MacroBuilder &Builder) const { + // Also include the ARMv8.2-A defines + Builder.defineMacro("__ARM_FEATURE_COMPLEX", "1"); + getTargetDefinesARMV82A(Opts, Builder); +} + void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { // Target identification. @@ -809,6 +816,11 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, case llvm::ARM::ArchKind::ARMV8_2A: getTargetDefinesARMV82A(Opts, Builder); break; + case llvm::ARM::ArchKind::ARMV8_3A: + case llvm::ARM::ArchKind::ARMV8_4A: + case llvm::ARM::ArchKind::ARMV8_5A: + getTargetDefinesARMV83A(Opts, Builder); + break; } } diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index ce87a6265934..9696a4404589 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -148,9 +148,10 @@ public: void getTargetDefinesARMV81A(const LangOptions &Opts, MacroBuilder &Builder) const; - void getTargetDefinesARMV82A(const LangOptions &Opts, MacroBuilder &Builder) const; + void getTargetDefinesARMV83A(const LangOptions &Opts, + MacroBuilder &Builder) const; void getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const override; diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h index 117f81430bf4..b2f1831e960e 100644 --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -76,6 +76,8 @@ public: return None; } + bool allowDebugInfoForExternalVar() const override { return true; } + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override { switch (CC) { default: diff --git a/clang/lib/Basic/Targets/Hexagon.cpp b/clang/lib/Basic/Targets/Hexagon.cpp index be23fd2536e0..fcb94b93d69d 100644 --- a/clang/lib/Basic/Targets/Hexagon.cpp +++ b/clang/lib/Basic/Targets/Hexagon.cpp @@ -100,7 +100,10 @@ const char *const HexagonTargetInfo::GCCRegNames[] = { "r9", "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", "p0", "p1", "p2", "p3", - "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp" + "sa0", "lc0", "sa1", "lc1", "m0", "m1", "usr", "ugp", + "r1:0", "r3:2", "r5:4", "r7:6", "r9:8", "r11:10", "r13:12", "r15:14", + "r17:16", "r19:18", "r21:20", "r23:22", "r25:24", "r27:26", "r29:28", + "r31:30" }; ArrayRef<const char *> HexagonTargetInfo::getGCCRegNames() const { diff --git a/clang/lib/Basic/Targets/Mips.cpp b/clang/lib/Basic/Targets/Mips.cpp index 2cafbe87a996..ead5e91f7c8f 100644 --- a/clang/lib/Basic/Targets/Mips.cpp +++ b/clang/lib/Basic/Targets/Mips.cpp @@ -39,6 +39,7 @@ bool MipsTargetInfo::processorSupportsGPR64() const { .Case("mips64r5", true) .Case("mips64r6", true) .Case("octeon", true) + .Case("octeon+", true) .Default(false); return false; } @@ -47,7 +48,7 @@ static constexpr llvm::StringLiteral ValidCPUNames[] = { {"mips1"}, {"mips2"}, {"mips3"}, {"mips4"}, {"mips5"}, {"mips32"}, {"mips32r2"}, {"mips32r3"}, {"mips32r5"}, {"mips32r6"}, {"mips64"}, {"mips64r2"}, {"mips64r3"}, {"mips64r5"}, {"mips64r6"}, - {"octeon"}, {"p5600"}}; + {"octeon"}, {"octeon+"}, {"p5600"}}; bool MipsTargetInfo::isValidCPUName(StringRef Name) const { return llvm::find(ValidCPUNames, Name) != std::end(ValidCPUNames); @@ -61,7 +62,7 @@ void MipsTargetInfo::fillValidCPUList( unsigned MipsTargetInfo::getISARev() const { return llvm::StringSwitch<unsigned>(getCPU()) .Cases("mips32", "mips64", 1) - .Cases("mips32r2", "mips64r2", 2) + .Cases("mips32r2", "mips64r2", "octeon", "octeon+", 2) .Cases("mips32r3", "mips64r3", 3) .Cases("mips32r5", "mips64r5", 5) .Cases("mips32r6", "mips64r6", 6) @@ -187,7 +188,13 @@ void MipsTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("_MIPS_SZLONG", Twine(getLongWidth())); Builder.defineMacro("_MIPS_ARCH", "\"" + CPU + "\""); - Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper()); + if (CPU == "octeon+") + Builder.defineMacro("_MIPS_ARCH_OCTEONP"); + else + Builder.defineMacro("_MIPS_ARCH_" + StringRef(CPU).upper()); + + if (StringRef(CPU).startswith("octeon")) + Builder.defineMacro("__OCTEON__"); // These shouldn't be defined for MIPS-I but there's no need to check // for that since MIPS-I isn't supported. @@ -206,7 +213,10 @@ void MipsTargetInfo::getTargetDefines(const LangOptions &Opts, bool MipsTargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch<bool>(Feature) .Case("mips", true) + .Case("dsp", DspRev >= DSP1) + .Case("dspr2", DspRev >= DSP2) .Case("fp64", FPMode == FP64) + .Case("msa", HasMSA) .Default(false); } diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h index 474cda84a40e..224ec0783edf 100644 --- a/clang/lib/Basic/Targets/Mips.h +++ b/clang/lib/Basic/Targets/Mips.h @@ -180,6 +180,8 @@ public: CPU = getCPU(); if (CPU == "octeon") Features["mips64r2"] = Features["cnmips"] = true; + else if (CPU == "octeon+") + Features["mips64r2"] = Features["cnmips"] = Features["cnmipsp"] = true; else Features[CPU] = true; return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); diff --git a/clang/lib/Basic/Targets/NVPTX.h b/clang/lib/Basic/Targets/NVPTX.h index 2cdd37ca1b07..63780789c474 100644 --- a/clang/lib/Basic/Targets/NVPTX.h +++ b/clang/lib/Basic/Targets/NVPTX.h @@ -33,6 +33,9 @@ static const unsigned NVPTXAddrSpaceMap[] = { 1, // cuda_device 4, // cuda_constant 3, // cuda_shared + 0, // ptr32_sptr + 0, // ptr32_uptr + 0 // ptr64 }; /// The DWARF address class. Taken from diff --git a/clang/lib/Basic/Targets/OSTargets.cpp b/clang/lib/Basic/Targets/OSTargets.cpp index 72fdb0e7dde8..d4ffffc64ba8 100644 --- a/clang/lib/Basic/Targets/OSTargets.cpp +++ b/clang/lib/Basic/Targets/OSTargets.cpp @@ -180,7 +180,7 @@ static void addVisualCDefines(const LangOptions &Opts, MacroBuilder &Builder) { if (Opts.isCompatibleWithMSVC(LangOptions::MSVC2015)) { if (Opts.CPlusPlus2a) - Builder.defineMacro("_MSVC_LANG", "201704L"); + Builder.defineMacro("_MSVC_LANG", "201705L"); else if (Opts.CPlusPlus17) Builder.defineMacro("_MSVC_LANG", "201703L"); else if (Opts.CPlusPlus14) diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h index cc72a0a39f30..70fac030bc5d 100644 --- a/clang/lib/Basic/Targets/OSTargets.h +++ b/clang/lib/Basic/Targets/OSTargets.h @@ -538,6 +538,7 @@ protected: Builder.defineMacro("__KPRINTF_ATTRIBUTE__"); DefineStd(Builder, "unix", Opts); Builder.defineMacro("__ELF__"); + Builder.defineMacro("__SCE__"); Builder.defineMacro("__ORBIS__"); } @@ -808,6 +809,7 @@ public: FuchsiaTargetInfo(const llvm::Triple &Triple, const TargetOptions &Opts) : OSTargetInfo<Target>(Triple, Opts) { this->MCountName = "__mcount"; + this->TheCXXABI.set(TargetCXXABI::Fuchsia); } }; diff --git a/clang/lib/Basic/Targets/PPC.cpp b/clang/lib/Basic/Targets/PPC.cpp index a40991048873..1877d4a5ef70 100644 --- a/clang/lib/Basic/Targets/PPC.cpp +++ b/clang/lib/Basic/Targets/PPC.cpp @@ -157,6 +157,10 @@ void PPCTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("_ARCH_A2Q"); Builder.defineMacro("_ARCH_QP"); } + if (ArchDefs & ArchDefineE500) + Builder.defineMacro("__NO_LWSYNC__"); + if (ArchDefs & ArchDefineFuture) + Builder.defineMacro("_ARCH_PWR_FUTURE"); if (getTriple().getVendor() == llvm::Triple::BGQ) { Builder.defineMacro("__bg__"); @@ -312,6 +316,18 @@ bool PPCTargetInfo::initFeatureMap( .Case("pwr8", true) .Default(false); + Features["spe"] = llvm::StringSwitch<bool>(CPU) + .Case("8548", true) + .Case("e500", true) + .Default(false); + + // Future CPU should include all of the features of Power 9 as well as any + // additional features (yet to be determined) specific to it. + if (CPU == "future") { + initFeatureMap(Features, Diags, "pwr9", FeaturesVec); + addFutureSpecificFeatures(Features); + } + if (!ppcUserFeaturesCheck(Diags, FeaturesVec)) return false; @@ -325,6 +341,12 @@ bool PPCTargetInfo::initFeatureMap( return TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec); } +// Add features specific to the "Future" CPU. +void PPCTargetInfo::addFutureSpecificFeatures( + llvm::StringMap<bool> &Features) const { + return; +} + bool PPCTargetInfo::hasFeature(StringRef Feature) const { return llvm::StringSwitch<bool>(Feature) .Case("powerpc", true) @@ -449,16 +471,17 @@ ArrayRef<TargetInfo::AddlRegName> PPCTargetInfo::getGCCAddlRegNames() const { } static constexpr llvm::StringLiteral ValidCPUNames[] = { - {"generic"}, {"440"}, {"450"}, {"601"}, {"602"}, - {"603"}, {"603e"}, {"603ev"}, {"604"}, {"604e"}, - {"620"}, {"630"}, {"g3"}, {"7400"}, {"g4"}, - {"7450"}, {"g4+"}, {"750"}, {"970"}, {"g5"}, - {"a2"}, {"a2q"}, {"e500mc"}, {"e5500"}, {"power3"}, - {"pwr3"}, {"power4"}, {"pwr4"}, {"power5"}, {"pwr5"}, - {"power5x"}, {"pwr5x"}, {"power6"}, {"pwr6"}, {"power6x"}, - {"pwr6x"}, {"power7"}, {"pwr7"}, {"power8"}, {"pwr8"}, - {"power9"}, {"pwr9"}, {"powerpc"}, {"ppc"}, {"powerpc64"}, - {"ppc64"}, {"powerpc64le"}, {"ppc64le"}, + {"generic"}, {"440"}, {"450"}, {"601"}, {"602"}, + {"603"}, {"603e"}, {"603ev"}, {"604"}, {"604e"}, + {"620"}, {"630"}, {"g3"}, {"7400"}, {"g4"}, + {"7450"}, {"g4+"}, {"750"}, {"8548"}, {"970"}, + {"g5"}, {"a2"}, {"a2q"}, {"e500"}, {"e500mc"}, + {"e5500"}, {"power3"}, {"pwr3"}, {"power4"}, {"pwr4"}, + {"power5"}, {"pwr5"}, {"power5x"}, {"pwr5x"}, {"power6"}, + {"pwr6"}, {"power6x"}, {"pwr6x"}, {"power7"}, {"pwr7"}, + {"power8"}, {"pwr8"}, {"power9"}, {"pwr9"}, {"powerpc"}, + {"ppc"}, {"powerpc64"}, {"ppc64"}, {"powerpc64le"}, {"ppc64le"}, + {"future"} }; bool PPCTargetInfo::isValidCPUName(StringRef Name) const { diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index 6c6421c28e23..270aa7ff9181 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -43,8 +43,10 @@ class LLVM_LIBRARY_VISIBILITY PPCTargetInfo : public TargetInfo { ArchDefinePwr7 = 1 << 11, ArchDefinePwr8 = 1 << 12, ArchDefinePwr9 = 1 << 13, - ArchDefineA2 = 1 << 14, - ArchDefineA2q = 1 << 15 + ArchDefineFuture = 1 << 14, + ArchDefineA2 = 1 << 15, + ArchDefineA2q = 1 << 16, + ArchDefineE500 = 1 << 17 } ArchDefineTypes; @@ -85,8 +87,7 @@ public: // Note: GCC recognizes the following additional cpus: // 401, 403, 405, 405fp, 440fp, 464, 464fp, 476, 476fp, 505, 740, 801, - // 821, 823, 8540, 8548, e300c2, e300c3, e500mc64, e6500, 860, cell, - // titan, rs64. + // 821, 823, 8540, e300c2, e300c3, e500mc64, e6500, 860, cell, titan, rs64. bool isValidCPUName(StringRef Name) const override; void fillValidCPUList(SmallVectorImpl<StringRef> &Values) const override; @@ -145,6 +146,12 @@ public: ArchDefinePwr9 | ArchDefinePwr8 | ArchDefinePwr7 | ArchDefinePwr6 | ArchDefinePwr5x | ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | ArchDefinePpcsq) + .Case("future", + ArchDefineFuture | ArchDefinePwr9 | ArchDefinePwr8 | + ArchDefinePwr7 | ArchDefinePwr6 | ArchDefinePwr5x | + ArchDefinePwr5 | ArchDefinePwr4 | ArchDefinePpcgr | + ArchDefinePpcsq) + .Cases("8548", "e500", ArchDefineE500) .Default(ArchDefineNone); } return CPUKnown; @@ -164,6 +171,8 @@ public: StringRef CPU, const std::vector<std::string> &FeaturesVec) const override; + void addFutureSpecificFeatures(llvm::StringMap<bool> &Features) const; + bool handleTargetFeatures(std::vector<std::string> &Features, DiagnosticsEngine &Diags) override; @@ -380,7 +389,7 @@ public: ABI = "elfv2"; } else { resetDataLayout("E-m:e-i64:64-n32:64"); - ABI = Triple.getEnvironment() == llvm::Triple::ELFv2 ? "elfv2" : "elfv1"; + ABI = "elfv1"; } if (Triple.getOS() == llvm::Triple::AIX) diff --git a/clang/lib/Basic/Targets/SPIR.h b/clang/lib/Basic/Targets/SPIR.h index 802ccf8b671e..279d1866a428 100644 --- a/clang/lib/Basic/Targets/SPIR.h +++ b/clang/lib/Basic/Targets/SPIR.h @@ -30,7 +30,10 @@ static const unsigned SPIRAddrSpaceMap[] = { 4, // opencl_generic 0, // cuda_device 0, // cuda_constant - 0 // cuda_shared + 0, // cuda_shared + 0, // ptr32_sptr + 0, // ptr32_uptr + 0 // ptr64 }; class LLVM_LIBRARY_VISIBILITY SPIRTargetInfo : public TargetInfo { diff --git a/clang/lib/Basic/Targets/TCE.h b/clang/lib/Basic/Targets/TCE.h index 967ef5c59ee5..9cbf2a3688a2 100644 --- a/clang/lib/Basic/Targets/TCE.h +++ b/clang/lib/Basic/Targets/TCE.h @@ -39,7 +39,10 @@ static const unsigned TCEOpenCLAddrSpaceMap[] = { 0, // opencl_generic 0, // cuda_device 0, // cuda_constant - 0 // cuda_shared + 0, // cuda_shared + 0, // ptr32_sptr + 0, // ptr32_uptr + 0, // ptr64 }; class LLVM_LIBRARY_VISIBILITY TCETargetInfo : public TargetInfo { diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 311ae6e17028..d099d3742f0b 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -131,13 +131,6 @@ bool X86TargetInfo::initFeatureMap( case CK_Lakemont: break; - case CK_PentiumMMX: - case CK_Pentium2: - case CK_K6: - case CK_WinChipC6: - setFeatureEnabledImpl(Features, "mmx", true); - break; - case CK_Cooperlake: // CPX inherits all CLX features plus AVX512BF16 setFeatureEnabledImpl(Features, "avx512bf16", true); @@ -253,7 +246,14 @@ SkylakeCommon: case CK_Pentium3: case CK_C3_2: setFeatureEnabledImpl(Features, "sse", true); + LLVM_FALLTHROUGH; + case CK_Pentium2: setFeatureEnabledImpl(Features, "fxsr", true); + LLVM_FALLTHROUGH; + case CK_PentiumMMX: + case CK_K6: + case CK_WinChipC6: + setFeatureEnabledImpl(Features, "mmx", true); break; case CK_Tremont: @@ -291,6 +291,7 @@ SkylakeCommon: setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "sahf", true); + setFeatureEnabledImpl(Features, "mmx", true); break; case CK_KNM: @@ -321,6 +322,7 @@ SkylakeCommon: setFeatureEnabledImpl(Features, "xsave", true); setFeatureEnabledImpl(Features, "movbe", true); setFeatureEnabledImpl(Features, "sahf", true); + setFeatureEnabledImpl(Features, "mmx", true); break; case CK_K6_2: @@ -369,6 +371,7 @@ SkylakeCommon: setFeatureEnabledImpl(Features, "cx16", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "sahf", true); + setFeatureEnabledImpl(Features, "mmx", true); break; case CK_ZNVER2: @@ -390,6 +393,7 @@ SkylakeCommon: setFeatureEnabledImpl(Features, "fsgsbase", true); setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "lzcnt", true); + setFeatureEnabledImpl(Features, "mmx", true); setFeatureEnabledImpl(Features, "mwaitx", true); setFeatureEnabledImpl(Features, "movbe", true); setFeatureEnabledImpl(Features, "pclmul", true); @@ -433,6 +437,7 @@ SkylakeCommon: setFeatureEnabledImpl(Features, "fxsr", true); setFeatureEnabledImpl(Features, "xsave", true); setFeatureEnabledImpl(Features, "sahf", true); + setFeatureEnabledImpl(Features, "mmx", true); break; } if (!TargetInfo::initFeatureMap(Features, Diags, CPU, FeaturesVec)) @@ -1726,21 +1731,24 @@ bool X86TargetInfo::validateAsmConstraint( } } -bool X86TargetInfo::validateOutputSize(StringRef Constraint, +bool X86TargetInfo::validateOutputSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, unsigned Size) const { // Strip off constraint modifiers. while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') Constraint = Constraint.substr(1); - return validateOperandSize(Constraint, Size); + return validateOperandSize(FeatureMap, Constraint, Size); } -bool X86TargetInfo::validateInputSize(StringRef Constraint, +bool X86TargetInfo::validateInputSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, unsigned Size) const { - return validateOperandSize(Constraint, Size); + return validateOperandSize(FeatureMap, Constraint, Size); } -bool X86TargetInfo::validateOperandSize(StringRef Constraint, +bool X86TargetInfo::validateOperandSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, unsigned Size) const { switch (Constraint[0]) { default: @@ -1765,7 +1773,7 @@ bool X86TargetInfo::validateOperandSize(StringRef Constraint, case 'z': case '0': // XMM0 - if (SSELevel >= SSE1) + if (FeatureMap.lookup("sse")) return Size <= 128U; return false; case 'i': @@ -1779,10 +1787,10 @@ bool X86TargetInfo::validateOperandSize(StringRef Constraint, LLVM_FALLTHROUGH; case 'v': case 'x': - if (SSELevel >= AVX512F) + if (FeatureMap.lookup("avx512f")) // 512-bit zmm registers can be used if target supports AVX512F. return Size <= 512U; - else if (SSELevel >= AVX) + else if (FeatureMap.lookup("avx")) // 256-bit ymm registers can be used if target supports AVX. return Size <= 256U; return Size <= 128U; diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index cad869f71230..5b5e284e5141 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -22,6 +22,21 @@ namespace clang { namespace targets { +static const unsigned X86AddrSpaceMap[] = { + 0, // Default + 0, // opencl_global + 0, // opencl_local + 0, // opencl_constant + 0, // opencl_private + 0, // opencl_generic + 0, // cuda_device + 0, // cuda_constant + 0, // cuda_shared + 270, // ptr32_sptr + 271, // ptr32_uptr + 272 // ptr64 +}; + // X86 target abstract base class; x86-32 and x86-64 are very close, so // most of the implementation can be shared. class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { @@ -45,6 +60,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo { AMD3DNowAthlon } MMX3DNowLevel = NoMMX3DNow; enum XOPEnum { NoXOP, SSE4A, FMA4, XOP } XOPLevel = NoXOP; + enum AddrSpace { ptr32_sptr = 270, ptr32_uptr = 271, ptr64 = 272 }; bool HasAES = false; bool HasVAES = false; @@ -130,6 +146,7 @@ public: X86TargetInfo(const llvm::Triple &Triple, const TargetOptions &) : TargetInfo(Triple) { LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); + AddrSpaceMap = &X86AddrSpaceMap; } const char *getLongDoubleMangling() const override { @@ -177,9 +194,11 @@ public: return false; } - bool validateOutputSize(StringRef Constraint, unsigned Size) const override; + bool validateOutputSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, unsigned Size) const override; - bool validateInputSize(StringRef Constraint, unsigned Size) const override; + bool validateInputSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, unsigned Size) const override; virtual bool checkCFProtectionReturnSupported(DiagnosticsEngine &Diags) const override { @@ -191,8 +210,8 @@ public: return true; }; - - virtual bool validateOperandSize(StringRef Constraint, unsigned Size) const; + virtual bool validateOperandSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, unsigned Size) const; std::string convertConstraint(const char *&Constraint) const override; const char *getClobbers() const override { @@ -328,6 +347,18 @@ public: void setSupportedOpenCLOpts() override { getSupportedOpenCLOpts().supportAll(); } + + uint64_t getPointerWidthV(unsigned AddrSpace) const override { + if (AddrSpace == ptr32_sptr || AddrSpace == ptr32_uptr) + return 32; + if (AddrSpace == ptr64) + return 64; + return PointerWidth; + } + + uint64_t getPointerAlignV(unsigned AddrSpace) const override { + return getPointerWidthV(AddrSpace); + } }; // X86-32 generic target @@ -368,7 +399,8 @@ public: return -1; } - bool validateOperandSize(StringRef Constraint, unsigned Size) const override { + bool validateOperandSize(const llvm::StringMap<bool> &FeatureMap, + StringRef Constraint, unsigned Size) const override { switch (Constraint[0]) { default: break; @@ -386,7 +418,7 @@ public: return Size <= 64; } - return X86TargetInfo::validateOperandSize(Constraint, Size); + return X86TargetInfo::validateOperandSize(FeatureMap, Constraint, Size); } void setMaxAtomicWidth() override { diff --git a/clang/lib/Basic/Version.cpp b/clang/lib/Basic/Version.cpp index d6564582e772..c69d13b2f689 100644 --- a/clang/lib/Basic/Version.cpp +++ b/clang/lib/Basic/Version.cpp @@ -127,11 +127,6 @@ std::string getClangToolFullVersion(StringRef ToolName) { OS << ToolName << " version " CLANG_VERSION_STRING " " << getClangFullRepositoryVersion(); - // If vendor supplied, include the base LLVM version as well. -#ifdef CLANG_VENDOR - OS << " (based on " << BACKEND_PACKAGE_STRING << ")"; -#endif - return OS.str(); } diff --git a/clang/lib/Basic/XRayLists.cpp b/clang/lib/Basic/XRayLists.cpp index eb549436710a..222a28f79cc5 100644 --- a/clang/lib/Basic/XRayLists.cpp +++ b/clang/lib/Basic/XRayLists.cpp @@ -17,10 +17,13 @@ XRayFunctionFilter::XRayFunctionFilter( ArrayRef<std::string> AlwaysInstrumentPaths, ArrayRef<std::string> NeverInstrumentPaths, ArrayRef<std::string> AttrListPaths, SourceManager &SM) - : AlwaysInstrument( - llvm::SpecialCaseList::createOrDie(AlwaysInstrumentPaths)), - NeverInstrument(llvm::SpecialCaseList::createOrDie(NeverInstrumentPaths)), - AttrList(llvm::SpecialCaseList::createOrDie(AttrListPaths)), SM(SM) {} + : AlwaysInstrument(llvm::SpecialCaseList::createOrDie( + AlwaysInstrumentPaths, SM.getFileManager().getVirtualFileSystem())), + NeverInstrument(llvm::SpecialCaseList::createOrDie( + NeverInstrumentPaths, SM.getFileManager().getVirtualFileSystem())), + AttrList(llvm::SpecialCaseList::createOrDie( + AttrListPaths, SM.getFileManager().getVirtualFileSystem())), + SM(SM) {} XRayFunctionFilter::ImbueAttribute XRayFunctionFilter::shouldImbueFunction(StringRef FunctionName) const { diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 75a54d8f3c8a..0bfcab88a3a9 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -75,6 +75,10 @@ using namespace clang; using namespace llvm; +#define HANDLE_EXTENSION(Ext) \ + llvm::PassPluginLibraryInfo get##Ext##PluginInfo(); +#include "llvm/Support/Extension.def" + namespace { // Default filename used for profile generation. @@ -339,15 +343,6 @@ static void addDataFlowSanitizerPass(const PassManagerBuilder &Builder, static TargetLibraryInfoImpl *createTLII(llvm::Triple &TargetTriple, const CodeGenOptions &CodeGenOpts) { TargetLibraryInfoImpl *TLII = new TargetLibraryInfoImpl(TargetTriple); - if (!CodeGenOpts.SimplifyLibCalls) - TLII->disableAllFunctions(); - else { - // Disable individual libc/libm calls in TargetLibraryInfo. - LibFunc F; - for (auto &FuncName : CodeGenOpts.getNoBuiltinFuncs()) - if (TLII->getLibFunc(FuncName, F)) - TLII->setUnavailable(F); - } switch (CodeGenOpts.getVecLib()) { case CodeGenOptions::Accelerate: @@ -407,14 +402,14 @@ getCodeModel(const CodeGenOptions &CodeGenOpts) { return static_cast<llvm::CodeModel::Model>(CodeModel); } -static TargetMachine::CodeGenFileType getCodeGenFileType(BackendAction Action) { +static CodeGenFileType getCodeGenFileType(BackendAction Action) { if (Action == Backend_EmitObj) - return TargetMachine::CGFT_ObjectFile; + return CGFT_ObjectFile; else if (Action == Backend_EmitMCNull) - return TargetMachine::CGFT_Null; + return CGFT_Null; else { assert(Action == Backend_EmitAssembly && "Invalid action!"); - return TargetMachine::CGFT_AssemblyFile; + return CGFT_AssemblyFile; } } @@ -479,12 +474,14 @@ static void initTargetOptions(llvm::TargetOptions &Options, Options.FunctionSections = CodeGenOpts.FunctionSections; Options.DataSections = CodeGenOpts.DataSections; Options.UniqueSectionNames = CodeGenOpts.UniqueSectionNames; + Options.TLSSize = CodeGenOpts.TLSSize; Options.EmulatedTLS = CodeGenOpts.EmulatedTLS; Options.ExplicitEmulatedTLS = CodeGenOpts.ExplicitEmulatedTLS; Options.DebuggerTuning = CodeGenOpts.getDebuggerTuning(); Options.EmitStackSizeSection = CodeGenOpts.StackSizeSection; Options.EmitAddrsig = CodeGenOpts.Addrsig; Options.EnableDebugEntryValues = CodeGenOpts.EnableDebugEntryValues; + Options.ForceDwarfFrameSection = CodeGenOpts.ForceDwarfFrameSection; Options.MCOptions.SplitDwarfFile = CodeGenOpts.SplitDwarfFile; Options.MCOptions.MCRelaxAll = CodeGenOpts.RelaxAll; @@ -493,7 +490,6 @@ static void initTargetOptions(llvm::TargetOptions &Options, Options.MCOptions.MCNoExecStack = CodeGenOpts.NoExecStack; Options.MCOptions.MCIncrementalLinkerCompatible = CodeGenOpts.IncrementalLinkerCompatible; - Options.MCOptions.MCPIECopyRelocations = CodeGenOpts.PIECopyRelocations; Options.MCOptions.MCFatalWarnings = CodeGenOpts.FatalWarnings; Options.MCOptions.MCNoWarn = CodeGenOpts.NoWarn; Options.MCOptions.AsmVerbose = CodeGenOpts.AsmVerbose; @@ -787,7 +783,7 @@ bool EmitAssemblyHelper::AddEmitPasses(legacy::PassManager &CodeGenPasses, // Normal mode, emit a .s or .o file by running the code generator. Note, // this also adds codegenerator level optimization passes. - TargetMachine::CodeGenFileType CGFT = getCodeGenFileType(Action); + CodeGenFileType CGFT = getCodeGenFileType(Action); // Add ObjC ARC final-cleanup optimizations. This is done as part of the // "codegen" passes so that it isn't run multiple times when there is @@ -895,7 +891,7 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, { PrettyStackTraceString CrashInfo("Per-function optimization"); - llvm::TimeTraceScope TimeScope("PerFunctionPasses", StringRef("")); + llvm::TimeTraceScope TimeScope("PerFunctionPasses"); PerFunctionPasses.doInitialization(); for (Function &F : *TheModule) @@ -906,13 +902,13 @@ void EmitAssemblyHelper::EmitAssembly(BackendAction Action, { PrettyStackTraceString CrashInfo("Per-module optimization passes"); - llvm::TimeTraceScope TimeScope("PerModulePasses", StringRef("")); + llvm::TimeTraceScope TimeScope("PerModulePasses"); PerModulePasses.run(*TheModule); } { PrettyStackTraceString CrashInfo("Code generation"); - llvm::TimeTraceScope TimeScope("CodeGenPasses", StringRef("")); + llvm::TimeTraceScope TimeScope("CodeGenPasses"); CodeGenPasses.run(*TheModule); } @@ -1085,6 +1081,9 @@ void EmitAssemblyHelper::EmitAssemblyWithNewPassManager( << PluginFN << toString(PassPlugin.takeError()); } } +#define HANDLE_EXTENSION(Ext) \ + get##Ext##PluginInfo().RegisterPassBuilderCallbacks(PB); +#include "llvm/Support/Extension.def" LoopAnalysisManager LAM(CodeGenOpts.DebugPassManager); FunctionAnalysisManager FAM(CodeGenOpts.DebugPassManager); @@ -1439,6 +1438,12 @@ static void runThinLTOBackend(ModuleSummaryIndex *CombinedIndex, Module *M, Conf.OptLevel = CGOpts.OptimizationLevel; initTargetOptions(Conf.Options, CGOpts, TOpts, LOpts, HeaderOpts); Conf.SampleProfile = std::move(SampleProfile); + Conf.PTO.LoopUnrolling = CGOpts.UnrollLoops; + // For historical reasons, loop interleaving is set to mirror setting for loop + // unrolling. + Conf.PTO.LoopInterleaving = CGOpts.UnrollLoops; + Conf.PTO.LoopVectorization = CGOpts.VectorizeLoop; + Conf.PTO.SLPVectorization = CGOpts.VectorizeSLP; // Context sensitive profile. if (CGOpts.hasProfileCSIRInstr()) { @@ -1498,7 +1503,7 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags, BackendAction Action, std::unique_ptr<raw_pwrite_stream> OS) { - llvm::TimeTraceScope TimeScope("Backend", StringRef("")); + llvm::TimeTraceScope TimeScope("Backend"); std::unique_ptr<llvm::Module> EmptyModule; if (!CGOpts.ThinLTOIndexFile.empty()) { @@ -1557,129 +1562,14 @@ void clang::EmitBackendOutput(DiagnosticsEngine &Diags, } } -static const char* getSectionNameForBitcode(const Triple &T) { - switch (T.getObjectFormat()) { - case Triple::MachO: - return "__LLVM,__bitcode"; - case Triple::COFF: - case Triple::ELF: - case Triple::Wasm: - case Triple::UnknownObjectFormat: - return ".llvmbc"; - case Triple::XCOFF: - llvm_unreachable("XCOFF is not yet implemented"); - break; - } - llvm_unreachable("Unimplemented ObjectFormatType"); -} - -static const char* getSectionNameForCommandline(const Triple &T) { - switch (T.getObjectFormat()) { - case Triple::MachO: - return "__LLVM,__cmdline"; - case Triple::COFF: - case Triple::ELF: - case Triple::Wasm: - case Triple::UnknownObjectFormat: - return ".llvmcmd"; - case Triple::XCOFF: - llvm_unreachable("XCOFF is not yet implemented"); - break; - } - llvm_unreachable("Unimplemented ObjectFormatType"); -} - // With -fembed-bitcode, save a copy of the llvm IR as data in the // __LLVM,__bitcode section. void clang::EmbedBitcode(llvm::Module *M, const CodeGenOptions &CGOpts, llvm::MemoryBufferRef Buf) { if (CGOpts.getEmbedBitcode() == CodeGenOptions::Embed_Off) return; - - // Save llvm.compiler.used and remote it. - SmallVector<Constant*, 2> UsedArray; - SmallPtrSet<GlobalValue*, 4> UsedGlobals; - Type *UsedElementType = Type::getInt8Ty(M->getContext())->getPointerTo(0); - GlobalVariable *Used = collectUsedGlobalVariables(*M, UsedGlobals, true); - for (auto *GV : UsedGlobals) { - if (GV->getName() != "llvm.embedded.module" && - GV->getName() != "llvm.cmdline") - UsedArray.push_back( - ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType)); - } - if (Used) - Used->eraseFromParent(); - - // Embed the bitcode for the llvm module. - std::string Data; - ArrayRef<uint8_t> ModuleData; - Triple T(M->getTargetTriple()); - // Create a constant that contains the bitcode. - // In case of embedding a marker, ignore the input Buf and use the empty - // ArrayRef. It is also legal to create a bitcode marker even Buf is empty. - if (CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Marker) { - if (!isBitcode((const unsigned char *)Buf.getBufferStart(), - (const unsigned char *)Buf.getBufferEnd())) { - // If the input is LLVM Assembly, bitcode is produced by serializing - // the module. Use-lists order need to be perserved in this case. - llvm::raw_string_ostream OS(Data); - llvm::WriteBitcodeToFile(*M, OS, /* ShouldPreserveUseListOrder */ true); - ModuleData = - ArrayRef<uint8_t>((const uint8_t *)OS.str().data(), OS.str().size()); - } else - // If the input is LLVM bitcode, write the input byte stream directly. - ModuleData = ArrayRef<uint8_t>((const uint8_t *)Buf.getBufferStart(), - Buf.getBufferSize()); - } - llvm::Constant *ModuleConstant = - llvm::ConstantDataArray::get(M->getContext(), ModuleData); - llvm::GlobalVariable *GV = new llvm::GlobalVariable( - *M, ModuleConstant->getType(), true, llvm::GlobalValue::PrivateLinkage, - ModuleConstant); - GV->setSection(getSectionNameForBitcode(T)); - UsedArray.push_back( - ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType)); - if (llvm::GlobalVariable *Old = - M->getGlobalVariable("llvm.embedded.module", true)) { - assert(Old->hasOneUse() && - "llvm.embedded.module can only be used once in llvm.compiler.used"); - GV->takeName(Old); - Old->eraseFromParent(); - } else { - GV->setName("llvm.embedded.module"); - } - - // Skip if only bitcode needs to be embedded. - if (CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Bitcode) { - // Embed command-line options. - ArrayRef<uint8_t> CmdData(const_cast<uint8_t *>(CGOpts.CmdArgs.data()), - CGOpts.CmdArgs.size()); - llvm::Constant *CmdConstant = - llvm::ConstantDataArray::get(M->getContext(), CmdData); - GV = new llvm::GlobalVariable(*M, CmdConstant->getType(), true, - llvm::GlobalValue::PrivateLinkage, - CmdConstant); - GV->setSection(getSectionNameForCommandline(T)); - UsedArray.push_back( - ConstantExpr::getPointerBitCastOrAddrSpaceCast(GV, UsedElementType)); - if (llvm::GlobalVariable *Old = - M->getGlobalVariable("llvm.cmdline", true)) { - assert(Old->hasOneUse() && - "llvm.cmdline can only be used once in llvm.compiler.used"); - GV->takeName(Old); - Old->eraseFromParent(); - } else { - GV->setName("llvm.cmdline"); - } - } - - if (UsedArray.empty()) - return; - - // Recreate llvm.compiler.used. - ArrayType *ATy = ArrayType::get(UsedElementType, UsedArray.size()); - auto *NewUsed = new GlobalVariable( - *M, ATy, false, llvm::GlobalValue::AppendingLinkage, - llvm::ConstantArray::get(ATy, UsedArray), "llvm.compiler.used"); - NewUsed->setSection("llvm.metadata"); + llvm::EmbedBitcodeInModule( + *M, Buf, CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Marker, + CGOpts.getEmbedBitcode() != CodeGenOptions::Embed_Bitcode, + &CGOpts.CmdArgs); } diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index 505916350750..149982d82790 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -139,7 +139,7 @@ namespace { const LValue &getAtomicLValue() const { return LVal; } llvm::Value *getAtomicPointer() const { if (LVal.isSimple()) - return LVal.getPointer(); + return LVal.getPointer(CGF); else if (LVal.isBitField()) return LVal.getBitFieldPointer(); else if (LVal.isVectorElt()) @@ -343,14 +343,14 @@ bool AtomicInfo::requiresMemSetZero(llvm::Type *type) const { bool AtomicInfo::emitMemSetZeroIfNecessary() const { assert(LVal.isSimple()); - llvm::Value *addr = LVal.getPointer(); + llvm::Value *addr = LVal.getPointer(CGF); if (!requiresMemSetZero(addr->getType()->getPointerElementType())) return false; CGF.Builder.CreateMemSet( addr, llvm::ConstantInt::get(CGF.Int8Ty, 0), CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(), - LVal.getAlignment().getQuantity()); + LVal.getAlignment().getAsAlign()); return true; } @@ -488,13 +488,36 @@ static void emitAtomicCmpXchgFailureSet(CodeGenFunction &CGF, AtomicExpr *E, CGF.Builder.SetInsertPoint(ContBB); } +/// Duplicate the atomic min/max operation in conventional IR for the builtin +/// variants that return the new rather than the original value. +static llvm::Value *EmitPostAtomicMinMax(CGBuilderTy &Builder, + AtomicExpr::AtomicOp Op, + bool IsSigned, + llvm::Value *OldVal, + llvm::Value *RHS) { + llvm::CmpInst::Predicate Pred; + switch (Op) { + default: + llvm_unreachable("Unexpected min/max operation"); + case AtomicExpr::AO__atomic_max_fetch: + Pred = IsSigned ? llvm::CmpInst::ICMP_SGT : llvm::CmpInst::ICMP_UGT; + break; + case AtomicExpr::AO__atomic_min_fetch: + Pred = IsSigned ? llvm::CmpInst::ICMP_SLT : llvm::CmpInst::ICMP_ULT; + break; + } + llvm::Value *Cmp = Builder.CreateICmp(Pred, OldVal, RHS, "tst"); + return Builder.CreateSelect(Cmp, OldVal, RHS, "newval"); +} + static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, Address Ptr, Address Val1, Address Val2, llvm::Value *IsWeak, llvm::Value *FailureOrder, uint64_t Size, llvm::AtomicOrdering Order, llvm::SyncScope::ID Scope) { llvm::AtomicRMWInst::BinOp Op = llvm::AtomicRMWInst::Add; - llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0; + bool PostOpMinMax = false; + unsigned PostOp = 0; switch (E->getOp()) { case AtomicExpr::AO__c11_atomic_init: @@ -588,12 +611,20 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, Op = llvm::AtomicRMWInst::Sub; break; + case AtomicExpr::AO__atomic_min_fetch: + PostOpMinMax = true; + LLVM_FALLTHROUGH; + case AtomicExpr::AO__c11_atomic_fetch_min: case AtomicExpr::AO__opencl_atomic_fetch_min: case AtomicExpr::AO__atomic_fetch_min: Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Min : llvm::AtomicRMWInst::UMin; break; + case AtomicExpr::AO__atomic_max_fetch: + PostOpMinMax = true; + LLVM_FALLTHROUGH; + case AtomicExpr::AO__c11_atomic_fetch_max: case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_max: Op = E->getValueType()->isSignedIntegerType() ? llvm::AtomicRMWInst::Max @@ -643,8 +674,13 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, // For __atomic_*_fetch operations, perform the operation again to // determine the value which was written. llvm::Value *Result = RMWI; - if (PostOp) - Result = CGF.Builder.CreateBinOp(PostOp, RMWI, LoadVal1); + if (PostOpMinMax) + Result = EmitPostAtomicMinMax(CGF.Builder, E->getOp(), + E->getValueType()->isSignedIntegerType(), + RMWI, LoadVal1); + else if (PostOp) + Result = CGF.Builder.CreateBinOp((llvm::Instruction::BinaryOps)PostOp, RMWI, + LoadVal1); if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch) Result = CGF.Builder.CreateNot(Result); CGF.Builder.CreateStore(Result, Dest); @@ -853,6 +889,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__c11_atomic_fetch_xor: + case AtomicExpr::AO__c11_atomic_fetch_max: + case AtomicExpr::AO__c11_atomic_fetch_min: case AtomicExpr::AO__opencl_atomic_fetch_and: case AtomicExpr::AO__opencl_atomic_fetch_or: case AtomicExpr::AO__opencl_atomic_fetch_xor: @@ -866,8 +904,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__atomic_or_fetch: case AtomicExpr::AO__atomic_xor_fetch: case AtomicExpr::AO__atomic_nand_fetch: - case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_max_fetch: + case AtomicExpr::AO__atomic_min_fetch: case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__atomic_fetch_min: Val1 = EmitValToTemp(*this, E->getVal1()); break; } @@ -916,14 +956,18 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__opencl_atomic_fetch_min: case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_xor: + case AtomicExpr::AO__c11_atomic_fetch_max: + case AtomicExpr::AO__c11_atomic_fetch_min: case AtomicExpr::AO__atomic_add_fetch: case AtomicExpr::AO__atomic_and_fetch: case AtomicExpr::AO__atomic_nand_fetch: case AtomicExpr::AO__atomic_or_fetch: case AtomicExpr::AO__atomic_sub_fetch: case AtomicExpr::AO__atomic_xor_fetch: - case AtomicExpr::AO__atomic_fetch_min: case AtomicExpr::AO__atomic_fetch_max: + case AtomicExpr::AO__atomic_fetch_min: + case AtomicExpr::AO__atomic_max_fetch: + case AtomicExpr::AO__atomic_min_fetch: // For these, only library calls for certain sizes exist. UseOptimizedLibcall = true; break; @@ -991,6 +1035,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { QualType RetTy; bool HaveRetTy = false; llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0; + bool PostOpMinMax = false; switch (E->getOp()) { case AtomicExpr::AO__c11_atomic_init: case AtomicExpr::AO__opencl_atomic_init: @@ -1112,6 +1157,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), MemTy, E->getExprLoc(), sizeChars); break; + case AtomicExpr::AO__atomic_min_fetch: + PostOpMinMax = true; + LLVM_FALLTHROUGH; + case AtomicExpr::AO__c11_atomic_fetch_min: case AtomicExpr::AO__atomic_fetch_min: case AtomicExpr::AO__opencl_atomic_fetch_min: LibCallName = E->getValueType()->isSignedIntegerType() @@ -1120,6 +1169,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), LoweredMemTy, E->getExprLoc(), sizeChars); break; + case AtomicExpr::AO__atomic_max_fetch: + PostOpMinMax = true; + LLVM_FALLTHROUGH; + case AtomicExpr::AO__c11_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_max: case AtomicExpr::AO__opencl_atomic_fetch_max: LibCallName = E->getValueType()->isSignedIntegerType() @@ -1171,7 +1224,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { // PostOp is only needed for the atomic_*_fetch operations, and // thus is only needed for and implemented in the // UseOptimizedLibcall codepath. - assert(UseOptimizedLibcall || !PostOp); + assert(UseOptimizedLibcall || (!PostOp && !PostOpMinMax)); RValue Res = emitAtomicLibcall(*this, LibCallName, RetTy, Args); // The value is returned directly from the libcall. @@ -1182,7 +1235,12 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { // provided an out-param. if (UseOptimizedLibcall && Res.getScalarVal()) { llvm::Value *ResVal = Res.getScalarVal(); - if (PostOp) { + if (PostOpMinMax) { + llvm::Value *LoadVal1 = Args[1].getRValue(*this).getScalarVal(); + ResVal = EmitPostAtomicMinMax(Builder, E->getOp(), + E->getValueType()->isSignedIntegerType(), + ResVal, LoadVal1); + } else if (PostOp) { llvm::Value *LoadVal1 = Args[1].getRValue(*this).getScalarVal(); ResVal = Builder.CreateBinOp(PostOp, ResVal, LoadVal1); } @@ -1570,7 +1628,7 @@ Address AtomicInfo::materializeRValue(RValue rvalue) const { LValue TempLV = CGF.MakeAddrLValue(CreateTempAlloca(), getAtomicType()); AtomicInfo Atomics(CGF, TempLV); Atomics.emitCopyIntoMemory(rvalue); - return TempLV.getAddress(); + return TempLV.getAddress(CGF); } llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal) const { @@ -1917,8 +1975,8 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, // If this is an aggregate r-value, it should agree in type except // maybe for address-space qualification. assert(!rvalue.isAggregate() || - rvalue.getAggregateAddress().getElementType() - == dest.getAddress().getElementType()); + rvalue.getAggregateAddress().getElementType() == + dest.getAddress(*this).getElementType()); AtomicInfo atomics(*this, dest); LValue LVal = atomics.getAtomicLValue(); @@ -1985,10 +2043,10 @@ std::pair<RValue, llvm::Value *> CodeGenFunction::EmitAtomicCompareExchange( // maybe for address-space qualification. assert(!Expected.isAggregate() || Expected.getAggregateAddress().getElementType() == - Obj.getAddress().getElementType()); + Obj.getAddress(*this).getElementType()); assert(!Desired.isAggregate() || Desired.getAggregateAddress().getElementType() == - Obj.getAddress().getElementType()); + Obj.getAddress(*this).getElementType()); AtomicInfo Atomics(*this, Obj); return Atomics.EmitAtomicCompareExchange(Expected, Desired, Success, Failure, @@ -2028,13 +2086,11 @@ void CodeGenFunction::EmitAtomicInit(Expr *init, LValue dest) { } // Evaluate the expression directly into the destination. - AggValueSlot slot = AggValueSlot::forLValue(dest, - AggValueSlot::IsNotDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased, - AggValueSlot::DoesNotOverlap, - Zeroed ? AggValueSlot::IsZeroed : - AggValueSlot::IsNotZeroed); + AggValueSlot slot = AggValueSlot::forLValue( + dest, *this, AggValueSlot::IsNotDestructed, + AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased, + AggValueSlot::DoesNotOverlap, + Zeroed ? AggValueSlot::IsZeroed : AggValueSlot::IsNotZeroed); EmitAggExpr(init, slot); return; diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index f90d9439af25..11f54d1f7fb2 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -19,6 +19,7 @@ #include "CodeGenModule.h" #include "ConstantEmitter.h" #include "TargetInfo.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" #include "clang/CodeGen/ConstantInitBuilder.h" #include "llvm/ADT/SmallSet.h" @@ -1076,7 +1077,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { /*RefersToEnclosingVariableOrCapture*/ CI.isNested(), type.getNonReferenceType(), VK_LValue, SourceLocation()); - src = EmitDeclRefLValue(&declRef).getAddress(); + src = EmitDeclRefLValue(&declRef).getAddress(*this); }; // For byrefs, we just write the pointer to the byref struct into @@ -1482,8 +1483,7 @@ void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D, Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr"); Builder.CreateStore(arg, alloc); if (CGDebugInfo *DI = getDebugInfo()) { - if (CGM.getCodeGenOpts().getDebugInfo() >= - codegenoptions::LimitedDebugInfo) { + if (CGM.getCodeGenOpts().hasReducedDebugInfo()) { DI->setLocation(D->getLocation()); DI->EmitDeclareOfBlockLiteralArgVariable( *BlockInfo, D->getName(), argNum, @@ -1655,8 +1655,7 @@ CodeGenFunction::GenerateBlockFunction(GlobalDecl GD, const VarDecl *variable = CI.getVariable(); DI->EmitLocation(Builder, variable->getLocation()); - if (CGM.getCodeGenOpts().getDebugInfo() >= - codegenoptions::LimitedDebugInfo) { + if (CGM.getCodeGenOpts().hasReducedDebugInfo()) { const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); if (capture.isConstant()) { auto addr = LocalDeclMap.find(variable)->second; diff --git a/clang/lib/CodeGen/CGBuilder.h b/clang/lib/CodeGen/CGBuilder.h index 68c8c641139f..107c9275431c 100644 --- a/clang/lib/CodeGen/CGBuilder.h +++ b/clang/lib/CodeGen/CGBuilder.h @@ -107,7 +107,7 @@ public: llvm::StoreInst *CreateStore(llvm::Value *Val, Address Addr, bool IsVolatile = false) { return CreateAlignedStore(Val, Addr.getPointer(), - Addr.getAlignment().getQuantity(), IsVolatile); + Addr.getAlignment().getAsAlign(), IsVolatile); } using CGBuilderBaseTy::CreateAlignedStore; @@ -273,22 +273,22 @@ public: using CGBuilderBaseTy::CreateMemCpy; llvm::CallInst *CreateMemCpy(Address Dest, Address Src, llvm::Value *Size, bool IsVolatile = false) { - return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getQuantity(), - Src.getPointer(), Src.getAlignment().getQuantity(), - Size,IsVolatile); + return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getAsAlign(), + Src.getPointer(), Src.getAlignment().getAsAlign(), Size, + IsVolatile); } llvm::CallInst *CreateMemCpy(Address Dest, Address Src, uint64_t Size, bool IsVolatile = false) { - return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getQuantity(), - Src.getPointer(), Src.getAlignment().getQuantity(), - Size, IsVolatile); + return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getAsAlign(), + Src.getPointer(), Src.getAlignment().getAsAlign(), Size, + IsVolatile); } using CGBuilderBaseTy::CreateMemMove; llvm::CallInst *CreateMemMove(Address Dest, Address Src, llvm::Value *Size, bool IsVolatile = false) { - return CreateMemMove(Dest.getPointer(), Dest.getAlignment().getQuantity(), - Src.getPointer(), Src.getAlignment().getQuantity(), + return CreateMemMove(Dest.getPointer(), Dest.getAlignment().getAsAlign(), + Src.getPointer(), Src.getAlignment().getAsAlign(), Size, IsVolatile); } @@ -296,7 +296,7 @@ public: llvm::CallInst *CreateMemSet(Address Dest, llvm::Value *Value, llvm::Value *Size, bool IsVolatile = false) { return CreateMemSet(Dest.getPointer(), Value, Size, - Dest.getAlignment().getQuantity(), IsVolatile); + Dest.getAlignment().getAsAlign(), IsVolatile); } using CGBuilderBaseTy::CreatePreserveStructAccessIndex; @@ -309,7 +309,7 @@ public: const llvm::StructLayout *Layout = DL.getStructLayout(ElTy); auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index)); - return Address(CreatePreserveStructAccessIndex(Addr.getPointer(), + return Address(CreatePreserveStructAccessIndex(ElTy, Addr.getPointer(), Index, FieldIndex, DbgInfo), Addr.getAlignment().alignmentAtOffset(Offset)); } diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index f9871b233149..09fd3087b494 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -20,6 +20,7 @@ #include "PatternInit.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/OSLog.h" #include "clang/Basic/TargetBuiltins.h" @@ -30,6 +31,17 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsAArch64.h" +#include "llvm/IR/IntrinsicsAMDGPU.h" +#include "llvm/IR/IntrinsicsARM.h" +#include "llvm/IR/IntrinsicsBPF.h" +#include "llvm/IR/IntrinsicsHexagon.h" +#include "llvm/IR/IntrinsicsNVPTX.h" +#include "llvm/IR/IntrinsicsPowerPC.h" +#include "llvm/IR/IntrinsicsR600.h" +#include "llvm/IR/IntrinsicsS390.h" +#include "llvm/IR/IntrinsicsWebAssembly.h" +#include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/MDBuilder.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ScopedPrinter.h" @@ -45,7 +57,8 @@ int64_t clamp(int64_t Value, int64_t Low, int64_t High) { return std::min(High, std::max(Low, Value)); } -static void initializeAlloca(CodeGenFunction &CGF, AllocaInst *AI, Value *Size, unsigned AlignmentInBytes) { +static void initializeAlloca(CodeGenFunction &CGF, AllocaInst *AI, Value *Size, + Align AlignmentInBytes) { ConstantInt *Byte; switch (CGF.getLangOpts().getTrivialAutoVarInit()) { case LangOptions::TrivialAutoVarInitKind::Uninitialized: @@ -347,6 +360,58 @@ static Value *EmitISOVolatileStore(CodeGenFunction &CGF, const CallExpr *E) { } // Emit a simple mangled intrinsic that has 1 argument and a return type +// matching the argument type. Depending on mode, this may be a constrained +// floating-point intrinsic. +static Value *emitUnaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, + const CallExpr *E, unsigned IntrinsicID, + unsigned ConstrainedIntrinsicID) { + llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); + + if (CGF.Builder.getIsFPConstrained()) { + Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); + return CGF.Builder.CreateConstrainedFPCall(F, { Src0 }); + } else { + Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + return CGF.Builder.CreateCall(F, Src0); + } +} + +// Emit an intrinsic that has 2 operands of the same type as its result. +// Depending on mode, this may be a constrained floating-point intrinsic. +static Value *emitBinaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, + const CallExpr *E, unsigned IntrinsicID, + unsigned ConstrainedIntrinsicID) { + llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); + llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1)); + + if (CGF.Builder.getIsFPConstrained()) { + Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); + return CGF.Builder.CreateConstrainedFPCall(F, { Src0, Src1 }); + } else { + Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + return CGF.Builder.CreateCall(F, { Src0, Src1 }); + } +} + +// Emit an intrinsic that has 3 operands of the same type as its result. +// Depending on mode, this may be a constrained floating-point intrinsic. +static Value *emitTernaryMaybeConstrainedFPBuiltin(CodeGenFunction &CGF, + const CallExpr *E, unsigned IntrinsicID, + unsigned ConstrainedIntrinsicID) { + llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); + llvm::Value *Src1 = CGF.EmitScalarExpr(E->getArg(1)); + llvm::Value *Src2 = CGF.EmitScalarExpr(E->getArg(2)); + + if (CGF.Builder.getIsFPConstrained()) { + Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, Src0->getType()); + return CGF.Builder.CreateConstrainedFPCall(F, { Src0, Src1, Src2 }); + } else { + Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Src0->getType()); + return CGF.Builder.CreateCall(F, { Src0, Src1, Src2 }); + } +} + +// Emit a simple mangled intrinsic that has 1 argument and a return type // matching the argument type. static Value *emitUnaryBuiltin(CodeGenFunction &CGF, const CallExpr *E, @@ -392,15 +457,22 @@ static Value *emitFPIntBuiltin(CodeGenFunction &CGF, } // Emit an intrinsic that has overloaded integer result and fp operand. -static Value *emitFPToIntRoundBuiltin(CodeGenFunction &CGF, - const CallExpr *E, - unsigned IntrinsicID) { - llvm::Type *ResultType = CGF.ConvertType(E->getType()); - llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); +static Value * +emitMaybeConstrainedFPToIntRoundBuiltin(CodeGenFunction &CGF, const CallExpr *E, + unsigned IntrinsicID, + unsigned ConstrainedIntrinsicID) { + llvm::Type *ResultType = CGF.ConvertType(E->getType()); + llvm::Value *Src0 = CGF.EmitScalarExpr(E->getArg(0)); - Function *F = CGF.CGM.getIntrinsic(IntrinsicID, - {ResultType, Src0->getType()}); - return CGF.Builder.CreateCall(F, Src0); + if (CGF.Builder.getIsFPConstrained()) { + Function *F = CGF.CGM.getIntrinsic(ConstrainedIntrinsicID, + {ResultType, Src0->getType()}); + return CGF.Builder.CreateConstrainedFPCall(F, {Src0}); + } else { + Function *F = + CGF.CGM.getIntrinsic(IntrinsicID, {ResultType, Src0->getType()}); + return CGF.Builder.CreateCall(F, Src0); + } } /// EmitFAbs - Emit a call to @llvm.fabs(). @@ -749,8 +821,7 @@ static llvm::Value *EmitBitTestIntrinsic(CodeGenFunction &CGF, // X86 has special BT, BTC, BTR, and BTS instructions that handle the array // indexing operation internally. Use them if possible. - llvm::Triple::ArchType Arch = CGF.getTarget().getTriple().getArch(); - if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) + if (CGF.getTarget().getTriple().isX86()) return EmitX86BitTestIntrinsic(CGF, BT, E, BitBase, BitPos); // Otherwise, use generic code to load one byte and test the bit. Use all but @@ -1558,7 +1629,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_ceilf: case Builtin::BI__builtin_ceilf16: case Builtin::BI__builtin_ceill: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::ceil)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::ceil, + Intrinsic::experimental_constrained_ceil)); case Builtin::BIcopysign: case Builtin::BIcopysignf: @@ -1577,7 +1650,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_cosf: case Builtin::BI__builtin_cosf16: case Builtin::BI__builtin_cosl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::cos)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::cos, + Intrinsic::experimental_constrained_cos)); case Builtin::BIexp: case Builtin::BIexpf: @@ -1586,7 +1661,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_expf: case Builtin::BI__builtin_expf16: case Builtin::BI__builtin_expl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::exp, + Intrinsic::experimental_constrained_exp)); case Builtin::BIexp2: case Builtin::BIexp2f: @@ -1595,7 +1672,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_exp2f: case Builtin::BI__builtin_exp2f16: case Builtin::BI__builtin_exp2l: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::exp2)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::exp2, + Intrinsic::experimental_constrained_exp2)); case Builtin::BIfabs: case Builtin::BIfabsf: @@ -1614,7 +1693,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_floorf: case Builtin::BI__builtin_floorf16: case Builtin::BI__builtin_floorl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::floor)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::floor, + Intrinsic::experimental_constrained_floor)); case Builtin::BIfma: case Builtin::BIfmaf: @@ -1623,7 +1704,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_fmaf: case Builtin::BI__builtin_fmaf16: case Builtin::BI__builtin_fmal: - return RValue::get(emitTernaryBuiltin(*this, E, Intrinsic::fma)); + return RValue::get(emitTernaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::fma, + Intrinsic::experimental_constrained_fma)); case Builtin::BIfmax: case Builtin::BIfmaxf: @@ -1632,7 +1715,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_fmaxf: case Builtin::BI__builtin_fmaxf16: case Builtin::BI__builtin_fmaxl: - return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::maxnum)); + return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::maxnum, + Intrinsic::experimental_constrained_maxnum)); case Builtin::BIfmin: case Builtin::BIfminf: @@ -1641,7 +1726,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_fminf: case Builtin::BI__builtin_fminf16: case Builtin::BI__builtin_fminl: - return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::minnum)); + return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::minnum, + Intrinsic::experimental_constrained_minnum)); // fmod() is a special-case. It maps to the frem instruction rather than an // LLVM intrinsic. @@ -1664,7 +1751,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_logf: case Builtin::BI__builtin_logf16: case Builtin::BI__builtin_logl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::log, + Intrinsic::experimental_constrained_log)); case Builtin::BIlog10: case Builtin::BIlog10f: @@ -1673,7 +1762,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_log10f: case Builtin::BI__builtin_log10f16: case Builtin::BI__builtin_log10l: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log10)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::log10, + Intrinsic::experimental_constrained_log10)); case Builtin::BIlog2: case Builtin::BIlog2f: @@ -1682,7 +1773,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_log2f: case Builtin::BI__builtin_log2f16: case Builtin::BI__builtin_log2l: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::log2)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::log2, + Intrinsic::experimental_constrained_log2)); case Builtin::BInearbyint: case Builtin::BInearbyintf: @@ -1690,7 +1783,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_nearbyint: case Builtin::BI__builtin_nearbyintf: case Builtin::BI__builtin_nearbyintl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::nearbyint)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::nearbyint, + Intrinsic::experimental_constrained_nearbyint)); case Builtin::BIpow: case Builtin::BIpowf: @@ -1699,7 +1794,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_powf: case Builtin::BI__builtin_powf16: case Builtin::BI__builtin_powl: - return RValue::get(emitBinaryBuiltin(*this, E, Intrinsic::pow)); + return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::pow, + Intrinsic::experimental_constrained_pow)); case Builtin::BIrint: case Builtin::BIrintf: @@ -1708,7 +1805,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_rintf: case Builtin::BI__builtin_rintf16: case Builtin::BI__builtin_rintl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::rint)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::rint, + Intrinsic::experimental_constrained_rint)); case Builtin::BIround: case Builtin::BIroundf: @@ -1717,7 +1816,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_roundf: case Builtin::BI__builtin_roundf16: case Builtin::BI__builtin_roundl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::round)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::round, + Intrinsic::experimental_constrained_round)); case Builtin::BIsin: case Builtin::BIsinf: @@ -1726,7 +1827,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_sinf: case Builtin::BI__builtin_sinf16: case Builtin::BI__builtin_sinl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sin)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::sin, + Intrinsic::experimental_constrained_sin)); case Builtin::BIsqrt: case Builtin::BIsqrtf: @@ -1735,7 +1838,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_sqrtf: case Builtin::BI__builtin_sqrtf16: case Builtin::BI__builtin_sqrtl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::sqrt)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::sqrt, + Intrinsic::experimental_constrained_sqrt)); case Builtin::BItrunc: case Builtin::BItruncf: @@ -1744,7 +1849,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_truncf: case Builtin::BI__builtin_truncf16: case Builtin::BI__builtin_truncl: - return RValue::get(emitUnaryBuiltin(*this, E, Intrinsic::trunc)); + return RValue::get(emitUnaryMaybeConstrainedFPBuiltin(*this, E, + Intrinsic::trunc, + Intrinsic::experimental_constrained_trunc)); case Builtin::BIlround: case Builtin::BIlroundf: @@ -1752,7 +1859,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_lround: case Builtin::BI__builtin_lroundf: case Builtin::BI__builtin_lroundl: - return RValue::get(emitFPToIntRoundBuiltin(*this, E, Intrinsic::lround)); + return RValue::get(emitMaybeConstrainedFPToIntRoundBuiltin( + *this, E, Intrinsic::lround, + Intrinsic::experimental_constrained_lround)); case Builtin::BIllround: case Builtin::BIllroundf: @@ -1760,7 +1869,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_llround: case Builtin::BI__builtin_llroundf: case Builtin::BI__builtin_llroundl: - return RValue::get(emitFPToIntRoundBuiltin(*this, E, Intrinsic::llround)); + return RValue::get(emitMaybeConstrainedFPToIntRoundBuiltin( + *this, E, Intrinsic::llround, + Intrinsic::experimental_constrained_llround)); case Builtin::BIlrint: case Builtin::BIlrintf: @@ -1768,7 +1879,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_lrint: case Builtin::BI__builtin_lrintf: case Builtin::BI__builtin_lrintl: - return RValue::get(emitFPToIntRoundBuiltin(*this, E, Intrinsic::lrint)); + return RValue::get(emitMaybeConstrainedFPToIntRoundBuiltin( + *this, E, Intrinsic::lrint, + Intrinsic::experimental_constrained_lrint)); case Builtin::BIllrint: case Builtin::BIllrintf: @@ -1776,7 +1889,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_llrint: case Builtin::BI__builtin_llrintf: case Builtin::BI__builtin_llrintl: - return RValue::get(emitFPToIntRoundBuiltin(*this, E, Intrinsic::llrint)); + return RValue::get(emitMaybeConstrainedFPToIntRoundBuiltin( + *this, E, Intrinsic::llrint, + Intrinsic::experimental_constrained_llrint)); default: break; @@ -1822,16 +1937,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, } case Builtin::BI__builtin_conj: case Builtin::BI__builtin_conjf: - case Builtin::BI__builtin_conjl: { + case Builtin::BI__builtin_conjl: + case Builtin::BIconj: + case Builtin::BIconjf: + case Builtin::BIconjl: { ComplexPairTy ComplexVal = EmitComplexExpr(E->getArg(0)); Value *Real = ComplexVal.first; Value *Imag = ComplexVal.second; - Value *Zero = - Imag->getType()->isFPOrFPVectorTy() - ? llvm::ConstantFP::getZeroValueForNegation(Imag->getType()) - : llvm::Constant::getNullValue(Imag->getType()); - - Imag = Builder.CreateFSub(Zero, Imag, "sub"); + Imag = Builder.CreateFNeg(Imag, "neg"); return RValue::getComplex(std::make_pair(Real, Imag)); } case Builtin::BI__builtin_creal: @@ -2178,13 +2291,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_powi: case Builtin::BI__builtin_powif: - case Builtin::BI__builtin_powil: { - Value *Base = EmitScalarExpr(E->getArg(0)); - Value *Exponent = EmitScalarExpr(E->getArg(1)); - llvm::Type *ArgType = Base->getType(); - Function *F = CGM.getIntrinsic(Intrinsic::powi, ArgType); - return RValue::get(Builder.CreateCall(F, {Base, Exponent})); - } + case Builtin::BI__builtin_powil: + return RValue::get(emitBinaryMaybeConstrainedFPBuiltin( + *this, E, Intrinsic::powi, Intrinsic::experimental_constrained_powi)); case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: @@ -2358,12 +2467,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Value *Size = EmitScalarExpr(E->getArg(0)); const TargetInfo &TI = getContext().getTargetInfo(); // The alignment of the alloca should correspond to __BIGGEST_ALIGNMENT__. - unsigned SuitableAlignmentInBytes = + const Align SuitableAlignmentInBytes = CGM.getContext() .toCharUnitsFromBits(TI.getSuitableAlign()) - .getQuantity(); + .getAsAlign(); AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size); - AI->setAlignment(MaybeAlign(SuitableAlignmentInBytes)); + AI->setAlignment(SuitableAlignmentInBytes); initializeAlloca(*this, AI, Size, SuitableAlignmentInBytes); return RValue::get(AI); } @@ -2373,10 +2482,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Value *AlignmentInBitsValue = EmitScalarExpr(E->getArg(1)); auto *AlignmentInBitsCI = cast<ConstantInt>(AlignmentInBitsValue); unsigned AlignmentInBits = AlignmentInBitsCI->getZExtValue(); - unsigned AlignmentInBytes = - CGM.getContext().toCharUnitsFromBits(AlignmentInBits).getQuantity(); + const Align AlignmentInBytes = + CGM.getContext().toCharUnitsFromBits(AlignmentInBits).getAsAlign(); AllocaInst *AI = Builder.CreateAlloca(Builder.getInt8Ty(), Size); - AI->setAlignment(MaybeAlign(AlignmentInBytes)); + AI->setAlignment(AlignmentInBytes); initializeAlloca(*this, AI, Size, AlignmentInBytes); return RValue::get(AI); } @@ -2391,7 +2500,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); } case Builtin::BImemcpy: - case Builtin::BI__builtin_memcpy: { + case Builtin::BI__builtin_memcpy: + case Builtin::BImempcpy: + case Builtin::BI__builtin_mempcpy: { Address Dest = EmitPointerWithAlignment(E->getArg(0)); Address Src = EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = EmitScalarExpr(E->getArg(2)); @@ -2400,7 +2511,11 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(1)->getType(), E->getArg(1)->getExprLoc(), FD, 1); Builder.CreateMemCpy(Dest, Src, SizeVal, false); - return RValue::get(Dest.getPointer()); + if (BuiltinID == Builtin::BImempcpy || + BuiltinID == Builtin::BI__builtin_mempcpy) + return RValue::get(Builder.CreateInBoundsGEP(Dest.getPointer(), SizeVal)); + else + return RValue::get(Dest.getPointer()); } case Builtin::BI__builtin_char_memchr: @@ -3367,7 +3482,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(Carry); } case Builtin::BI__builtin_addressof: - return RValue::get(EmitLValue(E->getArg(0)).getPointer()); + return RValue::get(EmitLValue(E->getArg(0)).getPointer(*this)); case Builtin::BI__builtin_operator_new: return EmitBuiltinNewDeleteCall( E->getCallee()->getType()->castAs<FunctionProtoType>(), E, false); @@ -3375,6 +3490,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return EmitBuiltinNewDeleteCall( E->getCallee()->getType()->castAs<FunctionProtoType>(), E, true); + case Builtin::BI__builtin_is_aligned: + return EmitBuiltinIsAligned(E); + case Builtin::BI__builtin_align_up: + return EmitBuiltinAlignTo(E, true); + case Builtin::BI__builtin_align_down: + return EmitBuiltinAlignTo(E, false); + case Builtin::BI__noop: // __noop always evaluates to an integer literal zero. return RValue::get(ConstantInt::get(IntTy, 0)); @@ -3750,8 +3872,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Value *Queue = EmitScalarExpr(E->getArg(0)); llvm::Value *Flags = EmitScalarExpr(E->getArg(1)); LValue NDRangeL = EmitAggExprToLValue(E->getArg(2)); - llvm::Value *Range = NDRangeL.getAddress().getPointer(); - llvm::Type *RangeTy = NDRangeL.getAddress().getType(); + llvm::Value *Range = NDRangeL.getAddress(*this).getPointer(); + llvm::Type *RangeTy = NDRangeL.getAddress(*this).getType(); if (NumArgs == 4) { // The most basic form of the call with parameters: @@ -3770,7 +3892,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Builder.CreatePointerCast(Info.BlockArg, GenericVoidPtrTy); AttrBuilder B; - B.addByValAttr(NDRangeL.getAddress().getElementType()); + B.addByValAttr(NDRangeL.getAddress(*this).getElementType()); llvm::AttributeList ByValAttrSet = llvm::AttributeList::get(CGM.getModule().getContext(), 3U, B); @@ -3955,7 +4077,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Type *GenericVoidPtrTy = Builder.getInt8PtrTy( getContext().getTargetAddressSpace(LangAS::opencl_generic)); LValue NDRangeL = EmitAggExprToLValue(E->getArg(0)); - llvm::Value *NDRange = NDRangeL.getAddress().getPointer(); + llvm::Value *NDRange = NDRangeL.getAddress(*this).getPointer(); auto Info = CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(1)); Value *Kernel = Builder.CreatePointerCast(Info.Kernel, GenericVoidPtrTy); @@ -4217,9 +4339,29 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(V); } - // See if we have a target specific builtin that needs to be lowered. - if (Value *V = EmitTargetBuiltinExpr(BuiltinID, E)) - return RValue::get(V); + // Some target-specific builtins can have aggregate return values, e.g. + // __builtin_arm_mve_vld2q_u32. So if the result is an aggregate, force + // ReturnValue to be non-null, so that the target-specific emission code can + // always just emit into it. + TypeEvaluationKind EvalKind = getEvaluationKind(E->getType()); + if (EvalKind == TEK_Aggregate && ReturnValue.isNull()) { + Address DestPtr = CreateMemTemp(E->getType(), "agg.tmp"); + ReturnValue = ReturnValueSlot(DestPtr, false); + } + + // Now see if we can emit a target-specific builtin. + if (Value *V = EmitTargetBuiltinExpr(BuiltinID, E, ReturnValue)) { + switch (EvalKind) { + case TEK_Scalar: + return RValue::get(V); + case TEK_Aggregate: + return RValue::getAggregate(ReturnValue.getValue(), + ReturnValue.isVolatile()); + case TEK_Complex: + llvm_unreachable("No current target builtin returns complex"); + } + llvm_unreachable("Bad evaluation kind in EmitBuiltinExpr"); + } ErrorUnsupported(E, "builtin function"); @@ -4229,14 +4371,16 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF, unsigned BuiltinID, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Triple::ArchType Arch) { switch (Arch) { case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: case llvm::Triple::thumbeb: - return CGF->EmitARMBuiltinExpr(BuiltinID, E, Arch); + return CGF->EmitARMBuiltinExpr(BuiltinID, E, ReturnValue, Arch); case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: return CGF->EmitAArch64BuiltinExpr(BuiltinID, E, Arch); case llvm::Triple::bpfeb: @@ -4268,15 +4412,16 @@ static Value *EmitTargetArchBuiltinExpr(CodeGenFunction *CGF, } Value *CodeGenFunction::EmitTargetBuiltinExpr(unsigned BuiltinID, - const CallExpr *E) { + const CallExpr *E, + ReturnValueSlot ReturnValue) { if (getContext().BuiltinInfo.isAuxBuiltinID(BuiltinID)) { assert(getContext().getAuxTargetInfo() && "Missing aux target info"); return EmitTargetArchBuiltinExpr( this, getContext().BuiltinInfo.getAuxBuiltinID(BuiltinID), E, - getContext().getAuxTargetInfo()->getTriple().getArch()); + ReturnValue, getContext().getAuxTargetInfo()->getTriple().getArch()); } - return EmitTargetArchBuiltinExpr(this, BuiltinID, E, + return EmitTargetArchBuiltinExpr(this, BuiltinID, E, ReturnValue, getTarget().getTriple().getArch()); } @@ -4451,6 +4596,10 @@ static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = { NEONMAP1(vaesmcq_v, arm_neon_aesmc, 0), NEONMAP1(vbsl_v, arm_neon_vbsl, AddRetType), NEONMAP1(vbslq_v, arm_neon_vbsl, AddRetType), + NEONMAP1(vcadd_rot270_v, arm_neon_vcadd_rot270, Add1ArgType), + NEONMAP1(vcadd_rot90_v, arm_neon_vcadd_rot90, Add1ArgType), + NEONMAP1(vcaddq_rot270_v, arm_neon_vcadd_rot270, Add1ArgType), + NEONMAP1(vcaddq_rot90_v, arm_neon_vcadd_rot90, Add1ArgType), NEONMAP1(vcage_v, arm_neon_vacge, 0), NEONMAP1(vcageq_v, arm_neon_vacge, 0), NEONMAP1(vcagt_v, arm_neon_vacgt, 0), @@ -4618,10 +4767,10 @@ static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = { NEONMAP2(vpmin_v, arm_neon_vpminu, arm_neon_vpmins, Add1ArgType | UnsignedAlts), NEONMAP1(vqabs_v, arm_neon_vqabs, Add1ArgType), NEONMAP1(vqabsq_v, arm_neon_vqabs, Add1ArgType), - NEONMAP2(vqadd_v, arm_neon_vqaddu, arm_neon_vqadds, Add1ArgType | UnsignedAlts), - NEONMAP2(vqaddq_v, arm_neon_vqaddu, arm_neon_vqadds, Add1ArgType | UnsignedAlts), - NEONMAP2(vqdmlal_v, arm_neon_vqdmull, arm_neon_vqadds, 0), - NEONMAP2(vqdmlsl_v, arm_neon_vqdmull, arm_neon_vqsubs, 0), + NEONMAP2(vqadd_v, uadd_sat, sadd_sat, Add1ArgType | UnsignedAlts), + NEONMAP2(vqaddq_v, uadd_sat, sadd_sat, Add1ArgType | UnsignedAlts), + NEONMAP2(vqdmlal_v, arm_neon_vqdmull, sadd_sat, 0), + NEONMAP2(vqdmlsl_v, arm_neon_vqdmull, ssub_sat, 0), NEONMAP1(vqdmulh_v, arm_neon_vqdmulh, Add1ArgType), NEONMAP1(vqdmulhq_v, arm_neon_vqdmulh, Add1ArgType), NEONMAP1(vqdmull_v, arm_neon_vqdmull, Add1ArgType), @@ -4639,8 +4788,8 @@ static const NeonIntrinsicInfo ARMSIMDIntrinsicMap [] = { NEONMAP2(vqshlq_v, arm_neon_vqshiftu, arm_neon_vqshifts, Add1ArgType | UnsignedAlts), NEONMAP1(vqshlu_n_v, arm_neon_vqshiftsu, 0), NEONMAP1(vqshluq_n_v, arm_neon_vqshiftsu, 0), - NEONMAP2(vqsub_v, arm_neon_vqsubu, arm_neon_vqsubs, Add1ArgType | UnsignedAlts), - NEONMAP2(vqsubq_v, arm_neon_vqsubu, arm_neon_vqsubs, Add1ArgType | UnsignedAlts), + NEONMAP2(vqsub_v, usub_sat, ssub_sat, Add1ArgType | UnsignedAlts), + NEONMAP2(vqsubq_v, usub_sat, ssub_sat, Add1ArgType | UnsignedAlts), NEONMAP1(vraddhn_v, arm_neon_vraddhn, Add1ArgType), NEONMAP2(vrecpe_v, arm_neon_vrecpe, arm_neon_vrecpe, 0), NEONMAP2(vrecpeq_v, arm_neon_vrecpe, arm_neon_vrecpe, 0), @@ -4724,6 +4873,10 @@ static const NeonIntrinsicInfo AArch64SIMDIntrinsicMap[] = { NEONMAP1(vaeseq_v, aarch64_crypto_aese, 0), NEONMAP1(vaesimcq_v, aarch64_crypto_aesimc, 0), NEONMAP1(vaesmcq_v, aarch64_crypto_aesmc, 0), + NEONMAP1(vcadd_rot270_v, aarch64_neon_vcadd_rot270, Add1ArgType), + NEONMAP1(vcadd_rot90_v, aarch64_neon_vcadd_rot90, Add1ArgType), + NEONMAP1(vcaddq_rot270_v, aarch64_neon_vcadd_rot270, Add1ArgType), + NEONMAP1(vcaddq_rot90_v, aarch64_neon_vcadd_rot90, Add1ArgType), NEONMAP1(vcage_v, aarch64_neon_facge, 0), NEONMAP1(vcageq_v, aarch64_neon_facge, 0), NEONMAP1(vcagt_v, aarch64_neon_facgt, 0), @@ -5453,6 +5606,11 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( llvm::Type *Tys[2] = { Ty, GetFloatNeonType(this, Type) }; return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, NameHint); } + case NEON::BI__builtin_neon_vcvtx_f32_v: { + llvm::Type *Tys[2] = { VTy->getTruncatedElementVectorType(VTy), Ty}; + return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, NameHint); + + } case NEON::BI__builtin_neon_vext_v: case NEON::BI__builtin_neon_vextq_v: { int CV = cast<ConstantInt>(Ops[2])->getSExtValue(); @@ -5668,7 +5826,8 @@ Value *CodeGenFunction::EmitCommonNeonBuiltinExpr( llvm::Type *PTy = llvm::PointerType::getUnqual(VTy->getVectorElementType()); // TODO: Currently in AArch32 mode the pointer operand comes first, whereas // in AArch64 it comes last. We may want to stick to one or another. - if (Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_be) { + if (Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_be || + Arch == llvm::Triple::aarch64_32) { llvm::Type *Tys[2] = { VTy, PTy }; std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end()); return EmitNeonCall(CGM.getIntrinsic(LLVMIntrinsic, Tys), Ops, ""); @@ -6004,6 +6163,7 @@ static bool HasExtraNeonArgument(unsigned BuiltinID) { Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Triple::ArchType Arch) { if (auto Hint = GetValueForARMHint(BuiltinID)) return Hint; @@ -6052,6 +6212,16 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, CGM.getIntrinsic(Intrinsic::bitreverse, Arg->getType()), Arg, "rbit"); } + if (BuiltinID == ARM::BI__builtin_arm_cls) { + llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_cls), Arg, "cls"); + } + if (BuiltinID == ARM::BI__builtin_arm_cls64) { + llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::arm_cls64), Arg, + "cls"); + } + if (BuiltinID == ARM::BI__clear_cache) { assert(E->getNumArgs() == 2 && "__clear_cache takes 2 arguments"); const FunctionDecl *FD = E->getDirectCallee(); @@ -6320,6 +6490,10 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, return EmitSpecialRegisterBuiltin(*this, E, RegisterType, ValueType, IsRead); } + // Deal with MVE builtins + if (Value *Result = EmitARMMVEBuiltinExpr(BuiltinID, E, ReturnValue, Arch)) + return Result; + // Find out if any arguments are required to be integer constant // expressions. unsigned ICEArguments = 0; @@ -6769,6 +6943,152 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, } } +template<typename Integer> +static Integer GetIntegerConstantValue(const Expr *E, ASTContext &Context) { + llvm::APSInt IntVal; + bool IsConst = E->isIntegerConstantExpr(IntVal, Context); + assert(IsConst && "Sema should have checked this was a constant"); + (void)IsConst; + return IntVal.getExtValue(); +} + +static llvm::Value *SignOrZeroExtend(CGBuilderTy &Builder, llvm::Value *V, + llvm::Type *T, bool Unsigned) { + // Helper function called by Tablegen-constructed ARM MVE builtin codegen, + // which finds it convenient to specify signed/unsigned as a boolean flag. + return Unsigned ? Builder.CreateZExt(V, T) : Builder.CreateSExt(V, T); +} + +static llvm::Value *MVEImmediateShr(CGBuilderTy &Builder, llvm::Value *V, + uint32_t Shift, bool Unsigned) { + // MVE helper function for integer shift right. This must handle signed vs + // unsigned, and also deal specially with the case where the shift count is + // equal to the lane size. In LLVM IR, an LShr with that parameter would be + // undefined behavior, but in MVE it's legal, so we must convert it to code + // that is not undefined in IR. + unsigned LaneBits = + V->getType()->getVectorElementType()->getPrimitiveSizeInBits(); + if (Shift == LaneBits) { + // An unsigned shift of the full lane size always generates zero, so we can + // simply emit a zero vector. A signed shift of the full lane size does the + // same thing as shifting by one bit fewer. + if (Unsigned) + return llvm::Constant::getNullValue(V->getType()); + else + --Shift; + } + return Unsigned ? Builder.CreateLShr(V, Shift) : Builder.CreateAShr(V, Shift); +} + +static llvm::Value *ARMMVEVectorSplat(CGBuilderTy &Builder, llvm::Value *V) { + // MVE-specific helper function for a vector splat, which infers the element + // count of the output vector by knowing that MVE vectors are all 128 bits + // wide. + unsigned Elements = 128 / V->getType()->getPrimitiveSizeInBits(); + return Builder.CreateVectorSplat(Elements, V); +} + +Value *CodeGenFunction::EmitARMMVEBuiltinExpr(unsigned BuiltinID, + const CallExpr *E, + ReturnValueSlot ReturnValue, + llvm::Triple::ArchType Arch) { + enum class CustomCodeGen { VLD24, VST24 } CustomCodeGenType; + Intrinsic::ID IRIntr; + unsigned NumVectors; + + // Code autogenerated by Tablegen will handle all the simple builtins. + switch (BuiltinID) { + #include "clang/Basic/arm_mve_builtin_cg.inc" + + // If we didn't match an MVE builtin id at all, go back to the + // main EmitARMBuiltinExpr. + default: + return nullptr; + } + + // Anything that breaks from that switch is an MVE builtin that + // needs handwritten code to generate. + + switch (CustomCodeGenType) { + + case CustomCodeGen::VLD24: { + llvm::SmallVector<Value *, 4> Ops; + llvm::SmallVector<llvm::Type *, 4> Tys; + + auto MvecCType = E->getType(); + auto MvecLType = ConvertType(MvecCType); + assert(MvecLType->isStructTy() && + "Return type for vld[24]q should be a struct"); + assert(MvecLType->getStructNumElements() == 1 && + "Return-type struct for vld[24]q should have one element"); + auto MvecLTypeInner = MvecLType->getStructElementType(0); + assert(MvecLTypeInner->isArrayTy() && + "Return-type struct for vld[24]q should contain an array"); + assert(MvecLTypeInner->getArrayNumElements() == NumVectors && + "Array member of return-type struct vld[24]q has wrong length"); + auto VecLType = MvecLTypeInner->getArrayElementType(); + + Tys.push_back(VecLType); + + auto Addr = E->getArg(0); + Ops.push_back(EmitScalarExpr(Addr)); + Tys.push_back(ConvertType(Addr->getType())); + + Function *F = CGM.getIntrinsic(IRIntr, makeArrayRef(Tys)); + Value *LoadResult = Builder.CreateCall(F, Ops); + Value *MvecOut = UndefValue::get(MvecLType); + for (unsigned i = 0; i < NumVectors; ++i) { + Value *Vec = Builder.CreateExtractValue(LoadResult, i); + MvecOut = Builder.CreateInsertValue(MvecOut, Vec, {0, i}); + } + + if (ReturnValue.isNull()) + return MvecOut; + else + return Builder.CreateStore(MvecOut, ReturnValue.getValue()); + } + + case CustomCodeGen::VST24: { + llvm::SmallVector<Value *, 4> Ops; + llvm::SmallVector<llvm::Type *, 4> Tys; + + auto Addr = E->getArg(0); + Ops.push_back(EmitScalarExpr(Addr)); + Tys.push_back(ConvertType(Addr->getType())); + + auto MvecCType = E->getArg(1)->getType(); + auto MvecLType = ConvertType(MvecCType); + assert(MvecLType->isStructTy() && "Data type for vst2q should be a struct"); + assert(MvecLType->getStructNumElements() == 1 && + "Data-type struct for vst2q should have one element"); + auto MvecLTypeInner = MvecLType->getStructElementType(0); + assert(MvecLTypeInner->isArrayTy() && + "Data-type struct for vst2q should contain an array"); + assert(MvecLTypeInner->getArrayNumElements() == NumVectors && + "Array member of return-type struct vld[24]q has wrong length"); + auto VecLType = MvecLTypeInner->getArrayElementType(); + + Tys.push_back(VecLType); + + AggValueSlot MvecSlot = CreateAggTemp(MvecCType); + EmitAggExpr(E->getArg(1), MvecSlot); + auto Mvec = Builder.CreateLoad(MvecSlot.getAddress()); + for (unsigned i = 0; i < NumVectors; i++) + Ops.push_back(Builder.CreateExtractValue(Mvec, {0, i})); + + Function *F = CGM.getIntrinsic(IRIntr, makeArrayRef(Tys)); + Value *ToReturn = nullptr; + for (unsigned i = 0; i < NumVectors; i++) { + Ops.push_back(llvm::ConstantInt::get(Int32Ty, i)); + ToReturn = Builder.CreateCall(F, Ops); + Ops.pop_back(); + } + return ToReturn; + } + } + llvm_unreachable("unknown custom codegen type."); +} + static Value *EmitAArch64TblBuiltinExpr(CodeGenFunction &CGF, unsigned BuiltinID, const CallExpr *E, SmallVectorImpl<Value *> &Ops, @@ -7000,6 +7320,17 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, CGM.getIntrinsic(Intrinsic::bitreverse, Arg->getType()), Arg, "rbit"); } + if (BuiltinID == AArch64::BI__builtin_arm_cls) { + llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_cls), Arg, + "cls"); + } + if (BuiltinID == AArch64::BI__builtin_arm_cls64) { + llvm::Value *Arg = EmitScalarExpr(E->getArg(0)); + return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::aarch64_cls64), Arg, + "cls"); + } + if (BuiltinID == AArch64::BI__builtin_arm_jcvt) { assert((getContext().getTypeSize(E->getType()) == 32) && "__jcvt of unusual size!"); @@ -9311,14 +9642,14 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, if (!getDebugInfo()) { CGM.Error(E->getExprLoc(), "using builtin_preserve_field_info() without -g"); return IsBitField ? EmitLValue(Arg).getBitFieldPointer() - : EmitLValue(Arg).getPointer(); + : EmitLValue(Arg).getPointer(*this); } // Enable underlying preserve_*_access_index() generation. bool OldIsInPreservedAIRegion = IsInPreservedAIRegion; IsInPreservedAIRegion = true; Value *FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer() - : EmitLValue(Arg).getPointer(); + : EmitLValue(Arg).getPointer(*this); IsInPreservedAIRegion = OldIsInPreservedAIRegion; ConstantInt *C = cast<ConstantInt>(EmitScalarExpr(E->getArg(1))); @@ -12175,7 +12506,7 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, case X86::BI__stosb: { // We treat __stosb as a volatile memset - it may not generate "rep stosb" // instruction, but it will create a memset that won't be optimized away. - return Builder.CreateMemSet(Ops[0], Ops[1], Ops[2], 1, true); + return Builder.CreateMemSet(Ops[0], Ops[1], Ops[2], Align::None(), true); } case X86::BI__ud2: // llvm.trap makes a ud2a instruction on x86. @@ -12993,9 +13324,8 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID, Value *X = EmitScalarExpr(E->getArg(0)); Value *Y = EmitScalarExpr(E->getArg(1)); Value *Z = EmitScalarExpr(E->getArg(2)); - Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType); Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType); - return Builder.CreateCall(F, {X, Y, Builder.CreateFSub(Zero, Z, "sub")}); + return Builder.CreateCall(F, {X, Y, Builder.CreateFNeg(Z, "neg")}); } case SystemZ::BI__builtin_s390_vfnmasb: case SystemZ::BI__builtin_s390_vfnmadb: { @@ -13003,9 +13333,8 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID, Value *X = EmitScalarExpr(E->getArg(0)); Value *Y = EmitScalarExpr(E->getArg(1)); Value *Z = EmitScalarExpr(E->getArg(2)); - Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType); Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType); - return Builder.CreateFSub(Zero, Builder.CreateCall(F, {X, Y, Z}), "sub"); + return Builder.CreateFNeg(Builder.CreateCall(F, {X, Y, Z}), "neg"); } case SystemZ::BI__builtin_s390_vfnmssb: case SystemZ::BI__builtin_s390_vfnmsdb: { @@ -13013,10 +13342,9 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID, Value *X = EmitScalarExpr(E->getArg(0)); Value *Y = EmitScalarExpr(E->getArg(1)); Value *Z = EmitScalarExpr(E->getArg(2)); - Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType); Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType); - Value *NegZ = Builder.CreateFSub(Zero, Z, "sub"); - return Builder.CreateFSub(Zero, Builder.CreateCall(F, {X, Y, NegZ})); + Value *NegZ = Builder.CreateFNeg(Z, "neg"); + return Builder.CreateFNeg(Builder.CreateCall(F, {X, Y, NegZ})); } case SystemZ::BI__builtin_s390_vflpsb: case SystemZ::BI__builtin_s390_vflpdb: { @@ -13029,9 +13357,8 @@ Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID, case SystemZ::BI__builtin_s390_vflndb: { llvm::Type *ResultType = ConvertType(E->getType()); Value *X = EmitScalarExpr(E->getArg(0)); - Value *Zero = llvm::ConstantFP::getZeroValueForNegation(ResultType); Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType); - return Builder.CreateFSub(Zero, Builder.CreateCall(F, X), "sub"); + return Builder.CreateFNeg(Builder.CreateCall(F, X), "neg"); } case SystemZ::BI__builtin_s390_vfisb: case SystemZ::BI__builtin_s390_vfidb: { @@ -13933,6 +14260,96 @@ CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { } } +namespace { +struct BuiltinAlignArgs { + llvm::Value *Src = nullptr; + llvm::Type *SrcType = nullptr; + llvm::Value *Alignment = nullptr; + llvm::Value *Mask = nullptr; + llvm::IntegerType *IntType = nullptr; + + BuiltinAlignArgs(const CallExpr *E, CodeGenFunction &CGF) { + QualType AstType = E->getArg(0)->getType(); + if (AstType->isArrayType()) + Src = CGF.EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + else + Src = CGF.EmitScalarExpr(E->getArg(0)); + SrcType = Src->getType(); + if (SrcType->isPointerTy()) { + IntType = IntegerType::get( + CGF.getLLVMContext(), + CGF.CGM.getDataLayout().getIndexTypeSizeInBits(SrcType)); + } else { + assert(SrcType->isIntegerTy()); + IntType = cast<llvm::IntegerType>(SrcType); + } + Alignment = CGF.EmitScalarExpr(E->getArg(1)); + Alignment = CGF.Builder.CreateZExtOrTrunc(Alignment, IntType, "alignment"); + auto *One = llvm::ConstantInt::get(IntType, 1); + Mask = CGF.Builder.CreateSub(Alignment, One, "mask"); + } +}; +} // namespace + +/// Generate (x & (y-1)) == 0. +RValue CodeGenFunction::EmitBuiltinIsAligned(const CallExpr *E) { + BuiltinAlignArgs Args(E, *this); + llvm::Value *SrcAddress = Args.Src; + if (Args.SrcType->isPointerTy()) + SrcAddress = + Builder.CreateBitOrPointerCast(Args.Src, Args.IntType, "src_addr"); + return RValue::get(Builder.CreateICmpEQ( + Builder.CreateAnd(SrcAddress, Args.Mask, "set_bits"), + llvm::Constant::getNullValue(Args.IntType), "is_aligned")); +} + +/// Generate (x & ~(y-1)) to align down or ((x+(y-1)) & ~(y-1)) to align up. +/// Note: For pointer types we can avoid ptrtoint/inttoptr pairs by using the +/// llvm.ptrmask instrinsic (with a GEP before in the align_up case). +/// TODO: actually use ptrmask once most optimization passes know about it. +RValue CodeGenFunction::EmitBuiltinAlignTo(const CallExpr *E, bool AlignUp) { + BuiltinAlignArgs Args(E, *this); + llvm::Value *SrcAddr = Args.Src; + if (Args.Src->getType()->isPointerTy()) + SrcAddr = Builder.CreatePtrToInt(Args.Src, Args.IntType, "intptr"); + llvm::Value *SrcForMask = SrcAddr; + if (AlignUp) { + // When aligning up we have to first add the mask to ensure we go over the + // next alignment value and then align down to the next valid multiple. + // By adding the mask, we ensure that align_up on an already aligned + // value will not change the value. + SrcForMask = Builder.CreateAdd(SrcForMask, Args.Mask, "over_boundary"); + } + // Invert the mask to only clear the lower bits. + llvm::Value *InvertedMask = Builder.CreateNot(Args.Mask, "inverted_mask"); + llvm::Value *Result = + Builder.CreateAnd(SrcForMask, InvertedMask, "aligned_result"); + if (Args.Src->getType()->isPointerTy()) { + /// TODO: Use ptrmask instead of ptrtoint+gep once it is optimized well. + // Result = Builder.CreateIntrinsic( + // Intrinsic::ptrmask, {Args.SrcType, SrcForMask->getType(), Args.IntType}, + // {SrcForMask, NegatedMask}, nullptr, "aligned_result"); + Result->setName("aligned_intptr"); + llvm::Value *Difference = Builder.CreateSub(Result, SrcAddr, "diff"); + // The result must point to the same underlying allocation. This means we + // can use an inbounds GEP to enable better optimization. + Value *Base = EmitCastToVoidPtr(Args.Src); + if (getLangOpts().isSignedOverflowDefined()) + Result = Builder.CreateGEP(Base, Difference, "aligned_result"); + else + Result = EmitCheckedInBoundsGEP(Base, Difference, + /*SignedIndices=*/true, + /*isSubtraction=*/!AlignUp, + E->getExprLoc(), "aligned_result"); + Result = Builder.CreatePointerCast(Result, Args.SrcType); + // Emit an alignment assumption to ensure that the new alignment is + // propagated to loads/stores, etc. + EmitAlignmentAssumption(Result, E, E->getExprLoc(), Args.Alignment); + } + assert(Result->getType() == Args.SrcType); + return RValue::get(Result); +} + Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, const CallExpr *E) { switch (BuiltinID) { @@ -14181,6 +14598,14 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType())); return Builder.CreateCall(Callee, {LHS, RHS}); } + case WebAssembly::BI__builtin_wasm_avgr_u_i8x16: + case WebAssembly::BI__builtin_wasm_avgr_u_i16x8: { + Value *LHS = EmitScalarExpr(E->getArg(0)); + Value *RHS = EmitScalarExpr(E->getArg(1)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_avgr_unsigned, + ConvertType(E->getType())); + return Builder.CreateCall(Callee, {LHS, RHS}); + } case WebAssembly::BI__builtin_wasm_bitselect: { Value *V1 = EmitScalarExpr(E->getArg(0)); Value *V2 = EmitScalarExpr(E->getArg(1)); @@ -14189,6 +14614,12 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, ConvertType(E->getType())); return Builder.CreateCall(Callee, {V1, V2, C}); } + case WebAssembly::BI__builtin_wasm_dot_s_i32x4_i16x8: { + Value *LHS = EmitScalarExpr(E->getArg(0)); + Value *RHS = EmitScalarExpr(E->getArg(1)); + Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_dot); + return Builder.CreateCall(Callee, {LHS, RHS}); + } case WebAssembly::BI__builtin_wasm_any_true_i8x16: case WebAssembly::BI__builtin_wasm_any_true_i16x8: case WebAssembly::BI__builtin_wasm_any_true_i32x4: diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index 7e5fe0fd6b1d..1928e0df3809 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -12,10 +12,11 @@ // We might split this into multiple files if it gets too unwieldy -#include "CodeGenModule.h" #include "CGCXXABI.h" #include "CodeGenFunction.h" +#include "CodeGenModule.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp index 23dae2b61d04..7ada4032b3ee 100644 --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/lib/CodeGen/CGCXXABI.cpp @@ -13,6 +13,7 @@ #include "CGCXXABI.h" #include "CGCleanup.h" +#include "clang/AST/Attr.h" using namespace clang; using namespace CodeGen; diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index b74f6f942426..e4803fde230f 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -19,6 +19,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "TargetInfo.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -28,7 +29,6 @@ #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/CodeGen/SwiftCallingConv.h" #include "llvm/ADT/StringExtras.h" -#include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/CallingConv.h" @@ -36,6 +36,7 @@ #include "llvm/IR/InlineAsm.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/Transforms/Utils/Local.h" using namespace clang; using namespace CodeGen; @@ -1020,13 +1021,13 @@ void CodeGenFunction::ExpandTypeFromArgs( auto Exp = getTypeExpansion(Ty, getContext()); if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) { - forConstantArrayExpansion(*this, CAExp, LV.getAddress(), - [&](Address EltAddr) { - LValue LV = MakeAddrLValue(EltAddr, CAExp->EltTy); - ExpandTypeFromArgs(CAExp->EltTy, LV, AI); - }); + forConstantArrayExpansion( + *this, CAExp, LV.getAddress(*this), [&](Address EltAddr) { + LValue LV = MakeAddrLValue(EltAddr, CAExp->EltTy); + ExpandTypeFromArgs(CAExp->EltTy, LV, AI); + }); } else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) { - Address This = LV.getAddress(); + Address This = LV.getAddress(*this); for (const CXXBaseSpecifier *BS : RExp->Bases) { // Perform a single step derived-to-base conversion. Address Base = @@ -1047,8 +1048,13 @@ void CodeGenFunction::ExpandTypeFromArgs( auto imagValue = *AI++; EmitStoreOfComplex(ComplexPairTy(realValue, imagValue), LV, /*init*/ true); } else { + // Call EmitStoreOfScalar except when the lvalue is a bitfield to emit a + // primitive store. assert(isa<NoExpansion>(Exp.get())); - EmitStoreThroughLValue(RValue::get(*AI++), LV); + if (LV.isBitField()) + EmitStoreThroughLValue(RValue::get(*AI++), LV); + else + EmitStoreOfScalar(*AI++, LV); } } @@ -1057,7 +1063,7 @@ void CodeGenFunction::ExpandTypeToArgs( SmallVectorImpl<llvm::Value *> &IRCallArgs, unsigned &IRCallArgPos) { auto Exp = getTypeExpansion(Ty, getContext()); if (auto CAExp = dyn_cast<ConstantArrayExpansion>(Exp.get())) { - Address Addr = Arg.hasLValue() ? Arg.getKnownLValue().getAddress() + Address Addr = Arg.hasLValue() ? Arg.getKnownLValue().getAddress(*this) : Arg.getKnownRValue().getAggregateAddress(); forConstantArrayExpansion( *this, CAExp, Addr, [&](Address EltAddr) { @@ -1068,7 +1074,7 @@ void CodeGenFunction::ExpandTypeToArgs( IRCallArgPos); }); } else if (auto RExp = dyn_cast<RecordExpansion>(Exp.get())) { - Address This = Arg.hasLValue() ? Arg.getKnownLValue().getAddress() + Address This = Arg.hasLValue() ? Arg.getKnownLValue().getAddress(*this) : Arg.getKnownRValue().getAggregateAddress(); for (const CXXBaseSpecifier *BS : RExp->Bases) { // Perform a single step derived-to-base conversion. @@ -1305,6 +1311,15 @@ static void CreateCoercedStore(llvm::Value *Src, DstTy = Dst.getType()->getElementType(); } + llvm::PointerType *SrcPtrTy = llvm::dyn_cast<llvm::PointerType>(SrcTy); + llvm::PointerType *DstPtrTy = llvm::dyn_cast<llvm::PointerType>(DstTy); + if (SrcPtrTy && DstPtrTy && + SrcPtrTy->getAddressSpace() != DstPtrTy->getAddressSpace()) { + Src = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(Src, DstTy); + CGF.Builder.CreateStore(Src, Dst, DstIsVolatile); + return; + } + // If the source and destination are integer or pointer types, just do an // extension or truncation to the desired type. if ((isa<llvm::IntegerType>(SrcTy) || isa<llvm::PointerType>(SrcTy)) && @@ -1732,8 +1747,9 @@ void CodeGenModule::ConstructDefaultFnAttrList(StringRef Name, bool HasOptnone, if (CodeGenOpts.NullPointerIsValid) FuncAttrs.addAttribute("null-pointer-is-valid", "true"); - if (!CodeGenOpts.FPDenormalMode.empty()) - FuncAttrs.addAttribute("denormal-fp-math", CodeGenOpts.FPDenormalMode); + if (CodeGenOpts.FPDenormalMode != llvm::DenormalMode::Invalid) + FuncAttrs.addAttribute("denormal-fp-math", + llvm::denormalModeName(CodeGenOpts.FPDenormalMode)); FuncAttrs.addAttribute("no-trapping-math", llvm::toStringRef(CodeGenOpts.NoTrappingMath)); @@ -1853,11 +1869,30 @@ void CodeGenModule::ConstructAttributeList( if (const FunctionDecl *Fn = dyn_cast<FunctionDecl>(TargetDecl)) { AddAttributesFromFunctionProtoType( getContext(), FuncAttrs, Fn->getType()->getAs<FunctionProtoType>()); - // Don't use [[noreturn]] or _Noreturn for a call to a virtual function. - // These attributes are not inherited by overloads. const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn); - if (Fn->isNoReturn() && !(AttrOnCallSite && MD && MD->isVirtual())) - FuncAttrs.addAttribute(llvm::Attribute::NoReturn); + const bool IsVirtualCall = MD && MD->isVirtual(); + // Don't use [[noreturn]], _Noreturn or [[no_builtin]] for a call to a + // virtual function. These attributes are not inherited by overloads. + if (!(AttrOnCallSite && IsVirtualCall)) { + if (Fn->isNoReturn()) + FuncAttrs.addAttribute(llvm::Attribute::NoReturn); + + const auto *NBA = Fn->getAttr<NoBuiltinAttr>(); + bool HasWildcard = NBA && llvm::is_contained(NBA->builtinNames(), "*"); + if (getLangOpts().NoBuiltin || HasWildcard) + FuncAttrs.addAttribute("no-builtins"); + else { + auto AddNoBuiltinAttr = [&FuncAttrs](StringRef BuiltinName) { + SmallString<32> AttributeName; + AttributeName += "no-builtin-"; + AttributeName += BuiltinName; + FuncAttrs.addAttribute(AttributeName); + }; + llvm::for_each(getLangOpts().NoBuiltinFuncs, AddNoBuiltinAttr); + if (NBA) + llvm::for_each(NBA->builtinNames(), AddNoBuiltinAttr); + } + } } // 'const', 'pure' and 'noalias' attributed functions are also nounwind. @@ -3112,7 +3147,7 @@ static bool isProvablyNull(llvm::Value *addr) { static void emitWriteback(CodeGenFunction &CGF, const CallArgList::Writeback &writeback) { const LValue &srcLV = writeback.Source; - Address srcAddr = srcLV.getAddress(); + Address srcAddr = srcLV.getAddress(CGF); assert(!isProvablyNull(srcAddr.getPointer()) && "shouldn't have writeback for provably null argument"); @@ -3220,7 +3255,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, CRE->getSubExpr()->getType()->castAs<PointerType>()->getPointeeType(); srcLV = CGF.MakeAddrLValue(srcAddr, srcAddrType); } - Address srcAddr = srcLV.getAddress(); + Address srcAddr = srcLV.getAddress(CGF); // The dest and src types don't necessarily match in LLVM terms // because of the crazy ObjC compatibility rules. @@ -3534,7 +3569,7 @@ RValue CallArg::getRValue(CodeGenFunction &CGF) const { CGF.EmitAggregateCopy(Copy, LV, Ty, AggValueSlot::DoesNotOverlap, LV.isVolatile()); IsUsed = true; - return RValue::getAggregate(Copy.getAddress()); + return RValue::getAggregate(Copy.getAddress(CGF)); } void CallArg::copyInto(CodeGenFunction &CGF, Address Addr) const { @@ -3544,7 +3579,7 @@ void CallArg::copyInto(CodeGenFunction &CGF, Address Addr) const { else if (!HasLV && RV.isComplex()) CGF.EmitStoreOfComplex(RV.getComplexVal(), Dst, /*init=*/true); else { - auto Addr = HasLV ? LV.getAddress() : RV.getAggregateAddress(); + auto Addr = HasLV ? LV.getAddress(CGF) : RV.getAggregateAddress(); LValue SrcLV = CGF.MakeAddrLValue(Addr, Ty); // We assume that call args are never copied into subobjects. CGF.EmitAggregateCopy(Dst, SrcLV, Ty, AggValueSlot::DoesNotOverlap, @@ -3907,7 +3942,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (I->isAggregate()) { // Replace the placeholder with the appropriate argument slot GEP. Address Addr = I->hasLValue() - ? I->getKnownLValue().getAddress() + ? I->getKnownLValue().getAddress(*this) : I->getKnownRValue().getAggregateAddress(); llvm::Instruction *Placeholder = cast<llvm::Instruction>(Addr.getPointer()); @@ -3952,7 +3987,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // 3. If the argument is byval, but RV is not located in default // or alloca address space. Address Addr = I->hasLValue() - ? I->getKnownLValue().getAddress() + ? I->getKnownLValue().getAddress(*this) : I->getKnownRValue().getAggregateAddress(); llvm::Value *V = Addr.getPointer(); CharUnits Align = ArgInfo.getIndirectAlign(); @@ -3973,9 +4008,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, auto LV = I->getKnownLValue(); auto AS = LV.getAddressSpace(); - if ((!ArgInfo.getIndirectByVal() && - (LV.getAlignment() >= - getContext().getTypeAlignInChars(I->Ty)))) { + if (!ArgInfo.getIndirectByVal() || + (LV.getAlignment() < getContext().getTypeAlignInChars(I->Ty))) { NeedCopy = true; } if (!getLangOpts().OpenCL) { @@ -4039,7 +4073,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, V = I->getKnownRValue().getScalarVal(); else V = Builder.CreateLoad( - I->hasLValue() ? I->getKnownLValue().getAddress() + I->hasLValue() ? I->getKnownLValue().getAddress(*this) : I->getKnownRValue().getAggregateAddress()); // Implement swifterror by copying into a new swifterror argument. @@ -4082,7 +4116,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Src = CreateMemTemp(I->Ty, "coerce"); I->copyInto(*this, Src); } else { - Src = I->hasLValue() ? I->getKnownLValue().getAddress() + Src = I->hasLValue() ? I->getKnownLValue().getAddress(*this) : I->getKnownRValue().getAggregateAddress(); } @@ -4137,7 +4171,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Address addr = Address::invalid(); Address AllocaAddr = Address::invalid(); if (I->isAggregate()) { - addr = I->hasLValue() ? I->getKnownLValue().getAddress() + addr = I->hasLValue() ? I->getKnownLValue().getAddress(*this) : I->getKnownRValue().getAggregateAddress(); } else { @@ -4305,6 +4339,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Callee.getAbstractInfo(), Attrs, CallingConv, /*AttrOnCallSite=*/true); + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) + if (FD->usesFPIntrin()) + // All calls within a strictfp function are marked strictfp + Attrs = + Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex, + llvm::Attribute::StrictFP); + // Apply some call-site-specific attributes. // TODO: work this into building the attribute set. @@ -4354,6 +4395,13 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, SmallVector<llvm::OperandBundleDef, 1> BundleList = getBundlesForFunclet(CalleePtr); + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) + if (FD->usesFPIntrin()) + // All calls within a strictfp function are marked strictfp + Attrs = + Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex, + llvm::Attribute::StrictFP); + // Emit the actual call/invoke instruction. llvm::CallBase *CI; if (!InvokeDest) { @@ -4367,6 +4415,17 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (callOrInvoke) *callOrInvoke = CI; + // If this is within a function that has the guard(nocf) attribute and is an + // indirect call, add the "guard_nocf" attribute to this call to indicate that + // Control Flow Guard checks should not be added, even if the call is inlined. + if (const auto *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) { + if (const auto *A = FD->getAttr<CFGuardAttr>()) { + if (A->getGuard() == CFGuardAttr::GuardArg::nocf && !CI->getCalledFunction()) + Attrs = Attrs.addAttribute( + getLLVMContext(), llvm::AttributeList::FunctionIndex, "guard_nocf"); + } + } + // Apply the attributes and calling convention. CI->setAttributes(Attrs); CI->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv)); diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h index cc11ded704ab..34558be5adb1 100644 --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -29,14 +29,14 @@ class AttributeList; class Function; class Type; class Value; -} +} // namespace llvm namespace clang { - class ASTContext; - class Decl; - class FunctionDecl; - class ObjCMethodDecl; - class VarDecl; +class ASTContext; +class Decl; +class FunctionDecl; +class ObjCMethodDecl; +class VarDecl; namespace CodeGen { @@ -60,331 +60,327 @@ public: return CalleeProtoTy; } const GlobalDecl getCalleeDecl() const { return CalleeDecl; } - }; - - /// All available information about a concrete callee. - class CGCallee { - enum class SpecialKind : uintptr_t { - Invalid, - Builtin, - PseudoDestructor, - Virtual, +}; - Last = Virtual - }; +/// All available information about a concrete callee. +class CGCallee { + enum class SpecialKind : uintptr_t { + Invalid, + Builtin, + PseudoDestructor, + Virtual, - struct BuiltinInfoStorage { - const FunctionDecl *Decl; - unsigned ID; - }; - struct PseudoDestructorInfoStorage { - const CXXPseudoDestructorExpr *Expr; - }; - struct VirtualInfoStorage { - const CallExpr *CE; - GlobalDecl MD; - Address Addr; - llvm::FunctionType *FTy; - }; + Last = Virtual + }; - SpecialKind KindOrFunctionPointer; - union { - CGCalleeInfo AbstractInfo; - BuiltinInfoStorage BuiltinInfo; - PseudoDestructorInfoStorage PseudoDestructorInfo; - VirtualInfoStorage VirtualInfo; - }; + struct BuiltinInfoStorage { + const FunctionDecl *Decl; + unsigned ID; + }; + struct PseudoDestructorInfoStorage { + const CXXPseudoDestructorExpr *Expr; + }; + struct VirtualInfoStorage { + const CallExpr *CE; + GlobalDecl MD; + Address Addr; + llvm::FunctionType *FTy; + }; - explicit CGCallee(SpecialKind kind) : KindOrFunctionPointer(kind) {} + SpecialKind KindOrFunctionPointer; + union { + CGCalleeInfo AbstractInfo; + BuiltinInfoStorage BuiltinInfo; + PseudoDestructorInfoStorage PseudoDestructorInfo; + VirtualInfoStorage VirtualInfo; + }; - CGCallee(const FunctionDecl *builtinDecl, unsigned builtinID) - : KindOrFunctionPointer(SpecialKind::Builtin) { - BuiltinInfo.Decl = builtinDecl; - BuiltinInfo.ID = builtinID; - } + explicit CGCallee(SpecialKind kind) : KindOrFunctionPointer(kind) {} - public: - CGCallee() : KindOrFunctionPointer(SpecialKind::Invalid) {} + CGCallee(const FunctionDecl *builtinDecl, unsigned builtinID) + : KindOrFunctionPointer(SpecialKind::Builtin) { + BuiltinInfo.Decl = builtinDecl; + BuiltinInfo.ID = builtinID; + } - /// Construct a callee. Call this constructor directly when this - /// isn't a direct call. - CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr) - : KindOrFunctionPointer(SpecialKind(uintptr_t(functionPtr))) { - AbstractInfo = abstractInfo; - assert(functionPtr && "configuring callee without function pointer"); - assert(functionPtr->getType()->isPointerTy()); - assert(functionPtr->getType()->getPointerElementType()->isFunctionTy()); - } +public: + CGCallee() : KindOrFunctionPointer(SpecialKind::Invalid) {} - static CGCallee forBuiltin(unsigned builtinID, - const FunctionDecl *builtinDecl) { - CGCallee result(SpecialKind::Builtin); - result.BuiltinInfo.Decl = builtinDecl; - result.BuiltinInfo.ID = builtinID; - return result; - } + /// Construct a callee. Call this constructor directly when this + /// isn't a direct call. + CGCallee(const CGCalleeInfo &abstractInfo, llvm::Value *functionPtr) + : KindOrFunctionPointer(SpecialKind(uintptr_t(functionPtr))) { + AbstractInfo = abstractInfo; + assert(functionPtr && "configuring callee without function pointer"); + assert(functionPtr->getType()->isPointerTy()); + assert(functionPtr->getType()->getPointerElementType()->isFunctionTy()); + } - static CGCallee forPseudoDestructor(const CXXPseudoDestructorExpr *E) { - CGCallee result(SpecialKind::PseudoDestructor); - result.PseudoDestructorInfo.Expr = E; - return result; - } + static CGCallee forBuiltin(unsigned builtinID, + const FunctionDecl *builtinDecl) { + CGCallee result(SpecialKind::Builtin); + result.BuiltinInfo.Decl = builtinDecl; + result.BuiltinInfo.ID = builtinID; + return result; + } - static CGCallee forDirect(llvm::Constant *functionPtr, - const CGCalleeInfo &abstractInfo = CGCalleeInfo()) { - return CGCallee(abstractInfo, functionPtr); - } + static CGCallee forPseudoDestructor(const CXXPseudoDestructorExpr *E) { + CGCallee result(SpecialKind::PseudoDestructor); + result.PseudoDestructorInfo.Expr = E; + return result; + } - static CGCallee - forDirect(llvm::FunctionCallee functionPtr, - const CGCalleeInfo &abstractInfo = CGCalleeInfo()) { - return CGCallee(abstractInfo, functionPtr.getCallee()); - } + static CGCallee forDirect(llvm::Constant *functionPtr, + const CGCalleeInfo &abstractInfo = CGCalleeInfo()) { + return CGCallee(abstractInfo, functionPtr); + } - static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr, - llvm::FunctionType *FTy) { - CGCallee result(SpecialKind::Virtual); - result.VirtualInfo.CE = CE; - result.VirtualInfo.MD = MD; - result.VirtualInfo.Addr = Addr; - result.VirtualInfo.FTy = FTy; - return result; - } + static CGCallee forDirect(llvm::FunctionCallee functionPtr, + const CGCalleeInfo &abstractInfo = CGCalleeInfo()) { + return CGCallee(abstractInfo, functionPtr.getCallee()); + } - bool isBuiltin() const { - return KindOrFunctionPointer == SpecialKind::Builtin; - } - const FunctionDecl *getBuiltinDecl() const { - assert(isBuiltin()); - return BuiltinInfo.Decl; - } - unsigned getBuiltinID() const { - assert(isBuiltin()); - return BuiltinInfo.ID; - } + static CGCallee forVirtual(const CallExpr *CE, GlobalDecl MD, Address Addr, + llvm::FunctionType *FTy) { + CGCallee result(SpecialKind::Virtual); + result.VirtualInfo.CE = CE; + result.VirtualInfo.MD = MD; + result.VirtualInfo.Addr = Addr; + result.VirtualInfo.FTy = FTy; + return result; + } - bool isPseudoDestructor() const { - return KindOrFunctionPointer == SpecialKind::PseudoDestructor; - } - const CXXPseudoDestructorExpr *getPseudoDestructorExpr() const { - assert(isPseudoDestructor()); - return PseudoDestructorInfo.Expr; - } + bool isBuiltin() const { + return KindOrFunctionPointer == SpecialKind::Builtin; + } + const FunctionDecl *getBuiltinDecl() const { + assert(isBuiltin()); + return BuiltinInfo.Decl; + } + unsigned getBuiltinID() const { + assert(isBuiltin()); + return BuiltinInfo.ID; + } - bool isOrdinary() const { - return uintptr_t(KindOrFunctionPointer) > uintptr_t(SpecialKind::Last); - } - CGCalleeInfo getAbstractInfo() const { - if (isVirtual()) - return VirtualInfo.MD; - assert(isOrdinary()); - return AbstractInfo; - } - llvm::Value *getFunctionPointer() const { - assert(isOrdinary()); - return reinterpret_cast<llvm::Value*>(uintptr_t(KindOrFunctionPointer)); - } - void setFunctionPointer(llvm::Value *functionPtr) { - assert(isOrdinary()); - KindOrFunctionPointer = SpecialKind(uintptr_t(functionPtr)); - } + bool isPseudoDestructor() const { + return KindOrFunctionPointer == SpecialKind::PseudoDestructor; + } + const CXXPseudoDestructorExpr *getPseudoDestructorExpr() const { + assert(isPseudoDestructor()); + return PseudoDestructorInfo.Expr; + } - bool isVirtual() const { - return KindOrFunctionPointer == SpecialKind::Virtual; - } - const CallExpr *getVirtualCallExpr() const { - assert(isVirtual()); - return VirtualInfo.CE; - } - GlobalDecl getVirtualMethodDecl() const { - assert(isVirtual()); + bool isOrdinary() const { + return uintptr_t(KindOrFunctionPointer) > uintptr_t(SpecialKind::Last); + } + CGCalleeInfo getAbstractInfo() const { + if (isVirtual()) return VirtualInfo.MD; - } - Address getThisAddress() const { - assert(isVirtual()); - return VirtualInfo.Addr; - } - llvm::FunctionType *getVirtualFunctionType() const { - assert(isVirtual()); - return VirtualInfo.FTy; - } + assert(isOrdinary()); + return AbstractInfo; + } + llvm::Value *getFunctionPointer() const { + assert(isOrdinary()); + return reinterpret_cast<llvm::Value *>(uintptr_t(KindOrFunctionPointer)); + } + void setFunctionPointer(llvm::Value *functionPtr) { + assert(isOrdinary()); + KindOrFunctionPointer = SpecialKind(uintptr_t(functionPtr)); + } - /// If this is a delayed callee computation of some sort, prepare - /// a concrete callee. - CGCallee prepareConcreteCallee(CodeGenFunction &CGF) const; - }; + bool isVirtual() const { + return KindOrFunctionPointer == SpecialKind::Virtual; + } + const CallExpr *getVirtualCallExpr() const { + assert(isVirtual()); + return VirtualInfo.CE; + } + GlobalDecl getVirtualMethodDecl() const { + assert(isVirtual()); + return VirtualInfo.MD; + } + Address getThisAddress() const { + assert(isVirtual()); + return VirtualInfo.Addr; + } + llvm::FunctionType *getVirtualFunctionType() const { + assert(isVirtual()); + return VirtualInfo.FTy; + } - struct CallArg { - private: - union { - RValue RV; - LValue LV; /// The argument is semantically a load from this l-value. - }; - bool HasLV; + /// If this is a delayed callee computation of some sort, prepare + /// a concrete callee. + CGCallee prepareConcreteCallee(CodeGenFunction &CGF) const; +}; - /// A data-flow flag to make sure getRValue and/or copyInto are not - /// called twice for duplicated IR emission. - mutable bool IsUsed; +struct CallArg { +private: + union { + RValue RV; + LValue LV; /// The argument is semantically a load from this l-value. + }; + bool HasLV; - public: - QualType Ty; - CallArg(RValue rv, QualType ty) - : RV(rv), HasLV(false), IsUsed(false), Ty(ty) {} - CallArg(LValue lv, QualType ty) - : LV(lv), HasLV(true), IsUsed(false), Ty(ty) {} - bool hasLValue() const { return HasLV; } - QualType getType() const { return Ty; } + /// A data-flow flag to make sure getRValue and/or copyInto are not + /// called twice for duplicated IR emission. + mutable bool IsUsed; - /// \returns an independent RValue. If the CallArg contains an LValue, - /// a temporary copy is returned. - RValue getRValue(CodeGenFunction &CGF) const; +public: + QualType Ty; + CallArg(RValue rv, QualType ty) + : RV(rv), HasLV(false), IsUsed(false), Ty(ty) {} + CallArg(LValue lv, QualType ty) + : LV(lv), HasLV(true), IsUsed(false), Ty(ty) {} + bool hasLValue() const { return HasLV; } + QualType getType() const { return Ty; } - LValue getKnownLValue() const { - assert(HasLV && !IsUsed); - return LV; - } - RValue getKnownRValue() const { - assert(!HasLV && !IsUsed); - return RV; - } - void setRValue(RValue _RV) { - assert(!HasLV); - RV = _RV; - } + /// \returns an independent RValue. If the CallArg contains an LValue, + /// a temporary copy is returned. + RValue getRValue(CodeGenFunction &CGF) const; - bool isAggregate() const { return HasLV || RV.isAggregate(); } + LValue getKnownLValue() const { + assert(HasLV && !IsUsed); + return LV; + } + RValue getKnownRValue() const { + assert(!HasLV && !IsUsed); + return RV; + } + void setRValue(RValue _RV) { + assert(!HasLV); + RV = _RV; + } - void copyInto(CodeGenFunction &CGF, Address A) const; - }; + bool isAggregate() const { return HasLV || RV.isAggregate(); } - /// CallArgList - Type for representing both the value and type of - /// arguments in a call. - class CallArgList : - public SmallVector<CallArg, 8> { - public: - CallArgList() : StackBase(nullptr) {} + void copyInto(CodeGenFunction &CGF, Address A) const; +}; - struct Writeback { - /// The original argument. Note that the argument l-value - /// is potentially null. - LValue Source; +/// CallArgList - Type for representing both the value and type of +/// arguments in a call. +class CallArgList : public SmallVector<CallArg, 8> { +public: + CallArgList() : StackBase(nullptr) {} - /// The temporary alloca. - Address Temporary; + struct Writeback { + /// The original argument. Note that the argument l-value + /// is potentially null. + LValue Source; - /// A value to "use" after the writeback, or null. - llvm::Value *ToUse; - }; + /// The temporary alloca. + Address Temporary; - struct CallArgCleanup { - EHScopeStack::stable_iterator Cleanup; + /// A value to "use" after the writeback, or null. + llvm::Value *ToUse; + }; - /// The "is active" insertion point. This instruction is temporary and - /// will be removed after insertion. - llvm::Instruction *IsActiveIP; - }; + struct CallArgCleanup { + EHScopeStack::stable_iterator Cleanup; - void add(RValue rvalue, QualType type) { push_back(CallArg(rvalue, type)); } + /// The "is active" insertion point. This instruction is temporary and + /// will be removed after insertion. + llvm::Instruction *IsActiveIP; + }; - void addUncopiedAggregate(LValue LV, QualType type) { - push_back(CallArg(LV, type)); - } + void add(RValue rvalue, QualType type) { push_back(CallArg(rvalue, type)); } - /// Add all the arguments from another CallArgList to this one. After doing - /// this, the old CallArgList retains its list of arguments, but must not - /// be used to emit a call. - void addFrom(const CallArgList &other) { - insert(end(), other.begin(), other.end()); - Writebacks.insert(Writebacks.end(), - other.Writebacks.begin(), other.Writebacks.end()); - CleanupsToDeactivate.insert(CleanupsToDeactivate.end(), - other.CleanupsToDeactivate.begin(), - other.CleanupsToDeactivate.end()); - assert(!(StackBase && other.StackBase) && "can't merge stackbases"); - if (!StackBase) - StackBase = other.StackBase; - } + void addUncopiedAggregate(LValue LV, QualType type) { + push_back(CallArg(LV, type)); + } + + /// Add all the arguments from another CallArgList to this one. After doing + /// this, the old CallArgList retains its list of arguments, but must not + /// be used to emit a call. + void addFrom(const CallArgList &other) { + insert(end(), other.begin(), other.end()); + Writebacks.insert(Writebacks.end(), other.Writebacks.begin(), + other.Writebacks.end()); + CleanupsToDeactivate.insert(CleanupsToDeactivate.end(), + other.CleanupsToDeactivate.begin(), + other.CleanupsToDeactivate.end()); + assert(!(StackBase && other.StackBase) && "can't merge stackbases"); + if (!StackBase) + StackBase = other.StackBase; + } - void addWriteback(LValue srcLV, Address temporary, - llvm::Value *toUse) { - Writeback writeback = { srcLV, temporary, toUse }; - Writebacks.push_back(writeback); - } + void addWriteback(LValue srcLV, Address temporary, llvm::Value *toUse) { + Writeback writeback = {srcLV, temporary, toUse}; + Writebacks.push_back(writeback); + } - bool hasWritebacks() const { return !Writebacks.empty(); } + bool hasWritebacks() const { return !Writebacks.empty(); } - typedef llvm::iterator_range<SmallVectorImpl<Writeback>::const_iterator> + typedef llvm::iterator_range<SmallVectorImpl<Writeback>::const_iterator> writeback_const_range; - writeback_const_range writebacks() const { - return writeback_const_range(Writebacks.begin(), Writebacks.end()); - } + writeback_const_range writebacks() const { + return writeback_const_range(Writebacks.begin(), Writebacks.end()); + } - void addArgCleanupDeactivation(EHScopeStack::stable_iterator Cleanup, - llvm::Instruction *IsActiveIP) { - CallArgCleanup ArgCleanup; - ArgCleanup.Cleanup = Cleanup; - ArgCleanup.IsActiveIP = IsActiveIP; - CleanupsToDeactivate.push_back(ArgCleanup); - } + void addArgCleanupDeactivation(EHScopeStack::stable_iterator Cleanup, + llvm::Instruction *IsActiveIP) { + CallArgCleanup ArgCleanup; + ArgCleanup.Cleanup = Cleanup; + ArgCleanup.IsActiveIP = IsActiveIP; + CleanupsToDeactivate.push_back(ArgCleanup); + } - ArrayRef<CallArgCleanup> getCleanupsToDeactivate() const { - return CleanupsToDeactivate; - } + ArrayRef<CallArgCleanup> getCleanupsToDeactivate() const { + return CleanupsToDeactivate; + } - void allocateArgumentMemory(CodeGenFunction &CGF); - llvm::Instruction *getStackBase() const { return StackBase; } - void freeArgumentMemory(CodeGenFunction &CGF) const; + void allocateArgumentMemory(CodeGenFunction &CGF); + llvm::Instruction *getStackBase() const { return StackBase; } + void freeArgumentMemory(CodeGenFunction &CGF) const; - /// Returns if we're using an inalloca struct to pass arguments in - /// memory. - bool isUsingInAlloca() const { return StackBase; } + /// Returns if we're using an inalloca struct to pass arguments in + /// memory. + bool isUsingInAlloca() const { return StackBase; } - private: - SmallVector<Writeback, 1> Writebacks; +private: + SmallVector<Writeback, 1> Writebacks; - /// Deactivate these cleanups immediately before making the call. This - /// is used to cleanup objects that are owned by the callee once the call - /// occurs. - SmallVector<CallArgCleanup, 1> CleanupsToDeactivate; + /// Deactivate these cleanups immediately before making the call. This + /// is used to cleanup objects that are owned by the callee once the call + /// occurs. + SmallVector<CallArgCleanup, 1> CleanupsToDeactivate; - /// The stacksave call. It dominates all of the argument evaluation. - llvm::CallInst *StackBase; - }; + /// The stacksave call. It dominates all of the argument evaluation. + llvm::CallInst *StackBase; +}; - /// FunctionArgList - Type for representing both the decl and type - /// of parameters to a function. The decl must be either a - /// ParmVarDecl or ImplicitParamDecl. - class FunctionArgList : public SmallVector<const VarDecl*, 16> { - }; +/// FunctionArgList - Type for representing both the decl and type +/// of parameters to a function. The decl must be either a +/// ParmVarDecl or ImplicitParamDecl. +class FunctionArgList : public SmallVector<const VarDecl *, 16> {}; - /// ReturnValueSlot - Contains the address where the return value of a - /// function can be stored, and whether the address is volatile or not. - class ReturnValueSlot { - llvm::PointerIntPair<llvm::Value *, 2, unsigned int> Value; - CharUnits Alignment; +/// ReturnValueSlot - Contains the address where the return value of a +/// function can be stored, and whether the address is volatile or not. +class ReturnValueSlot { + llvm::PointerIntPair<llvm::Value *, 2, unsigned int> Value; + CharUnits Alignment; - // Return value slot flags - enum Flags { - IS_VOLATILE = 0x1, - IS_UNUSED = 0x2, - }; + // Return value slot flags + enum Flags { + IS_VOLATILE = 0x1, + IS_UNUSED = 0x2, + }; - public: - ReturnValueSlot() {} - ReturnValueSlot(Address Addr, bool IsVolatile, bool IsUnused = false) +public: + ReturnValueSlot() {} + ReturnValueSlot(Address Addr, bool IsVolatile, bool IsUnused = false) : Value(Addr.isValid() ? Addr.getPointer() : nullptr, (IsVolatile ? IS_VOLATILE : 0) | (IsUnused ? IS_UNUSED : 0)), Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {} - bool isNull() const { return !getValue().isValid(); } + bool isNull() const { return !getValue().isValid(); } - bool isVolatile() const { return Value.getInt() & IS_VOLATILE; } - Address getValue() const { return Address(Value.getPointer(), Alignment); } - bool isUnused() const { return Value.getInt() & IS_UNUSED; } - }; + bool isVolatile() const { return Value.getInt() & IS_VOLATILE; } + Address getValue() const { return Address(Value.getPointer(), Alignment); } + bool isUnused() const { return Value.getInt() & IS_UNUSED; } +}; -} // end namespace CodeGen -} // end namespace clang +} // end namespace CodeGen +} // end namespace clang #endif diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 04ef912b18bd..3f3825b76275 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -16,6 +16,7 @@ #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "TargetInfo.h" +#include "clang/AST/Attr.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" @@ -657,7 +658,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, // the constructor. QualType::DestructionKind dtorKind = FieldType.isDestructedType(); if (CGF.needsEHCleanup(dtorKind)) - CGF.pushEHDestroy(dtorKind, LHS.getAddress(), FieldType); + CGF.pushEHDestroy(dtorKind, LHS.getAddress(CGF), FieldType); return; } } @@ -681,16 +682,12 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field, LValue LHS, EmitComplexExprIntoLValue(Init, LHS, /*isInit*/ true); break; case TEK_Aggregate: { - AggValueSlot Slot = - AggValueSlot::forLValue( - LHS, - AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased, - getOverlapForFieldInit(Field), - AggValueSlot::IsNotZeroed, - // Checks are made by the code that calls constructor. - AggValueSlot::IsSanitizerChecked); + AggValueSlot Slot = AggValueSlot::forLValue( + LHS, *this, AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased, + getOverlapForFieldInit(Field), AggValueSlot::IsNotZeroed, + // Checks are made by the code that calls constructor. + AggValueSlot::IsSanitizerChecked); EmitAggExpr(Init, Slot); break; } @@ -700,7 +697,7 @@ void CodeGenFunction::EmitInitializerForField(FieldDecl *Field, LValue LHS, // later in the constructor. QualType::DestructionKind dtorKind = FieldType.isDestructedType(); if (needsEHCleanup(dtorKind)) - pushEHDestroy(dtorKind, LHS.getAddress(), FieldType); + pushEHDestroy(dtorKind, LHS.getAddress(*this), FieldType); } /// Checks whether the given constructor is a valid subject for the @@ -914,6 +911,8 @@ namespace { } void addMemcpyableField(FieldDecl *F) { + if (F->isZeroSize(CGF.getContext())) + return; if (!FirstField) addInitialField(F); else @@ -961,9 +960,10 @@ namespace { LValue SrcLV = CGF.MakeNaturalAlignAddrLValue(SrcPtr, RecordTy); LValue Src = CGF.EmitLValueForFieldInitialization(SrcLV, FirstField); - emitMemcpyIR(Dest.isBitField() ? Dest.getBitFieldAddress() : Dest.getAddress(), - Src.isBitField() ? Src.getBitFieldAddress() : Src.getAddress(), - MemcpySize); + emitMemcpyIR( + Dest.isBitField() ? Dest.getBitFieldAddress() : Dest.getAddress(CGF), + Src.isBitField() ? Src.getBitFieldAddress() : Src.getAddress(CGF), + MemcpySize); reset(); } @@ -1117,7 +1117,7 @@ namespace { continue; LValue FieldLHS = LHS; EmitLValueForAnyFieldInitialization(CGF, MemberInit, FieldLHS); - CGF.pushEHDestroy(dtorKind, FieldLHS.getAddress(), FieldType); + CGF.pushEHDestroy(dtorKind, FieldLHS.getAddress(CGF), FieldType); } } @@ -1627,7 +1627,7 @@ namespace { LValue LV = CGF.EmitLValueForField(ThisLV, field); assert(LV.isSimple()); - CGF.emitDestroy(LV.getAddress(), field->getType(), destroyer, + CGF.emitDestroy(LV.getAddress(CGF), field->getType(), destroyer, flags.isForNormalCleanup() && useEHCleanupForArray); } }; diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 7c63743f3b43..cbd524eda9d0 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -18,8 +18,8 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" -#include "clang/Analysis/Analyses/ExprMutationAnalyzer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclFriend.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" @@ -46,6 +46,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/MD5.h" #include "llvm/Support/Path.h" +#include "llvm/Support/TimeProfiler.h" using namespace clang; using namespace clang::CodeGen; @@ -235,8 +236,7 @@ PrintingPolicy CGDebugInfo::getPrintingPolicy() const { PP.MSVCFormatting = true; // Apply -fdebug-prefix-map. - PP.RemapFilePaths = true; - PP.remapPath = [this](StringRef Path) { return remapDIPath(Path); }; + PP.Callbacks = &PrintCB; return PP; } @@ -293,13 +293,6 @@ StringRef CGDebugInfo::getObjCMethodName(const ObjCMethodDecl *OMD) { } } else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) { OS << OCD->getClassInterface()->getName() << '(' << OCD->getName() << ')'; - } else if (isa<ObjCProtocolDecl>(DC)) { - // We can extract the type of the class from the self pointer. - if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) { - QualType ClassTy = - cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType(); - ClassTy.print(OS, PrintingPolicy(LangOptions())); - } } OS << ' ' << OMD->getSelector().getAsString() << ']'; @@ -598,6 +591,7 @@ void CGDebugInfo::CreateCompileUnit() { case codegenoptions::DebugDirectivesOnly: EmissionKind = llvm::DICompileUnit::DebugDirectivesOnly; break; + case codegenoptions::DebugInfoConstructor: case codegenoptions::LimitedDebugInfo: case codegenoptions::FullDebugInfo: EmissionKind = llvm::DICompileUnit::FullDebug; @@ -1142,10 +1136,11 @@ llvm::DIType *CGDebugInfo::CreateType(const TypedefType *Ty, // declared. SourceLocation Loc = Ty->getDecl()->getLocation(); + uint32_t Align = getDeclAlignIfRequired(Ty->getDecl(), CGM.getContext()); // Typedefs are derived from some other type. return DBuilder.createTypedef(Underlying, Ty->getDecl()->getName(), getOrCreateFile(Loc), getLineNumber(Loc), - getDeclContextDescriptor(Ty->getDecl())); + getDeclContextDescriptor(Ty->getDecl()), Align); } static unsigned getDwarfCC(CallingConv CC) { @@ -1607,8 +1602,31 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( ContainingType = RecordTy; } + // We're checking for deleted C++ special member functions + // [Ctors,Dtors, Copy/Move] + auto checkAttrDeleted = [&](const auto *Method) { + if (Method->getCanonicalDecl()->isDeleted()) + SPFlags |= llvm::DISubprogram::SPFlagDeleted; + }; + + switch (Method->getKind()) { + + case Decl::CXXConstructor: + case Decl::CXXDestructor: + checkAttrDeleted(Method); + break; + case Decl::CXXMethod: + if (Method->isCopyAssignmentOperator() || + Method->isMoveAssignmentOperator()) + checkAttrDeleted(Method); + break; + default: + break; + } + if (Method->isNoReturn()) Flags |= llvm::DINode::FlagNoReturn; + if (Method->isStatic()) Flags |= llvm::DINode::FlagStaticMember; if (Method->isImplicit()) @@ -1630,6 +1648,12 @@ llvm::DISubprogram *CGDebugInfo::CreateCXXMemberFunction( if (CGM.getLangOpts().Optimize) SPFlags |= llvm::DISubprogram::SPFlagOptimized; + // In this debug mode, emit type info for a class when its constructor type + // info is emitted. + if (DebugKind == codegenoptions::DebugInfoConstructor) + if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Method)) + completeClass(CD->getParent()); + llvm::DINodeArray TParamsArray = CollectFunctionTemplateParams(Method, Unit); llvm::DISubprogram *SP = DBuilder.createMethod( RecordTy, MethodName, MethodLinkageName, MethodDefUnit, MethodLine, @@ -2026,7 +2050,7 @@ void CGDebugInfo::CollectVTableInfo(const CXXRecordDecl *RD, llvm::DIFile *Unit, llvm::DIType *CGDebugInfo::getOrCreateRecordType(QualType RTy, SourceLocation Loc) { - assert(DebugKind >= codegenoptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); llvm::DIType *T = getOrCreateType(RTy, getOrCreateFile(Loc)); return T; } @@ -2038,7 +2062,7 @@ llvm::DIType *CGDebugInfo::getOrCreateInterfaceType(QualType D, llvm::DIType *CGDebugInfo::getOrCreateStandaloneType(QualType D, SourceLocation Loc) { - assert(DebugKind >= codegenoptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); assert(!D.isNull() && "null type"); llvm::DIType *T = getOrCreateType(D, getOrCreateFile(Loc)); assert(T && "could not create debug info for type"); @@ -2193,6 +2217,17 @@ static bool shouldOmitDefinition(codegenoptions::DebugInfoKind DebugKind, !isClassOrMethodDLLImport(CXXDecl)) return true; + // In constructor debug mode, only emit debug info for a class when its + // constructor is emitted. Skip this optimization if the class or any of + // its methods are marked dllimport. + if (DebugKind == codegenoptions::DebugInfoConstructor && + !CXXDecl->isLambda() && !isClassOrMethodDLLImport(CXXDecl)) { + for (const auto *Ctor : CXXDecl->ctors()) { + if (Ctor->isUserProvided()) + return true; + } + } + TemplateSpecializationKind Spec = TSK_Undeclared; if (const auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) Spec = SD->getSpecializationKind(); @@ -2577,8 +2612,8 @@ llvm::DIType *CGDebugInfo::CreateTypeDefinition(const ObjCInterfaceType *Ty, SourceLocation Loc = PD->getLocation(); llvm::DIFile *PUnit = getOrCreateFile(Loc); unsigned PLine = getLineNumber(Loc); - ObjCMethodDecl *Getter = PD->getGetterMethodDecl(); - ObjCMethodDecl *Setter = PD->getSetterMethodDecl(); + ObjCMethodDecl *Getter = PImpD->getGetterMethodDecl(); + ObjCMethodDecl *Setter = PImpD->getSetterMethodDecl(); PropertyNode = DBuilder.createObjCProperty( PD->getName(), PUnit, PLine, hasDefaultGetterName(PD, Getter) @@ -2711,19 +2746,17 @@ llvm::DIType *CGDebugInfo::CreateType(const MemberPointerType *Ty, // Set the MS inheritance model. There is no flag for the unspecified model. if (CGM.getTarget().getCXXABI().isMicrosoft()) { switch (Ty->getMostRecentCXXRecordDecl()->getMSInheritanceModel()) { - case MSInheritanceAttr::Keyword_single_inheritance: + case MSInheritanceModel::Single: Flags |= llvm::DINode::FlagSingleInheritance; break; - case MSInheritanceAttr::Keyword_multiple_inheritance: + case MSInheritanceModel::Multiple: Flags |= llvm::DINode::FlagMultipleInheritance; break; - case MSInheritanceAttr::Keyword_virtual_inheritance: + case MSInheritanceModel::Virtual: Flags |= llvm::DINode::FlagVirtualInheritance; break; - case MSInheritanceAttr::Keyword_unspecified_inheritance: + case MSInheritanceModel::Unspecified: break; - case MSInheritanceAttr::SpellingNotCalculated: - llvm_unreachable("Spelling not yet calculated"); } } } @@ -2946,6 +2979,13 @@ llvm::DIType *CGDebugInfo::getOrCreateType(QualType Ty, llvm::DIFile *Unit) { if (Ty.isNull()) return nullptr; + llvm::TimeTraceScope TimeScope("DebugType", [&]() { + std::string Name; + llvm::raw_string_ostream OS(Name); + Ty.print(OS, getPrintingPolicy()); + return Name; + }); + // Unwrap the type as needed for debug information. Ty = UnwrapTypeForDebugInfo(Ty, CGM.getContext()); @@ -3248,7 +3288,7 @@ void CGDebugInfo::collectFunctionDeclProps(GlobalDecl GD, llvm::DIFile *Unit, DebugKind <= codegenoptions::DebugLineTablesOnly)) LinkageName = StringRef(); - if (DebugKind >= codegenoptions::LimitedDebugInfo) { + if (CGM.getCodeGenOpts().hasReducedDebugInfo()) { if (const NamespaceDecl *NSDecl = dyn_cast_or_null<NamespaceDecl>(FD->getDeclContext())) FDContext = getOrCreateNamespace(NSDecl); @@ -3460,6 +3500,42 @@ llvm::DISubprogram *CGDebugInfo::getFunctionDeclaration(const Decl *D) { return nullptr; } +llvm::DISubprogram *CGDebugInfo::getObjCMethodDeclaration( + const Decl *D, llvm::DISubroutineType *FnType, unsigned LineNo, + llvm::DINode::DIFlags Flags, llvm::DISubprogram::DISPFlags SPFlags) { + if (!D || DebugKind <= codegenoptions::DebugLineTablesOnly) + return nullptr; + + const auto *OMD = dyn_cast<ObjCMethodDecl>(D); + if (!OMD) + return nullptr; + + if (CGM.getCodeGenOpts().DwarfVersion < 5 && !OMD->isDirectMethod()) + return nullptr; + + if (OMD->isDirectMethod()) + SPFlags |= llvm::DISubprogram::SPFlagObjCDirect; + + // Starting with DWARF V5 method declarations are emitted as children of + // the interface type. + auto *ID = dyn_cast_or_null<ObjCInterfaceDecl>(D->getDeclContext()); + if (!ID) + ID = OMD->getClassInterface(); + if (!ID) + return nullptr; + QualType QTy(ID->getTypeForDecl(), 0); + auto It = TypeCache.find(QTy.getAsOpaquePtr()); + if (It == TypeCache.end()) + return nullptr; + auto *InterfaceType = cast<llvm::DICompositeType>(It->second); + llvm::DISubprogram *FD = DBuilder.createFunction( + InterfaceType, getObjCMethodName(OMD), StringRef(), + InterfaceType->getFile(), LineNo, FnType, LineNo, Flags, SPFlags); + DBuilder.finalizeSubprogram(FD); + ObjCMethodCache[ID].push_back({FD, OMD->isDirectMethod()}); + return FD; +} + // getOrCreateFunctionType - Construct type. If it is a c++ method, include // implicit parameter "this". llvm::DISubroutineType *CGDebugInfo::getOrCreateFunctionType(const Decl *D, @@ -3602,6 +3678,12 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, unsigned LineNo = getLineNumber(Loc); unsigned ScopeLine = getLineNumber(ScopeLoc); + llvm::DISubroutineType *DIFnType = getOrCreateFunctionType(D, FnType, Unit); + llvm::DISubprogram *Decl = nullptr; + if (D) + Decl = isa<ObjCMethodDecl>(D) + ? getObjCMethodDeclaration(D, DIFnType, LineNo, Flags, SPFlags) + : getFunctionDeclaration(D); // FIXME: The function declaration we're constructing here is mostly reusing // declarations from CXXMethodDecl and not constructing new ones for arbitrary @@ -3609,9 +3691,8 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, // all subprograms instead of the actual context since subprogram definitions // are emitted as CU level entities by the backend. llvm::DISubprogram *SP = DBuilder.createFunction( - FDContext, Name, LinkageName, Unit, LineNo, - getOrCreateFunctionType(D, FnType, Unit), ScopeLine, FlagsForDef, - SPFlagsForDef, TParamsArray.get(), getFunctionDeclaration(D)); + FDContext, Name, LinkageName, Unit, LineNo, DIFnType, ScopeLine, + FlagsForDef, SPFlagsForDef, TParamsArray.get(), Decl); Fn->setSubprogram(SP); // We might get here with a VarDecl in the case we're generating // code for the initialization of globals. Do not record these decls @@ -3619,35 +3700,6 @@ void CGDebugInfo::EmitFunctionStart(GlobalDecl GD, SourceLocation Loc, if (HasDecl && isa<FunctionDecl>(D)) DeclCache[D->getCanonicalDecl()].reset(SP); - // We use the SPDefCache only in the case when the debug entry values option - // is set, in order to speed up parameters modification analysis. - // - // FIXME: Use AbstractCallee here to support ObjCMethodDecl. - if (CGM.getCodeGenOpts().EnableDebugEntryValues && HasDecl) - if (auto *FD = dyn_cast<FunctionDecl>(D)) - if (FD->hasBody() && !FD->param_empty()) - SPDefCache[FD].reset(SP); - - if (CGM.getCodeGenOpts().DwarfVersion >= 5) { - // Starting with DWARF V5 method declarations are emitted as children of - // the interface type. - if (const auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(D)) { - const ObjCInterfaceDecl *ID = OMD->getClassInterface(); - QualType QTy(ID->getTypeForDecl(), 0); - auto It = TypeCache.find(QTy.getAsOpaquePtr()); - if (It != TypeCache.end()) { - llvm::DICompositeType *InterfaceDecl = - cast<llvm::DICompositeType>(It->second); - llvm::DISubprogram *FD = DBuilder.createFunction( - InterfaceDecl, Name, LinkageName, Unit, LineNo, - getOrCreateFunctionType(D, FnType, Unit), ScopeLine, Flags, SPFlags, - TParamsArray.get()); - DBuilder.finalizeSubprogram(FD); - ObjCMethodCache[ID].push_back(FD); - } - } - } - // Push the function onto the lexical block stack. LexicalBlockStack.emplace_back(SP); @@ -3664,6 +3716,15 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, if (!D) return; + llvm::TimeTraceScope TimeScope("DebugFunction", [&]() { + std::string Name; + llvm::raw_string_ostream OS(Name); + if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) + ND->getNameForDiagnostic(OS, getPrintingPolicy(), + /*Qualified=*/true); + return Name; + }); + llvm::DINode::DIFlags Flags = llvm::DINode::FlagZero; llvm::DIFile *Unit = getOrCreateFile(Loc); bool IsDeclForCallSite = Fn ? true : false; @@ -3709,21 +3770,29 @@ void CGDebugInfo::EmitFunctionDecl(GlobalDecl GD, SourceLocation Loc, void CGDebugInfo::EmitFuncDeclForCallSite(llvm::CallBase *CallOrInvoke, QualType CalleeType, const FunctionDecl *CalleeDecl) { - auto &CGOpts = CGM.getCodeGenOpts(); - if (!CGOpts.EnableDebugEntryValues || !CGM.getLangOpts().Optimize || - !CallOrInvoke) + if (!CallOrInvoke) return; - auto *Func = CallOrInvoke->getCalledFunction(); if (!Func) return; + if (Func->getSubprogram()) + return; + + // Do not emit a declaration subprogram for a builtin or if call site info + // isn't required. Also, elide declarations for functions with reserved names, + // as call site-related features aren't interesting in this case (& also, the + // compiler may emit calls to these functions without debug locations, which + // makes the verifier complain). + if (CalleeDecl->getBuiltinID() != 0 || + getCallSiteRelatedAttrs() == llvm::DINode::FlagZero) + return; + if (const auto *Id = CalleeDecl->getIdentifier()) + if (Id->isReservedName()) + return; // If there is no DISubprogram attached to the function being called, // create the one describing the function in order to have complete // call site debug info. - if (Func->getSubprogram()) - return; - if (!CalleeDecl->isStatic() && !CalleeDecl->isInlined()) EmitFunctionDecl(CalleeDecl, CalleeDecl->getLocation(), CalleeType, Func); } @@ -3906,7 +3975,7 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::Optional<unsigned> ArgNo, CGBuilderTy &Builder, const bool UsePointerValue) { - assert(DebugKind >= codegenoptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); if (VD->hasAttr<NoDebugAttr>()) return nullptr; @@ -4033,11 +4102,6 @@ llvm::DILocalVariable *CGDebugInfo::EmitDeclare(const VarDecl *VD, llvm::DebugLoc::get(Line, Column, Scope, CurInlinedAt), Builder.GetInsertBlock()); - if (CGM.getCodeGenOpts().EnableDebugEntryValues && ArgNo) { - if (auto *PD = dyn_cast<ParmVarDecl>(VD)) - ParamCache[PD].reset(D); - } - return D; } @@ -4045,12 +4109,12 @@ llvm::DILocalVariable * CGDebugInfo::EmitDeclareOfAutoVariable(const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder, const bool UsePointerValue) { - assert(DebugKind >= codegenoptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); return EmitDeclare(VD, Storage, llvm::None, Builder, UsePointerValue); } void CGDebugInfo::EmitLabel(const LabelDecl *D, CGBuilderTy &Builder) { - assert(DebugKind >= codegenoptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); if (D->hasAttr<NoDebugAttr>()) @@ -4086,7 +4150,7 @@ llvm::DIType *CGDebugInfo::CreateSelfType(const QualType &QualTy, void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( const VarDecl *VD, llvm::Value *Storage, CGBuilderTy &Builder, const CGBlockInfo &blockInfo, llvm::Instruction *InsertPoint) { - assert(DebugKind >= codegenoptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); assert(!LexicalBlockStack.empty() && "Region stack mismatch, stack empty!"); if (Builder.GetInsertBlock() == nullptr) @@ -4157,7 +4221,7 @@ void CGDebugInfo::EmitDeclareOfBlockDeclRefVariable( void CGDebugInfo::EmitDeclareOfArgVariable(const VarDecl *VD, llvm::Value *AI, unsigned ArgNo, CGBuilderTy &Builder) { - assert(DebugKind >= codegenoptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); EmitDeclare(VD, AI, ArgNo, Builder); } @@ -4214,7 +4278,7 @@ void CGDebugInfo::EmitDeclareOfBlockLiteralArgVariable(const CGBlockInfo &block, unsigned ArgNo, llvm::AllocaInst *Alloca, CGBuilderTy &Builder) { - assert(DebugKind >= codegenoptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); ASTContext &C = CGM.getContext(); const BlockDecl *blockDecl = block.getBlockDecl(); @@ -4380,10 +4444,18 @@ llvm::DIGlobalVariableExpression *CGDebugInfo::CollectAnonRecordDecls( void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, const VarDecl *D) { - assert(DebugKind >= codegenoptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); if (D->hasAttr<NoDebugAttr>()) return; + llvm::TimeTraceScope TimeScope("DebugGlobalVariable", [&]() { + std::string Name; + llvm::raw_string_ostream OS(Name); + D->getNameForDiagnostic(OS, getPrintingPolicy(), + /*Qualified=*/true); + return Name; + }); + // If we already created a DIGlobalVariable for this declaration, just attach // it to the llvm::GlobalVariable. auto Cached = DeclCache.find(D->getCanonicalDecl()); @@ -4431,7 +4503,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, GVE = DBuilder.createGlobalVariableExpression( DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit), - Var->hasLocalLinkage(), + Var->hasLocalLinkage(), true, Expr.empty() ? nullptr : DBuilder.createExpression(Expr), getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters, Align); @@ -4441,9 +4513,17 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var, } void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) { - assert(DebugKind >= codegenoptions::LimitedDebugInfo); + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); if (VD->hasAttr<NoDebugAttr>()) return; + llvm::TimeTraceScope TimeScope("DebugConstGlobalVariable", [&]() { + std::string Name; + llvm::raw_string_ostream OS(Name); + VD->getNameForDiagnostic(OS, getPrintingPolicy(), + /*Qualified=*/true); + return Name; + }); + auto Align = getDeclAlignIfRequired(VD, CGM.getContext()); // Create the descriptor for the variable. llvm::DIFile *Unit = getOrCreateFile(VD->getLocation()); @@ -4526,10 +4606,29 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) { GV.reset(DBuilder.createGlobalVariableExpression( DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty, - true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD), + true, true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD), TemplateParameters, Align)); } +void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var, + const VarDecl *D) { + assert(CGM.getCodeGenOpts().hasReducedDebugInfo()); + if (D->hasAttr<NoDebugAttr>()) + return; + + auto Align = getDeclAlignIfRequired(D, CGM.getContext()); + llvm::DIFile *Unit = getOrCreateFile(D->getLocation()); + StringRef Name = D->getName(); + llvm::DIType *Ty = getOrCreateType(D->getType(), Unit); + + llvm::DIScope *DContext = getDeclContextDescriptor(D); + llvm::DIGlobalVariableExpression *GVE = + DBuilder.createGlobalVariableExpression( + DContext, Name, StringRef(), Unit, getLineNumber(D->getLocation()), + Ty, false, false, nullptr, nullptr, nullptr, Align); + Var->addDebugInfo(GVE); +} + llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) { if (!LexicalBlockStack.empty()) return LexicalBlockStack.back(); @@ -4538,7 +4637,7 @@ llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) { } void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) { - if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) + if (!CGM.getCodeGenOpts().hasReducedDebugInfo()) return; const NamespaceDecl *NSDecl = UD.getNominatedNamespace(); if (!NSDecl->isAnonymousNamespace() || @@ -4551,7 +4650,7 @@ void CGDebugInfo::EmitUsingDirective(const UsingDirectiveDecl &UD) { } void CGDebugInfo::EmitUsingDecl(const UsingDecl &UD) { - if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) + if (!CGM.getCodeGenOpts().hasReducedDebugInfo()) return; assert(UD.shadow_size() && "We shouldn't be codegening an invalid UsingDecl containing no decls"); @@ -4592,7 +4691,7 @@ void CGDebugInfo::EmitImportDecl(const ImportDecl &ID) { llvm::DIImportedEntity * CGDebugInfo::EmitNamespaceAlias(const NamespaceAliasDecl &NA) { - if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) + if (!CGM.getCodeGenOpts().hasReducedDebugInfo()) return nullptr; auto &VH = NamespaceAliasCache[&NA]; if (VH) @@ -4637,29 +4736,6 @@ void CGDebugInfo::setDwoId(uint64_t Signature) { TheCU->setDWOId(Signature); } -/// Analyzes each function parameter to determine whether it is constant -/// throughout the function body. -static void analyzeParametersModification( - ASTContext &Ctx, - llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> &SPDefCache, - llvm::DenseMap<const ParmVarDecl *, llvm::TrackingMDRef> &ParamCache) { - for (auto &SP : SPDefCache) { - auto *FD = SP.first; - assert(FD->hasBody() && "Functions must have body here"); - const Stmt *FuncBody = (*FD).getBody(); - for (auto Parm : FD->parameters()) { - ExprMutationAnalyzer FuncAnalyzer(*FuncBody, Ctx); - if (FuncAnalyzer.isMutated(Parm)) - continue; - - auto I = ParamCache.find(Parm); - assert(I != ParamCache.end() && "Parameters should be already cached"); - auto *DIParm = cast<llvm::DILocalVariable>(I->second); - DIParm->setIsNotModified(); - } - } -} - void CGDebugInfo::finalize() { // Creating types might create further types - invalidating the current // element and the size(), so don't cache/reference them. @@ -4671,27 +4747,28 @@ void CGDebugInfo::finalize() { DBuilder.replaceTemporary(llvm::TempDIType(E.Decl), Ty); } - if (CGM.getCodeGenOpts().DwarfVersion >= 5) { - // Add methods to interface. - for (const auto &P : ObjCMethodCache) { - if (P.second.empty()) - continue; + // Add methods to interface. + for (const auto &P : ObjCMethodCache) { + if (P.second.empty()) + continue; - QualType QTy(P.first->getTypeForDecl(), 0); - auto It = TypeCache.find(QTy.getAsOpaquePtr()); - assert(It != TypeCache.end()); + QualType QTy(P.first->getTypeForDecl(), 0); + auto It = TypeCache.find(QTy.getAsOpaquePtr()); + assert(It != TypeCache.end()); - llvm::DICompositeType *InterfaceDecl = - cast<llvm::DICompositeType>(It->second); + llvm::DICompositeType *InterfaceDecl = + cast<llvm::DICompositeType>(It->second); - SmallVector<llvm::Metadata *, 16> EltTys; - auto CurrenetElts = InterfaceDecl->getElements(); - EltTys.append(CurrenetElts.begin(), CurrenetElts.end()); - for (auto &MD : P.second) - EltTys.push_back(MD); - llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); - DBuilder.replaceArrays(InterfaceDecl, Elements); - } + auto CurElts = InterfaceDecl->getElements(); + SmallVector<llvm::Metadata *, 16> EltTys(CurElts.begin(), CurElts.end()); + + // For DWARF v4 or earlier, only add objc_direct methods. + for (auto &SubprogramDirect : P.second) + if (CGM.getCodeGenOpts().DwarfVersion >= 5 || SubprogramDirect.getInt()) + EltTys.push_back(SubprogramDirect.getPointer()); + + llvm::DINodeArray Elements = DBuilder.getOrCreateArray(EltTys); + DBuilder.replaceArrays(InterfaceDecl, Elements); } for (const auto &P : ReplaceMap) { @@ -4732,15 +4809,11 @@ void CGDebugInfo::finalize() { if (auto MD = TypeCache[RT]) DBuilder.retainType(cast<llvm::DIType>(MD)); - if (CGM.getCodeGenOpts().EnableDebugEntryValues) - // This will be used to emit debug entry values. - analyzeParametersModification(CGM.getContext(), SPDefCache, ParamCache); - DBuilder.finalize(); } void CGDebugInfo::EmitExplicitCastType(QualType Ty) { - if (CGM.getCodeGenOpts().getDebugInfo() < codegenoptions::LimitedDebugInfo) + if (!CGM.getCodeGenOpts().hasReducedDebugInfo()) return; if (auto *DieTy = getOrCreateType(Ty, TheCU->getFile())) @@ -4769,10 +4842,10 @@ llvm::DINode::DIFlags CGDebugInfo::getCallSiteRelatedAttrs() const { bool SupportsDWARFv4Ext = CGM.getCodeGenOpts().DwarfVersion == 4 && (CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB || - (CGM.getCodeGenOpts().EnableDebugEntryValues && - CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::GDB)); + CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::GDB); - if (!SupportsDWARFv4Ext && CGM.getCodeGenOpts().DwarfVersion < 5) + if (!SupportsDWARFv4Ext && CGM.getCodeGenOpts().DwarfVersion < 5 && + !CGM.getCodeGenOpts().EnableDebugEntryValues) return llvm::DINode::FlagZero; return llvm::DINode::FlagAllCallsDescribed; diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index 7edbea86633a..90e9a61ebe96 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -83,12 +83,25 @@ class CGDebugInfo { /// Cache of previously constructed Types. llvm::DenseMap<const void *, llvm::TrackingMDRef> TypeCache; - llvm::SmallDenseMap<llvm::StringRef, llvm::StringRef> DebugPrefixMap; + std::map<llvm::StringRef, llvm::StringRef, std::greater<llvm::StringRef>> + DebugPrefixMap; /// Cache that maps VLA types to size expressions for that type, /// represented by instantiated Metadata nodes. llvm::SmallDenseMap<QualType, llvm::Metadata *> SizeExprCache; + /// Callbacks to use when printing names and types. + class PrintingCallbacks final : public clang::PrintingCallbacks { + const CGDebugInfo &Self; + + public: + PrintingCallbacks(const CGDebugInfo &Self) : Self(Self) {} + std::string remapPath(StringRef Path) const override { + return Self.remapDIPath(Path); + } + }; + PrintingCallbacks PrintCB = {*this}; + struct ObjCInterfaceCacheEntry { const ObjCInterfaceType *Type; llvm::DIType *Decl; @@ -102,7 +115,10 @@ class CGDebugInfo { llvm::SmallVector<ObjCInterfaceCacheEntry, 32> ObjCInterfaceCache; /// Cache of forward declarations for methods belonging to the interface. - llvm::DenseMap<const ObjCInterfaceDecl *, std::vector<llvm::DISubprogram *>> + /// The extra bit on the DISubprogram specifies whether a method is + /// "objc_direct". + llvm::DenseMap<const ObjCInterfaceDecl *, + std::vector<llvm::PointerIntPair<llvm::DISubprogram *, 1>>> ObjCMethodCache; /// Cache of references to clang modules and precompiled headers. @@ -134,10 +150,6 @@ class CGDebugInfo { llvm::DenseMap<const char *, llvm::TrackingMDRef> DIFileCache; llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> SPCache; - /// Cache function definitions relevant to use for parameters mutation - /// analysis. - llvm::DenseMap<const FunctionDecl *, llvm::TrackingMDRef> SPDefCache; - llvm::DenseMap<const ParmVarDecl *, llvm::TrackingMDRef> ParamCache; /// Cache declarations relevant to DW_TAG_imported_declarations (C++ /// using declarations) that aren't covered by other more specific caches. llvm::DenseMap<const Decl *, llvm::TrackingMDRef> DeclCache; @@ -466,6 +478,9 @@ public: /// Emit a constant global variable's debug info. void EmitGlobalVariable(const ValueDecl *VD, const APValue &Init); + /// Emit information about an external variable. + void EmitExternalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl); + /// Emit C++ using directive. void EmitUsingDirective(const UsingDirectiveDecl &UD); @@ -601,6 +616,17 @@ private: /// declaration for the given method definition. llvm::DISubprogram *getFunctionDeclaration(const Decl *D); + /// \return debug info descriptor to the describe method declaration + /// for the given method definition. + /// \param FnType For Objective-C methods, their type. + /// \param LineNo The declaration's line number. + /// \param Flags The DIFlags for the method declaration. + /// \param SPFlags The subprogram-spcific flags for the method declaration. + llvm::DISubprogram * + getObjCMethodDeclaration(const Decl *D, llvm::DISubroutineType *FnType, + unsigned LineNo, llvm::DINode::DIFlags Flags, + llvm::DISubprogram::DISPFlags SPFlags); + /// \return debug info descriptor to describe in-class static data /// member declaration for the given out-of-class definition. If D /// is an out-of-class definition of a static data member of a @@ -725,6 +751,7 @@ public: ApplyDebugLocation(ApplyDebugLocation &&Other) : CGF(Other.CGF) { Other.CGF = nullptr; } + ApplyDebugLocation &operator=(ApplyDebugLocation &&) = default; ~ApplyDebugLocation(); diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 563841c068f6..5aac7a8d54c7 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -22,6 +22,7 @@ #include "PatternInit.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" @@ -109,6 +110,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::OMPRequires: case Decl::Empty: case Decl::Concept: + case Decl::LifetimeExtendedTemporary: // None of these decls require codegen support. return; @@ -364,7 +366,8 @@ CodeGenFunction::AddInitializerToStaticVarDecl(const VarDecl &D, emitter.finalize(GV); - if (D.needsDestruction(getContext()) && HaveInsertPoint()) { + if (D.needsDestruction(getContext()) == QualType::DK_cxx_destructor && + HaveInsertPoint()) { // We have a constant initializer, but a nontrivial destructor. We still // need to perform a guarded "initialization" in order to register the // destructor. @@ -443,8 +446,7 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, // Emit global variable debug descriptor for static vars. CGDebugInfo *DI = getDebugInfo(); - if (DI && - CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) { + if (DI && CGM.getCodeGenOpts().hasReducedDebugInfo()) { DI->setLocation(D.getLocation()); DI->EmitGlobalVariable(var, &D); } @@ -569,7 +571,7 @@ namespace { Var.getType(), VK_LValue, SourceLocation()); // Compute the address of the local variable, in case it's a byref // or something. - llvm::Value *Addr = CGF.EmitDeclRefLValue(&DRE).getPointer(); + llvm::Value *Addr = CGF.EmitDeclRefLValue(&DRE).getPointer(CGF); // In some cases, the type of the function argument will be different from // the type of the pointer. An example of this is @@ -684,18 +686,18 @@ static bool tryEmitARCCopyWeakInit(CodeGenFunction &CGF, LValue srcLV = CGF.EmitLValue(srcExpr); // Handle a formal type change to avoid asserting. - auto srcAddr = srcLV.getAddress(); + auto srcAddr = srcLV.getAddress(CGF); if (needsCast) { - srcAddr = CGF.Builder.CreateElementBitCast(srcAddr, - destLV.getAddress().getElementType()); + srcAddr = CGF.Builder.CreateElementBitCast( + srcAddr, destLV.getAddress(CGF).getElementType()); } // If it was an l-value, use objc_copyWeak. if (srcExpr->getValueKind() == VK_LValue) { - CGF.EmitARCCopyWeak(destLV.getAddress(), srcAddr); + CGF.EmitARCCopyWeak(destLV.getAddress(CGF), srcAddr); } else { assert(srcExpr->getValueKind() == VK_XValue); - CGF.EmitARCMoveWeak(destLV.getAddress(), srcAddr); + CGF.EmitARCMoveWeak(destLV.getAddress(CGF), srcAddr); } return true; } @@ -713,7 +715,7 @@ static bool tryEmitARCCopyWeakInit(CodeGenFunction &CGF, static void drillIntoBlockVariable(CodeGenFunction &CGF, LValue &lvalue, const VarDecl *var) { - lvalue.setAddress(CGF.emitBlockByrefAddress(lvalue.getAddress(), var)); + lvalue.setAddress(CGF.emitBlockByrefAddress(lvalue.getAddress(CGF), var)); } void CodeGenFunction::EmitNullabilityCheck(LValue LHS, llvm::Value *RHS, @@ -773,17 +775,18 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, if (capturedByInit) { // We can use a simple GEP for this because it can't have been // moved yet. - tempLV.setAddress(emitBlockByrefAddress(tempLV.getAddress(), + tempLV.setAddress(emitBlockByrefAddress(tempLV.getAddress(*this), cast<VarDecl>(D), /*follow*/ false)); } - auto ty = cast<llvm::PointerType>(tempLV.getAddress().getElementType()); + auto ty = + cast<llvm::PointerType>(tempLV.getAddress(*this).getElementType()); llvm::Value *zero = CGM.getNullPointer(ty, tempLV.getType()); // If __weak, we want to use a barrier under certain conditions. if (lifetime == Qualifiers::OCL_Weak) - EmitARCInitWeak(tempLV.getAddress(), zero); + EmitARCInitWeak(tempLV.getAddress(*this), zero); // Otherwise just do a simple store. else @@ -826,9 +829,9 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D, if (capturedByInit) drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D)); if (accessedByInit) - EmitARCStoreWeak(lvalue.getAddress(), value, /*ignored*/ true); + EmitARCStoreWeak(lvalue.getAddress(*this), value, /*ignored*/ true); else - EmitARCInitWeak(lvalue.getAddress(), value); + EmitARCInitWeak(lvalue.getAddress(*this), value); return; } @@ -1390,8 +1393,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { EmitVariablyModifiedType(Ty); auto *DI = getDebugInfo(); - bool EmitDebugInfo = DI && CGM.getCodeGenOpts().getDebugInfo() >= - codegenoptions::LimitedDebugInfo; + bool EmitDebugInfo = DI && CGM.getCodeGenOpts().hasReducedDebugInfo(); Address address = Address::invalid(); Address AllocaAddr = Address::invalid(); @@ -1896,11 +1898,10 @@ void CodeGenFunction::EmitExprAsInit(const Expr *init, const ValueDecl *D, else if (auto *FD = dyn_cast<FieldDecl>(D)) Overlap = getOverlapForFieldInit(FD); // TODO: how can we delay here if D is captured by its initializer? - EmitAggExpr(init, AggValueSlot::forLValue(lvalue, - AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased, - Overlap)); + EmitAggExpr(init, AggValueSlot::forLValue( + lvalue, *this, AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased, Overlap)); } return; } @@ -2456,7 +2457,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, // objc_storeStrong attempts to release its old value. llvm::Value *Null = CGM.EmitNullConstant(D.getType()); EmitStoreOfScalar(Null, lv, /* isInitialization */ true); - EmitARCStoreStrongCall(lv.getAddress(), ArgVal, true); + EmitARCStoreStrongCall(lv.getAddress(*this), ArgVal, true); DoStore = false; } else @@ -2493,9 +2494,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, // Emit debug info for param declarations in non-thunk functions. if (CGDebugInfo *DI = getDebugInfo()) { - if (CGM.getCodeGenOpts().getDebugInfo() >= - codegenoptions::LimitedDebugInfo && - !CurFuncIsThunk) { + if (CGM.getCodeGenOpts().hasReducedDebugInfo() && !CurFuncIsThunk) { DI->EmitDeclareOfArgVariable(&D, DeclPtr.getPointer(), ArgNo, Builder); } } diff --git a/clang/lib/CodeGen/CGDeclCXX.cpp b/clang/lib/CodeGen/CGDeclCXX.cpp index bf16b7bec4b1..3baa0a080f5d 100644 --- a/clang/lib/CodeGen/CGDeclCXX.cpp +++ b/clang/lib/CodeGen/CGDeclCXX.cpp @@ -10,11 +10,12 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenFunction.h" #include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGOpenMPRuntime.h" +#include "CodeGenFunction.h" #include "TargetInfo.h" +#include "clang/AST/Attr.h" #include "clang/Basic/CodeGenOptions.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Intrinsics.h" @@ -54,10 +55,11 @@ static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, CGF.EmitComplexExprIntoLValue(Init, lv, /*isInit*/ true); return; case TEK_Aggregate: - CGF.EmitAggExpr(Init, AggValueSlot::forLValue(lv,AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased, - AggValueSlot::DoesNotOverlap)); + CGF.EmitAggExpr(Init, + AggValueSlot::forLValue(lv, CGF, AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased, + AggValueSlot::DoesNotOverlap)); return; } llvm_unreachable("bad evaluation kind"); @@ -437,7 +439,7 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, // that are of class type, cannot have a non-empty constructor. All // the checks have been done in Sema by now. Whatever initializers // are allowed are empty and we just need to ignore them here. - if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice && + if (getLangOpts().CUDAIsDevice && !getLangOpts().GPUAllowDeviceInit && (D->hasAttr<CUDADeviceAttr>() || D->hasAttr<CUDAConstantAttr>() || D->hasAttr<CUDASharedAttr>())) return; @@ -608,6 +610,11 @@ CodeGenModule::EmitCXXGlobalInitFunc() { Fn->setCallingConv(llvm::CallingConv::SPIR_KERNEL); } + if (getLangOpts().HIP) { + Fn->setCallingConv(llvm::CallingConv::AMDGPU_KERNEL); + Fn->addFnAttr("device-init"); + } + CXXGlobalInits.clear(); } diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index 645d7a878e3b..53fafab3e0e6 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -10,10 +10,10 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenFunction.h" #include "CGCXXABI.h" #include "CGCleanup.h" #include "CGObjCRuntime.h" +#include "CodeGenFunction.h" #include "ConstantEmitter.h" #include "TargetInfo.h" #include "clang/AST/Mangle.h" @@ -21,8 +21,9 @@ #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/TargetBuiltins.h" -#include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsWebAssembly.h" #include "llvm/Support/SaveAndRestore.h" using namespace clang; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index dcd365c8eaf0..8e0604181fb1 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -417,7 +417,7 @@ static Address createReferenceTemporary(CodeGenFunction &CGF, LValue CodeGenFunction:: EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { - const Expr *E = M->GetTemporaryExpr(); + const Expr *E = M->getSubExpr(); assert((!M->getExtendingDecl() || !isa<VarDecl>(M->getExtendingDecl()) || !cast<VarDecl>(M->getExtendingDecl())->isARCPseudoStrong()) && @@ -573,7 +573,7 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { LV = EmitLValueForField(LV, Adjustment.Field); assert(LV.isSimple() && "materialized temporary field is not a simple lvalue"); - Object = LV.getAddress(); + Object = LV.getAddress(*this); break; } @@ -594,7 +594,7 @@ CodeGenFunction::EmitReferenceBindingToExpr(const Expr *E) { // Emit the expression as an lvalue. LValue LV = EmitLValue(E); assert(LV.isSimple()); - llvm::Value *Value = LV.getPointer(); + llvm::Value *Value = LV.getPointer(*this); if (sanitizePerformTypeCheck() && !E->getType()->isFunctionType()) { // C++11 [dcl.ref]p5 (as amended by core issue 453): @@ -1011,6 +1011,9 @@ EmitComplexPrePostIncDec(const UnaryOperator *E, LValue LV, // Store the updated result through the lvalue. EmitStoreOfComplex(IncVal, LV, /*init*/ false); + if (getLangOpts().OpenMP) + CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this, + E->getSubExpr()); // If this is a postinc, return the value read from memory, otherwise use the // updated value. @@ -1129,7 +1132,7 @@ Address CodeGenFunction::EmitPointerWithAlignment(const Expr *E, LValue LV = EmitLValue(UO->getSubExpr()); if (BaseInfo) *BaseInfo = LV.getBaseInfo(); if (TBAAInfo) *TBAAInfo = LV.getTBAAInfo(); - return LV.getAddress(); + return LV.getAddress(*this); } } @@ -1219,8 +1222,8 @@ LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) { if (IsBaseCXXThis || isa<DeclRefExpr>(ME->getBase())) SkippedChecks.set(SanitizerKind::Null, true); } - EmitTypeCheck(TCK, E->getExprLoc(), LV.getPointer(), - E->getType(), LV.getAlignment(), SkippedChecks); + EmitTypeCheck(TCK, E->getExprLoc(), LV.getPointer(*this), E->getType(), + LV.getAlignment(), SkippedChecks); } return LV; } @@ -1307,7 +1310,7 @@ LValue CodeGenFunction::EmitLValue(const Expr *E) { if (LV.isSimple()) { // Defend against branches out of gnu statement expressions surrounded by // cleanups. - llvm::Value *V = LV.getPointer(); + llvm::Value *V = LV.getPointer(*this); Scope.ForceCleanup({&V}); return LValue::MakeAddr(Address(V, LV.getAlignment()), LV.getType(), getContext(), LV.getBaseInfo(), LV.getTBAAInfo()); @@ -1523,7 +1526,7 @@ llvm::Value *CodeGenFunction::emitScalarConstant( llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue, SourceLocation Loc) { - return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(), + return EmitLoadOfScalar(lvalue.getAddress(*this), lvalue.isVolatile(), lvalue.getType(), Loc, lvalue.getBaseInfo(), lvalue.getTBAAInfo(), lvalue.isNontemporal()); } @@ -1763,7 +1766,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr, void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue, bool isInit) { - EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(), + EmitStoreOfScalar(value, lvalue.getAddress(*this), lvalue.isVolatile(), lvalue.getType(), lvalue.getBaseInfo(), lvalue.getTBAAInfo(), isInit, lvalue.isNontemporal()); } @@ -1774,18 +1777,18 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue, RValue CodeGenFunction::EmitLoadOfLValue(LValue LV, SourceLocation Loc) { if (LV.isObjCWeak()) { // load of a __weak object. - Address AddrWeakObj = LV.getAddress(); + Address AddrWeakObj = LV.getAddress(*this); return RValue::get(CGM.getObjCRuntime().EmitObjCWeakRead(*this, AddrWeakObj)); } if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) { // In MRC mode, we do a load+autorelease. if (!getLangOpts().ObjCAutoRefCount) { - return RValue::get(EmitARCLoadWeak(LV.getAddress())); + return RValue::get(EmitARCLoadWeak(LV.getAddress(*this))); } // In ARC mode, we load retained and then consume the value. - llvm::Value *Object = EmitARCLoadWeakRetained(LV.getAddress()); + llvm::Value *Object = EmitARCLoadWeakRetained(LV.getAddress(*this)); Object = EmitObjCConsumeObject(LV.getType(), Object); return RValue::get(Object); } @@ -1880,8 +1883,7 @@ RValue CodeGenFunction::EmitLoadOfExtVectorElementLValue(LValue LV) { /// Generates lvalue for partial ext_vector access. Address CodeGenFunction::EmitExtVectorElementLValue(LValue LV) { Address VectorAddress = LV.getExtVectorAddress(); - const VectorType *ExprVT = LV.getType()->getAs<VectorType>(); - QualType EQT = ExprVT->getElementType(); + QualType EQT = LV.getType()->castAs<VectorType>()->getElementType(); llvm::Type *VectorElementTy = CGM.getTypes().ConvertType(EQT); Address CastToPointerElement = @@ -1971,9 +1973,10 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, case Qualifiers::OCL_Weak: if (isInit) // Initialize and then skip the primitive store. - EmitARCInitWeak(Dst.getAddress(), Src.getScalarVal()); + EmitARCInitWeak(Dst.getAddress(*this), Src.getScalarVal()); else - EmitARCStoreWeak(Dst.getAddress(), Src.getScalarVal(), /*ignore*/ true); + EmitARCStoreWeak(Dst.getAddress(*this), Src.getScalarVal(), + /*ignore*/ true); return; case Qualifiers::OCL_Autoreleasing: @@ -1986,7 +1989,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, if (Dst.isObjCWeak() && !Dst.isNonGC()) { // load of a __weak object. - Address LvalueDst = Dst.getAddress(); + Address LvalueDst = Dst.getAddress(*this); llvm::Value *src = Src.getScalarVal(); CGM.getObjCRuntime().EmitObjCWeakAssign(*this, src, LvalueDst); return; @@ -1994,7 +1997,7 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, if (Dst.isObjCStrong() && !Dst.isNonGC()) { // load of a __strong object. - Address LvalueDst = Dst.getAddress(); + Address LvalueDst = Dst.getAddress(*this); llvm::Value *src = Src.getScalarVal(); if (Dst.isObjCIvar()) { assert(Dst.getBaseIvarExp() && "BaseIvarExp is NULL"); @@ -2320,8 +2323,8 @@ Address CodeGenFunction::EmitLoadOfReference(LValue RefLVal, LValueBaseInfo *PointeeBaseInfo, TBAAAccessInfo *PointeeTBAAInfo) { - llvm::LoadInst *Load = Builder.CreateLoad(RefLVal.getAddress(), - RefLVal.isVolatile()); + llvm::LoadInst *Load = + Builder.CreateLoad(RefLVal.getAddress(*this), RefLVal.isVolatile()); CGM.DecorateInstructionWithTBAA(Load, RefLVal.getTBAAInfo()); CharUnits Align = getNaturalTypeAlignment(RefLVal.getType()->getPointeeType(), @@ -2565,21 +2568,35 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { VD = VD->getCanonicalDecl(); if (auto *FD = LambdaCaptureFields.lookup(VD)) return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue); - else if (CapturedStmtInfo) { + if (CapturedStmtInfo) { auto I = LocalDeclMap.find(VD); if (I != LocalDeclMap.end()) { + LValue CapLVal; if (VD->getType()->isReferenceType()) - return EmitLoadOfReferenceLValue(I->second, VD->getType(), - AlignmentSource::Decl); - return MakeAddrLValue(I->second, T); + CapLVal = EmitLoadOfReferenceLValue(I->second, VD->getType(), + AlignmentSource::Decl); + else + CapLVal = MakeAddrLValue(I->second, T); + // Mark lvalue as nontemporal if the variable is marked as nontemporal + // in simd context. + if (getLangOpts().OpenMP && + CGM.getOpenMPRuntime().isNontemporalDecl(VD)) + CapLVal.setNontemporal(/*Value=*/true); + return CapLVal; } LValue CapLVal = EmitCapturedFieldLValue(*this, CapturedStmtInfo->lookup(VD), CapturedStmtInfo->getContextValue()); - return MakeAddrLValue( - Address(CapLVal.getPointer(), getContext().getDeclAlign(VD)), + CapLVal = MakeAddrLValue( + Address(CapLVal.getPointer(*this), getContext().getDeclAlign(VD)), CapLVal.getType(), LValueBaseInfo(AlignmentSource::Decl), CapLVal.getTBAAInfo()); + // Mark lvalue as nontemporal if the variable is marked as nontemporal + // in simd context. + if (getLangOpts().OpenMP && + CGM.getOpenMPRuntime().isNontemporalDecl(VD)) + CapLVal.setNontemporal(/*Value=*/true); + return CapLVal; } assert(isa<BlockDecl>(CurCodeDecl)); @@ -2712,7 +2729,7 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { // __real is valid on scalars. This is a faster way of testing that. // __imag can only produce an rvalue on scalars. if (E->getOpcode() == UO_Real && - !LV.getAddress().getElementType()->isStructTy()) { + !LV.getAddress(*this).getElementType()->isStructTy()) { assert(E->getSubExpr()->getType()->isArithmeticType()); return LV; } @@ -2720,9 +2737,9 @@ LValue CodeGenFunction::EmitUnaryOpLValue(const UnaryOperator *E) { QualType T = ExprTy->castAs<ComplexType>()->getElementType(); Address Component = - (E->getOpcode() == UO_Real - ? emitAddrOfRealComponent(LV.getAddress(), LV.getType()) - : emitAddrOfImagComponent(LV.getAddress(), LV.getType())); + (E->getOpcode() == UO_Real + ? emitAddrOfRealComponent(LV.getAddress(*this), LV.getType()) + : emitAddrOfImagComponent(LV.getAddress(*this), LV.getType())); LValue ElemLV = MakeAddrLValue(Component, T, LV.getBaseInfo(), CGM.getTBAAInfoForSubobject(LV, T)); ElemLV.getQuals().addQualifiers(LV.getQuals()); @@ -3200,6 +3217,9 @@ void CodeGenFunction::EmitCfiCheckFail() { llvm::Function *F = llvm::Function::Create( llvm::FunctionType::get(VoidTy, {VoidPtrTy, VoidPtrTy}, false), llvm::GlobalValue::WeakODRLinkage, "__cfi_check_fail", &CGM.getModule()); + + CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, F); + CGM.SetLLVMFunctionAttributesForDefinition(nullptr, F); F->setVisibility(llvm::GlobalValue::HiddenVisibility); StartFunction(GlobalDecl(), CGM.getContext().VoidTy, F, FI, Args, @@ -3319,7 +3339,7 @@ Address CodeGenFunction::EmitArrayToPointerDecay(const Expr *E, // Expressions of array type can't be bitfields or vector elements. LValue LV = EmitLValue(E); - Address Addr = LV.getAddress(); + Address Addr = LV.getAddress(*this); // If the array type was an incomplete type, we need to make sure // the decay ends up being the right type. @@ -3402,11 +3422,48 @@ static QualType getFixedSizeElementType(const ASTContext &ctx, return eltType; } +/// Given an array base, check whether its member access belongs to a record +/// with preserve_access_index attribute or not. +static bool IsPreserveAIArrayBase(CodeGenFunction &CGF, const Expr *ArrayBase) { + if (!ArrayBase || !CGF.getDebugInfo()) + return false; + + // Only support base as either a MemberExpr or DeclRefExpr. + // DeclRefExpr to cover cases like: + // struct s { int a; int b[10]; }; + // struct s *p; + // p[1].a + // p[1] will generate a DeclRefExpr and p[1].a is a MemberExpr. + // p->b[5] is a MemberExpr example. + const Expr *E = ArrayBase->IgnoreImpCasts(); + if (const auto *ME = dyn_cast<MemberExpr>(E)) + return ME->getMemberDecl()->hasAttr<BPFPreserveAccessIndexAttr>(); + + if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) { + const auto *VarDef = dyn_cast<VarDecl>(DRE->getDecl()); + if (!VarDef) + return false; + + const auto *PtrT = VarDef->getType()->getAs<PointerType>(); + if (!PtrT) + return false; + + const auto *PointeeT = PtrT->getPointeeType() + ->getUnqualifiedDesugaredType(); + if (const auto *RecT = dyn_cast<RecordType>(PointeeT)) + return RecT->getDecl()->hasAttr<BPFPreserveAccessIndexAttr>(); + return false; + } + + return false; +} + static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, ArrayRef<llvm::Value *> indices, QualType eltType, bool inbounds, bool signedIndices, SourceLocation loc, QualType *arrayType = nullptr, + const Expr *Base = nullptr, const llvm::Twine &name = "arrayidx") { // All the indices except that last must be zero. #ifndef NDEBUG @@ -3428,7 +3485,8 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, llvm::Value *eltPtr; auto LastIndex = dyn_cast<llvm::ConstantInt>(indices.back()); - if (!CGF.IsInPreservedAIRegion || !LastIndex) { + if (!LastIndex || + (!CGF.IsInPreservedAIRegion && !IsPreserveAIArrayBase(CGF, Base))) { eltPtr = emitArraySubscriptGEP( CGF, addr.getPointer(), indices, inbounds, signedIndices, loc, name); @@ -3438,7 +3496,8 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, llvm::DIType *DbgInfo = nullptr; if (arrayType) DbgInfo = CGF.getDebugInfo()->getOrCreateStandaloneType(*arrayType, loc); - eltPtr = CGF.Builder.CreatePreserveArrayAccessIndex(addr.getPointer(), + eltPtr = CGF.Builder.CreatePreserveArrayAccessIndex(addr.getElementType(), + addr.getPointer(), indices.size() - 1, idx, DbgInfo); } @@ -3483,8 +3542,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, LValue LHS = EmitLValue(E->getBase()); auto *Idx = EmitIdxAfterBase(/*Promote*/false); assert(LHS.isSimple() && "Can only subscript lvalue vectors here!"); - return LValue::MakeVectorElt(LHS.getAddress(), Idx, E->getBase()->getType(), - LHS.getBaseInfo(), TBAAAccessInfo()); + return LValue::MakeVectorElt(LHS.getAddress(*this), Idx, + E->getBase()->getType(), LHS.getBaseInfo(), + TBAAAccessInfo()); } // All the other cases basically behave like simple offsetting. @@ -3579,9 +3639,9 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, // Propagate the alignment from the array itself to the result. QualType arrayType = Array->getType(); Addr = emitArraySubscriptGEP( - *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx}, + *this, ArrayLV.getAddress(*this), {CGM.getSize(CharUnits::Zero()), Idx}, E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices, - E->getExprLoc(), &arrayType); + E->getExprLoc(), &arrayType, E->getBase()); EltBaseInfo = ArrayLV.getBaseInfo(); EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType()); } else { @@ -3591,7 +3651,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, QualType ptrType = E->getBase()->getType(); Addr = emitArraySubscriptGEP(*this, Addr, Idx, E->getType(), !getLangOpts().isSignedOverflowDefined(), - SignedIndices, E->getExprLoc(), &ptrType); + SignedIndices, E->getExprLoc(), &ptrType, + E->getBase()); } LValue LV = MakeAddrLValue(Addr, E->getType(), EltBaseInfo, EltTBAAInfo); @@ -3613,7 +3674,7 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base, if (auto *ASE = dyn_cast<OMPArraySectionExpr>(Base->IgnoreParenImpCasts())) { BaseLVal = CGF.EmitOMPArraySectionExpr(ASE, IsLowerBound); if (BaseTy->isArrayType()) { - Address Addr = BaseLVal.getAddress(); + Address Addr = BaseLVal.getAddress(CGF); BaseInfo = BaseLVal.getBaseInfo(); // If the array type was an incomplete type, we need to make sure @@ -3638,7 +3699,7 @@ static Address emitOMPArraySectionBase(CodeGenFunction &CGF, const Expr *Base, &TypeTBAAInfo); BaseInfo.mergeForCast(TypeBaseInfo); TBAAInfo = CGF.CGM.mergeTBAAInfoForCast(TBAAInfo, TypeTBAAInfo); - return Address(CGF.Builder.CreateLoad(BaseLVal.getAddress()), Align); + return Address(CGF.Builder.CreateLoad(BaseLVal.getAddress(CGF)), Align); } return CGF.EmitPointerWithAlignment(Base, &BaseInfo, &TBAAInfo); } @@ -3779,7 +3840,7 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, // Propagate the alignment from the array itself to the result. EltPtr = emitArraySubscriptGEP( - *this, ArrayLV.getAddress(), {CGM.getSize(CharUnits::Zero()), Idx}, + *this, ArrayLV.getAddress(*this), {CGM.getSize(CharUnits::Zero()), Idx}, ResultExprTy, !getLangOpts().isSignedOverflowDefined(), /*signedIndices=*/false, E->getExprLoc()); BaseInfo = ArrayLV.getBaseInfo(); @@ -3808,7 +3869,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; Address Ptr = EmitPointerWithAlignment(E->getBase(), &BaseInfo, &TBAAInfo); - const PointerType *PT = E->getBase()->getType()->getAs<PointerType>(); + const auto *PT = E->getBase()->getType()->castAs<PointerType>(); Base = MakeAddrLValue(Ptr, PT->getPointeeType(), BaseInfo, TBAAInfo); Base.getQuals().removeObjCGCAttr(); } else if (E->getBase()->isGLValue()) { @@ -3839,7 +3900,7 @@ EmitExtVectorElementExpr(const ExtVectorElementExpr *E) { if (Base.isSimple()) { llvm::Constant *CV = llvm::ConstantDataVector::get(getLLVMContext(), Indices); - return LValue::MakeExtVectorElt(Base.getAddress(), CV, type, + return LValue::MakeExtVectorElt(Base.getAddress(*this), CV, type, Base.getBaseInfo(), TBAAAccessInfo()); } assert(Base.isExtVectorElt() && "Can only subscript lvalue vec elts here!"); @@ -3884,6 +3945,15 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { if (auto *Field = dyn_cast<FieldDecl>(ND)) { LValue LV = EmitLValueForField(BaseLV, Field); setObjCGCLValueClass(getContext(), E, LV); + if (getLangOpts().OpenMP) { + // If the member was explicitly marked as nontemporal, mark it as + // nontemporal. If the base lvalue is marked as nontemporal, mark access + // to children as nontemporal too. + if ((IsWrappedCXXThis(BaseExpr) && + CGM.getOpenMPRuntime().isNontemporalDecl(Field)) || + BaseLV.isNontemporal()) + LV.setNontemporal(/*Value=*/true); + } return LV; } @@ -3990,14 +4060,15 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, const CGRecordLayout &RL = CGM.getTypes().getCGRecordLayout(field->getParent()); const CGBitFieldInfo &Info = RL.getBitFieldInfo(field); - Address Addr = base.getAddress(); + Address Addr = base.getAddress(*this); unsigned Idx = RL.getLLVMFieldNo(field); - if (!IsInPreservedAIRegion) { + const RecordDecl *rec = field->getParent(); + if (!IsInPreservedAIRegion && + (!getDebugInfo() || !rec->hasAttr<BPFPreserveAccessIndexAttr>())) { if (Idx != 0) // For structs, we GEP to the field that the record layout suggests. Addr = Builder.CreateStructGEP(Addr, Idx, field->getName()); } else { - const RecordDecl *rec = field->getParent(); llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateRecordType( getContext().getRecordType(rec), rec->getLocation()); Addr = Builder.CreatePreserveStructAccessIndex(Addr, Idx, @@ -4057,7 +4128,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, getContext().getTypeSizeInChars(FieldType).getQuantity(); } - Address addr = base.getAddress(); + Address addr = base.getAddress(*this); if (auto *ClassDef = dyn_cast<CXXRecordDecl>(rec)) { if (CGM.getCodeGenOpts().StrictVTablePointers && ClassDef->isDynamicClass()) { @@ -4080,7 +4151,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, addr = Address(Builder.CreateLaunderInvariantGroup(addr.getPointer()), addr.getAlignment()); - if (IsInPreservedAIRegion) { + if (IsInPreservedAIRegion || + (getDebugInfo() && rec->hasAttr<BPFPreserveAccessIndexAttr>())) { // Remember the original union field index llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateRecordType( getContext().getRecordType(rec), rec->getLocation()); @@ -4094,7 +4166,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, addr = Builder.CreateElementBitCast( addr, CGM.getTypes().ConvertTypeForMem(FieldType), field->getName()); } else { - if (!IsInPreservedAIRegion) + if (!IsInPreservedAIRegion && + (!getDebugInfo() || !rec->hasAttr<BPFPreserveAccessIndexAttr>())) // For structs, we GEP to the field that the record layout suggests. addr = emitAddrOfFieldStorage(*this, addr, field); else @@ -4143,7 +4216,7 @@ CodeGenFunction::EmitLValueForFieldInitialization(LValue Base, if (!FieldType->isReferenceType()) return EmitLValueForField(Base, Field); - Address V = emitAddrOfFieldStorage(*this, Base.getAddress(), Field); + Address V = emitAddrOfFieldStorage(*this, Base.getAddress(*this), Field); // Make sure that the address is pointing to the right type. llvm::Type *llvmType = ConvertTypeForMem(FieldType); @@ -4261,10 +4334,10 @@ EmitConditionalOperatorLValue(const AbstractConditionalOperator *expr) { EmitBlock(contBlock); if (lhs && rhs) { - llvm::PHINode *phi = Builder.CreatePHI(lhs->getPointer()->getType(), - 2, "cond-lvalue"); - phi->addIncoming(lhs->getPointer(), lhsBlock); - phi->addIncoming(rhs->getPointer(), rhsBlock); + llvm::PHINode *phi = + Builder.CreatePHI(lhs->getPointer(*this)->getType(), 2, "cond-lvalue"); + phi->addIncoming(lhs->getPointer(*this), lhsBlock); + phi->addIncoming(rhs->getPointer(*this), rhsBlock); Address result(phi, std::min(lhs->getAlignment(), rhs->getAlignment())); AlignmentSource alignSource = std::max(lhs->getBaseInfo().getAlignmentSource(), @@ -4347,7 +4420,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_Dynamic: { LValue LV = EmitLValue(E->getSubExpr()); - Address V = LV.getAddress(); + Address V = LV.getAddress(*this); const auto *DCE = cast<CXXDynamicCastExpr>(E); return MakeNaturalAlignAddrLValue(EmitDynamicCast(V, DCE), E->getType()); } @@ -4362,12 +4435,12 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { - const RecordType *DerivedClassTy = - E->getSubExpr()->getType()->getAs<RecordType>(); + const auto *DerivedClassTy = + E->getSubExpr()->getType()->castAs<RecordType>(); auto *DerivedClassDecl = cast<CXXRecordDecl>(DerivedClassTy->getDecl()); LValue LV = EmitLValue(E->getSubExpr()); - Address This = LV.getAddress(); + Address This = LV.getAddress(*this); // Perform the derived-to-base conversion Address Base = GetAddressOfBaseClass( @@ -4383,16 +4456,15 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_ToUnion: return EmitAggExprToLValue(E); case CK_BaseToDerived: { - const RecordType *DerivedClassTy = E->getType()->getAs<RecordType>(); + const auto *DerivedClassTy = E->getType()->castAs<RecordType>(); auto *DerivedClassDecl = cast<CXXRecordDecl>(DerivedClassTy->getDecl()); LValue LV = EmitLValue(E->getSubExpr()); // Perform the base-to-derived conversion - Address Derived = - GetAddressOfDerivedClass(LV.getAddress(), DerivedClassDecl, - E->path_begin(), E->path_end(), - /*NullCheckValue=*/false); + Address Derived = GetAddressOfDerivedClass( + LV.getAddress(*this), DerivedClassDecl, E->path_begin(), E->path_end(), + /*NullCheckValue=*/false); // C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is // performed and the object is not of the derived type. @@ -4414,7 +4486,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { CGM.EmitExplicitCastExprType(CE, this); LValue LV = EmitLValue(E->getSubExpr()); - Address V = Builder.CreateBitCast(LV.getAddress(), + Address V = Builder.CreateBitCast(LV.getAddress(*this), ConvertType(CE->getTypeAsWritten())); if (SanOpts.has(SanitizerKind::CFIUnrelatedCast)) @@ -4429,14 +4501,15 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { LValue LV = EmitLValue(E->getSubExpr()); QualType DestTy = getContext().getPointerType(E->getType()); llvm::Value *V = getTargetHooks().performAddrSpaceCast( - *this, LV.getPointer(), E->getSubExpr()->getType().getAddressSpace(), + *this, LV.getPointer(*this), + E->getSubExpr()->getType().getAddressSpace(), E->getType().getAddressSpace(), ConvertType(DestTy)); - return MakeAddrLValue(Address(V, LV.getAddress().getAlignment()), + return MakeAddrLValue(Address(V, LV.getAddress(*this).getAlignment()), E->getType(), LV.getBaseInfo(), LV.getTBAAInfo()); } case CK_ObjCObjectLValueCast: { LValue LV = EmitLValue(E->getSubExpr()); - Address V = Builder.CreateElementBitCast(LV.getAddress(), + Address V = Builder.CreateElementBitCast(LV.getAddress(*this), ConvertType(E->getType())); return MakeAddrLValue(V, E->getType(), LV.getBaseInfo(), CGM.getTBAAInfoForSubobject(LV, E->getType())); @@ -4490,13 +4563,17 @@ RValue CodeGenFunction::EmitRValueForField(LValue LV, case TEK_Complex: return RValue::getComplex(EmitLoadOfComplex(FieldLV, Loc)); case TEK_Aggregate: - return FieldLV.asAggregateRValue(); + return FieldLV.asAggregateRValue(*this); case TEK_Scalar: // This routine is used to load fields one-by-one to perform a copy, so // don't load reference fields. if (FD->getType()->isReferenceType()) - return RValue::get(FieldLV.getPointer()); - return EmitLoadOfLValue(FieldLV, Loc); + return RValue::get(FieldLV.getPointer(*this)); + // Call EmitLoadOfScalar except when the lvalue is a bitfield to emit a + // primitive load. + if (FieldLV.isBitField()) + return EmitLoadOfLValue(FieldLV, Loc); + return RValue::get(EmitLoadOfScalar(FieldLV, Loc)); } llvm_unreachable("bad evaluation kind"); } @@ -4544,8 +4621,15 @@ RValue CodeGenFunction::EmitSimpleCallExpr(const CallExpr *E, } static CGCallee EmitDirectCallee(CodeGenFunction &CGF, const FunctionDecl *FD) { + if (auto builtinID = FD->getBuiltinID()) { - return CGCallee::forBuiltin(builtinID, FD); + // Replaceable builtin provide their own implementation of a builtin. Unless + // we are in the builtin implementation itself, don't call the actual + // builtin. If we are in the builtin implementation, avoid trivial infinite + // recursion. + if (!FD->isInlineBuiltinDeclaration() || + CGF.CurFn->getName() == FD->getName()) + return CGCallee::forBuiltin(builtinID, FD); } llvm::Constant *calleePtr = EmitFunctionDeclPointer(CGF.CGM, FD); @@ -4590,7 +4674,7 @@ CGCallee CodeGenFunction::EmitCallee(const Expr *E) { functionType = ptrType->getPointeeType(); } else { functionType = E->getType(); - calleePtr = EmitLValue(E).getPointer(); + calleePtr = EmitLValue(E).getPointer(*this); } assert(functionType->isFunctionType()); @@ -4642,6 +4726,9 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { if (RV.isScalar()) EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc()); EmitStoreThroughLValue(RV, LV); + if (getLangOpts().OpenMP) + CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this, + E->getLHS()); return LV; } @@ -4750,7 +4837,7 @@ LValue CodeGenFunction::EmitObjCIvarRefLValue(const ObjCIvarRefExpr *E) { BaseQuals = ObjectTy.getQualifiers(); } else { LValue BaseLV = EmitLValue(BaseExpr); - BaseValue = BaseLV.getPointer(); + BaseValue = BaseLV.getPointer(*this); ObjectTy = BaseExpr->getType(); BaseQuals = ObjectTy.getQualifiers(); } @@ -4960,13 +5047,11 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) { if (E->getOpcode() == BO_PtrMemI) { BaseAddr = EmitPointerWithAlignment(E->getLHS()); } else { - BaseAddr = EmitLValue(E->getLHS()).getAddress(); + BaseAddr = EmitLValue(E->getLHS()).getAddress(*this); } llvm::Value *OffsetV = EmitScalarExpr(E->getRHS()); - - const MemberPointerType *MPT - = E->getRHS()->getType()->getAs<MemberPointerType>(); + const auto *MPT = E->getRHS()->getType()->castAs<MemberPointerType>(); LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; @@ -4987,7 +5072,7 @@ RValue CodeGenFunction::convertTempToRValue(Address addr, case TEK_Complex: return RValue::getComplex(EmitLoadOfComplex(lvalue, loc)); case TEK_Aggregate: - return lvalue.asAggregateRValue(); + return lvalue.asAggregateRValue(*this); case TEK_Scalar: return RValue::get(EmitLoadOfScalar(lvalue, loc)); } diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 2f0e4937613f..8de609a2ccd9 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -10,20 +10,21 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenFunction.h" #include "CGCXXABI.h" #include "CGObjCRuntime.h" +#include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/StmtVisitor.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" -#include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" using namespace clang; using namespace CodeGen; @@ -345,10 +346,9 @@ void AggExprEmitter::EmitFinalDestCopy(QualType type, const LValue &src, } } - AggValueSlot srcAgg = - AggValueSlot::forLValue(src, AggValueSlot::IsDestructed, - needsGC(type), AggValueSlot::IsAliased, - AggValueSlot::MayOverlap); + AggValueSlot srcAgg = AggValueSlot::forLValue( + src, CGF, AggValueSlot::IsDestructed, needsGC(type), + AggValueSlot::IsAliased, AggValueSlot::MayOverlap); EmitCopy(type, Dest, srcAgg); } @@ -386,7 +386,7 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { ASTContext &Ctx = CGF.getContext(); LValue Array = CGF.EmitLValue(E->getSubExpr()); assert(Array.isSimple() && "initializer_list array not a simple lvalue"); - Address ArrayPtr = Array.getAddress(); + Address ArrayPtr = Array.getAddress(CGF); const ConstantArrayType *ArrayType = Ctx.getAsConstantArrayType(E->getSubExpr()->getType()); @@ -493,7 +493,7 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, if (NumInitElements * elementSize.getQuantity() > 16 && elementType.isTriviallyCopyableType(CGF.getContext())) { CodeGen::CodeGenModule &CGM = CGF.CGM; - ConstantEmitter Emitter(CGM); + ConstantEmitter Emitter(CGF); LangAS AS = ArrayQTy.getAddressSpace(); if (llvm::Constant *C = Emitter.tryEmitForInitializer(E, AS, ArrayQTy)) { auto GV = new llvm::GlobalVariable( @@ -637,7 +637,7 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, //===----------------------------------------------------------------------===// void AggExprEmitter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E){ - Visit(E->GetTemporaryExpr()); + Visit(E->getSubExpr()); } void AggExprEmitter::VisitOpaqueValueExpr(OpaqueValueExpr *e) { @@ -688,7 +688,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { CodeGenFunction::TCK_Load); // FIXME: Do we also need to handle property references here? if (LV.isSimple()) - CGF.EmitDynamicCast(LV.getAddress(), cast<CXXDynamicCastExpr>(E)); + CGF.EmitDynamicCast(LV.getAddress(CGF), cast<CXXDynamicCastExpr>(E)); else CGF.CGM.ErrorUnsupported(E, "non-simple lvalue dynamic_cast"); @@ -723,7 +723,7 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { LValue SourceLV = CGF.EmitLValue(E->getSubExpr()); Address SourceAddress = - Builder.CreateElementBitCast(SourceLV.getAddress(), CGF.Int8Ty); + Builder.CreateElementBitCast(SourceLV.getAddress(CGF), CGF.Int8Ty); Address DestAddress = Builder.CreateElementBitCast(Dest.getAddress(), CGF.Int8Ty); llvm::Value *SizeVal = llvm::ConstantInt::get( @@ -981,10 +981,6 @@ void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) { QualType ArgTy = E->getLHS()->getType(); - // TODO: Handle comparing these types. - if (ArgTy->isVectorType()) - return CGF.ErrorUnsupported( - E, "aggregate three-way comparison with vector arguments"); if (!ArgTy->isIntegralOrEnumerationType() && !ArgTy->isRealFloatingType() && !ArgTy->isNullPtrType() && !ArgTy->isPointerType() && !ArgTy->isMemberPointerType() && !ArgTy->isAnyComplexType()) { @@ -1022,10 +1018,6 @@ void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) { Value *Select; if (ArgTy->isNullPtrType()) { Select = EmitCmpRes(CmpInfo.getEqualOrEquiv()); - } else if (CmpInfo.isEquality()) { - Select = Builder.CreateSelect( - EmitCmp(CK_Equal), EmitCmpRes(CmpInfo.getEqualOrEquiv()), - EmitCmpRes(CmpInfo.getNonequalOrNonequiv()), "sel.eq"); } else if (!CmpInfo.isPartial()) { Value *SelectOne = Builder.CreateSelect(EmitCmp(CK_Less), EmitCmpRes(CmpInfo.getLess()), @@ -1163,7 +1155,7 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { } EmitCopy(E->getLHS()->getType(), - AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed, + AggValueSlot::forLValue(LHS, CGF, AggValueSlot::IsDestructed, needsGC(E->getLHS()->getType()), AggValueSlot::IsAliased, AggValueSlot::MayOverlap), @@ -1184,11 +1176,9 @@ void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) { } // Codegen the RHS so that it stores directly into the LHS. - AggValueSlot LHSSlot = - AggValueSlot::forLValue(LHS, AggValueSlot::IsDestructed, - needsGC(E->getLHS()->getType()), - AggValueSlot::IsAliased, - AggValueSlot::MayOverlap); + AggValueSlot LHSSlot = AggValueSlot::forLValue( + LHS, CGF, AggValueSlot::IsDestructed, needsGC(E->getLHS()->getType()), + AggValueSlot::IsAliased, AggValueSlot::MayOverlap); // A non-volatile aggregate destination might have volatile member. if (!LHSSlot.isVolatile() && CGF.hasVolatileMember(E->getLHS()->getType())) @@ -1320,7 +1310,7 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) { llvm::Constant::getNullValue(CGF.Int8PtrTy), CharUnits::One()); // placeholder - CGF.pushDestroy(EHCleanup, LV.getAddress(), CurField->getType(), + CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), CurField->getType(), CGF.getDestroyer(DtorKind), false); Cleanups.push_back(CGF.EHStack.stable_begin()); } @@ -1408,12 +1398,11 @@ AggExprEmitter::EmitInitializationToLValue(Expr *E, LValue LV) { CGF.EmitComplexExprIntoLValue(E, LV, /*isInit*/ true); return; case TEK_Aggregate: - CGF.EmitAggExpr(E, AggValueSlot::forLValue(LV, - AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased, - AggValueSlot::MayOverlap, - Dest.isZeroed())); + CGF.EmitAggExpr( + E, AggValueSlot::forLValue(LV, CGF, AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased, + AggValueSlot::MayOverlap, Dest.isZeroed())); return; case TEK_Scalar: if (LV.isSimple()) { @@ -1449,7 +1438,7 @@ void AggExprEmitter::EmitNullInitializationToLValue(LValue lv) { // There's a potential optimization opportunity in combining // memsets; that would be easy for arrays, but relatively // difficult for structures with the current code. - CGF.EmitNullInitialization(lv.getAddress(), lv.getType()); + CGF.EmitNullInitialization(lv.getAddress(CGF), lv.getType()); } } @@ -1606,7 +1595,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { = field->getType().isDestructedType()) { assert(LV.isSimple()); if (CGF.needsEHCleanup(dtorKind)) { - CGF.pushDestroy(EHCleanup, LV.getAddress(), field->getType(), + CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), field->getType(), CGF.getDestroyer(dtorKind), false); addCleanup(CGF.EHStack.stable_begin()); pushedCleanup = true; @@ -1617,7 +1606,7 @@ void AggExprEmitter::VisitInitListExpr(InitListExpr *E) { // else, clean it up for -O0 builds and general tidiness. if (!pushedCleanup && LV.isSimple()) if (llvm::GetElementPtrInst *GEP = - dyn_cast<llvm::GetElementPtrInst>(LV.getPointer())) + dyn_cast<llvm::GetElementPtrInst>(LV.getPointer(CGF))) if (GEP->use_empty()) GEP->eraseFromParent(); } @@ -1699,9 +1688,8 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E, if (InnerLoop) { // If the subexpression is an ArrayInitLoopExpr, share its cleanup. auto elementSlot = AggValueSlot::forLValue( - elementLV, AggValueSlot::IsDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased, + elementLV, CGF, AggValueSlot::IsDestructed, + AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap); AggExprEmitter(CGF, elementSlot, false) .VisitArrayInitLoopExpr(InnerLoop, outerBegin); @@ -1864,10 +1852,10 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) { assert(hasAggregateEvaluationKind(E->getType()) && "Invalid argument!"); Address Temp = CreateMemTemp(E->getType()); LValue LV = MakeAddrLValue(Temp, E->getType()); - EmitAggExpr(E, AggValueSlot::forLValue(LV, AggValueSlot::IsNotDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased, - AggValueSlot::DoesNotOverlap)); + EmitAggExpr(E, AggValueSlot::forLValue( + LV, *this, AggValueSlot::IsNotDestructed, + AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap)); return LV; } @@ -1916,8 +1904,8 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, LValue Src, QualType Ty, bool isVolatile) { assert(!Ty->isAnyComplexType() && "Shouldn't happen for complex"); - Address DestPtr = Dest.getAddress(); - Address SrcPtr = Src.getAddress(); + Address DestPtr = Dest.getAddress(*this); + Address SrcPtr = Src.getAddress(*this); if (getLangOpts().CPlusPlus) { if (const RecordType *RT = Ty->getAs<RecordType>()) { diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 114d806d454b..42c1c34c57ad 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -129,11 +129,11 @@ RValue CodeGenFunction::EmitCXXPseudoDestructorExpr( // If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar. if (E->isArrow()) { BaseValue = EmitPointerWithAlignment(BaseExpr); - const PointerType *PTy = BaseExpr->getType()->getAs<PointerType>(); + const auto *PTy = BaseExpr->getType()->castAs<PointerType>(); BaseQuals = PTy->getPointeeType().getQualifiers(); } else { LValue BaseLV = EmitLValue(BaseExpr); - BaseValue = BaseLV.getAddress(); + BaseValue = BaseLV.getAddress(*this); QualType BaseTy = BaseExpr->getType(); BaseQuals = BaseTy.getQualifiers(); } @@ -241,16 +241,28 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( } } + bool TrivialForCodegen = + MD->isTrivial() || (MD->isDefaulted() && MD->getParent()->isUnion()); + bool TrivialAssignment = + TrivialForCodegen && + (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) && + !MD->getParent()->mayInsertExtraPadding(); + // C++17 demands that we evaluate the RHS of a (possibly-compound) assignment // operator before the LHS. CallArgList RtlArgStorage; CallArgList *RtlArgs = nullptr; + LValue TrivialAssignmentRHS; if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(CE)) { if (OCE->isAssignmentOp()) { - RtlArgs = &RtlArgStorage; - EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(), - drop_begin(CE->arguments(), 1), CE->getDirectCallee(), - /*ParamsToSkip*/0, EvaluationOrder::ForceRightToLeft); + if (TrivialAssignment) { + TrivialAssignmentRHS = EmitLValue(CE->getArg(1)); + } else { + RtlArgs = &RtlArgStorage; + EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(), + drop_begin(CE->arguments(), 1), CE->getDirectCallee(), + /*ParamsToSkip*/0, EvaluationOrder::ForceRightToLeft); + } } } @@ -271,32 +283,35 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( assert(ReturnValue.isNull() && "Constructor shouldn't have return value"); CallArgList Args; commonEmitCXXMemberOrOperatorCall( - *this, Ctor, This.getPointer(), /*ImplicitParam=*/nullptr, + *this, Ctor, This.getPointer(*this), /*ImplicitParam=*/nullptr, /*ImplicitParamTy=*/QualType(), CE, Args, nullptr); EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false, - /*Delegating=*/false, This.getAddress(), Args, + /*Delegating=*/false, This.getAddress(*this), Args, AggValueSlot::DoesNotOverlap, CE->getExprLoc(), /*NewPointerIsChecked=*/false); return RValue::get(nullptr); } - if (MD->isTrivial() || (MD->isDefaulted() && MD->getParent()->isUnion())) { - if (isa<CXXDestructorDecl>(MD)) return RValue::get(nullptr); - if (!MD->getParent()->mayInsertExtraPadding()) { - if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) { - // We don't like to generate the trivial copy/move assignment operator - // when it isn't necessary; just produce the proper effect here. - LValue RHS = isa<CXXOperatorCallExpr>(CE) - ? MakeNaturalAlignAddrLValue( - (*RtlArgs)[0].getRValue(*this).getScalarVal(), - (*(CE->arg_begin() + 1))->getType()) - : EmitLValue(*CE->arg_begin()); - EmitAggregateAssign(This, RHS, CE->getType()); - return RValue::get(This.getPointer()); - } - llvm_unreachable("unknown trivial member function"); + if (TrivialForCodegen) { + if (isa<CXXDestructorDecl>(MD)) + return RValue::get(nullptr); + + if (TrivialAssignment) { + // We don't like to generate the trivial copy/move assignment operator + // when it isn't necessary; just produce the proper effect here. + // It's important that we use the result of EmitLValue here rather than + // emitting call arguments, in order to preserve TBAA information from + // the RHS. + LValue RHS = isa<CXXOperatorCallExpr>(CE) + ? TrivialAssignmentRHS + : EmitLValue(*CE->arg_begin()); + EmitAggregateAssign(This, RHS, CE->getType()); + return RValue::get(This.getPointer(*this)); } + + assert(MD->getParent()->mayInsertExtraPadding() && + "unknown trivial member function"); } // Compute the function type we're calling. @@ -328,7 +343,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( if (IsImplicitObjectCXXThis || isa<DeclRefExpr>(IOA)) SkippedChecks.set(SanitizerKind::Null, true); } - EmitTypeCheck(CodeGenFunction::TCK_MemberCall, CallLoc, This.getPointer(), + EmitTypeCheck(CodeGenFunction::TCK_MemberCall, CallLoc, + This.getPointer(*this), C.getRecordType(CalleeDecl->getParent()), /*Alignment=*/CharUnits::Zero(), SkippedChecks); @@ -345,9 +361,9 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( "Destructor shouldn't have explicit parameters"); assert(ReturnValue.isNull() && "Destructor shouldn't have return value"); if (UseVirtualCall) { - CGM.getCXXABI().EmitVirtualDestructorCall( - *this, Dtor, Dtor_Complete, This.getAddress(), - cast<CXXMemberCallExpr>(CE)); + CGM.getCXXABI().EmitVirtualDestructorCall(*this, Dtor, Dtor_Complete, + This.getAddress(*this), + cast<CXXMemberCallExpr>(CE)); } else { GlobalDecl GD(Dtor, Dtor_Complete); CGCallee Callee; @@ -362,7 +378,7 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( QualType ThisTy = IsArrow ? Base->getType()->getPointeeType() : Base->getType(); - EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, + EmitCXXDestructorCall(GD, Callee, This.getPointer(*this), ThisTy, /*ImplicitParam=*/nullptr, /*ImplicitParamTy=*/QualType(), nullptr); } @@ -374,15 +390,14 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( CGCallee Callee; if (UseVirtualCall) { - Callee = CGCallee::forVirtual(CE, MD, This.getAddress(), Ty); + Callee = CGCallee::forVirtual(CE, MD, This.getAddress(*this), Ty); } else { if (SanOpts.has(SanitizerKind::CFINVCall) && MD->getParent()->isDynamicClass()) { llvm::Value *VTable; const CXXRecordDecl *RD; - std::tie(VTable, RD) = - CGM.getCXXABI().LoadVTablePtr(*this, This.getAddress(), - CalleeDecl->getParent()); + std::tie(VTable, RD) = CGM.getCXXABI().LoadVTablePtr( + *this, This.getAddress(*this), CalleeDecl->getParent()); EmitVTablePtrCheckForCall(RD, VTable, CFITCK_NVCall, CE->getBeginLoc()); } @@ -401,12 +416,12 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( if (MD->isVirtual()) { Address NewThisAddr = CGM.getCXXABI().adjustThisArgumentForVirtualFunctionCall( - *this, CalleeDecl, This.getAddress(), UseVirtualCall); + *this, CalleeDecl, This.getAddress(*this), UseVirtualCall); This.setAddress(NewThisAddr); } return EmitCXXMemberOrOperatorCall( - CalleeDecl, Callee, ReturnValue, This.getPointer(), + CalleeDecl, Callee, ReturnValue, This.getPointer(*this), /*ImplicitParam=*/nullptr, QualType(), CE, RtlArgs); } @@ -428,7 +443,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, if (BO->getOpcode() == BO_PtrMemI) This = EmitPointerWithAlignment(BaseExpr); else - This = EmitLValue(BaseExpr).getAddress(); + This = EmitLValue(BaseExpr).getAddress(*this); EmitTypeCheck(TCK_MemberCall, E->getExprLoc(), This.getPointer(), QualType(MPT->getClass(), 0)); @@ -1412,8 +1427,7 @@ namespace { } void Emit(CodeGenFunction &CGF, Flags flags) override { - const FunctionProtoType *FPT = - OperatorDelete->getType()->getAs<FunctionProtoType>(); + const auto *FPT = OperatorDelete->getType()->castAs<FunctionProtoType>(); CallArgList DeleteArgs; // The first argument is always a void* (or C* for a destroying operator @@ -1755,9 +1769,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD, assert((!NumElements && CookieSize.isZero()) || DeleteFD->getOverloadedOperator() == OO_Array_Delete); - const FunctionProtoType *DeleteFTy = - DeleteFD->getType()->getAs<FunctionProtoType>(); - + const auto *DeleteFTy = DeleteFD->getType()->castAs<FunctionProtoType>(); CallArgList DeleteArgs; auto Params = getUsualDeleteParams(DeleteFD); @@ -2103,7 +2115,7 @@ static bool isGLValueFromPointerDeref(const Expr *E) { static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E, llvm::Type *StdTypeInfoPtrTy) { // Get the vtable pointer. - Address ThisPtr = CGF.EmitLValue(E).getAddress(); + Address ThisPtr = CGF.EmitLValue(E).getAddress(CGF); QualType SrcRecordTy = E->getType(); diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index 385f87f12a9b..f7a4e9e94712 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "CGOpenMPRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/AST/StmtVisitor.h" @@ -348,7 +349,7 @@ ComplexPairTy ComplexExprEmitter::EmitLoadOfLValue(LValue lvalue, if (lvalue.getType()->isAtomicType()) return CGF.EmitAtomicLoad(lvalue, loc).getComplexVal(); - Address SrcPtr = lvalue.getAddress(); + Address SrcPtr = lvalue.getAddress(CGF); bool isVolatile = lvalue.isVolatileQualified(); llvm::Value *Real = nullptr, *Imag = nullptr; @@ -374,7 +375,7 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy Val, LValue lvalue, (!isInit && CGF.LValueIsSuitableForInlineAtomic(lvalue))) return CGF.EmitAtomicStore(RValue::getComplex(Val), lvalue, isInit); - Address Ptr = lvalue.getAddress(); + Address Ptr = lvalue.getAddress(CGF); Address RealPtr = CGF.emitAddrOfRealComponent(Ptr, lvalue.getType()); Address ImagPtr = CGF.emitAddrOfImagComponent(Ptr, lvalue.getType()); @@ -463,14 +464,14 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op, case CK_LValueBitCast: { LValue origLV = CGF.EmitLValue(Op); - Address V = origLV.getAddress(); + Address V = origLV.getAddress(CGF); V = Builder.CreateElementBitCast(V, CGF.ConvertType(DestTy)); return EmitLoadOfLValue(CGF.MakeAddrLValue(V, DestTy), Op->getExprLoc()); } case CK_LValueToRValueBitCast: { LValue SourceLVal = CGF.EmitLValue(Op); - Address Addr = Builder.CreateElementBitCast(SourceLVal.getAddress(), + Address Addr = Builder.CreateElementBitCast(SourceLVal.getAddress(CGF), CGF.ConvertTypeForMem(DestTy)); LValue DestLV = CGF.MakeAddrLValue(Addr, DestTy); DestLV.setTBAAInfo(TBAAAccessInfo::getMayAliasInfo()); @@ -1136,7 +1137,11 @@ ComplexPairTy CodeGenFunction::EmitLoadOfComplex(LValue src, LValue CodeGenFunction::EmitComplexAssignmentLValue(const BinaryOperator *E) { assert(E->getOpcode() == BO_Assign); ComplexPairTy Val; // ignored - return ComplexExprEmitter(*this).EmitBinAssignLValue(E, Val); + LValue LVal = ComplexExprEmitter(*this).EmitBinAssignLValue(E, Val); + if (getLangOpts().OpenMP) + CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this, + E->getLHS()); + return LVal; } typedef ComplexPairTy (ComplexExprEmitter::*CompoundFunc)( diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 96e8c9c0d0e6..46ed90a20264 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -10,20 +10,21 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenFunction.h" #include "CGCXXABI.h" #include "CGObjCRuntime.h" #include "CGRecordLayout.h" +#include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" #include "TargetInfo.h" #include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" -#include "llvm/ADT/Sequence.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Sequence.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" @@ -1173,7 +1174,7 @@ public: llvm::Constant *VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E, QualType T) { - return Visit(E->GetTemporaryExpr(), T); + return Visit(E->getSubExpr(), T); } llvm::Constant *EmitArrayInitialization(InitListExpr *ILE, QualType T) { @@ -1728,7 +1729,7 @@ struct ConstantLValue { /*implicit*/ ConstantLValue(llvm::Constant *value, bool hasOffsetApplied = false) - : Value(value), HasOffsetApplied(false) {} + : Value(value), HasOffsetApplied(hasOffsetApplied) {} /*implicit*/ ConstantLValue(ConstantAddress address) : ConstantLValue(address.getPointer()) {} @@ -2003,8 +2004,8 @@ ConstantLValueEmitter::VisitMaterializeTemporaryExpr( assert(E->getStorageDuration() == SD_Static); SmallVector<const Expr *, 2> CommaLHSs; SmallVector<SubobjectAdjustment, 2> Adjustments; - const Expr *Inner = E->GetTemporaryExpr() - ->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); + const Expr *Inner = + E->getSubExpr()->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments); return CGM.GetAddrOfGlobalTemporary(E, Inner); } diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 55a413a2a717..3f23fe11e4f5 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -14,11 +14,13 @@ #include "CGCleanup.h" #include "CGDebugInfo.h" #include "CGObjCRuntime.h" +#include "CGOpenMPRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/RecordLayout.h" @@ -34,6 +36,7 @@ #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsPowerPC.h" #include "llvm/IR/Module.h" #include <cstdarg> @@ -615,7 +618,7 @@ public: if (isa<MemberPointerType>(E->getType())) // never sugared return CGF.CGM.getMemberPointerConstant(E); - return EmitLValue(E->getSubExpr()).getPointer(); + return EmitLValue(E->getSubExpr()).getPointer(CGF); } Value *VisitUnaryDeref(const UnaryOperator *E) { if (E->getType()->isVoidType()) @@ -644,8 +647,8 @@ public: auto &Ctx = CGF.getContext(); APValue Evaluated = SLE->EvaluateInContext(Ctx, CGF.CurSourceLocExprScope.getDefaultExpr()); - return ConstantEmitter(CGF.CGM, &CGF) - .emitAbstract(SLE->getLocation(), Evaluated, SLE->getType()); + return ConstantEmitter(CGF).emitAbstract(SLE->getLocation(), Evaluated, + SLE->getType()); } Value *VisitCXXDefaultArgExpr(CXXDefaultArgExpr *DAE) { @@ -795,17 +798,17 @@ public: // Comparisons. Value *EmitCompare(const BinaryOperator *E, llvm::CmpInst::Predicate UICmpOpc, llvm::CmpInst::Predicate SICmpOpc, - llvm::CmpInst::Predicate FCmpOpc); -#define VISITCOMP(CODE, UI, SI, FP) \ + llvm::CmpInst::Predicate FCmpOpc, bool IsSignaling); +#define VISITCOMP(CODE, UI, SI, FP, SIG) \ Value *VisitBin##CODE(const BinaryOperator *E) { \ return EmitCompare(E, llvm::ICmpInst::UI, llvm::ICmpInst::SI, \ - llvm::FCmpInst::FP); } - VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT) - VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT) - VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE) - VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE) - VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ) - VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE) + llvm::FCmpInst::FP, SIG); } + VISITCOMP(LT, ICMP_ULT, ICMP_SLT, FCMP_OLT, true) + VISITCOMP(GT, ICMP_UGT, ICMP_SGT, FCMP_OGT, true) + VISITCOMP(LE, ICMP_ULE, ICMP_SLE, FCMP_OLE, true) + VISITCOMP(GE, ICMP_UGE, ICMP_SGE, FCMP_OGE, true) + VISITCOMP(EQ, ICMP_EQ , ICMP_EQ , FCMP_OEQ, false) + VISITCOMP(NE, ICMP_NE , ICMP_NE , FCMP_UNE, false) #undef VISITCOMP Value *VisitBinAssign (const BinaryOperator *E); @@ -976,6 +979,11 @@ EmitIntegerTruncationCheckHelper(Value *Src, QualType SrcType, Value *Dst, return std::make_pair(Kind, std::make_pair(Check, Mask)); } +static bool PromotionIsPotentiallyEligibleForImplicitIntegerConversionCheck( + QualType SrcType, QualType DstType) { + return SrcType->isIntegerType() && DstType->isIntegerType(); +} + void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType, Value *Dst, QualType DstType, SourceLocation Loc) { @@ -984,7 +992,8 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType, // We only care about int->int conversions here. // We ignore conversions to/from pointer and/or bool. - if (!(SrcType->isIntegerType() && DstType->isIntegerType())) + if (!PromotionIsPotentiallyEligibleForImplicitIntegerConversionCheck(SrcType, + DstType)) return; unsigned SrcBits = Src->getType()->getScalarSizeInBits(); @@ -1095,7 +1104,8 @@ void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType, // We only care about int->int conversions here. // We ignore conversions to/from pointer and/or bool. - if (!(SrcType->isIntegerType() && DstType->isIntegerType())) + if (!PromotionIsPotentiallyEligibleForImplicitIntegerConversionCheck(SrcType, + DstType)) return; bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType(); @@ -1972,7 +1982,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { case CK_LValueBitCast: case CK_ObjCObjectLValueCast: { - Address Addr = EmitLValue(E).getAddress(); + Address Addr = EmitLValue(E).getAddress(CGF); Addr = Builder.CreateElementBitCast(Addr, CGF.ConvertTypeForMem(DestTy)); LValue LV = CGF.MakeAddrLValue(Addr, DestTy); return EmitLoadOfLValue(LV, CE->getExprLoc()); @@ -1980,7 +1990,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { case CK_LValueToRValueBitCast: { LValue SourceLVal = CGF.EmitLValue(E); - Address Addr = Builder.CreateElementBitCast(SourceLVal.getAddress(), + Address Addr = Builder.CreateElementBitCast(SourceLVal.getAddress(CGF), CGF.ConvertTypeForMem(DestTy)); LValue DestLV = CGF.MakeAddrLValue(Addr, DestTy); DestLV.setTBAAInfo(TBAAAccessInfo::getMayAliasInfo()); @@ -2098,7 +2108,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { case CK_ArrayToPointerDecay: return CGF.EmitArrayToPointerDecay(E).getPointer(); case CK_FunctionToPointerDecay: - return EmitLValue(E).getPointer(); + return EmitLValue(E).getPointer(CGF); case CK_NullToPointer: if (MustVisitNullValue(E)) @@ -2346,10 +2356,29 @@ llvm::Value *ScalarExprEmitter::EmitIncDecConsiderOverflowBehavior( llvm_unreachable("Unknown SignedOverflowBehaviorTy"); } +namespace { +/// Handles check and update for lastprivate conditional variables. +class OMPLastprivateConditionalUpdateRAII { +private: + CodeGenFunction &CGF; + const UnaryOperator *E; + +public: + OMPLastprivateConditionalUpdateRAII(CodeGenFunction &CGF, + const UnaryOperator *E) + : CGF(CGF), E(E) {} + ~OMPLastprivateConditionalUpdateRAII() { + if (CGF.getLangOpts().OpenMP) + CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional( + CGF, E->getSubExpr()); + } +}; +} // namespace + llvm::Value * ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, bool isInc, bool isPre) { - + OMPLastprivateConditionalUpdateRAII OMPRegion(CGF, E); QualType type = E->getSubExpr()->getType(); llvm::PHINode *atomicPHI = nullptr; llvm::Value *value; @@ -2363,14 +2392,14 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, if (isInc && type->isBooleanType()) { llvm::Value *True = CGF.EmitToMemory(Builder.getTrue(), type); if (isPre) { - Builder.CreateStore(True, LV.getAddress(), LV.isVolatileQualified()) - ->setAtomic(llvm::AtomicOrdering::SequentiallyConsistent); + Builder.CreateStore(True, LV.getAddress(CGF), LV.isVolatileQualified()) + ->setAtomic(llvm::AtomicOrdering::SequentiallyConsistent); return Builder.getTrue(); } // For atomic bool increment, we just store true and return it for // preincrement, do an atomic swap with true for postincrement return Builder.CreateAtomicRMW( - llvm::AtomicRMWInst::Xchg, LV.getPointer(), True, + llvm::AtomicRMWInst::Xchg, LV.getPointer(CGF), True, llvm::AtomicOrdering::SequentiallyConsistent); } // Special case for atomic increment / decrement on integers, emit @@ -2387,8 +2416,9 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, llvm::Instruction::Sub; llvm::Value *amt = CGF.EmitToMemory( llvm::ConstantInt::get(ConvertType(type), 1, true), type); - llvm::Value *old = Builder.CreateAtomicRMW(aop, - LV.getPointer(), amt, llvm::AtomicOrdering::SequentiallyConsistent); + llvm::Value *old = + Builder.CreateAtomicRMW(aop, LV.getPointer(CGF), amt, + llvm::AtomicOrdering::SequentiallyConsistent); return isPre ? Builder.CreateBinOp(op, old, amt) : old; } value = EmitLoadOfLValue(LV, E->getExprLoc()); @@ -2419,9 +2449,51 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, // Most common case by far: integer increment. } else if (type->isIntegerType()) { - // Note that signed integer inc/dec with width less than int can't - // overflow because of promotion rules; we're just eliding a few steps here. - if (E->canOverflow() && type->isSignedIntegerOrEnumerationType()) { + QualType promotedType; + bool canPerformLossyDemotionCheck = false; + if (type->isPromotableIntegerType()) { + promotedType = CGF.getContext().getPromotedIntegerType(type); + assert(promotedType != type && "Shouldn't promote to the same type."); + canPerformLossyDemotionCheck = true; + canPerformLossyDemotionCheck &= + CGF.getContext().getCanonicalType(type) != + CGF.getContext().getCanonicalType(promotedType); + canPerformLossyDemotionCheck &= + PromotionIsPotentiallyEligibleForImplicitIntegerConversionCheck( + type, promotedType); + assert((!canPerformLossyDemotionCheck || + type->isSignedIntegerOrEnumerationType() || + promotedType->isSignedIntegerOrEnumerationType() || + ConvertType(type)->getScalarSizeInBits() == + ConvertType(promotedType)->getScalarSizeInBits()) && + "The following check expects that if we do promotion to different " + "underlying canonical type, at least one of the types (either " + "base or promoted) will be signed, or the bitwidths will match."); + } + if (CGF.SanOpts.hasOneOf( + SanitizerKind::ImplicitIntegerArithmeticValueChange) && + canPerformLossyDemotionCheck) { + // While `x += 1` (for `x` with width less than int) is modeled as + // promotion+arithmetics+demotion, and we can catch lossy demotion with + // ease; inc/dec with width less than int can't overflow because of + // promotion rules, so we omit promotion+demotion, which means that we can + // not catch lossy "demotion". Because we still want to catch these cases + // when the sanitizer is enabled, we perform the promotion, then perform + // the increment/decrement in the wider type, and finally + // perform the demotion. This will catch lossy demotions. + + value = EmitScalarConversion(value, type, promotedType, E->getExprLoc()); + Value *amt = llvm::ConstantInt::get(value->getType(), amount, true); + value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); + // Do pass non-default ScalarConversionOpts so that sanitizer check is + // emitted. + value = EmitScalarConversion(value, promotedType, type, E->getExprLoc(), + ScalarConversionOpts(CGF.SanOpts)); + + // Note that signed integer inc/dec with width less than int can't + // overflow because of promotion rules; we're just eliding a few steps + // here. + } else if (E->canOverflow() && type->isSignedIntegerOrEnumerationType()) { value = EmitIncDecConsiderOverflowBehavior(E, value, isInc); } else if (E->canOverflow() && type->isUnsignedIntegerType() && CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) { @@ -2849,7 +2921,8 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue( CGF.SanOpts.has(SanitizerKind::UnsignedIntegerOverflow)) && CGF.getLangOpts().getSignedOverflowBehavior() != LangOptions::SOB_Trapping) { - llvm::AtomicRMWInst::BinOp aop = llvm::AtomicRMWInst::BAD_BINOP; + llvm::AtomicRMWInst::BinOp AtomicOp = llvm::AtomicRMWInst::BAD_BINOP; + llvm::Instruction::BinaryOps Op; switch (OpInfo.Opcode) { // We don't have atomicrmw operands for *, %, /, <<, >> case BO_MulAssign: case BO_DivAssign: @@ -2858,30 +2931,40 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue( case BO_ShrAssign: break; case BO_AddAssign: - aop = llvm::AtomicRMWInst::Add; + AtomicOp = llvm::AtomicRMWInst::Add; + Op = llvm::Instruction::Add; break; case BO_SubAssign: - aop = llvm::AtomicRMWInst::Sub; + AtomicOp = llvm::AtomicRMWInst::Sub; + Op = llvm::Instruction::Sub; break; case BO_AndAssign: - aop = llvm::AtomicRMWInst::And; + AtomicOp = llvm::AtomicRMWInst::And; + Op = llvm::Instruction::And; break; case BO_XorAssign: - aop = llvm::AtomicRMWInst::Xor; + AtomicOp = llvm::AtomicRMWInst::Xor; + Op = llvm::Instruction::Xor; break; case BO_OrAssign: - aop = llvm::AtomicRMWInst::Or; + AtomicOp = llvm::AtomicRMWInst::Or; + Op = llvm::Instruction::Or; break; default: llvm_unreachable("Invalid compound assignment type"); } - if (aop != llvm::AtomicRMWInst::BAD_BINOP) { - llvm::Value *amt = CGF.EmitToMemory( + if (AtomicOp != llvm::AtomicRMWInst::BAD_BINOP) { + llvm::Value *Amt = CGF.EmitToMemory( EmitScalarConversion(OpInfo.RHS, E->getRHS()->getType(), LHSTy, E->getExprLoc()), LHSTy); - Builder.CreateAtomicRMW(aop, LHSLV.getPointer(), amt, + Value *OldVal = Builder.CreateAtomicRMW( + AtomicOp, LHSLV.getPointer(CGF), Amt, llvm::AtomicOrdering::SequentiallyConsistent); + + // Since operation is atomic, the result type is guaranteed to be the + // same as the input in LLVM terms. + Result = Builder.CreateBinOp(Op, OldVal, Amt); return LHSLV; } } @@ -2934,6 +3017,9 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue( else CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV); + if (CGF.getLangOpts().OpenMP) + CGF.CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(CGF, + E->getLHS()); return LHSLV; } @@ -3201,10 +3287,10 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, expr->getRHS())) return CGF.Builder.CreateIntToPtr(index, pointer->getType()); - if (width != DL.getTypeSizeInBits(PtrTy)) { + if (width != DL.getIndexTypeSizeInBits(PtrTy)) { // Zero-extend or sign-extend the pointer value according to // whether the index is signed or not. - index = CGF.Builder.CreateIntCast(index, DL.getIntPtrType(PtrTy), isSigned, + index = CGF.Builder.CreateIntCast(index, DL.getIndexType(PtrTy), isSigned, "idx.ext"); } @@ -3258,7 +3344,7 @@ static Value *emitPointerArithmetic(CodeGenFunction &CGF, // GNU void* casts amount to no-ops since our void* type is i8*, but this is // future proof. if (elementType->isVoidType() || elementType->isFunctionType()) { - Value *result = CGF.Builder.CreateBitCast(pointer, CGF.VoidPtrTy); + Value *result = CGF.EmitCastToVoidPtr(pointer); result = CGF.Builder.CreateGEP(result, index, "add.ptr"); return CGF.Builder.CreateBitCast(result, pointer->getType()); } @@ -3282,17 +3368,10 @@ static Value* buildFMulAdd(llvm::BinaryOperator *MulOp, Value *Addend, Value *MulOp0 = MulOp->getOperand(0); Value *MulOp1 = MulOp->getOperand(1); - if (negMul) { - MulOp0 = - Builder.CreateFSub( - llvm::ConstantFP::getZeroValueForNegation(MulOp0->getType()), MulOp0, - "neg"); - } else if (negAdd) { - Addend = - Builder.CreateFSub( - llvm::ConstantFP::getZeroValueForNegation(Addend->getType()), Addend, - "neg"); - } + if (negMul) + MulOp0 = Builder.CreateFNeg(MulOp0, "neg"); + if (negAdd) + Addend = Builder.CreateFNeg(Addend, "neg"); Value *FMulAdd = Builder.CreateCall( CGF.CGM.getIntrinsic(llvm::Intrinsic::fmuladd, Addend->getType()), @@ -3725,7 +3804,8 @@ static llvm::Intrinsic::ID GetIntrinsic(IntrinsicType IT, Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E, llvm::CmpInst::Predicate UICmpOpc, llvm::CmpInst::Predicate SICmpOpc, - llvm::CmpInst::Predicate FCmpOpc) { + llvm::CmpInst::Predicate FCmpOpc, + bool IsSignaling) { TestAndClearIgnoreResultAssign(); Value *Result; QualType LHSTy = E->getLHS()->getType(); @@ -3755,8 +3835,7 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E, *SecondVecArg = RHS; QualType ElTy = LHSTy->castAs<VectorType>()->getElementType(); - const BuiltinType *BTy = ElTy->getAs<BuiltinType>(); - BuiltinType::Kind ElementKind = BTy->getKind(); + BuiltinType::Kind ElementKind = ElTy->castAs<BuiltinType>()->getKind(); switch(E->getOpcode()) { default: llvm_unreachable("is not a comparison operation"); @@ -3821,7 +3900,10 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E, if (BOInfo.isFixedPointBinOp()) { Result = EmitFixedPointBinOp(BOInfo); } else if (LHS->getType()->isFPOrFPVectorTy()) { - Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp"); + if (!IsSignaling) + Result = Builder.CreateFCmp(FCmpOpc, LHS, RHS, "cmp"); + else + Result = Builder.CreateFCmpS(FCmpOpc, LHS, RHS, "cmp"); } else if (LHSTy->hasSignedIntegerRepresentation()) { Result = Builder.CreateICmp(SICmpOpc, LHS, RHS, "cmp"); } else { @@ -3878,6 +3960,8 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E, Value *ResultR, *ResultI; if (CETy->isRealFloatingType()) { + // As complex comparisons can only be equality comparisons, they + // are never signaling comparisons. ResultR = Builder.CreateFCmp(FCmpOpc, LHS.first, RHS.first, "cmp.r"); ResultI = Builder.CreateFCmp(FCmpOpc, LHS.second, RHS.second, "cmp.i"); } else { @@ -3922,7 +4006,7 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { case Qualifiers::OCL_Weak: RHS = Visit(E->getRHS()); LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); - RHS = CGF.EmitARCStoreWeak(LHS.getAddress(), RHS, Ignore); + RHS = CGF.EmitARCStoreWeak(LHS.getAddress(CGF), RHS, Ignore); break; case Qualifiers::OCL_None: @@ -4227,6 +4311,21 @@ VisitAbstractConditionalOperator(const AbstractConditionalOperator *E) { return tmp5; } + if (condExpr->getType()->isVectorType()) { + CGF.incrementProfileCounter(E); + + llvm::Value *CondV = CGF.EmitScalarExpr(condExpr); + llvm::Value *LHS = Visit(lhsExpr); + llvm::Value *RHS = Visit(rhsExpr); + + llvm::Type *CondType = ConvertType(condExpr->getType()); + auto *VecTy = cast<llvm::VectorType>(CondType); + llvm::Value *ZeroVec = llvm::Constant::getNullValue(VecTy); + + CondV = Builder.CreateICmpNE(CondV, ZeroVec, "vector_cond"); + return Builder.CreateSelect(CondV, LHS, RHS, "vector_select"); + } + // If this is a really simple expression (like x ? 4 : 5), emit this as a // select instead of as control flow. We can only do this if it is cheap and // safe to evaluate the LHS and RHS unconditionally. @@ -4483,7 +4582,7 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr *E) { if (BaseExpr->isRValue()) { Addr = Address(EmitScalarExpr(BaseExpr), getPointerAlign()); } else { - Addr = EmitLValue(BaseExpr).getAddress(); + Addr = EmitLValue(BaseExpr).getAddress(*this); } // Cast the address to Class*. diff --git a/clang/lib/CodeGen/CGLoopInfo.cpp b/clang/lib/CodeGen/CGLoopInfo.cpp index c21d4feee7a8..e4b184eb8798 100644 --- a/clang/lib/CodeGen/CGLoopInfo.cpp +++ b/clang/lib/CodeGen/CGLoopInfo.cpp @@ -270,14 +270,6 @@ LoopInfo::createLoopVectorizeMetadata(const LoopAttributes &Attrs, // Setting vectorize.width if (Attrs.VectorizeWidth > 0) { - // This implies vectorize.enable = true, but only add it when it is not - // already enabled. - if (Attrs.VectorizeEnable != LoopAttributes::Enable) - Args.push_back( - MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.vectorize.enable"), - ConstantAsMetadata::get(ConstantInt::get( - llvm::Type::getInt1Ty(Ctx), 1))})); - Metadata *Vals[] = { MDString::get(Ctx, "llvm.loop.vectorize.width"), ConstantAsMetadata::get(ConstantInt::get(llvm::Type::getInt32Ty(Ctx), @@ -294,17 +286,18 @@ LoopInfo::createLoopVectorizeMetadata(const LoopAttributes &Attrs, Args.push_back(MDNode::get(Ctx, Vals)); } - // Setting vectorize.enable + // vectorize.enable is set if: + // 1) loop hint vectorize.enable is set, or + // 2) it is implied when vectorize.predicate is set, or + // 3) it is implied when vectorize.width is set. if (Attrs.VectorizeEnable != LoopAttributes::Unspecified || - IsVectorPredicateEnabled) { - Metadata *Vals[] = { - MDString::get(Ctx, "llvm.loop.vectorize.enable"), - ConstantAsMetadata::get(ConstantInt::get( - llvm::Type::getInt1Ty(Ctx), - IsVectorPredicateEnabled - ? true - : (Attrs.VectorizeEnable == LoopAttributes::Enable)))}; - Args.push_back(MDNode::get(Ctx, Vals)); + IsVectorPredicateEnabled || + Attrs.VectorizeWidth > 1 ) { + bool AttrVal = Attrs.VectorizeEnable != LoopAttributes::Disable; + Args.push_back( + MDNode::get(Ctx, {MDString::get(Ctx, "llvm.loop.vectorize.enable"), + ConstantAsMetadata::get(ConstantInt::get( + llvm::Type::getInt1Ty(Ctx), AttrVal))})); } if (FollowupHasTransforms) diff --git a/clang/lib/CodeGen/CGNonTrivialStruct.cpp b/clang/lib/CodeGen/CGNonTrivialStruct.cpp index 05615aa12881..d5f378c52232 100644 --- a/clang/lib/CodeGen/CGNonTrivialStruct.cpp +++ b/clang/lib/CodeGen/CGNonTrivialStruct.cpp @@ -707,7 +707,7 @@ struct GenMoveConstructor : GenBinaryFunc<GenMoveConstructor, true> { LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT); llvm::Value *SrcVal = CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal(); - CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV); + CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress(*CGF)), SrcLV); CGF->EmitStoreOfScalar(SrcVal, CGF->MakeAddrLValue(Addrs[DstIdx], QT), /* isInitialization */ true); } @@ -770,7 +770,7 @@ struct GenMoveAssignment : GenBinaryFunc<GenMoveAssignment, true> { LValue SrcLV = CGF->MakeAddrLValue(Addrs[SrcIdx], QT); llvm::Value *SrcVal = CGF->EmitLoadOfLValue(SrcLV, SourceLocation()).getScalarVal(); - CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress()), SrcLV); + CGF->EmitStoreOfScalar(getNullForVariable(SrcLV.getAddress(*CGF)), SrcLV); LValue DstLV = CGF->MakeAddrLValue(Addrs[DstIdx], QT); llvm::Value *DstVal = CGF->EmitLoadOfLValue(DstLV, SourceLocation()).getScalarVal(); @@ -806,7 +806,8 @@ void CodeGenFunction::destroyNonTrivialCStruct(CodeGenFunction &CGF, // such structure. void CodeGenFunction::defaultInitNonTrivialCStructVar(LValue Dst) { GenDefaultInitialize Gen(getContext()); - Address DstPtr = Builder.CreateBitCast(Dst.getAddress(), CGM.Int8PtrPtrTy); + Address DstPtr = + Builder.CreateBitCast(Dst.getAddress(*this), CGM.Int8PtrPtrTy); Gen.setCGF(this); QualType QT = Dst.getType(); QT = Dst.isVolatile() ? QT.withVolatile() : QT; @@ -817,6 +818,7 @@ template <class G, size_t N> static void callSpecialFunction(G &&Gen, StringRef FuncName, QualType QT, bool IsVolatile, CodeGenFunction &CGF, std::array<Address, N> Addrs) { + auto SetArtificialLoc = ApplyDebugLocation::CreateArtificial(CGF); for (unsigned I = 0; I < N; ++I) Addrs[I] = CGF.Builder.CreateBitCast(Addrs[I], CGF.CGM.Int8PtrPtrTy); QT = IsVolatile ? QT.withVolatile() : QT; @@ -849,7 +851,7 @@ getSpecialFunction(G &&Gen, StringRef FuncName, QualType QT, bool IsVolatile, // Functions to emit calls to the special functions of a non-trivial C struct. void CodeGenFunction::callCStructDefaultConstructor(LValue Dst) { bool IsVolatile = Dst.isVolatile(); - Address DstPtr = Dst.getAddress(); + Address DstPtr = Dst.getAddress(*this); QualType QT = Dst.getType(); GenDefaultInitializeFuncName GenName(DstPtr.getAlignment(), getContext()); std::string FuncName = GenName.getName(QT, IsVolatile); @@ -873,7 +875,7 @@ std::string CodeGenFunction::getNonTrivialDestructorStr(QualType QT, void CodeGenFunction::callCStructDestructor(LValue Dst) { bool IsVolatile = Dst.isVolatile(); - Address DstPtr = Dst.getAddress(); + Address DstPtr = Dst.getAddress(*this); QualType QT = Dst.getType(); GenDestructorFuncName GenName("__destructor_", DstPtr.getAlignment(), getContext()); @@ -884,7 +886,7 @@ void CodeGenFunction::callCStructDestructor(LValue Dst) { void CodeGenFunction::callCStructCopyConstructor(LValue Dst, LValue Src) { bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); - Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); + Address DstPtr = Dst.getAddress(*this), SrcPtr = Src.getAddress(*this); QualType QT = Dst.getType(); GenBinaryFuncName<false> GenName("__copy_constructor_", DstPtr.getAlignment(), SrcPtr.getAlignment(), getContext()); @@ -898,7 +900,7 @@ void CodeGenFunction::callCStructCopyAssignmentOperator(LValue Dst, LValue Src ) { bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); - Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); + Address DstPtr = Dst.getAddress(*this), SrcPtr = Src.getAddress(*this); QualType QT = Dst.getType(); GenBinaryFuncName<false> GenName("__copy_assignment_", DstPtr.getAlignment(), SrcPtr.getAlignment(), getContext()); @@ -909,7 +911,7 @@ void CodeGenFunction::callCStructCopyAssignmentOperator(LValue Dst, LValue Src void CodeGenFunction::callCStructMoveConstructor(LValue Dst, LValue Src) { bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); - Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); + Address DstPtr = Dst.getAddress(*this), SrcPtr = Src.getAddress(*this); QualType QT = Dst.getType(); GenBinaryFuncName<true> GenName("__move_constructor_", DstPtr.getAlignment(), SrcPtr.getAlignment(), getContext()); @@ -923,7 +925,7 @@ void CodeGenFunction::callCStructMoveAssignmentOperator(LValue Dst, LValue Src ) { bool IsVolatile = Dst.isVolatile() || Src.isVolatile(); - Address DstPtr = Dst.getAddress(), SrcPtr = Src.getAddress(); + Address DstPtr = Dst.getAddress(*this), SrcPtr = Src.getAddress(*this); QualType QT = Dst.getType(); GenBinaryFuncName<true> GenName("__move_assignment_", DstPtr.getAlignment(), SrcPtr.getAlignment(), getContext()); diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index 1fa72678081a..90fca2836d99 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -17,6 +17,7 @@ #include "ConstantEmitter.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/Diagnostic.h" @@ -430,6 +431,20 @@ tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType, return None; } +CodeGen::RValue CGObjCRuntime::GeneratePossiblySpecializedMessageSend( + CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, + Selector Sel, llvm::Value *Receiver, const CallArgList &Args, + const ObjCInterfaceDecl *OID, const ObjCMethodDecl *Method, + bool isClassMessage) { + if (Optional<llvm::Value *> SpecializedResult = + tryGenerateSpecializedMessageSend(CGF, ResultType, Receiver, Args, + Sel, Method, isClassMessage)) { + return RValue::get(SpecializedResult.getValue()); + } + return GenerateMessageSend(CGF, Return, ResultType, Sel, Receiver, Args, OID, + Method); +} + /// Instead of '[[MyClass alloc] init]', try to generate /// 'objc_alloc_init(MyClass)'. This provides a code size improvement on the /// caller side, as well as the optimized objc_alloc. @@ -446,38 +461,39 @@ tryEmitSpecializedAllocInit(CodeGenFunction &CGF, const ObjCMessageExpr *OME) { Sel.getNameForSlot(0) != "init") return None; - // Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]' or - // we are in an ObjC class method and 'receiver' is '[self alloc]'. + // Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]' + // with 'cls' a Class. auto *SubOME = dyn_cast<ObjCMessageExpr>(OME->getInstanceReceiver()->IgnoreParenCasts()); if (!SubOME) return None; Selector SubSel = SubOME->getSelector(); - // Check if we are in an ObjC class method and the receiver expression is - // 'self'. - const Expr *SelfInClassMethod = nullptr; - if (const auto *CurMD = dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl)) - if (CurMD->isClassMethod()) - if ((SelfInClassMethod = SubOME->getInstanceReceiver())) - if (!SelfInClassMethod->isObjCSelfExpr()) - SelfInClassMethod = nullptr; - - if ((SubOME->getReceiverKind() != ObjCMessageExpr::Class && - !SelfInClassMethod) || !SubOME->getType()->isObjCObjectPointerType() || + if (!SubOME->getType()->isObjCObjectPointerType() || !SubSel.isUnarySelector() || SubSel.getNameForSlot(0) != "alloc") return None; - llvm::Value *Receiver; - if (SelfInClassMethod) { - Receiver = CGF.EmitScalarExpr(SelfInClassMethod); - } else { + llvm::Value *Receiver = nullptr; + switch (SubOME->getReceiverKind()) { + case ObjCMessageExpr::Instance: + if (!SubOME->getInstanceReceiver()->getType()->isObjCClassType()) + return None; + Receiver = CGF.EmitScalarExpr(SubOME->getInstanceReceiver()); + break; + + case ObjCMessageExpr::Class: { QualType ReceiverType = SubOME->getClassReceiver(); - const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>(); + const ObjCObjectType *ObjTy = ReceiverType->castAs<ObjCObjectType>(); const ObjCInterfaceDecl *ID = ObjTy->getInterface(); assert(ID && "null interface should be impossible here"); Receiver = CGF.CGM.getObjCRuntime().GetClass(CGF, ID); + break; + } + case ObjCMessageExpr::SuperInstance: + case ObjCMessageExpr::SuperClass: + return None; } + return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType())); } @@ -497,7 +513,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, method->getMethodFamily() == OMF_retain) { if (auto lvalueExpr = findWeakLValue(E->getInstanceReceiver())) { LValue lvalue = EmitLValue(lvalueExpr); - llvm::Value *result = EmitARCLoadWeakRetained(lvalue.getAddress()); + llvm::Value *result = EmitARCLoadWeakRetained(lvalue.getAddress(*this)); return AdjustObjCObjectType(*this, E->getType(), RValue::get(result)); } } @@ -525,10 +541,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, switch (E->getReceiverKind()) { case ObjCMessageExpr::Instance: ReceiverType = E->getInstanceReceiver()->getType(); - if (auto *OMD = dyn_cast_or_null<ObjCMethodDecl>(CurFuncDecl)) - if (OMD->isClassMethod()) - if (E->getInstanceReceiver()->isObjCSelfExpr()) - isClassMessage = true; + isClassMessage = ReceiverType->isObjCClassType(); if (retainSelf) { TryEmitResult ter = tryEmitARCRetainScalarExpr(*this, E->getInstanceReceiver()); @@ -540,9 +553,7 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, case ObjCMessageExpr::Class: { ReceiverType = E->getClassReceiver(); - const ObjCObjectType *ObjTy = ReceiverType->getAs<ObjCObjectType>(); - assert(ObjTy && "Invalid Objective-C class message send"); - OID = ObjTy->getInterface(); + OID = ReceiverType->castAs<ObjCObjectType>()->getInterface(); assert(OID && "Invalid Objective-C class message send"); Receiver = Runtime.GetClass(*this, OID); isClassMessage = true; @@ -611,16 +622,9 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E, method); } else { // Call runtime methods directly if we can. - if (Optional<llvm::Value *> SpecializedResult = - tryGenerateSpecializedMessageSend(*this, ResultType, Receiver, Args, - E->getSelector(), method, - isClassMessage)) { - result = RValue::get(SpecializedResult.getValue()); - } else { - result = Runtime.GenerateMessageSend(*this, Return, ResultType, - E->getSelector(), Receiver, Args, - OID, method); - } + result = Runtime.GeneratePossiblySpecializedMessageSend( + *this, Return, ResultType, E->getSelector(), Receiver, Args, OID, + method, isClassMessage); } // For delegate init calls in ARC, implicitly store the result of @@ -683,7 +687,13 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD, llvm::Function *Fn = CGM.getObjCRuntime().GenerateMethod(OMD, CD); const CGFunctionInfo &FI = CGM.getTypes().arrangeObjCMethodDeclaration(OMD); - CGM.SetInternalFunctionAttributes(OMD, Fn, FI); + if (OMD->isDirectMethod()) { + Fn->setVisibility(llvm::Function::HiddenVisibility); + CGM.SetLLVMFunctionAttributes(OMD, FI, Fn); + CGM.SetLLVMFunctionAttributesForDefinition(OMD, Fn); + } else { + CGM.SetInternalFunctionAttributes(OMD, Fn, FI); + } args.push_back(OMD->getSelfDecl()); args.push_back(OMD->getCmdDecl()); @@ -696,6 +706,14 @@ void CodeGenFunction::StartObjCMethod(const ObjCMethodDecl *OMD, StartFunction(OMD, OMD->getReturnType(), Fn, FI, args, OMD->getLocation(), StartLoc); + if (OMD->isDirectMethod()) { + // This function is a direct call, it has to implement a nil check + // on entry. + // + // TODO: possibly have several entry points to elide the check + CGM.getObjCRuntime().GenerateDirectMethodPrologue(*this, Fn, OMD, CD); + } + // In ARC, certain methods get an extra cleanup. if (CGM.getLangOpts().ObjCAutoRefCount && OMD->isInstanceMethod() && @@ -728,8 +746,8 @@ static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar, ASTContext &Context = CGF.getContext(); Address src = - CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0) - .getAddress(); + CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0) + .getAddress(CGF); // objc_copyStruct (ReturnValue, &structIvar, // sizeof (Type of Ivar), isAtomic, false); @@ -954,14 +972,13 @@ void CodeGenFunction::GenerateObjCGetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID) { llvm::Constant *AtomicHelperFn = CodeGenFunction(CGM).GenerateObjCAtomicGetterCopyHelperFunction(PID); - const ObjCPropertyDecl *PD = PID->getPropertyDecl(); - ObjCMethodDecl *OMD = PD->getGetterMethodDecl(); + ObjCMethodDecl *OMD = PID->getGetterMethodDecl(); assert(OMD && "Invalid call to generate getter (empty method)"); StartObjCMethod(OMD, IMP->getClassInterface()); generateObjCGetterBody(IMP, PID, OMD, AtomicHelperFn); - FinishFunction(); + FinishFunction(OMD->getEndLoc()); } static bool hasTrivialGetExpr(const ObjCPropertyImplDecl *propImpl) { @@ -1002,8 +1019,8 @@ static void emitCPPObjectAtomicGetterCall(CodeGenFunction &CGF, // The 2nd argument is the address of the ivar. llvm::Value *ivarAddr = - CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), - CGF.LoadObjCSelf(), ivar, 0).getPointer(); + CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0) + .getPointer(CGF); ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy); args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy); @@ -1041,7 +1058,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, const ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); QualType propType = prop->getType(); - ObjCMethodDecl *getterMethod = prop->getGetterMethodDecl(); + ObjCMethodDecl *getterMethod = propImpl->getGetterMethodDecl(); ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); @@ -1062,7 +1079,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, bitcastType = bitcastType->getPointerTo(); // addrspace 0 okay // Perform an atomic load. This does not impose ordering constraints. - Address ivarAddr = LV.getAddress(); + Address ivarAddr = LV.getAddress(*this); ivarAddr = Builder.CreateBitCast(ivarAddr, bitcastType); llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load"); load->setAtomic(llvm::AtomicOrdering::Unordered); @@ -1163,14 +1180,14 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, case TEK_Scalar: { llvm::Value *value; if (propType->isReferenceType()) { - value = LV.getAddress().getPointer(); + value = LV.getAddress(*this).getPointer(); } else { // We want to load and autoreleaseReturnValue ARC __weak ivars. if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) { if (getLangOpts().ObjCAutoRefCount) { value = emitARCRetainLoadOfScalar(*this, LV, ivarType); } else { - value = EmitARCLoadWeak(LV.getAddress()); + value = EmitARCLoadWeak(LV.getAddress(*this)); } // Otherwise we want to do a simple load, suppressing the @@ -1204,9 +1221,9 @@ static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD, CallArgList args; // The first argument is the address of the ivar. - llvm::Value *ivarAddr = CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), - CGF.LoadObjCSelf(), ivar, 0) - .getPointer(); + llvm::Value *ivarAddr = + CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0) + .getPointer(CGF); ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy); args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy); @@ -1215,7 +1232,7 @@ static void emitStructSetterCall(CodeGenFunction &CGF, ObjCMethodDecl *OMD, DeclRefExpr argRef(CGF.getContext(), argVar, false, argVar->getType().getNonReferenceType(), VK_LValue, SourceLocation()); - llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer(); + llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer(CGF); argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy); args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy); @@ -1251,8 +1268,8 @@ static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF, // The first argument is the address of the ivar. llvm::Value *ivarAddr = - CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), - CGF.LoadObjCSelf(), ivar, 0).getPointer(); + CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), CGF.LoadObjCSelf(), ivar, 0) + .getPointer(CGF); ivarAddr = CGF.Builder.CreateBitCast(ivarAddr, CGF.Int8PtrTy); args.add(RValue::get(ivarAddr), CGF.getContext().VoidPtrTy); @@ -1261,7 +1278,7 @@ static void emitCPPObjectAtomicSetterCall(CodeGenFunction &CGF, DeclRefExpr argRef(CGF.getContext(), argVar, false, argVar->getType().getNonReferenceType(), VK_LValue, SourceLocation()); - llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer(); + llvm::Value *argAddr = CGF.EmitLValue(&argRef).getPointer(CGF); argAddr = CGF.Builder.CreateBitCast(argAddr, CGF.Int8PtrTy); args.add(RValue::get(argAddr), CGF.getContext().VoidPtrTy); @@ -1311,9 +1328,8 @@ void CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, const ObjCPropertyImplDecl *propImpl, llvm::Constant *AtomicHelperFn) { - const ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); - ObjCMethodDecl *setterMethod = prop->getSetterMethodDecl(); + ObjCMethodDecl *setterMethod = propImpl->getSetterMethodDecl(); // Just use the setter expression if Sema gave us one and it's // non-trivial. @@ -1339,7 +1355,7 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl, LValue ivarLValue = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, /*quals*/ 0); - Address ivarAddr = ivarLValue.getAddress(); + Address ivarAddr = ivarLValue.getAddress(*this); // Currently, all atomic accesses have to be through integer // types, so there's no point in trying to pick a prettier type. @@ -1490,14 +1506,13 @@ void CodeGenFunction::GenerateObjCSetter(ObjCImplementationDecl *IMP, const ObjCPropertyImplDecl *PID) { llvm::Constant *AtomicHelperFn = CodeGenFunction(CGM).GenerateObjCAtomicSetterCopyHelperFunction(PID); - const ObjCPropertyDecl *PD = PID->getPropertyDecl(); - ObjCMethodDecl *OMD = PD->getSetterMethodDecl(); + ObjCMethodDecl *OMD = PID->getSetterMethodDecl(); assert(OMD && "Invalid call to generate setter (empty method)"); StartObjCMethod(OMD, IMP->getClassInterface()); generateObjCSetterBody(IMP, PID, AtomicHelperFn); - FinishFunction(); + FinishFunction(OMD->getEndLoc()); } namespace { @@ -1517,7 +1532,7 @@ namespace { void Emit(CodeGenFunction &CGF, Flags flags) override { LValue lvalue = CGF.EmitLValueForIvar(CGF.TypeOfSelfObject(), addr, ivar, /*CVR*/ 0); - CGF.emitDestroy(lvalue.getAddress(), ivar->getType(), destroyer, + CGF.emitDestroy(lvalue.getAddress(CGF), ivar->getType(), destroyer, flags.isForNormalCleanup() && useEHCleanupForArray); } }; @@ -1584,7 +1599,7 @@ void CodeGenFunction::GenerateObjCCtorDtorMethod(ObjCImplementationDecl *IMP, LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), Ivar, 0); EmitAggExpr(IvarInit->getInit(), - AggValueSlot::forLValue(LV, AggValueSlot::IsDestructed, + AggValueSlot::forLValue(LV, *this, AggValueSlot::IsDestructed, AggValueSlot::DoesNotNeedGCBarriers, AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap)); @@ -2309,7 +2324,7 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrong(LValue dst, !isBlock && (dst.getAlignment().isZero() || dst.getAlignment() >= CharUnits::fromQuantity(PointerAlignInBytes))) { - return EmitARCStoreStrongCall(dst.getAddress(), newValue, ignored); + return EmitARCStoreStrongCall(dst.getAddress(*this), newValue, ignored); } // Otherwise, split it out. @@ -2708,7 +2723,7 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF, result = CGF.EmitLoadOfLValue(lvalue, SourceLocation()).getScalarVal(); } else { assert(type.getObjCLifetime() == Qualifiers::OCL_Weak); - result = CGF.EmitARCLoadWeakRetained(lvalue.getAddress()); + result = CGF.EmitARCLoadWeakRetained(lvalue.getAddress(CGF)); } return TryEmitResult(result, !shouldRetain); } @@ -2732,7 +2747,7 @@ static TryEmitResult tryEmitARCRetainLoadOfScalar(CodeGenFunction &CGF, SourceLocation()).getScalarVal(); // Set the source pointer to NULL. - CGF.EmitStoreOfScalar(getNullForVariable(lv.getAddress()), lv); + CGF.EmitStoreOfScalar(getNullForVariable(lv.getAddress(CGF)), lv); return TryEmitResult(result, true); } diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index d2c089d0360e..a27b6d4ed637 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -13,19 +13,20 @@ // //===----------------------------------------------------------------------===// -#include "CGObjCRuntime.h" +#include "CGCXXABI.h" #include "CGCleanup.h" +#include "CGObjCRuntime.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" -#include "CGCXXABI.h" -#include "clang/CodeGen/ConstantInitBuilder.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtObjC.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" +#include "clang/CodeGen/ConstantInitBuilder.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/IR/DataLayout.h" @@ -606,6 +607,9 @@ public: llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) override; + void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn, + const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD) override; void GenerateCategory(const ObjCCategoryImplDecl *CMD) override; void GenerateClass(const ObjCImplementationDecl *ClassDecl) override; void RegisterAlias(const ObjCCompatibleAliasDecl *OAD) override; @@ -1232,6 +1236,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { // The first Interface we find may be a @class, // which should only be treated as the source of // truth in the absence of a true declaration. + assert(OID && "Failed to find ObjCInterfaceDecl"); const ObjCInterfaceDecl *OIDDef = OID->getDefinition(); if (OIDDef != nullptr) OID = OIDDef; @@ -1880,13 +1885,12 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { for (auto *propImpl : OID->property_impls()) if (propImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { - ObjCPropertyDecl *prop = propImpl->getPropertyDecl(); - auto addIfExists = [&](const ObjCMethodDecl* OMD) { - if (OMD) + auto addIfExists = [&](const ObjCMethodDecl *OMD) { + if (OMD && OMD->hasBody()) InstanceMethods.push_back(OMD); }; - addIfExists(prop->getGetterMethodDecl()); - addIfExists(prop->getSetterMethodDecl()); + addIfExists(propImpl->getGetterMethodDecl()); + addIfExists(propImpl->getSetterMethodDecl()); } if (InstanceMethods.size() == 0) @@ -3033,6 +3037,7 @@ llvm::Value *CGObjCGNU::GenerateProtocolRef(CodeGenFunction &CGF, llvm::Constant *&protocol = ExistingProtocols[PD->getNameAsString()]; if (!protocol) GenerateProtocol(PD); + assert(protocol && "Unknown protocol"); llvm::Type *T = CGM.getTypes().ConvertType(CGM.getContext().getObjCProtoType()); return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T)); @@ -3494,13 +3499,12 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) { for (auto *propertyImpl : OID->property_impls()) if (propertyImpl->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { - ObjCPropertyDecl *property = propertyImpl->getPropertyDecl(); auto addPropertyMethod = [&](const ObjCMethodDecl *accessor) { if (accessor) InstanceMethods.push_back(accessor); }; - addPropertyMethod(property->getGetterMethodDecl()); - addPropertyMethod(property->getSetterMethodDecl()); + addPropertyMethod(propertyImpl->getGetterMethodDecl()); + addPropertyMethod(propertyImpl->getSetterMethodDecl()); } llvm::Constant *Properties = GeneratePropertyList(OID, ClassDecl); @@ -3873,6 +3877,13 @@ llvm::Function *CGObjCGNU::GenerateMethod(const ObjCMethodDecl *OMD, return Method; } +void CGObjCGNU::GenerateDirectMethodPrologue(CodeGenFunction &CGF, + llvm::Function *Fn, + const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD) { + // GNU runtime doesn't support direct calls at this time +} + llvm::FunctionCallee CGObjCGNU::GetPropertyGetFunction() { return GetPropertyFn; } diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 8e28b2f05c16..f36c28a85a68 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -16,8 +16,8 @@ #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" -#include "clang/CodeGen/ConstantInitBuilder.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/RecordLayout.h" @@ -25,6 +25,7 @@ #include "clang/Basic/CodeGenOptions.h" #include "clang/Basic/LangOptions.h" #include "clang/CodeGen/CGFunctionInfo.h" +#include "clang/CodeGen/ConstantInitBuilder.h" #include "llvm/ADT/CachedHashString.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SetVector.h" @@ -874,6 +875,10 @@ protected: /// this translation unit. llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> MethodDefinitions; + /// DirectMethodDefinitions - map of direct methods which have been defined in + /// this translation unit. + llvm::DenseMap<const ObjCMethodDecl*, llvm::Function*> DirectMethodDefinitions; + /// PropertyNames - uniqued method variable names. llvm::DenseMap<IdentifierInfo*, llvm::GlobalVariable*> PropertyNames; @@ -923,7 +928,8 @@ protected: /// \param[out] NameOut - The return value. void GetNameForMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD, - SmallVectorImpl<char> &NameOut); + SmallVectorImpl<char> &NameOut, + bool ignoreCategoryNamespace = false); /// GetMethodVarName - Return a unique constant for the given /// selector's name. The return value has type char *. @@ -1065,7 +1071,7 @@ protected: CodeGen::RValue EmitMessageSend(CodeGen::CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, - llvm::Value *Sel, + Selector Sel, llvm::Value *Arg0, QualType Arg0Ty, bool IsSuper, @@ -1092,6 +1098,13 @@ public: llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD=nullptr) override; + llvm::Function *GenerateDirectMethod(const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD); + + void GenerateDirectMethodPrologue(CodeGenFunction &CGF, llvm::Function *Fn, + const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD) override; + void GenerateProtocol(const ObjCProtocolDecl *PD) override; /// GetOrEmitProtocol - Get the protocol object for the given @@ -1303,7 +1316,7 @@ private: /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy, /// for the given selector. llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel); - Address EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel); + Address EmitSelectorAddr(Selector Sel); public: CGObjCMac(CodeGen::CodeGenModule &cgm); @@ -1531,7 +1544,7 @@ private: /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy, /// for the given selector. llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel); - Address EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel); + Address EmitSelectorAddr(Selector Sel); /// GetInterfaceEHType - Get the cached ehtype for the given Objective-C /// interface. The return value has type EHTypePtrTy. @@ -1573,9 +1586,13 @@ private: // base of the ivar access is a parameter to an Objective C method. // However, because the parameters are not available in the current // interface, we cannot perform this check. + // + // Note that for direct methods, because objc_msgSend is skipped, + // and that the method may be inlined, this optimization actually + // can't be performed. if (const ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(CGF.CurFuncDecl)) - if (MD->isInstanceMethod()) + if (MD->isInstanceMethod() && !MD->isDirectMethod()) if (const ObjCInterfaceDecl *ID = MD->getClassInterface()) return IV->getContainingInterface()->isSuperClassOf(ID); return false; @@ -1619,7 +1636,7 @@ public: llvm::Value *GetSelector(CodeGenFunction &CGF, Selector Sel) override { return EmitSelector(CGF, Sel); } Address GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) override - { return EmitSelectorAddr(CGF, Sel); } + { return EmitSelectorAddr(Sel); } /// The NeXT/Apple runtimes do not support typed selectors; just emit an /// untyped one. @@ -1887,7 +1904,7 @@ llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, Selector Sel) { return EmitSelector(CGF, Sel); } Address CGObjCMac::GetAddrOfSelector(CodeGenFunction &CGF, Selector Sel) { - return EmitSelectorAddr(CGF, Sel); + return EmitSelectorAddr(Sel); } llvm::Value *CGObjCMac::GetSelector(CodeGenFunction &CGF, const ObjCMethodDecl *Method) { @@ -2103,10 +2120,9 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, CGM.getTypes().ConvertType(CGF.getContext().getObjCClassType()); Target = CGF.Builder.CreateBitCast(Target, ClassTy); CGF.Builder.CreateStore(Target, CGF.Builder.CreateStructGEP(ObjCSuper, 1)); - return EmitMessageSend(CGF, Return, ResultType, - EmitSelector(CGF, Sel), - ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy, - true, CallArgs, Method, Class, ObjCTypes); + return EmitMessageSend(CGF, Return, ResultType, Sel, ObjCSuper.getPointer(), + ObjCTypes.SuperPtrCTy, true, CallArgs, Method, Class, + ObjCTypes); } /// Generate code for a message send expression. @@ -2118,10 +2134,9 @@ CodeGen::RValue CGObjCMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, const CallArgList &CallArgs, const ObjCInterfaceDecl *Class, const ObjCMethodDecl *Method) { - return EmitMessageSend(CGF, Return, ResultType, - EmitSelector(CGF, Sel), - Receiver, CGF.getContext().getObjCIdType(), - false, CallArgs, Method, Class, ObjCTypes); + return EmitMessageSend(CGF, Return, ResultType, Sel, Receiver, + CGF.getContext().getObjCIdType(), false, CallArgs, + Method, Class, ObjCTypes); } static bool isWeakLinkedClass(const ObjCInterfaceDecl *ID) { @@ -2137,7 +2152,7 @@ CodeGen::RValue CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, ReturnValueSlot Return, QualType ResultType, - llvm::Value *Sel, + Selector Sel, llvm::Value *Arg0, QualType Arg0Ty, bool IsSuper, @@ -2145,11 +2160,24 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, const ObjCMethodDecl *Method, const ObjCInterfaceDecl *ClassReceiver, const ObjCCommonTypesHelper &ObjCTypes) { + CodeGenTypes &Types = CGM.getTypes(); + auto selTy = CGF.getContext().getObjCSelType(); + llvm::Value *SelValue; + + if (Method && Method->isDirectMethod()) { + // Direct methods will synthesize the proper `_cmd` internally, + // so just don't bother with setting the `_cmd` argument. + assert(!IsSuper); + SelValue = llvm::UndefValue::get(Types.ConvertType(selTy)); + } else { + SelValue = GetSelector(CGF, Sel); + } + CallArgList ActualArgs; if (!IsSuper) Arg0 = CGF.Builder.CreateBitCast(Arg0, ObjCTypes.ObjectPtrTy); ActualArgs.add(RValue::get(Arg0), Arg0Ty); - ActualArgs.add(RValue::get(Sel), CGF.getContext().getObjCSelType()); + ActualArgs.add(RValue::get(SelValue), selTy); ActualArgs.addFrom(CallArgs); // If we're calling a method, use the formal signature. @@ -2190,7 +2218,9 @@ CGObjCCommonMac::EmitMessageSend(CodeGen::CodeGenFunction &CGF, bool RequiresNullCheck = false; llvm::FunctionCallee Fn = nullptr; - if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) { + if (Method && Method->isDirectMethod()) { + Fn = GenerateDirectMethod(Method, Method->getClassInterface()); + } else if (CGM.ReturnSlotInterferesWithArgs(MSI.CallInfo)) { if (ReceiverCanBeNull) RequiresNullCheck = true; Fn = (ObjCABI == 2) ? ObjCTypes.getSendStretFn2(IsSuper) : ObjCTypes.getSendStretFn(IsSuper); @@ -3215,9 +3245,6 @@ PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet, SmallVectorImpl<const ObjCPropertyDecl *> &Properties, const ObjCProtocolDecl *Proto, bool IsClassProperty) { - for (const auto *P : Proto->protocols()) - PushProtocolProperties(PropertySet, Properties, P, IsClassProperty); - for (const auto *PD : Proto->properties()) { if (IsClassProperty != PD->isClassProperty()) continue; @@ -3225,6 +3252,9 @@ PushProtocolProperties(llvm::SmallPtrSet<const IdentifierInfo*,16> &PropertySet, continue; Properties.push_back(PD); } + + for (const auto *P : Proto->protocols()) + PushProtocolProperties(PropertySet, Properties, P, IsClassProperty); } /* @@ -3297,6 +3327,8 @@ llvm::Constant *CGObjCCommonMac::EmitPropertyList(Twine Name, values.addInt(ObjCTypes.IntTy, Properties.size()); auto propertiesArray = values.beginArray(ObjCTypes.PropertyTy); for (auto PD : Properties) { + if (PD->isDirectProperty()) + continue; auto property = propertiesArray.beginStruct(ObjCTypes.PropertyTy); property.add(GetPropertyName(PD->getIdentifier())); property.add(GetPropertyTypeString(PD, Container)); @@ -3372,7 +3404,8 @@ void CGObjCMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { }; SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists]; for (const auto *MD : OCD->methods()) { - Methods[unsigned(MD->isClassMethod())].push_back(MD); + if (!MD->isDirectMethod()) + Methods[unsigned(MD->isClassMethod())].push_back(MD); } Values.add(GetClassName(OCD->getName())); @@ -3554,17 +3587,18 @@ void CGObjCMac::GenerateClass(const ObjCImplementationDecl *ID) { }; SmallVector<const ObjCMethodDecl *, 16> Methods[NumMethodLists]; for (const auto *MD : ID->methods()) { - Methods[unsigned(MD->isClassMethod())].push_back(MD); + if (!MD->isDirectMethod()) + Methods[unsigned(MD->isClassMethod())].push_back(MD); } for (const auto *PID : ID->property_impls()) { if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize) { - ObjCPropertyDecl *PD = PID->getPropertyDecl(); - - if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) + if (PID->getPropertyDecl()->isDirectProperty()) + continue; + if (ObjCMethodDecl *MD = PID->getGetterMethodDecl()) if (GetMethodDefinition(MD)) Methods[InstanceMethods].push_back(MD); - if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *MD = PID->getSetterMethodDecl()) if (GetMethodDefinition(MD)) Methods[InstanceMethods].push_back(MD); } @@ -3959,7 +3993,8 @@ llvm::Constant *CGObjCMac::emitMethodList(Twine name, MethodListType MLT, values.addInt(ObjCTypes.IntTy, methods.size()); auto methodArray = values.beginArray(ObjCTypes.MethodTy); for (auto MD : methods) { - emitMethodConstant(methodArray, MD); + if (!MD->isDirectMethod()) + emitMethodConstant(methodArray, MD); } methodArray.finishAndAddTo(values); @@ -3970,22 +4005,133 @@ llvm::Constant *CGObjCMac::emitMethodList(Twine name, MethodListType MLT, llvm::Function *CGObjCCommonMac::GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) { + llvm::Function *Method; + + if (OMD->isDirectMethod()) { + Method = GenerateDirectMethod(OMD, CD); + } else { + SmallString<256> Name; + GetNameForMethod(OMD, CD, Name); + + CodeGenTypes &Types = CGM.getTypes(); + llvm::FunctionType *MethodTy = + Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD)); + Method = + llvm::Function::Create(MethodTy, llvm::GlobalValue::InternalLinkage, + Name.str(), &CGM.getModule()); + } + + MethodDefinitions.insert(std::make_pair(OMD, Method)); + + return Method; +} + +llvm::Function * +CGObjCCommonMac::GenerateDirectMethod(const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD) { + auto I = DirectMethodDefinitions.find(OMD->getCanonicalDecl()); + if (I != DirectMethodDefinitions.end()) + return I->second; + SmallString<256> Name; - GetNameForMethod(OMD, CD, Name); + GetNameForMethod(OMD, CD, Name, /*ignoreCategoryNamespace*/true); CodeGenTypes &Types = CGM.getTypes(); llvm::FunctionType *MethodTy = Types.GetFunctionType(Types.arrangeObjCMethodDeclaration(OMD)); llvm::Function *Method = - llvm::Function::Create(MethodTy, - llvm::GlobalValue::InternalLinkage, - Name.str(), - &CGM.getModule()); - MethodDefinitions.insert(std::make_pair(OMD, Method)); + llvm::Function::Create(MethodTy, llvm::GlobalValue::ExternalLinkage, + Name.str(), &CGM.getModule()); + DirectMethodDefinitions.insert(std::make_pair(OMD->getCanonicalDecl(), Method)); return Method; } +void CGObjCCommonMac::GenerateDirectMethodPrologue( + CodeGenFunction &CGF, llvm::Function *Fn, const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD) { + auto &Builder = CGF.Builder; + bool ReceiverCanBeNull = true; + auto selfAddr = CGF.GetAddrOfLocalVar(OMD->getSelfDecl()); + auto selfValue = Builder.CreateLoad(selfAddr); + + // Generate: + // + // /* for class methods only to force class lazy initialization */ + // self = [self self]; + // + // /* unless the receiver is never NULL */ + // if (self == nil) { + // return (ReturnType){ }; + // } + // + // _cmd = @selector(...) + // ... + + if (OMD->isClassMethod()) { + const ObjCInterfaceDecl *OID = cast<ObjCInterfaceDecl>(CD); + assert(OID && + "GenerateDirectMethod() should be called with the Class Interface"); + Selector SelfSel = GetNullarySelector("self", CGM.getContext()); + auto ResultType = CGF.getContext().getObjCIdType(); + RValue result; + CallArgList Args; + + // TODO: If this method is inlined, the caller might know that `self` is + // already initialized; for example, it might be an ordinary Objective-C + // method which always receives an initialized `self`, or it might have just + // forced initialization on its own. + // + // We should find a way to eliminate this unnecessary initialization in such + // cases in LLVM. + result = GeneratePossiblySpecializedMessageSend( + CGF, ReturnValueSlot(), ResultType, SelfSel, selfValue, Args, OID, + nullptr, true); + Builder.CreateStore(result.getScalarVal(), selfAddr); + + // Nullable `Class` expressions cannot be messaged with a direct method + // so the only reason why the receive can be null would be because + // of weak linking. + ReceiverCanBeNull = isWeakLinkedClass(OID); + } + + if (ReceiverCanBeNull) { + llvm::BasicBlock *SelfIsNilBlock = + CGF.createBasicBlock("objc_direct_method.self_is_nil"); + llvm::BasicBlock *ContBlock = + CGF.createBasicBlock("objc_direct_method.cont"); + + // if (self == nil) { + auto selfTy = cast<llvm::PointerType>(selfValue->getType()); + auto Zero = llvm::ConstantPointerNull::get(selfTy); + + llvm::MDBuilder MDHelper(CGM.getLLVMContext()); + Builder.CreateCondBr(Builder.CreateICmpEQ(selfValue, Zero), SelfIsNilBlock, + ContBlock, MDHelper.createBranchWeights(1, 1 << 20)); + + CGF.EmitBlock(SelfIsNilBlock); + + // return (ReturnType){ }; + auto retTy = OMD->getReturnType(); + Builder.SetInsertPoint(SelfIsNilBlock); + if (!retTy->isVoidType()) { + CGF.EmitNullInitialization(CGF.ReturnValue, retTy); + } + CGF.EmitBranchThroughCleanup(CGF.ReturnBlock); + // } + + // rest of the body + CGF.EmitBlock(ContBlock); + Builder.SetInsertPoint(ContBlock); + } + + // only synthesize _cmd if it's referenced + if (OMD->getCmdDecl()->isUsed()) { + Builder.CreateStore(GetSelector(CGF, OMD), + CGF.GetAddrOfLocalVar(OMD->getCmdDecl())); + } +} + llvm::GlobalVariable *CGObjCCommonMac::CreateMetadataVar(Twine Name, ConstantStructBuilder &Init, StringRef Section, @@ -5118,11 +5264,11 @@ llvm::Value *CGObjCMac::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) { } llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel) { - return CGF.Builder.CreateLoad(EmitSelectorAddr(CGF, Sel)); + return CGF.Builder.CreateLoad(EmitSelectorAddr(Sel)); } -Address CGObjCMac::EmitSelectorAddr(CodeGenFunction &CGF, Selector Sel) { - CharUnits Align = CGF.getPointerAlign(); +Address CGObjCMac::EmitSelectorAddr(Selector Sel) { + CharUnits Align = CGM.getPointerAlign(); llvm::GlobalVariable *&Entry = SelectorReferences[Sel]; if (!Entry) { @@ -5542,14 +5688,16 @@ CGObjCCommonMac::GetPropertyTypeString(const ObjCPropertyDecl *PD, void CGObjCCommonMac::GetNameForMethod(const ObjCMethodDecl *D, const ObjCContainerDecl *CD, - SmallVectorImpl<char> &Name) { + SmallVectorImpl<char> &Name, + bool ignoreCategoryNamespace) { llvm::raw_svector_ostream OS(Name); assert (CD && "Missing container decl in GetNameForMethod"); OS << '\01' << (D->isInstanceMethod() ? '-' : '+') << '[' << CD->getName(); - if (const ObjCCategoryImplDecl *CID = - dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext())) - OS << '(' << *CID << ')'; + if (!ignoreCategoryNamespace) + if (const ObjCCategoryImplDecl *CID = + dyn_cast<ObjCCategoryImplDecl>(D->getDeclContext())) + OS << '(' << *CID << ')'; OS << ' ' << D->getSelector().getAsString() << ']'; } @@ -6228,23 +6376,12 @@ llvm::GlobalVariable * CGObjCNonFragileABIMac::BuildClassRoTInitializer( SmallVector<const ObjCMethodDecl*, 16> methods; if (flags & NonFragileABI_Class_Meta) { for (const auto *MD : ID->class_methods()) - methods.push_back(MD); + if (!MD->isDirectMethod()) + methods.push_back(MD); } else { for (const auto *MD : ID->instance_methods()) - methods.push_back(MD); - - for (const auto *PID : ID->property_impls()) { - if (PID->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize){ - ObjCPropertyDecl *PD = PID->getPropertyDecl(); - - if (auto MD = PD->getGetterMethodDecl()) - if (GetMethodDefinition(MD)) - methods.push_back(MD); - if (auto MD = PD->getSetterMethodDecl()) - if (GetMethodDefinition(MD)) - methods.push_back(MD); - } - } + if (!MD->isDirectMethod()) + methods.push_back(MD); } values.add(emitMethodList(ID->getObjCRuntimeNameAsString(), @@ -6565,6 +6702,8 @@ void CGObjCNonFragileABIMac::GenerateCategory(const ObjCCategoryImplDecl *OCD) { SmallVector<const ObjCMethodDecl *, 16> instanceMethods; SmallVector<const ObjCMethodDecl *, 8> classMethods; for (const auto *MD : OCD->methods()) { + if (MD->isDirectMethod()) + continue; if (MD->isInstanceMethod()) { instanceMethods.push_back(MD); } else { @@ -6707,9 +6846,8 @@ CGObjCNonFragileABIMac::emitMethodList(Twine name, MethodListType kind, // method_count values.addInt(ObjCTypes.IntTy, methods.size()); auto methodArray = values.beginArray(ObjCTypes.MethodTy); - for (auto MD : methods) { + for (auto MD : methods) emitMethodConstant(methodArray, MD, forProtocol); - } methodArray.finishAndAddTo(values); llvm::GlobalVariable *GV = finishAndCreateGlobal(values, prefix + name, CGM); @@ -7234,8 +7372,7 @@ CGObjCNonFragileABIMac::GenerateMessageSend(CodeGen::CodeGenFunction &CGF, ? EmitVTableMessageSend(CGF, Return, ResultType, Sel, Receiver, CGF.getContext().getObjCIdType(), false, CallArgs, Method) - : EmitMessageSend(CGF, Return, ResultType, - EmitSelector(CGF, Sel), + : EmitMessageSend(CGF, Return, ResultType, Sel, Receiver, CGF.getContext().getObjCIdType(), false, CallArgs, Method, Class, ObjCTypes); } @@ -7466,15 +7603,14 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, ? EmitVTableMessageSend(CGF, Return, ResultType, Sel, ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy, true, CallArgs, Method) - : EmitMessageSend(CGF, Return, ResultType, - EmitSelector(CGF, Sel), + : EmitMessageSend(CGF, Return, ResultType, Sel, ObjCSuper.getPointer(), ObjCTypes.SuperPtrCTy, true, CallArgs, Method, Class, ObjCTypes); } llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF, Selector Sel) { - Address Addr = EmitSelectorAddr(CGF, Sel); + Address Addr = EmitSelectorAddr(Sel); llvm::LoadInst* LI = CGF.Builder.CreateLoad(Addr); LI->setMetadata(CGM.getModule().getMDKindID("invariant.load"), @@ -7482,11 +7618,9 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF, return LI; } -Address CGObjCNonFragileABIMac::EmitSelectorAddr(CodeGenFunction &CGF, - Selector Sel) { +Address CGObjCNonFragileABIMac::EmitSelectorAddr(Selector Sel) { llvm::GlobalVariable *&Entry = SelectorReferences[Sel]; - - CharUnits Align = CGF.getPointerAlign(); + CharUnits Align = CGM.getPointerAlign(); if (!Entry) { llvm::Constant *Casted = llvm::ConstantExpr::getBitCast(GetMethodVarName(Sel), diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h index 471816cb5988..f0b3525cfde2 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.h +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -169,6 +169,21 @@ public: const ObjCInterfaceDecl *Class = nullptr, const ObjCMethodDecl *Method = nullptr) = 0; + /// Generate an Objective-C message send operation. + /// + /// This variant allows for the call to be substituted with an optimized + /// variant. + CodeGen::RValue + GeneratePossiblySpecializedMessageSend(CodeGenFunction &CGF, + ReturnValueSlot Return, + QualType ResultType, + Selector Sel, + llvm::Value *Receiver, + const CallArgList& Args, + const ObjCInterfaceDecl *OID, + const ObjCMethodDecl *Method, + bool isClassMessage); + /// Generate an Objective-C message send operation to the super /// class initiated in a method for Class and with the given Self /// object. @@ -205,6 +220,12 @@ public: virtual llvm::Function *GenerateMethod(const ObjCMethodDecl *OMD, const ObjCContainerDecl *CD) = 0; + /// Generates prologue for direct Objective-C Methods. + virtual void GenerateDirectMethodPrologue(CodeGenFunction &CGF, + llvm::Function *Fn, + const ObjCMethodDecl *OMD, + const ObjCContainerDecl *CD) = 0; + /// Return the runtime function for getting properties. virtual llvm::FunctionCallee GetPropertyGetFunction() = 0; diff --git a/clang/lib/CodeGen/CGOpenCLRuntime.cpp b/clang/lib/CodeGen/CGOpenCLRuntime.cpp index 191a95c62992..dbe375294d17 100644 --- a/clang/lib/CodeGen/CGOpenCLRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenCLRuntime.cpp @@ -96,7 +96,7 @@ llvm::PointerType *CGOpenCLRuntime::getSamplerType(const Type *T) { } llvm::Value *CGOpenCLRuntime::getPipeElemSize(const Expr *PipeArg) { - const PipeType *PipeTy = PipeArg->getType()->getAs<PipeType>(); + const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>(); // The type of the last (implicit) argument to be passed. llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext()); unsigned TypeSize = CGM.getContext() @@ -106,7 +106,7 @@ llvm::Value *CGOpenCLRuntime::getPipeElemSize(const Expr *PipeArg) { } llvm::Value *CGOpenCLRuntime::getPipeElemAlign(const Expr *PipeArg) { - const PipeType *PipeTy = PipeArg->getType()->getAs<PipeType>(); + const PipeType *PipeTy = PipeArg->getType()->castAs<PipeType>(); // The type of the last (implicit) argument to be passed. llvm::Type *Int32Ty = llvm::IntegerType::getInt32Ty(CGM.getLLVMContext()); unsigned TypeSize = CGM.getContext() diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 2a13a2a58156..97b17799a03e 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -10,17 +10,22 @@ // //===----------------------------------------------------------------------===// +#include "CGOpenMPRuntime.h" #include "CGCXXABI.h" #include "CGCleanup.h" -#include "CGOpenMPRuntime.h" #include "CGRecordLayout.h" #include "CodeGenFunction.h" -#include "clang/CodeGen/ConstantInitBuilder.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/StmtOpenMP.h" +#include "clang/AST/StmtVisitor.h" #include "clang/Basic/BitmaskEnum.h" +#include "clang/CodeGen/ConstantInitBuilder.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SetOperations.h" #include "llvm/Bitcode/BitcodeReader.h" +#include "llvm/Frontend/OpenMP/OMPIRBuilder.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Value.h" @@ -30,6 +35,7 @@ using namespace clang; using namespace CodeGen; +using namespace llvm::omp; namespace { /// Base class for handling code generation inside OpenMP regions. @@ -356,7 +362,7 @@ public: VD->getType().getNonReferenceType(), VK_LValue, C.getLocation()); PrivScope.addPrivate( - VD, [&CGF, &DRE]() { return CGF.EmitLValue(&DRE).getAddress(); }); + VD, [&CGF, &DRE]() { return CGF.EmitLValue(&DRE).getAddress(CGF); }); } (void)PrivScope.Privatize(); } @@ -727,10 +733,6 @@ enum OpenMPRTLFunction { OMPRTL__tgt_target_teams_nowait, // Call to void __tgt_register_requires(int64_t flags); OMPRTL__tgt_register_requires, - // Call to void __tgt_register_lib(__tgt_bin_desc *desc); - OMPRTL__tgt_register_lib, - // Call to void __tgt_unregister_lib(__tgt_bin_desc *desc); - OMPRTL__tgt_unregister_lib, // Call to void __tgt_target_data_begin(int64_t device_id, int32_t arg_num, // void** args_base, void **args, int64_t *arg_sizes, int64_t *arg_types); OMPRTL__tgt_target_data_begin, @@ -841,7 +843,7 @@ static void emitInitWithReductionInitializer(CodeGenFunction &CGF, RValue::getComplex(CGF.EmitLoadOfComplex(LV, DRD->getLocation())); break; case TEK_Aggregate: - InitRVal = RValue::getAggregate(LV.getAddress()); + InitRVal = RValue::getAggregate(LV.getAddress(CGF)); break; } OpaqueValueExpr OVE(DRD->getLocation(), Ty, VK_RValue); @@ -965,7 +967,7 @@ void ReductionCodeGen::emitAggregateInitialization( EmitDeclareReductionInit, EmitDeclareReductionInit ? ClausesData[N].ReductionOp : PrivateVD->getInit(), - DRD, SharedLVal.getAddress()); + DRD, SharedLVal.getAddress(CGF)); } ReductionCodeGen::ReductionCodeGen(ArrayRef<const Expr *> Shareds, @@ -1006,13 +1008,13 @@ void ReductionCodeGen::emitAggregateType(CodeGenFunction &CGF, unsigned N) { } llvm::Value *Size; llvm::Value *SizeInChars; - auto *ElemType = - cast<llvm::PointerType>(SharedAddresses[N].first.getPointer()->getType()) - ->getElementType(); + auto *ElemType = cast<llvm::PointerType>( + SharedAddresses[N].first.getPointer(CGF)->getType()) + ->getElementType(); auto *ElemSizeOf = llvm::ConstantExpr::getSizeOf(ElemType); if (AsArraySection) { - Size = CGF.Builder.CreatePtrDiff(SharedAddresses[N].second.getPointer(), - SharedAddresses[N].first.getPointer()); + Size = CGF.Builder.CreatePtrDiff(SharedAddresses[N].second.getPointer(CGF), + SharedAddresses[N].first.getPointer(CGF)); Size = CGF.Builder.CreateNUWAdd( Size, llvm::ConstantInt::get(Size->getType(), /*V=*/1)); SizeInChars = CGF.Builder.CreateNUWMul(Size, ElemSizeOf); @@ -1062,7 +1064,7 @@ void ReductionCodeGen::emitInitialization( PrivateAddr, CGF.ConvertTypeForMem(PrivateType)); QualType SharedType = SharedAddresses[N].first.getType(); SharedLVal = CGF.MakeAddrLValue( - CGF.Builder.CreateElementBitCast(SharedLVal.getAddress(), + CGF.Builder.CreateElementBitCast(SharedLVal.getAddress(CGF), CGF.ConvertTypeForMem(SharedType)), SharedType, SharedAddresses[N].first.getBaseInfo(), CGF.CGM.getTBAAInfoForSubobject(SharedAddresses[N].first, SharedType)); @@ -1070,7 +1072,7 @@ void ReductionCodeGen::emitInitialization( emitAggregateInitialization(CGF, N, PrivateAddr, SharedLVal, DRD); } else if (DRD && (DRD->getInitializer() || !PrivateVD->hasInit())) { emitInitWithReductionInitializer(CGF, DRD, ClausesData[N].ReductionOp, - PrivateAddr, SharedLVal.getAddress(), + PrivateAddr, SharedLVal.getAddress(CGF), SharedLVal.getType()); } else if (!DefaultInit(CGF) && PrivateVD->hasInit() && !CGF.isTrivialInitializer(PrivateVD->getInit())) { @@ -1107,15 +1109,15 @@ static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, while ((BaseTy->isPointerType() || BaseTy->isReferenceType()) && !CGF.getContext().hasSameType(BaseTy, ElTy)) { if (const auto *PtrTy = BaseTy->getAs<PointerType>()) { - BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(), PtrTy); + BaseLV = CGF.EmitLoadOfPointerLValue(BaseLV.getAddress(CGF), PtrTy); } else { - LValue RefLVal = CGF.MakeAddrLValue(BaseLV.getAddress(), BaseTy); + LValue RefLVal = CGF.MakeAddrLValue(BaseLV.getAddress(CGF), BaseTy); BaseLV = CGF.EmitLoadOfReferenceLValue(RefLVal); } BaseTy = BaseTy->getPointeeType(); } return CGF.MakeAddrLValue( - CGF.Builder.CreateElementBitCast(BaseLV.getAddress(), + CGF.Builder.CreateElementBitCast(BaseLV.getAddress(CGF), CGF.ConvertTypeForMem(ElTy)), BaseLV.getType(), BaseLV.getBaseInfo(), CGF.CGM.getTBAAInfoForSubobject(BaseLV, BaseLV.getType())); @@ -1179,15 +1181,15 @@ Address ReductionCodeGen::adjustPrivateAddress(CodeGenFunction &CGF, unsigned N, loadToBegin(CGF, OrigVD->getType(), SharedAddresses[N].first.getType(), OriginalBaseLValue); llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff( - BaseLValue.getPointer(), SharedAddresses[N].first.getPointer()); + BaseLValue.getPointer(CGF), SharedAddresses[N].first.getPointer(CGF)); llvm::Value *PrivatePointer = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( PrivateAddr.getPointer(), - SharedAddresses[N].first.getAddress().getType()); + SharedAddresses[N].first.getAddress(CGF).getType()); llvm::Value *Ptr = CGF.Builder.CreateGEP(PrivatePointer, Adjustment); return castToBase(CGF, OrigVD->getType(), SharedAddresses[N].first.getType(), - OriginalBaseLValue.getAddress().getType(), + OriginalBaseLValue.getAddress(CGF).getType(), OriginalBaseLValue.getAlignment(), Ptr); } BaseDecls.emplace_back( @@ -1276,7 +1278,7 @@ bool CGOpenMPRuntime::tryEmitDeclareVariant(const GlobalDecl &NewGD, llvm::GlobalValue *Addr = CGM.GetGlobalValue(NewMangledName); if (Addr && !Addr->isDeclaration()) { const auto *D = cast<FunctionDecl>(OldGD.getDecl()); - const CGFunctionInfo &FI = CGM.getTypes().arrangeGlobalDeclaration(OldGD); + const CGFunctionInfo &FI = CGM.getTypes().arrangeGlobalDeclaration(NewGD); llvm::Type *DeclTy = CGM.getTypes().GetFunctionType(FI); // Create a reference to the named value. This ensures that it is emitted @@ -1380,12 +1382,12 @@ emitCombinerOrInitializer(CodeGenModule &CGM, QualType Ty, Address AddrIn = CGF.GetAddrOfLocalVar(&OmpInParm); Scope.addPrivate(In, [&CGF, AddrIn, PtrTy]() { return CGF.EmitLoadOfPointerLValue(AddrIn, PtrTy->castAs<PointerType>()) - .getAddress(); + .getAddress(CGF); }); Address AddrOut = CGF.GetAddrOfLocalVar(&OmpOutParm); Scope.addPrivate(Out, [&CGF, AddrOut, PtrTy]() { return CGF.EmitLoadOfPointerLValue(AddrOut, PtrTy->castAs<PointerType>()) - .getAddress(); + .getAddress(CGF); }); (void)Scope.Privatize(); if (!IsCombiner && Out->hasInit() && @@ -1436,6 +1438,52 @@ CGOpenMPRuntime::getUserDefinedReduction(const OMPDeclareReductionDecl *D) { return UDRMap.lookup(D); } +namespace { +// Temporary RAII solution to perform a push/pop stack event on the OpenMP IR +// Builder if one is present. +struct PushAndPopStackRAII { + PushAndPopStackRAII(llvm::OpenMPIRBuilder *OMPBuilder, CodeGenFunction &CGF, + bool HasCancel) + : OMPBuilder(OMPBuilder) { + if (!OMPBuilder) + return; + + // The following callback is the crucial part of clangs cleanup process. + // + // NOTE: + // Once the OpenMPIRBuilder is used to create parallel regions (and + // similar), the cancellation destination (Dest below) is determined via + // IP. That means if we have variables to finalize we split the block at IP, + // use the new block (=BB) as destination to build a JumpDest (via + // getJumpDestInCurrentScope(BB)) which then is fed to + // EmitBranchThroughCleanup. Furthermore, there will not be the need + // to push & pop an FinalizationInfo object. + // The FiniCB will still be needed but at the point where the + // OpenMPIRBuilder is asked to construct a parallel (or similar) construct. + auto FiniCB = [&CGF](llvm::OpenMPIRBuilder::InsertPointTy IP) { + assert(IP.getBlock()->end() == IP.getPoint() && + "Clang CG should cause non-terminated block!"); + CGBuilderTy::InsertPointGuard IPG(CGF.Builder); + CGF.Builder.restoreIP(IP); + CodeGenFunction::JumpDest Dest = + CGF.getOMPCancelDestination(OMPD_parallel); + CGF.EmitBranchThroughCleanup(Dest); + }; + + // TODO: Remove this once we emit parallel regions through the + // OpenMPIRBuilder as it can do this setup internally. + llvm::OpenMPIRBuilder::FinalizationInfo FI( + {FiniCB, OMPD_parallel, HasCancel}); + OMPBuilder->pushFinalizationCB(std::move(FI)); + } + ~PushAndPopStackRAII() { + if (OMPBuilder) + OMPBuilder->popFinalizationCB(); + } + llvm::OpenMPIRBuilder *OMPBuilder; +}; +} // namespace + static llvm::Function *emitParallelOrTeamsOutlinedFunction( CodeGenModule &CGM, const OMPExecutableDirective &D, const CapturedStmt *CS, const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind, @@ -1460,6 +1508,11 @@ static llvm::Function *emitParallelOrTeamsOutlinedFunction( else if (const auto *OPFD = dyn_cast<OMPTargetTeamsDistributeParallelForDirective>(&D)) HasCancel = OPFD->hasCancel(); + + // TODO: Temporarily inform the OpenMPIRBuilder, if any, about the new + // parallel region to make cancellation barriers work properly. + llvm::OpenMPIRBuilder *OMPBuilder = CGM.getOpenMPIRBuilder(); + PushAndPopStackRAII PSR(OMPBuilder, CGF, HasCancel); CGOpenMPOutlinedRegionInfo CGInfo(*CS, ThreadIDVar, CodeGen, InnermostKind, HasCancel, OutlinedHelperName); CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CGInfo); @@ -1495,7 +1548,7 @@ llvm::Function *CGOpenMPRuntime::emitTaskOutlinedFunction( UpLoc, ThreadID, CGF.EmitLoadOfPointerLValue(CGF.GetAddrOfLocalVar(TaskTVar), TaskTVar->getType()->castAs<PointerType>()) - .getPointer()}; + .getPointer(CGF)}; CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_omp_task), TaskArgs); }; CGOpenMPTaskOutlinedRegionInfo::UntiedTaskActionTy Action(Tied, PartIDVar, @@ -1706,9 +1759,10 @@ llvm::Value *CGOpenMPRuntime::getThreadID(CodeGenFunction &CGF, if (!CGF.EHStack.requiresLandingPad() || !CGF.getLangOpts().Exceptions || !CGF.getLangOpts().CXXExceptions || CGF.Builder.GetInsertBlock() == TopBlock || - !isa<llvm::Instruction>(LVal.getPointer()) || - cast<llvm::Instruction>(LVal.getPointer())->getParent() == TopBlock || - cast<llvm::Instruction>(LVal.getPointer())->getParent() == + !isa<llvm::Instruction>(LVal.getPointer(CGF)) || + cast<llvm::Instruction>(LVal.getPointer(CGF))->getParent() == + TopBlock || + cast<llvm::Instruction>(LVal.getPointer(CGF))->getParent() == CGF.Builder.GetInsertBlock()) { ThreadID = CGF.EmitLoadOfScalar(LVal, Loc); // If value loaded in entry block, cache it and use it everywhere in @@ -2422,26 +2476,6 @@ llvm::FunctionCallee CGOpenMPRuntime::createRuntimeFunction(unsigned Function) { RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_register_requires"); break; } - case OMPRTL__tgt_register_lib: { - // Build void __tgt_register_lib(__tgt_bin_desc *desc); - QualType ParamTy = - CGM.getContext().getPointerType(getTgtBinaryDescriptorQTy()); - llvm::Type *TypeParams[] = {CGM.getTypes().ConvertTypeForMem(ParamTy)}; - auto *FnTy = - llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false); - RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_register_lib"); - break; - } - case OMPRTL__tgt_unregister_lib: { - // Build void __tgt_unregister_lib(__tgt_bin_desc *desc); - QualType ParamTy = - CGM.getContext().getPointerType(getTgtBinaryDescriptorQTy()); - llvm::Type *TypeParams[] = {CGM.getTypes().ConvertTypeForMem(ParamTy)}; - auto *FnTy = - llvm::FunctionType::get(CGM.Int32Ty, TypeParams, /*isVarArg*/ false); - RTLFn = CGM.CreateRuntimeFunction(FnTy, "__tgt_unregister_lib"); - break; - } case OMPRTL__tgt_target_data_begin: { // Build void __tgt_target_data_begin(int64_t device_id, int32_t arg_num, // void** args_base, void **args, int64_t *arg_sizes, int64_t *arg_types); @@ -2988,10 +3022,15 @@ Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF, QualType VarType, StringRef Name) { std::string Suffix = getName({"artificial", ""}); - std::string CacheSuffix = getName({"cache", ""}); llvm::Type *VarLVType = CGF.ConvertTypeForMem(VarType); llvm::Value *GAddr = getOrCreateInternalVariable(VarLVType, Twine(Name).concat(Suffix)); + if (CGM.getLangOpts().OpenMP && CGM.getLangOpts().OpenMPUseTLS && + CGM.getTarget().isTLSSupported()) { + cast<llvm::GlobalVariable>(GAddr)->setThreadLocal(/*Val=*/true); + return Address(GAddr, CGM.getContext().getTypeAlignInChars(VarType)); + } + std::string CacheSuffix = getName({"cache", ""}); llvm::Value *Args[] = { emitUpdateLocation(CGF, SourceLocation()), getThreadID(CGF, SourceLocation()), @@ -3005,12 +3044,12 @@ Address CGOpenMPRuntime::getAddrOfArtificialThreadPrivate(CodeGenFunction &CGF, CGF.EmitRuntimeCall( createRuntimeFunction(OMPRTL__kmpc_threadprivate_cached), Args), VarLVType->getPointerTo(/*AddrSpace=*/0)), - CGM.getPointerAlign()); + CGM.getContext().getTypeAlignInChars(VarType)); } -void CGOpenMPRuntime::emitOMPIfClause(CodeGenFunction &CGF, const Expr *Cond, - const RegionCodeGenTy &ThenGen, - const RegionCodeGenTy &ElseGen) { +void CGOpenMPRuntime::emitIfClause(CodeGenFunction &CGF, const Expr *Cond, + const RegionCodeGenTy &ThenGen, + const RegionCodeGenTy &ElseGen) { CodeGenFunction::LexicalScope ConditionScope(CGF, Cond->getSourceRange()); // If the condition constant folds and can be elided, try to avoid emitting @@ -3100,7 +3139,7 @@ void CGOpenMPRuntime::emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc, EndArgs); }; if (IfCond) { - emitOMPIfClause(CGF, IfCond, ThenGen, ElseGen); + emitIfClause(CGF, IfCond, ThenGen, ElseGen); } else { RegionCodeGenTy ThenRCG(ThenGen); ThenRCG(CGF); @@ -3118,7 +3157,7 @@ Address CGOpenMPRuntime::emitThreadIDAddress(CodeGenFunction &CGF, if (auto *OMPRegionInfo = dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) if (OMPRegionInfo->getThreadIDVariable()) - return OMPRegionInfo->getThreadIDVariableLValue(CGF).getAddress(); + return OMPRegionInfo->getThreadIDVariableLValue(CGF).getAddress(CGF); llvm::Value *ThreadID = getThreadID(CGF, Loc); QualType Int32Ty = @@ -3394,7 +3433,8 @@ void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF, Address Elem = CGF.Builder.CreateConstArrayGEP(CopyprivateList, I); CGF.Builder.CreateStore( CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLValue(CopyprivateVars[I]).getPointer(), CGF.VoidPtrTy), + CGF.EmitLValue(CopyprivateVars[I]).getPointer(CGF), + CGF.VoidPtrTy), Elem); } // Build function that copies private values from single region to all other @@ -3476,6 +3516,16 @@ void CGOpenMPRuntime::getDefaultScheduleAndChunk( void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind Kind, bool EmitChecks, bool ForceSimpleCall) { + // Check if we should use the OMPBuilder + auto *OMPRegionInfo = + dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo); + llvm::OpenMPIRBuilder *OMPBuilder = CGF.CGM.getOpenMPIRBuilder(); + if (OMPBuilder) { + CGF.Builder.restoreIP(OMPBuilder->CreateBarrier( + CGF.Builder, Kind, ForceSimpleCall, EmitChecks)); + return; + } + if (!CGF.HaveInsertPoint()) return; // Build call __kmpc_cancel_barrier(loc, thread_id); @@ -3485,8 +3535,7 @@ void CGOpenMPRuntime::emitBarrierCall(CodeGenFunction &CGF, SourceLocation Loc, // thread_id); llvm::Value *Args[] = {emitUpdateLocation(CGF, Loc, Flags), getThreadID(CGF, Loc)}; - if (auto *OMPRegionInfo = - dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) { + if (OMPRegionInfo) { if (!ForceSimpleCall && OMPRegionInfo->hasCancel()) { llvm::Value *Result = CGF.EmitRuntimeCall( createRuntimeFunction(OMPRTL__kmpc_cancel_barrier), Args); @@ -3616,7 +3665,9 @@ static int addMonoNonMonoModifier(CodeGenModule &CGM, OpenMPSchedType Schedule, if (CGM.getLangOpts().OpenMP >= 50 && Modifier == 0) { if (!(Schedule == OMP_sch_static_chunked || Schedule == OMP_sch_static || Schedule == OMP_sch_static_balanced_chunked || - Schedule == OMP_ord_static_chunked || Schedule == OMP_ord_static)) + Schedule == OMP_ord_static_chunked || Schedule == OMP_ord_static || + Schedule == OMP_dist_sch_static_chunked || + Schedule == OMP_dist_sch_static)) Modifier = OMP_sch_modifier_nonmonotonic; } return Schedule | Modifier; @@ -3807,37 +3858,15 @@ void CGOpenMPRuntime::emitNumThreadsClause(CodeGenFunction &CGF, } void CGOpenMPRuntime::emitProcBindClause(CodeGenFunction &CGF, - OpenMPProcBindClauseKind ProcBind, + ProcBindKind ProcBind, SourceLocation Loc) { if (!CGF.HaveInsertPoint()) return; - // Constants for proc bind value accepted by the runtime. - enum ProcBindTy { - ProcBindFalse = 0, - ProcBindTrue, - ProcBindMaster, - ProcBindClose, - ProcBindSpread, - ProcBindIntel, - ProcBindDefault - } RuntimeProcBind; - switch (ProcBind) { - case OMPC_PROC_BIND_master: - RuntimeProcBind = ProcBindMaster; - break; - case OMPC_PROC_BIND_close: - RuntimeProcBind = ProcBindClose; - break; - case OMPC_PROC_BIND_spread: - RuntimeProcBind = ProcBindSpread; - break; - case OMPC_PROC_BIND_unknown: - llvm_unreachable("Unsupported proc_bind value."); - } + assert(ProcBind != OMP_PROC_BIND_unknown && "Unsupported proc_bind value."); // Build call __kmpc_push_proc_bind(&loc, global_tid, proc_bind) llvm::Value *Args[] = { emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), - llvm::ConstantInt::get(CGM.IntTy, RuntimeProcBind, /*isSigned=*/true)}; + llvm::ConstantInt::get(CGM.IntTy, unsigned(ProcBind), /*isSigned=*/true)}; CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_push_proc_bind), Args); } @@ -4327,57 +4356,6 @@ QualType CGOpenMPRuntime::getTgtOffloadEntryQTy() { return TgtOffloadEntryQTy; } -QualType CGOpenMPRuntime::getTgtDeviceImageQTy() { - // These are the types we need to build: - // struct __tgt_device_image{ - // void *ImageStart; // Pointer to the target code start. - // void *ImageEnd; // Pointer to the target code end. - // // We also add the host entries to the device image, as it may be useful - // // for the target runtime to have access to that information. - // __tgt_offload_entry *EntriesBegin; // Begin of the table with all - // // the entries. - // __tgt_offload_entry *EntriesEnd; // End of the table with all the - // // entries (non inclusive). - // }; - if (TgtDeviceImageQTy.isNull()) { - ASTContext &C = CGM.getContext(); - RecordDecl *RD = C.buildImplicitRecord("__tgt_device_image"); - RD->startDefinition(); - addFieldToRecordDecl(C, RD, C.VoidPtrTy); - addFieldToRecordDecl(C, RD, C.VoidPtrTy); - addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy())); - addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy())); - RD->completeDefinition(); - TgtDeviceImageQTy = C.getRecordType(RD); - } - return TgtDeviceImageQTy; -} - -QualType CGOpenMPRuntime::getTgtBinaryDescriptorQTy() { - // struct __tgt_bin_desc{ - // int32_t NumDevices; // Number of devices supported. - // __tgt_device_image *DeviceImages; // Arrays of device images - // // (one per device). - // __tgt_offload_entry *EntriesBegin; // Begin of the table with all the - // // entries. - // __tgt_offload_entry *EntriesEnd; // End of the table with all the - // // entries (non inclusive). - // }; - if (TgtBinaryDescriptorQTy.isNull()) { - ASTContext &C = CGM.getContext(); - RecordDecl *RD = C.buildImplicitRecord("__tgt_bin_desc"); - RD->startDefinition(); - addFieldToRecordDecl( - C, RD, C.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/true)); - addFieldToRecordDecl(C, RD, C.getPointerType(getTgtDeviceImageQTy())); - addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy())); - addFieldToRecordDecl(C, RD, C.getPointerType(getTgtOffloadEntryQTy())); - RD->completeDefinition(); - TgtBinaryDescriptorQTy = C.getRecordType(RD); - } - return TgtBinaryDescriptorQTy; -} - namespace { struct PrivateHelpersTy { PrivateHelpersTy(const VarDecl *Original, const VarDecl *PrivateCopy, @@ -4537,7 +4515,7 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc, const auto *KmpTaskTQTyRD = cast<RecordDecl>(KmpTaskTQTy->getAsTagDecl()); auto PartIdFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTPartId); LValue PartIdLVal = CGF.EmitLValueForField(Base, *PartIdFI); - llvm::Value *PartidParam = PartIdLVal.getPointer(); + llvm::Value *PartidParam = PartIdLVal.getPointer(CGF); auto SharedsFI = std::next(KmpTaskTQTyRD->field_begin(), KmpTaskTShareds); LValue SharedsLVal = CGF.EmitLValueForField(Base, *SharedsFI); @@ -4550,7 +4528,7 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc, if (PrivatesFI != KmpTaskTWithPrivatesQTyRD->field_end()) { LValue PrivatesLVal = CGF.EmitLValueForField(TDBase, *PrivatesFI); PrivatesParam = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - PrivatesLVal.getPointer(), CGF.VoidPtrTy); + PrivatesLVal.getPointer(CGF), CGF.VoidPtrTy); } else { PrivatesParam = llvm::ConstantPointerNull::get(CGF.VoidPtrTy); } @@ -4559,7 +4537,7 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc, TaskPrivatesMap, CGF.Builder .CreatePointerBitCastOrAddrSpaceCast( - TDBase.getAddress(), CGF.VoidPtrTy) + TDBase.getAddress(CGF), CGF.VoidPtrTy) .getPointer()}; SmallVector<llvm::Value *, 16> CallArgs(std::begin(CommonArgs), std::end(CommonArgs)); @@ -4637,7 +4615,7 @@ static llvm::Value *emitDestructorsFunction(CodeGenModule &CGM, if (QualType::DestructionKind DtorKind = Field->getType().isDestructedType()) { LValue FieldLValue = CGF.EmitLValueForField(Base, Field); - CGF.pushDestroy(DtorKind, FieldLValue.getAddress(), Field->getType()); + CGF.pushDestroy(DtorKind, FieldLValue.getAddress(CGF), Field->getType()); } } CGF.FinishFunction(); @@ -4735,8 +4713,8 @@ emitTaskPrivateMappingFunction(CodeGenModule &CGM, SourceLocation Loc, LValue RefLVal = CGF.MakeAddrLValue(CGF.GetAddrOfLocalVar(VD), VD->getType()); LValue RefLoadLVal = CGF.EmitLoadOfPointerLValue( - RefLVal.getAddress(), RefLVal.getType()->castAs<PointerType>()); - CGF.EmitStoreOfScalar(FieldLVal.getPointer(), RefLoadLVal); + RefLVal.getAddress(CGF), RefLVal.getType()->castAs<PointerType>()); + CGF.EmitStoreOfScalar(FieldLVal.getPointer(CGF), RefLoadLVal); ++Counter; } CGF.FinishFunction(); @@ -4801,7 +4779,8 @@ static void emitPrivatesInit(CodeGenFunction &CGF, } else { SharedRefLValue = CGF.EmitLValueForField(SrcBase, SharedField); SharedRefLValue = CGF.MakeAddrLValue( - Address(SharedRefLValue.getPointer(), C.getDeclAlign(OriginalVD)), + Address(SharedRefLValue.getPointer(CGF), + C.getDeclAlign(OriginalVD)), SharedRefLValue.getType(), LValueBaseInfo(AlignmentSource::Decl), SharedRefLValue.getTBAAInfo()); } @@ -4814,7 +4793,8 @@ static void emitPrivatesInit(CodeGenFunction &CGF, // Initialize firstprivate array using element-by-element // initialization. CGF.EmitOMPAggregateAssign( - PrivateLValue.getAddress(), SharedRefLValue.getAddress(), Type, + PrivateLValue.getAddress(CGF), SharedRefLValue.getAddress(CGF), + Type, [&CGF, Elem, Init, &CapturesInfo](Address DestElement, Address SrcElement) { // Clean up any temporaries needed by the initialization. @@ -4832,8 +4812,8 @@ static void emitPrivatesInit(CodeGenFunction &CGF, } } else { CodeGenFunction::OMPPrivateScope InitScope(CGF); - InitScope.addPrivate(Elem, [SharedRefLValue]() -> Address { - return SharedRefLValue.getAddress(); + InitScope.addPrivate(Elem, [SharedRefLValue, &CGF]() -> Address { + return SharedRefLValue.getAddress(CGF); }); (void)InitScope.Privatize(); CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(CGF, &CapturesInfo); @@ -5233,10 +5213,10 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, dyn_cast<OMPArraySectionExpr>(E->IgnoreParenImpCasts())) { LValue UpAddrLVal = CGF.EmitOMPArraySectionExpr(ASE, /*IsLowerBound=*/false); - llvm::Value *UpAddr = - CGF.Builder.CreateConstGEP1_32(UpAddrLVal.getPointer(), /*Idx0=*/1); + llvm::Value *UpAddr = CGF.Builder.CreateConstGEP1_32( + UpAddrLVal.getPointer(CGF), /*Idx0=*/1); llvm::Value *LowIntPtr = - CGF.Builder.CreatePtrToInt(Addr.getPointer(), CGM.SizeTy); + CGF.Builder.CreatePtrToInt(Addr.getPointer(CGF), CGM.SizeTy); llvm::Value *UpIntPtr = CGF.Builder.CreatePtrToInt(UpAddr, CGM.SizeTy); Size = CGF.Builder.CreateNUWSub(UpIntPtr, LowIntPtr); } else { @@ -5249,7 +5229,7 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, LValue BaseAddrLVal = CGF.EmitLValueForField( Base, *std::next(KmpDependInfoRD->field_begin(), BaseAddr)); CGF.EmitStoreOfScalar( - CGF.Builder.CreatePtrToInt(Addr.getPointer(), CGF.IntPtrTy), + CGF.Builder.CreatePtrToInt(Addr.getPointer(CGF), CGF.IntPtrTy), BaseAddrLVal); // deps[i].len = sizeof(<Dependences[i].second>); LValue LenLVal = CGF.EmitLValueForField( @@ -5366,7 +5346,7 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, }; if (IfCond) { - emitOMPIfClause(CGF, IfCond, ThenCodeGen, ElseCodeGen); + emitIfClause(CGF, IfCond, ThenCodeGen, ElseCodeGen); } else { RegionCodeGenTy ThenRCG(ThenCodeGen); ThenRCG(CGF); @@ -5403,21 +5383,24 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc, *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTLowerBound)); const auto *LBVar = cast<VarDecl>(cast<DeclRefExpr>(D.getLowerBoundVariable())->getDecl()); - CGF.EmitAnyExprToMem(LBVar->getInit(), LBLVal.getAddress(), LBLVal.getQuals(), + CGF.EmitAnyExprToMem(LBVar->getInit(), LBLVal.getAddress(CGF), + LBLVal.getQuals(), /*IsInitializer=*/true); LValue UBLVal = CGF.EmitLValueForField( Result.TDBase, *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTUpperBound)); const auto *UBVar = cast<VarDecl>(cast<DeclRefExpr>(D.getUpperBoundVariable())->getDecl()); - CGF.EmitAnyExprToMem(UBVar->getInit(), UBLVal.getAddress(), UBLVal.getQuals(), + CGF.EmitAnyExprToMem(UBVar->getInit(), UBLVal.getAddress(CGF), + UBLVal.getQuals(), /*IsInitializer=*/true); LValue StLVal = CGF.EmitLValueForField( Result.TDBase, *std::next(Result.KmpTaskTQTyRD->field_begin(), KmpTaskTStride)); const auto *StVar = cast<VarDecl>(cast<DeclRefExpr>(D.getStrideVariable())->getDecl()); - CGF.EmitAnyExprToMem(StVar->getInit(), StLVal.getAddress(), StLVal.getQuals(), + CGF.EmitAnyExprToMem(StVar->getInit(), StLVal.getAddress(CGF), + StLVal.getQuals(), /*IsInitializer=*/true); // Store reductions address. LValue RedLVal = CGF.EmitLValueForField( @@ -5426,7 +5409,7 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc, if (Data.Reductions) { CGF.EmitStoreOfScalar(Data.Reductions, RedLVal); } else { - CGF.EmitNullInitialization(RedLVal.getAddress(), + CGF.EmitNullInitialization(RedLVal.getAddress(CGF), CGF.getContext().VoidPtrTy); } enum { NoSchedule = 0, Grainsize = 1, NumTasks = 2 }; @@ -5435,11 +5418,11 @@ void CGOpenMPRuntime::emitTaskLoopCall(CodeGenFunction &CGF, SourceLocation Loc, ThreadID, Result.NewTask, IfVal, - LBLVal.getPointer(), - UBLVal.getPointer(), + LBLVal.getPointer(CGF), + UBLVal.getPointer(CGF), CGF.EmitLoadOfScalar(StLVal, Loc), llvm::ConstantInt::getSigned( - CGF.IntTy, 1), // Always 1 because taskgroup emitted by the compiler + CGF.IntTy, 1), // Always 1 because taskgroup emitted by the compiler llvm::ConstantInt::getSigned( CGF.IntTy, Data.Schedule.getPointer() ? Data.Schedule.getInt() ? NumTasks : Grainsize @@ -5751,7 +5734,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx); CGF.Builder.CreateStore( CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLValue(RHSExprs[I]).getPointer(), CGF.VoidPtrTy), + CGF.EmitLValue(RHSExprs[I]).getPointer(CGF), CGF.VoidPtrTy), Elem); if ((*IPriv)->getType()->isVariablyModifiedType()) { // Store array size. @@ -6179,7 +6162,7 @@ static llvm::Value *emitReduceFiniFunction(CodeGenModule &CGM, // Emit the finalizer body: // <destroy>(<type>* %0) RCG.emitCleanups(CGF, N, PrivateAddr); - CGF.FinishFunction(); + CGF.FinishFunction(Loc); return Fn; } @@ -6231,7 +6214,7 @@ llvm::Value *CGOpenMPRuntime::emitTaskReductionInit( LValue SharedLVal = CGF.EmitLValueForField(ElemLVal, SharedFD); RCG.emitSharedLValue(CGF, Cnt); llvm::Value *CastedShared = - CGF.EmitCastToVoidPtr(RCG.getSharedLValue(Cnt).getPointer()); + CGF.EmitCastToVoidPtr(RCG.getSharedLValue(Cnt).getPointer(CGF)); CGF.EmitStoreOfScalar(CastedShared, SharedLVal); RCG.emitAggregateType(CGF, Cnt); llvm::Value *SizeValInChars; @@ -6274,7 +6257,8 @@ llvm::Value *CGOpenMPRuntime::emitTaskReductionInit( llvm::ConstantInt::get(CGM.Int32Ty, /*V=*/1, /*isSigned=*/true), FlagsLVal); } else - CGF.EmitNullInitialization(FlagsLVal.getAddress(), FlagsLVal.getType()); + CGF.EmitNullInitialization(FlagsLVal.getAddress(CGF), + FlagsLVal.getType()); } // Build call void *__kmpc_task_reduction_init(int gtid, int num_data, void // *data); @@ -6310,7 +6294,7 @@ void CGOpenMPRuntime::emitTaskReductionFixups(CodeGenFunction &CGF, generateUniqueName(CGM, "reduction", RCG.getRefExpr(N))); CGF.Builder.CreateStore( CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - RCG.getSharedLValue(N).getPointer(), CGM.VoidPtrTy), + RCG.getSharedLValue(N).getPointer(CGF), CGM.VoidPtrTy), SharedAddr, /*IsVolatile=*/false); } } @@ -6321,12 +6305,12 @@ Address CGOpenMPRuntime::getTaskReductionItem(CodeGenFunction &CGF, LValue SharedLVal) { // Build call void *__kmpc_task_reduction_get_th_data(int gtid, void *tg, void // *d); - llvm::Value *Args[] = { - CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), CGM.IntTy, - /*isSigned=*/true), - ReductionsPtr, - CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(SharedLVal.getPointer(), - CGM.VoidPtrTy)}; + llvm::Value *Args[] = {CGF.Builder.CreateIntCast(getThreadID(CGF, Loc), + CGM.IntTy, + /*isSigned=*/true), + ReductionsPtr, + CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( + SharedLVal.getPointer(CGF), CGM.VoidPtrTy)}; return Address( CGF.EmitRuntimeCall( createRuntimeFunction(OMPRTL__kmpc_task_reduction_get_th_data), Args), @@ -6449,8 +6433,8 @@ void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc, CGF.EmitBlock(ContBB, /*IsFinished=*/true); }; if (IfCond) { - emitOMPIfClause(CGF, IfCond, ThenGen, - [](CodeGenFunction &, PrePostActionTy &) {}); + emitIfClause(CGF, IfCond, ThenGen, + [](CodeGenFunction &, PrePostActionTy &) {}); } else { RegionCodeGenTy ThenRCG(ThenGen); ThenRCG(CGF); @@ -6663,6 +6647,7 @@ emitNumTeamsForTargetDirective(CodeGenFunction &CGF, case OMPD_parallel: case OMPD_for: case OMPD_parallel_for: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_for_simd: case OMPD_parallel_for_simd: @@ -6708,6 +6693,7 @@ emitNumTeamsForTargetDirective(CodeGenFunction &CGF, case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: break; @@ -6972,6 +6958,7 @@ emitNumThreadsForTargetDirective(CodeGenFunction &CGF, case OMPD_parallel: case OMPD_for: case OMPD_parallel_for: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_for_simd: case OMPD_parallel_for_simd: @@ -7017,6 +7004,7 @@ emitNumThreadsForTargetDirective(CodeGenFunction &CGF, case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: break; @@ -7509,11 +7497,11 @@ private: } else if ((AE && isa<CXXThisExpr>(AE->getBase()->IgnoreParenImpCasts())) || (OASE && isa<CXXThisExpr>(OASE->getBase()->IgnoreParenImpCasts()))) { - BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress(); + BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress(CGF); } else { // The base is the reference to the variable. // BP = &Var. - BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress(); + BP = CGF.EmitOMPSharedLValue(AssocExpr).getAddress(CGF); if (const auto *VD = dyn_cast_or_null<VarDecl>(I->getAssociatedDeclaration())) { if (llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res = @@ -7607,8 +7595,8 @@ private: isa<OMPArraySectionExpr>(Next->getAssociatedExpression())) && "Unexpected expression"); - Address LB = - CGF.EmitOMPSharedLValue(I->getAssociatedExpression()).getAddress(); + Address LB = CGF.EmitOMPSharedLValue(I->getAssociatedExpression()) + .getAddress(CGF); // If this component is a pointer inside the base struct then we don't // need to create any entry for it - it will be combined with the object @@ -7655,7 +7643,7 @@ private: if (MC.getAssociatedDeclaration()) { ComponentLB = CGF.EmitOMPSharedLValue(MC.getAssociatedExpression()) - .getAddress(); + .getAddress(CGF); Size = CGF.Builder.CreatePtrDiff( CGF.EmitCastToVoidPtr(ComponentLB.getPointer()), CGF.EmitCastToVoidPtr(LB.getPointer())); @@ -7938,17 +7926,17 @@ public: "Expect a executable directive"); const auto *CurExecDir = CurDir.get<const OMPExecutableDirective *>(); for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) - for (const auto &L : C->component_lists()) { + for (const auto L : C->component_lists()) { InfoGen(L.first, L.second, C->getMapType(), C->getMapTypeModifiers(), /*ReturnDevicePointer=*/false, C->isImplicit()); } for (const auto *C : CurExecDir->getClausesOfKind<OMPToClause>()) - for (const auto &L : C->component_lists()) { + for (const auto L : C->component_lists()) { InfoGen(L.first, L.second, OMPC_MAP_to, llvm::None, /*ReturnDevicePointer=*/false, C->isImplicit()); } for (const auto *C : CurExecDir->getClausesOfKind<OMPFromClause>()) - for (const auto &L : C->component_lists()) { + for (const auto L : C->component_lists()) { InfoGen(L.first, L.second, OMPC_MAP_from, llvm::None, /*ReturnDevicePointer=*/false, C->isImplicit()); } @@ -7964,7 +7952,7 @@ public: for (const auto *C : CurExecDir->getClausesOfKind<OMPUseDevicePtrClause>()) { - for (const auto &L : C->component_lists()) { + for (const auto L : C->component_lists()) { assert(!L.second.empty() && "Not expecting empty list of components!"); const ValueDecl *VD = L.second.back().getAssociatedDeclaration(); VD = cast<ValueDecl>(VD->getCanonicalDecl()); @@ -8059,7 +8047,7 @@ public: auto CI = DeferredInfo.find(M.first); if (CI != DeferredInfo.end()) { for (const DeferredDevicePtrEntryTy &L : CI->second) { - llvm::Value *BasePtr = this->CGF.EmitLValue(L.IE).getPointer(); + llvm::Value *BasePtr = this->CGF.EmitLValue(L.IE).getPointer(CGF); llvm::Value *Ptr = this->CGF.EmitLoadOfScalar( this->CGF.EmitLValue(L.IE), L.IE->getExprLoc()); CurBasePointers.emplace_back(BasePtr, L.VD); @@ -8117,7 +8105,7 @@ public: for (const auto *C : CurMapperDir->clauselists()) { const auto *MC = cast<OMPMapClause>(C); - for (const auto &L : MC->component_lists()) { + for (const auto L : MC->component_lists()) { InfoGen(L.first, L.second, MC->getMapType(), MC->getMapTypeModifiers(), /*ReturnDevicePointer=*/false, MC->isImplicit()); } @@ -8181,9 +8169,10 @@ public: LValue ThisLVal = CGF.EmitLValueForFieldInitialization(VDLVal, ThisCapture); LValue ThisLValVal = CGF.EmitLValueForField(VDLVal, ThisCapture); - LambdaPointers.try_emplace(ThisLVal.getPointer(), VDLVal.getPointer()); - BasePointers.push_back(ThisLVal.getPointer()); - Pointers.push_back(ThisLValVal.getPointer()); + LambdaPointers.try_emplace(ThisLVal.getPointer(CGF), + VDLVal.getPointer(CGF)); + BasePointers.push_back(ThisLVal.getPointer(CGF)); + Pointers.push_back(ThisLValVal.getPointer(CGF)); Sizes.push_back( CGF.Builder.CreateIntCast(CGF.getTypeSize(CGF.getContext().VoidPtrTy), CGF.Int64Ty, /*isSigned=*/true)); @@ -8201,17 +8190,19 @@ public: LValue VarLVal = CGF.EmitLValueForFieldInitialization(VDLVal, It->second); if (LC.getCaptureKind() == LCK_ByRef) { LValue VarLValVal = CGF.EmitLValueForField(VDLVal, It->second); - LambdaPointers.try_emplace(VarLVal.getPointer(), VDLVal.getPointer()); - BasePointers.push_back(VarLVal.getPointer()); - Pointers.push_back(VarLValVal.getPointer()); + LambdaPointers.try_emplace(VarLVal.getPointer(CGF), + VDLVal.getPointer(CGF)); + BasePointers.push_back(VarLVal.getPointer(CGF)); + Pointers.push_back(VarLValVal.getPointer(CGF)); Sizes.push_back(CGF.Builder.CreateIntCast( CGF.getTypeSize( VD->getType().getCanonicalType().getNonReferenceType()), CGF.Int64Ty, /*isSigned=*/true)); } else { RValue VarRVal = CGF.EmitLoadOfLValue(VarLVal, RD->getLocation()); - LambdaPointers.try_emplace(VarLVal.getPointer(), VDLVal.getPointer()); - BasePointers.push_back(VarLVal.getPointer()); + LambdaPointers.try_emplace(VarLVal.getPointer(CGF), + VDLVal.getPointer(CGF)); + BasePointers.push_back(VarLVal.getPointer(CGF)); Pointers.push_back(VarRVal.getScalarVal()); Sizes.push_back(llvm::ConstantInt::get(CGF.Int64Ty, 0)); } @@ -8286,7 +8277,7 @@ public: "Expect a executable directive"); const auto *CurExecDir = CurDir.get<const OMPExecutableDirective *>(); for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) { - for (const auto &L : C->decl_component_lists(VD)) { + for (const auto L : C->decl_component_lists(VD)) { assert(L.first == VD && "We got information for the wrong declaration??"); assert(!L.second.empty() && @@ -8439,7 +8430,7 @@ public: // Map other list items in the map clause which are not captured variables // but "declare target link" global variables. for (const auto *C : CurExecDir->getClausesOfKind<OMPMapClause>()) { - for (const auto &L : C->component_lists()) { + for (const auto L : C->component_lists()) { if (!L.first) continue; const auto *VD = dyn_cast<VarDecl>(L.first); @@ -8517,7 +8508,7 @@ public: CGF.CGM.getOpenMPRuntime().registerTargetFirstprivateCopy(CGF, VD); // Copy the value of the original variable to the new global copy. CGF.Builder.CreateMemCpy( - CGF.MakeNaturalAlignAddrLValue(Addr, ElementType).getAddress(), + CGF.MakeNaturalAlignAddrLValue(Addr, ElementType).getAddress(CGF), Address(CV, CGF.getContext().getTypeAlignInChars(ElementType)), CurSizes.back(), /*IsVolatile=*/false); // Use new global variable as the base pointers. @@ -8746,6 +8737,7 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) { case OMPD_parallel: case OMPD_for: case OMPD_parallel_for: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_for_simd: case OMPD_parallel_for_simd: @@ -8791,6 +8783,7 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) { case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: llvm_unreachable("Unexpected directive."); @@ -8926,7 +8919,7 @@ void CGOpenMPRuntime::emitUserDefinedMapper(const OMPDeclareMapperDecl *D, Scope.addPrivate(MapperVarDecl, [&MapperCGF, PtrCurrent, PtrTy]() { return MapperCGF .EmitLoadOfPointerLValue(PtrCurrent, PtrTy->castAs<PointerType>()) - .getAddress(); + .getAddress(MapperCGF); }); (void)Scope.Privatize(); @@ -9423,7 +9416,7 @@ void CGOpenMPRuntime::emitTargetCall( // specify target triples. if (OutlinedFnID) { if (IfCond) { - emitOMPIfClause(CGF, IfCond, TargetThenGen, TargetElseGen); + emitIfClause(CGF, IfCond, TargetThenGen, TargetElseGen); } else { RegionCodeGenTy ThenRCG(TargetThenGen); ThenRCG(CGF); @@ -9506,6 +9499,7 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S, case OMPD_parallel: case OMPD_for: case OMPD_parallel_for: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_for_simd: case OMPD_parallel_for_simd: @@ -9551,6 +9545,7 @@ void CGOpenMPRuntime::scanForTargetRegionsFunctions(const Stmt *S, case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: llvm_unreachable("Unknown target directive for OpenMP device codegen."); @@ -9591,9 +9586,9 @@ bool CGOpenMPRuntime::emitTargetFunctions(GlobalDecl GD) { } const ValueDecl *VD = cast<ValueDecl>(GD.getDecl()); - StringRef Name = CGM.getMangledName(GD); // Try to detect target regions in the function. if (const auto *FD = dyn_cast<FunctionDecl>(VD)) { + StringRef Name = CGM.getMangledName(GD); scanForTargetRegionsFunctions(FD->getBody(), Name); Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = OMPDeclareTargetDeclAttr::getDeviceType(FD); @@ -9604,7 +9599,7 @@ bool CGOpenMPRuntime::emitTargetFunctions(GlobalDecl GD) { // Do not to emit function if it is not marked as declare target. return !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) && - AlreadyEmittedTargetFunctions.count(Name) == 0; + AlreadyEmittedTargetDecls.count(VD) == 0; } bool CGOpenMPRuntime::emitTargetGlobalVariable(GlobalDecl GD) { @@ -9835,20 +9830,20 @@ bool CGOpenMPRuntime::markAsGlobalTarget(GlobalDecl GD) { if (!CGM.getLangOpts().OpenMPIsDevice || !ShouldMarkAsGlobal) return true; - StringRef Name = CGM.getMangledName(GD); const auto *D = cast<FunctionDecl>(GD.getDecl()); // Do not to emit function if it is marked as declare target as it was already // emitted. if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(D)) { - if (D->hasBody() && AlreadyEmittedTargetFunctions.count(Name) == 0) { - if (auto *F = dyn_cast_or_null<llvm::Function>(CGM.GetGlobalValue(Name))) + if (D->hasBody() && AlreadyEmittedTargetDecls.count(D) == 0) { + if (auto *F = dyn_cast_or_null<llvm::Function>( + CGM.GetGlobalValue(CGM.getMangledName(GD)))) return !F->isDeclaration(); return false; } return true; } - return !AlreadyEmittedTargetFunctions.insert(Name).second; + return !AlreadyEmittedTargetDecls.insert(D).second; } llvm::Function *CGOpenMPRuntime::emitRequiresDirectiveRegFun() { @@ -10050,7 +10045,7 @@ void CGOpenMPRuntime::emitTargetDataCalls( auto &&EndElseGen = [](CodeGenFunction &CGF, PrePostActionTy &) {}; if (IfCond) { - emitOMPIfClause(CGF, IfCond, BeginThenGen, BeginElseGen); + emitIfClause(CGF, IfCond, BeginThenGen, BeginElseGen); } else { RegionCodeGenTy RCG(BeginThenGen); RCG(CGF); @@ -10064,7 +10059,7 @@ void CGOpenMPRuntime::emitTargetDataCalls( } if (IfCond) { - emitOMPIfClause(CGF, IfCond, EndThenGen, EndElseGen); + emitIfClause(CGF, IfCond, EndThenGen, EndElseGen); } else { RegionCodeGenTy RCG(EndThenGen); RCG(CGF); @@ -10127,6 +10122,7 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( case OMPD_parallel: case OMPD_for: case OMPD_parallel_for: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_for_simd: case OMPD_parallel_for_simd: @@ -10169,6 +10165,7 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_target: case OMPD_target_simd: case OMPD_target_teams_distribute: @@ -10220,8 +10217,8 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( }; if (IfCond) { - emitOMPIfClause(CGF, IfCond, TargetThenGen, - [](CodeGenFunction &CGF, PrePostActionTy &) {}); + emitIfClause(CGF, IfCond, TargetThenGen, + [](CodeGenFunction &CGF, PrePostActionTy &) {}); } else { RegionCodeGenTy ThenRCG(TargetThenGen); ThenRCG(CGF); @@ -10759,8 +10756,7 @@ void CGOpenMPRuntime::emitDeclareSimdFunction(const FunctionDecl *FD, ExprLoc = VLENExpr->getExprLoc(); } OMPDeclareSimdDeclAttr::BranchStateTy State = Attr->getBranchState(); - if (CGM.getTriple().getArch() == llvm::Triple::x86 || - CGM.getTriple().getArch() == llvm::Triple::x86_64) { + if (CGM.getTriple().isX86()) { emitX86DeclareSimdFunction(FD, Fn, VLENVal, ParamAttrs, State); } else if (CGM.getTriple().getArch() == llvm::Triple::aarch64) { unsigned VLEN = VLENVal.getExtValue(); @@ -11018,12 +11014,18 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF, return Address(Addr, Align); } +namespace { +using OMPContextSelectorData = + OpenMPCtxSelectorData<ArrayRef<StringRef>, llvm::APSInt>; +using CompleteOMPContextSelectorData = SmallVector<OMPContextSelectorData, 4>; +} // anonymous namespace + /// Checks current context and returns true if it matches the context selector. -template <OMPDeclareVariantAttr::CtxSelectorSetType CtxSet, - OMPDeclareVariantAttr::CtxSelectorType Ctx> -static bool checkContext(const OMPDeclareVariantAttr *A) { - assert(CtxSet != OMPDeclareVariantAttr::CtxSetUnknown && - Ctx != OMPDeclareVariantAttr::CtxUnknown && +template <OpenMPContextSelectorSetKind CtxSet, OpenMPContextSelectorKind Ctx, + typename... Arguments> +static bool checkContext(const OMPContextSelectorData &Data, + Arguments... Params) { + assert(Data.CtxSet != OMP_CTX_SET_unknown && Data.Ctx != OMP_CTX_unknown && "Unknown context selector or context selector set."); return false; } @@ -11031,89 +11033,233 @@ static bool checkContext(const OMPDeclareVariantAttr *A) { /// Checks for implementation={vendor(<vendor>)} context selector. /// \returns true iff <vendor>="llvm", false otherwise. template <> -bool checkContext<OMPDeclareVariantAttr::CtxSetImplementation, - OMPDeclareVariantAttr::CtxVendor>( - const OMPDeclareVariantAttr *A) { - return llvm::all_of(A->implVendors(), +bool checkContext<OMP_CTX_SET_implementation, OMP_CTX_vendor>( + const OMPContextSelectorData &Data) { + return llvm::all_of(Data.Names, [](StringRef S) { return !S.compare_lower("llvm"); }); } -static bool greaterCtxScore(ASTContext &Ctx, const Expr *LHS, const Expr *RHS) { - // If both scores are unknown, choose the very first one. - if (!LHS && !RHS) - return true; - // If only one is known, return this one. - if (LHS && !RHS) - return true; - if (!LHS && RHS) - return false; - llvm::APSInt LHSVal = LHS->EvaluateKnownConstInt(Ctx); - llvm::APSInt RHSVal = RHS->EvaluateKnownConstInt(Ctx); - return llvm::APSInt::compareValues(LHSVal, RHSVal) >= 0; +/// Checks for device={kind(<kind>)} context selector. +/// \returns true if <kind>="host" and compilation is for host. +/// true if <kind>="nohost" and compilation is for device. +/// true if <kind>="cpu" and compilation is for Arm, X86 or PPC CPU. +/// true if <kind>="gpu" and compilation is for NVPTX or AMDGCN. +/// false otherwise. +template <> +bool checkContext<OMP_CTX_SET_device, OMP_CTX_kind, CodeGenModule &>( + const OMPContextSelectorData &Data, CodeGenModule &CGM) { + for (StringRef Name : Data.Names) { + if (!Name.compare_lower("host")) { + if (CGM.getLangOpts().OpenMPIsDevice) + return false; + continue; + } + if (!Name.compare_lower("nohost")) { + if (!CGM.getLangOpts().OpenMPIsDevice) + return false; + continue; + } + switch (CGM.getTriple().getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::aarch64_32: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + if (Name.compare_lower("cpu")) + return false; + break; + case llvm::Triple::amdgcn: + case llvm::Triple::nvptx: + case llvm::Triple::nvptx64: + if (Name.compare_lower("gpu")) + return false; + break; + case llvm::Triple::UnknownArch: + case llvm::Triple::arc: + case llvm::Triple::avr: + case llvm::Triple::bpfel: + case llvm::Triple::bpfeb: + case llvm::Triple::hexagon: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::msp430: + case llvm::Triple::r600: + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + case llvm::Triple::sparc: + case llvm::Triple::sparcv9: + case llvm::Triple::sparcel: + case llvm::Triple::systemz: + case llvm::Triple::tce: + case llvm::Triple::tcele: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::xcore: + case llvm::Triple::le32: + case llvm::Triple::le64: + case llvm::Triple::amdil: + case llvm::Triple::amdil64: + case llvm::Triple::hsail: + case llvm::Triple::hsail64: + case llvm::Triple::spir: + case llvm::Triple::spir64: + case llvm::Triple::kalimba: + case llvm::Triple::shave: + case llvm::Triple::lanai: + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + case llvm::Triple::renderscript32: + case llvm::Triple::renderscript64: + case llvm::Triple::ve: + return false; + } + } + return true; } -namespace { -/// Comparator for the priority queue for context selector. -class OMPDeclareVariantAttrComparer - : public std::greater<const OMPDeclareVariantAttr *> { -private: - ASTContext &Ctx; +static bool matchesContext(CodeGenModule &CGM, + const CompleteOMPContextSelectorData &ContextData) { + for (const OMPContextSelectorData &Data : ContextData) { + switch (Data.Ctx) { + case OMP_CTX_vendor: + assert(Data.CtxSet == OMP_CTX_SET_implementation && + "Expected implementation context selector set."); + if (!checkContext<OMP_CTX_SET_implementation, OMP_CTX_vendor>(Data)) + return false; + break; + case OMP_CTX_kind: + assert(Data.CtxSet == OMP_CTX_SET_device && + "Expected device context selector set."); + if (!checkContext<OMP_CTX_SET_device, OMP_CTX_kind, CodeGenModule &>(Data, + CGM)) + return false; + break; + case OMP_CTX_unknown: + llvm_unreachable("Unknown context selector kind."); + } + } + return true; +} -public: - OMPDeclareVariantAttrComparer(ASTContext &Ctx) : Ctx(Ctx) {} - bool operator()(const OMPDeclareVariantAttr *LHS, - const OMPDeclareVariantAttr *RHS) const { - const Expr *LHSExpr = nullptr; - const Expr *RHSExpr = nullptr; - if (LHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified) - LHSExpr = LHS->getScore(); - if (RHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified) - RHSExpr = RHS->getScore(); - return greaterCtxScore(Ctx, LHSExpr, RHSExpr); +static CompleteOMPContextSelectorData +translateAttrToContextSelectorData(ASTContext &C, + const OMPDeclareVariantAttr *A) { + CompleteOMPContextSelectorData Data; + for (unsigned I = 0, E = A->scores_size(); I < E; ++I) { + Data.emplace_back(); + auto CtxSet = static_cast<OpenMPContextSelectorSetKind>( + *std::next(A->ctxSelectorSets_begin(), I)); + auto Ctx = static_cast<OpenMPContextSelectorKind>( + *std::next(A->ctxSelectors_begin(), I)); + Data.back().CtxSet = CtxSet; + Data.back().Ctx = Ctx; + const Expr *Score = *std::next(A->scores_begin(), I); + Data.back().Score = Score->EvaluateKnownConstInt(C); + switch (Ctx) { + case OMP_CTX_vendor: + assert(CtxSet == OMP_CTX_SET_implementation && + "Expected implementation context selector set."); + Data.back().Names = + llvm::makeArrayRef(A->implVendors_begin(), A->implVendors_end()); + break; + case OMP_CTX_kind: + assert(CtxSet == OMP_CTX_SET_device && + "Expected device context selector set."); + Data.back().Names = + llvm::makeArrayRef(A->deviceKinds_begin(), A->deviceKinds_end()); + break; + case OMP_CTX_unknown: + llvm_unreachable("Unknown context selector kind."); + } } -}; -} // anonymous namespace + return Data; +} + +static bool isStrictSubset(const CompleteOMPContextSelectorData &LHS, + const CompleteOMPContextSelectorData &RHS) { + llvm::SmallDenseMap<std::pair<int, int>, llvm::StringSet<>, 4> RHSData; + for (const OMPContextSelectorData &D : RHS) { + auto &Pair = RHSData.FindAndConstruct(std::make_pair(D.CtxSet, D.Ctx)); + Pair.getSecond().insert(D.Names.begin(), D.Names.end()); + } + bool AllSetsAreEqual = true; + for (const OMPContextSelectorData &D : LHS) { + auto It = RHSData.find(std::make_pair(D.CtxSet, D.Ctx)); + if (It == RHSData.end()) + return false; + if (D.Names.size() > It->getSecond().size()) + return false; + if (llvm::set_union(It->getSecond(), D.Names)) + return false; + AllSetsAreEqual = + AllSetsAreEqual && (D.Names.size() == It->getSecond().size()); + } + + return LHS.size() != RHS.size() || !AllSetsAreEqual; +} + +static bool greaterCtxScore(const CompleteOMPContextSelectorData &LHS, + const CompleteOMPContextSelectorData &RHS) { + // Score is calculated as sum of all scores + 1. + llvm::APSInt LHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false); + bool RHSIsSubsetOfLHS = isStrictSubset(RHS, LHS); + if (RHSIsSubsetOfLHS) { + LHSScore = llvm::APSInt::get(0); + } else { + for (const OMPContextSelectorData &Data : LHS) { + if (Data.Score.getBitWidth() > LHSScore.getBitWidth()) { + LHSScore = LHSScore.extend(Data.Score.getBitWidth()) + Data.Score; + } else if (Data.Score.getBitWidth() < LHSScore.getBitWidth()) { + LHSScore += Data.Score.extend(LHSScore.getBitWidth()); + } else { + LHSScore += Data.Score; + } + } + } + llvm::APSInt RHSScore(llvm::APInt(64, 1), /*isUnsigned=*/false); + if (!RHSIsSubsetOfLHS && isStrictSubset(LHS, RHS)) { + RHSScore = llvm::APSInt::get(0); + } else { + for (const OMPContextSelectorData &Data : RHS) { + if (Data.Score.getBitWidth() > RHSScore.getBitWidth()) { + RHSScore = RHSScore.extend(Data.Score.getBitWidth()) + Data.Score; + } else if (Data.Score.getBitWidth() < RHSScore.getBitWidth()) { + RHSScore += Data.Score.extend(RHSScore.getBitWidth()); + } else { + RHSScore += Data.Score; + } + } + } + return llvm::APSInt::compareValues(LHSScore, RHSScore) >= 0; +} /// Finds the variant function that matches current context with its context /// selector. -static const FunctionDecl *getDeclareVariantFunction(ASTContext &Ctx, +static const FunctionDecl *getDeclareVariantFunction(CodeGenModule &CGM, const FunctionDecl *FD) { if (!FD->hasAttrs() || !FD->hasAttr<OMPDeclareVariantAttr>()) return FD; // Iterate through all DeclareVariant attributes and check context selectors. - auto &&Comparer = [&Ctx](const OMPDeclareVariantAttr *LHS, - const OMPDeclareVariantAttr *RHS) { - const Expr *LHSExpr = nullptr; - const Expr *RHSExpr = nullptr; - if (LHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified) - LHSExpr = LHS->getScore(); - if (RHS->getCtxScore() == OMPDeclareVariantAttr::ScoreSpecified) - RHSExpr = RHS->getScore(); - return greaterCtxScore(Ctx, LHSExpr, RHSExpr); - }; const OMPDeclareVariantAttr *TopMostAttr = nullptr; + CompleteOMPContextSelectorData TopMostData; for (const auto *A : FD->specific_attrs<OMPDeclareVariantAttr>()) { - const OMPDeclareVariantAttr *SelectedAttr = nullptr; - switch (A->getCtxSelectorSet()) { - case OMPDeclareVariantAttr::CtxSetImplementation: - switch (A->getCtxSelector()) { - case OMPDeclareVariantAttr::CtxVendor: - if (checkContext<OMPDeclareVariantAttr::CtxSetImplementation, - OMPDeclareVariantAttr::CtxVendor>(A)) - SelectedAttr = A; - break; - case OMPDeclareVariantAttr::CtxUnknown: - llvm_unreachable( - "Unknown context selector in implementation selector set."); - } - break; - case OMPDeclareVariantAttr::CtxSetUnknown: - llvm_unreachable("Unknown context selector set."); - } + CompleteOMPContextSelectorData Data = + translateAttrToContextSelectorData(CGM.getContext(), A); + if (!matchesContext(CGM, Data)) + continue; // If the attribute matches the context, find the attribute with the highest // score. - if (SelectedAttr && (!TopMostAttr || !Comparer(TopMostAttr, SelectedAttr))) - TopMostAttr = SelectedAttr; + if (!TopMostAttr || !greaterCtxScore(TopMostData, Data)) { + TopMostAttr = A; + TopMostData.swap(Data); + } } if (!TopMostAttr) return FD; @@ -11129,7 +11275,7 @@ bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) { llvm::GlobalValue *Orig = CGM.GetGlobalValue(MangledName); if (Orig && !Orig->isDeclaration()) return false; - const FunctionDecl *NewFD = getDeclareVariantFunction(CGM.getContext(), D); + const FunctionDecl *NewFD = getDeclareVariantFunction(CGM, D); // Emit original function if it does not have declare variant attribute or the // context does not match. if (NewFD == D) @@ -11143,6 +11289,320 @@ bool CGOpenMPRuntime::emitDeclareVariant(GlobalDecl GD, bool IsForDefinition) { return true; } +CGOpenMPRuntime::NontemporalDeclsRAII::NontemporalDeclsRAII( + CodeGenModule &CGM, const OMPLoopDirective &S) + : CGM(CGM), NeedToPush(S.hasClausesOfKind<OMPNontemporalClause>()) { + assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode."); + if (!NeedToPush) + return; + NontemporalDeclsSet &DS = + CGM.getOpenMPRuntime().NontemporalDeclsStack.emplace_back(); + for (const auto *C : S.getClausesOfKind<OMPNontemporalClause>()) { + for (const Stmt *Ref : C->private_refs()) { + const auto *SimpleRefExpr = cast<Expr>(Ref)->IgnoreParenImpCasts(); + const ValueDecl *VD; + if (const auto *DRE = dyn_cast<DeclRefExpr>(SimpleRefExpr)) { + VD = DRE->getDecl(); + } else { + const auto *ME = cast<MemberExpr>(SimpleRefExpr); + assert((ME->isImplicitCXXThis() || + isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) && + "Expected member of current class."); + VD = ME->getMemberDecl(); + } + DS.insert(VD); + } + } +} + +CGOpenMPRuntime::NontemporalDeclsRAII::~NontemporalDeclsRAII() { + if (!NeedToPush) + return; + CGM.getOpenMPRuntime().NontemporalDeclsStack.pop_back(); +} + +bool CGOpenMPRuntime::isNontemporalDecl(const ValueDecl *VD) const { + assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode."); + + return llvm::any_of( + CGM.getOpenMPRuntime().NontemporalDeclsStack, + [VD](const NontemporalDeclsSet &Set) { return Set.count(VD) > 0; }); +} + +CGOpenMPRuntime::LastprivateConditionalRAII::LastprivateConditionalRAII( + CodeGenFunction &CGF, const OMPExecutableDirective &S, LValue IVLVal) + : CGM(CGF.CGM), + NeedToPush(llvm::any_of(S.getClausesOfKind<OMPLastprivateClause>(), + [](const OMPLastprivateClause *C) { + return C->getKind() == + OMPC_LASTPRIVATE_conditional; + })) { + assert(CGM.getLangOpts().OpenMP && "Not in OpenMP mode."); + if (!NeedToPush) + return; + LastprivateConditionalData &Data = + CGM.getOpenMPRuntime().LastprivateConditionalStack.emplace_back(); + for (const auto *C : S.getClausesOfKind<OMPLastprivateClause>()) { + if (C->getKind() != OMPC_LASTPRIVATE_conditional) + continue; + + for (const Expr *Ref : C->varlists()) { + Data.DeclToUniqeName.try_emplace( + cast<DeclRefExpr>(Ref->IgnoreParenImpCasts())->getDecl(), + generateUniqueName(CGM, "pl_cond", Ref)); + } + } + Data.IVLVal = IVLVal; + // In simd only mode or for simd directives no need to generate threadprivate + // references for the loop iteration counter, we can use the original one + // since outlining cannot happen in simd regions. + if (CGF.getLangOpts().OpenMPSimd || + isOpenMPSimdDirective(S.getDirectiveKind())) { + Data.UseOriginalIV = true; + return; + } + llvm::SmallString<16> Buffer; + llvm::raw_svector_ostream OS(Buffer); + PresumedLoc PLoc = + CGM.getContext().getSourceManager().getPresumedLoc(S.getBeginLoc()); + assert(PLoc.isValid() && "Source location is expected to be always valid."); + + llvm::sys::fs::UniqueID ID; + if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID)) + CGM.getDiags().Report(diag::err_cannot_open_file) + << PLoc.getFilename() << EC.message(); + OS << "$pl_cond_" << ID.getDevice() << "_" << ID.getFile() << "_" + << PLoc.getLine() << "_" << PLoc.getColumn() << "$iv"; + Data.IVName = OS.str(); +} + +CGOpenMPRuntime::LastprivateConditionalRAII::~LastprivateConditionalRAII() { + if (!NeedToPush) + return; + CGM.getOpenMPRuntime().LastprivateConditionalStack.pop_back(); +} + +void CGOpenMPRuntime::initLastprivateConditionalCounter( + CodeGenFunction &CGF, const OMPExecutableDirective &S) { + if (CGM.getLangOpts().OpenMPSimd || + !llvm::any_of(S.getClausesOfKind<OMPLastprivateClause>(), + [](const OMPLastprivateClause *C) { + return C->getKind() == OMPC_LASTPRIVATE_conditional; + })) + return; + const CGOpenMPRuntime::LastprivateConditionalData &Data = + LastprivateConditionalStack.back(); + if (Data.UseOriginalIV) + return; + // Global loop counter. Required to handle inner parallel-for regions. + // global_iv = iv; + Address GlobIVAddr = CGM.getOpenMPRuntime().getAddrOfArtificialThreadPrivate( + CGF, Data.IVLVal.getType(), Data.IVName); + LValue GlobIVLVal = CGF.MakeAddrLValue(GlobIVAddr, Data.IVLVal.getType()); + llvm::Value *IVVal = CGF.EmitLoadOfScalar(Data.IVLVal, S.getBeginLoc()); + CGF.EmitStoreOfScalar(IVVal, GlobIVLVal); +} + +namespace { +/// Checks if the lastprivate conditional variable is referenced in LHS. +class LastprivateConditionalRefChecker final + : public ConstStmtVisitor<LastprivateConditionalRefChecker, bool> { + CodeGenFunction &CGF; + ArrayRef<CGOpenMPRuntime::LastprivateConditionalData> LPM; + const Expr *FoundE = nullptr; + const Decl *FoundD = nullptr; + StringRef UniqueDeclName; + LValue IVLVal; + StringRef IVName; + SourceLocation Loc; + bool UseOriginalIV = false; + +public: + bool VisitDeclRefExpr(const DeclRefExpr *E) { + for (const CGOpenMPRuntime::LastprivateConditionalData &D : + llvm::reverse(LPM)) { + auto It = D.DeclToUniqeName.find(E->getDecl()); + if (It == D.DeclToUniqeName.end()) + continue; + FoundE = E; + FoundD = E->getDecl()->getCanonicalDecl(); + UniqueDeclName = It->getSecond(); + IVLVal = D.IVLVal; + IVName = D.IVName; + UseOriginalIV = D.UseOriginalIV; + break; + } + return FoundE == E; + } + bool VisitMemberExpr(const MemberExpr *E) { + if (!CGF.IsWrappedCXXThis(E->getBase())) + return false; + for (const CGOpenMPRuntime::LastprivateConditionalData &D : + llvm::reverse(LPM)) { + auto It = D.DeclToUniqeName.find(E->getMemberDecl()); + if (It == D.DeclToUniqeName.end()) + continue; + FoundE = E; + FoundD = E->getMemberDecl()->getCanonicalDecl(); + UniqueDeclName = It->getSecond(); + IVLVal = D.IVLVal; + IVName = D.IVName; + UseOriginalIV = D.UseOriginalIV; + break; + } + return FoundE == E; + } + bool VisitStmt(const Stmt *S) { + for (const Stmt *Child : S->children()) { + if (!Child) + continue; + if (const auto *E = dyn_cast<Expr>(Child)) + if (!E->isGLValue()) + continue; + if (Visit(Child)) + return true; + } + return false; + } + explicit LastprivateConditionalRefChecker( + CodeGenFunction &CGF, + ArrayRef<CGOpenMPRuntime::LastprivateConditionalData> LPM) + : CGF(CGF), LPM(LPM) {} + std::tuple<const Expr *, const Decl *, StringRef, LValue, StringRef, bool> + getFoundData() const { + return std::make_tuple(FoundE, FoundD, UniqueDeclName, IVLVal, IVName, + UseOriginalIV); + } +}; +} // namespace + +void CGOpenMPRuntime::checkAndEmitLastprivateConditional(CodeGenFunction &CGF, + const Expr *LHS) { + if (CGF.getLangOpts().OpenMP < 50) + return; + LastprivateConditionalRefChecker Checker(CGF, LastprivateConditionalStack); + if (!Checker.Visit(LHS)) + return; + const Expr *FoundE; + const Decl *FoundD; + StringRef UniqueDeclName; + LValue IVLVal; + StringRef IVName; + bool UseOriginalIV; + std::tie(FoundE, FoundD, UniqueDeclName, IVLVal, IVName, UseOriginalIV) = + Checker.getFoundData(); + + // Last updated loop counter for the lastprivate conditional var. + // int<xx> last_iv = 0; + llvm::Type *LLIVTy = CGF.ConvertTypeForMem(IVLVal.getType()); + llvm::Constant *LastIV = + getOrCreateInternalVariable(LLIVTy, UniqueDeclName + "$iv"); + cast<llvm::GlobalVariable>(LastIV)->setAlignment( + IVLVal.getAlignment().getAsAlign()); + LValue LastIVLVal = CGF.MakeNaturalAlignAddrLValue(LastIV, IVLVal.getType()); + + // Private address of the lastprivate conditional in the current context. + // priv_a + LValue LVal = CGF.EmitLValue(FoundE); + // Last value of the lastprivate conditional. + // decltype(priv_a) last_a; + llvm::Constant *Last = getOrCreateInternalVariable( + LVal.getAddress(CGF).getElementType(), UniqueDeclName); + cast<llvm::GlobalVariable>(Last)->setAlignment( + LVal.getAlignment().getAsAlign()); + LValue LastLVal = + CGF.MakeAddrLValue(Last, LVal.getType(), LVal.getAlignment()); + + // Global loop counter. Required to handle inner parallel-for regions. + // global_iv + if (!UseOriginalIV) { + Address IVAddr = + getAddrOfArtificialThreadPrivate(CGF, IVLVal.getType(), IVName); + IVLVal = CGF.MakeAddrLValue(IVAddr, IVLVal.getType()); + } + llvm::Value *IVVal = CGF.EmitLoadOfScalar(IVLVal, FoundE->getExprLoc()); + + // #pragma omp critical(a) + // if (last_iv <= iv) { + // last_iv = iv; + // last_a = priv_a; + // } + auto &&CodeGen = [&LastIVLVal, &IVLVal, IVVal, &LVal, &LastLVal, + FoundE](CodeGenFunction &CGF, PrePostActionTy &Action) { + Action.Enter(CGF); + llvm::Value *LastIVVal = + CGF.EmitLoadOfScalar(LastIVLVal, FoundE->getExprLoc()); + // (last_iv <= global_iv) ? Check if the variable is updated and store new + // value in global var. + llvm::Value *CmpRes; + if (IVLVal.getType()->isSignedIntegerType()) { + CmpRes = CGF.Builder.CreateICmpSLE(LastIVVal, IVVal); + } else { + assert(IVLVal.getType()->isUnsignedIntegerType() && + "Loop iteration variable must be integer."); + CmpRes = CGF.Builder.CreateICmpULE(LastIVVal, IVVal); + } + llvm::BasicBlock *ThenBB = CGF.createBasicBlock("lp_cond_then"); + llvm::BasicBlock *ExitBB = CGF.createBasicBlock("lp_cond_exit"); + CGF.Builder.CreateCondBr(CmpRes, ThenBB, ExitBB); + // { + CGF.EmitBlock(ThenBB); + + // last_iv = global_iv; + CGF.EmitStoreOfScalar(IVVal, LastIVLVal); + + // last_a = priv_a; + switch (CGF.getEvaluationKind(LVal.getType())) { + case TEK_Scalar: { + llvm::Value *PrivVal = CGF.EmitLoadOfScalar(LVal, FoundE->getExprLoc()); + CGF.EmitStoreOfScalar(PrivVal, LastLVal); + break; + } + case TEK_Complex: { + CodeGenFunction::ComplexPairTy PrivVal = + CGF.EmitLoadOfComplex(LVal, FoundE->getExprLoc()); + CGF.EmitStoreOfComplex(PrivVal, LastLVal, /*isInit=*/false); + break; + } + case TEK_Aggregate: + llvm_unreachable( + "Aggregates are not supported in lastprivate conditional."); + } + // } + CGF.EmitBranch(ExitBB); + // There is no need to emit line number for unconditional branch. + (void)ApplyDebugLocation::CreateEmpty(CGF); + CGF.EmitBlock(ExitBB, /*IsFinished=*/true); + }; + + if (CGM.getLangOpts().OpenMPSimd) { + // Do not emit as a critical region as no parallel region could be emitted. + RegionCodeGenTy ThenRCG(CodeGen); + ThenRCG(CGF); + } else { + emitCriticalRegion(CGF, UniqueDeclName, CodeGen, FoundE->getExprLoc()); + } +} + +void CGOpenMPRuntime::emitLastprivateConditionalFinalUpdate( + CodeGenFunction &CGF, LValue PrivLVal, const VarDecl *VD, + SourceLocation Loc) { + if (CGF.getLangOpts().OpenMP < 50) + return; + auto It = LastprivateConditionalStack.back().DeclToUniqeName.find(VD); + assert(It != LastprivateConditionalStack.back().DeclToUniqeName.end() && + "Unknown lastprivate conditional variable."); + StringRef UniqueName = It->getSecond(); + llvm::GlobalVariable *GV = CGM.getModule().getNamedGlobal(UniqueName); + // The variable was not updated in the region - exit. + if (!GV) + return; + LValue LPLVal = CGF.MakeAddrLValue( + GV, PrivLVal.getType().getNonReferenceType(), PrivLVal.getAlignment()); + llvm::Value *Res = CGF.EmitLoadOfScalar(LPLVal, Loc); + CGF.EmitStoreOfScalar(Res, PrivLVal); +} + llvm::Function *CGOpenMPSIMDRuntime::emitParallelOutlinedFunction( const OMPExecutableDirective &D, const VarDecl *ThreadIDVar, OpenMPDirectiveKind InnermostKind, const RegionCodeGenTy &CodeGen) { @@ -11265,7 +11725,7 @@ void CGOpenMPSIMDRuntime::emitNumThreadsClause(CodeGenFunction &CGF, } void CGOpenMPSIMDRuntime::emitProcBindClause(CodeGenFunction &CGF, - OpenMPProcBindClauseKind ProcBind, + ProcBindKind ProcBind, SourceLocation Loc) { llvm_unreachable("Not supported in SIMD-only mode"); } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index bf8e0ac80909..8159f5e8b790 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -20,8 +20,10 @@ #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringSet.h" +#include "llvm/Frontend/OpenMP/OMPConstants.h" #include "llvm/IR/Function.h" #include "llvm/IR/ValueHandle.h" @@ -211,6 +213,43 @@ public: ~DisableAutoDeclareTargetRAII(); }; + /// Manages list of nontemporal decls for the specified directive. + class NontemporalDeclsRAII { + CodeGenModule &CGM; + const bool NeedToPush; + + public: + NontemporalDeclsRAII(CodeGenModule &CGM, const OMPLoopDirective &S); + ~NontemporalDeclsRAII(); + }; + + /// Maps the expression for the lastprivate variable to the global copy used + /// to store new value because original variables are not mapped in inner + /// parallel regions. Only private copies are captured but we need also to + /// store private copy in shared address. + /// Also, stores the expression for the private loop counter and it + /// threaprivate name. + struct LastprivateConditionalData { + llvm::SmallDenseMap<CanonicalDeclPtr<const Decl>, SmallString<16>> + DeclToUniqeName; + LValue IVLVal; + SmallString<16> IVName; + /// True if original lvalue for loop counter can be used in codegen (simd + /// region or simd only mode) and no need to create threadprivate + /// references. + bool UseOriginalIV = false; + }; + /// Manages list of lastprivate conditional decls for the specified directive. + class LastprivateConditionalRAII { + CodeGenModule &CGM; + const bool NeedToPush; + + public: + LastprivateConditionalRAII(CodeGenFunction &CGF, + const OMPExecutableDirective &S, LValue IVLVal); + ~LastprivateConditionalRAII(); + }; + protected: CodeGenModule &CGM; StringRef FirstSeparator, Separator; @@ -241,17 +280,6 @@ protected: bool IsOffloadEntry, const RegionCodeGenTy &CodeGen); - /// Emits code for OpenMP 'if' clause using specified \a CodeGen - /// function. Here is the logic: - /// if (Cond) { - /// ThenGen(); - /// } else { - /// ElseGen(); - /// } - void emitOMPIfClause(CodeGenFunction &CGF, const Expr *Cond, - const RegionCodeGenTy &ThenGen, - const RegionCodeGenTy &ElseGen); - /// Emits object of ident_t type with info for source location. /// \param Flags Flags for OpenMP location. /// @@ -411,29 +439,10 @@ private: /// // (function or global) /// char *name; // Name of the function or global. /// size_t size; // Size of the entry info (0 if it a function). + /// int32_t flags; + /// int32_t reserved; /// }; QualType TgtOffloadEntryQTy; - /// struct __tgt_device_image{ - /// void *ImageStart; // Pointer to the target code start. - /// void *ImageEnd; // Pointer to the target code end. - /// // We also add the host entries to the device image, as it may be useful - /// // for the target runtime to have access to that information. - /// __tgt_offload_entry *EntriesBegin; // Begin of the table with all - /// // the entries. - /// __tgt_offload_entry *EntriesEnd; // End of the table with all the - /// // entries (non inclusive). - /// }; - QualType TgtDeviceImageQTy; - /// struct __tgt_bin_desc{ - /// int32_t NumDevices; // Number of devices supported. - /// __tgt_device_image *DeviceImages; // Arrays of device images - /// // (one per device). - /// __tgt_offload_entry *EntriesBegin; // Begin of the table with all the - /// // entries. - /// __tgt_offload_entry *EntriesEnd; // End of the table with all the - /// // entries (non inclusive). - /// }; - QualType TgtBinaryDescriptorQTy; /// Entity that registers the offloading constants that were emitted so /// far. class OffloadEntriesInfoManagerTy { @@ -645,8 +654,8 @@ private: OffloadEntriesInfoManagerTy OffloadEntriesInfoManager; bool ShouldMarkAsGlobal = true; - /// List of the emitted functions. - llvm::StringSet<> AlreadyEmittedTargetFunctions; + /// List of the emitted declarations. + llvm::DenseSet<CanonicalDeclPtr<const Decl>> AlreadyEmittedTargetDecls; /// List of the global variables with their addresses that should not be /// emitted for the target. llvm::StringMap<llvm::WeakTrackingVH> EmittedNonTargetVariables; @@ -661,6 +670,16 @@ private: std::pair<GlobalDecl, GlobalDecl>> DeferredVariantFunction; + using NontemporalDeclsSet = llvm::SmallDenseSet<CanonicalDeclPtr<const Decl>>; + /// Stack for list of declarations in current context marked as nontemporal. + /// The set is the union of all current stack elements. + llvm::SmallVector<NontemporalDeclsSet, 4> NontemporalDeclsStack; + + /// Stack for list of addresses of declarations in current context marked as + /// lastprivate conditional. The set is the union of all current stack + /// elements. + llvm::SmallVector<LastprivateConditionalData, 4> LastprivateConditionalStack; + /// Flag for keeping track of weather a requires unified_shared_memory /// directive is present. bool HasRequiresUnifiedSharedMemory = false; @@ -679,12 +698,6 @@ private: /// Returns __tgt_offload_entry type. QualType getTgtOffloadEntryQTy(); - /// Returns __tgt_device_image type. - QualType getTgtDeviceImageQTy(); - - /// Returns __tgt_bin_desc type. - QualType getTgtBinaryDescriptorQTy(); - /// Start scanning from statement \a S and and emit all target regions /// found along the way. /// \param S Starting statement. @@ -819,6 +832,17 @@ public: virtual ~CGOpenMPRuntime() {} virtual void clear(); + /// Emits code for OpenMP 'if' clause using specified \a CodeGen + /// function. Here is the logic: + /// if (Cond) { + /// ThenGen(); + /// } else { + /// ElseGen(); + /// } + void emitIfClause(CodeGenFunction &CGF, const Expr *Cond, + const RegionCodeGenTy &ThenGen, + const RegionCodeGenTy &ElseGen); + /// Checks if the \p Body is the \a CompoundStmt and returns its child /// statement iff there is only one that is not evaluatable at the compile /// time. @@ -1146,7 +1170,7 @@ public: /// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32 /// global_tid, int proc_bind) to generate code for 'proc_bind' clause. virtual void emitProcBindClause(CodeGenFunction &CGF, - OpenMPProcBindClauseKind ProcBind, + llvm::omp::ProcBindKind ProcBind, SourceLocation Loc); /// Returns address of the threadprivate variable for the current @@ -1663,6 +1687,40 @@ public: /// Emits the definition of the declare variant function. virtual bool emitDeclareVariant(GlobalDecl GD, bool IsForDefinition); + + /// Checks if the \p VD variable is marked as nontemporal declaration in + /// current context. + bool isNontemporalDecl(const ValueDecl *VD) const; + + /// Initializes global counter for lastprivate conditional. + virtual void + initLastprivateConditionalCounter(CodeGenFunction &CGF, + const OMPExecutableDirective &S); + + /// Checks if the provided \p LVal is lastprivate conditional and emits the + /// code to update the value of the original variable. + /// \code + /// lastprivate(conditional: a) + /// ... + /// <type> a; + /// lp_a = ...; + /// #pragma omp critical(a) + /// if (last_iv_a <= iv) { + /// last_iv_a = iv; + /// global_a = lp_a; + /// } + /// \endcode + virtual void checkAndEmitLastprivateConditional(CodeGenFunction &CGF, + const Expr *LHS); + + /// Gets the address of the global copy used for lastprivate conditional + /// update, if any. + /// \param PrivLVal LValue for the private copy. + /// \param VD Original lastprivate declaration. + virtual void emitLastprivateConditionalFinalUpdate(CodeGenFunction &CGF, + LValue PrivLVal, + const VarDecl *VD, + SourceLocation Loc); }; /// Class supports emissionof SIMD-only code. @@ -1891,7 +1949,7 @@ public: /// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32 /// global_tid, int proc_bind) to generate code for 'proc_bind' clause. void emitProcBindClause(CodeGenFunction &CGF, - OpenMPProcBindClauseKind ProcBind, + llvm::omp::ProcBindKind ProcBind, SourceLocation Loc) override; /// Returns address of the threadprivate variable for the current diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp index 708260429f68..d00d84b79cfe 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.cpp @@ -13,14 +13,17 @@ #include "CGOpenMPRuntimeNVPTX.h" #include "CodeGenFunction.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Cuda.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/IR/IntrinsicsNVPTX.h" using namespace clang; using namespace CodeGen; +using namespace llvm::omp; namespace { enum OpenMPRTLFunctionNVPTX { @@ -761,6 +764,7 @@ static bool hasNestedSPMDDirective(ASTContext &Ctx, case OMPD_parallel: case OMPD_for: case OMPD_parallel_for: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_for_simd: case OMPD_parallel_for_simd: @@ -806,6 +810,7 @@ static bool hasNestedSPMDDirective(ASTContext &Ctx, case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: llvm_unreachable("Unexpected directive."); @@ -835,6 +840,7 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx, case OMPD_parallel: case OMPD_for: case OMPD_parallel_for: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_for_simd: case OMPD_parallel_for_simd: @@ -880,6 +886,7 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx, case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: break; @@ -1002,6 +1009,7 @@ static bool hasNestedLightweightDirective(ASTContext &Ctx, case OMPD_parallel: case OMPD_for: case OMPD_parallel_for: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_for_simd: case OMPD_parallel_for_simd: @@ -1047,6 +1055,7 @@ static bool hasNestedLightweightDirective(ASTContext &Ctx, case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: llvm_unreachable("Unexpected directive."); @@ -1082,6 +1091,7 @@ static bool supportsLightweightRuntime(ASTContext &Ctx, case OMPD_parallel: case OMPD_for: case OMPD_parallel_for: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_for_simd: case OMPD_parallel_for_simd: @@ -1127,6 +1137,7 @@ static bool supportsLightweightRuntime(ASTContext &Ctx, case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: break; @@ -1799,9 +1810,8 @@ CGOpenMPRuntimeNVPTX::createNVPTXRuntimeFunction(unsigned Function) { llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; auto *FnTy = llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); - RTLFn = CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier"); - cast<llvm::Function>(RTLFn.getCallee()) - ->addFnAttr(llvm::Attribute::Convergent); + RTLFn = + CGM.CreateConvergentRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier"); break; } case OMPRTL__kmpc_barrier_simple_spmd: { @@ -1810,24 +1820,22 @@ CGOpenMPRuntimeNVPTX::createNVPTXRuntimeFunction(unsigned Function) { llvm::Type *TypeParams[] = {getIdentTyPointerTy(), CGM.Int32Ty}; auto *FnTy = llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false); - RTLFn = - CGM.CreateRuntimeFunction(FnTy, /*Name*/ "__kmpc_barrier_simple_spmd"); - cast<llvm::Function>(RTLFn.getCallee()) - ->addFnAttr(llvm::Attribute::Convergent); + RTLFn = CGM.CreateConvergentRuntimeFunction( + FnTy, /*Name*/ "__kmpc_barrier_simple_spmd"); break; } case OMPRTL_NVPTX__kmpc_warp_active_thread_mask: { // Build int32_t __kmpc_warp_active_thread_mask(void); auto *FnTy = llvm::FunctionType::get(CGM.Int32Ty, llvm::None, /*isVarArg=*/false); - RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_warp_active_thread_mask"); + RTLFn = CGM.CreateConvergentRuntimeFunction(FnTy, "__kmpc_warp_active_thread_mask"); break; } case OMPRTL_NVPTX__kmpc_syncwarp: { // Build void __kmpc_syncwarp(kmp_int32 Mask); auto *FnTy = llvm::FunctionType::get(CGM.VoidTy, CGM.Int32Ty, /*isVarArg=*/false); - RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_syncwarp"); + RTLFn = CGM.CreateConvergentRuntimeFunction(FnTy, "__kmpc_syncwarp"); break; } } @@ -1927,7 +1935,7 @@ CGOpenMPRuntimeNVPTX::CGOpenMPRuntimeNVPTX(CodeGenModule &CGM) } void CGOpenMPRuntimeNVPTX::emitProcBindClause(CodeGenFunction &CGF, - OpenMPProcBindClauseKind ProcBind, + ProcBindKind ProcBind, SourceLocation Loc) { // Do nothing in case of SPMD mode and L0 parallel. if (getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_SPMD) @@ -2317,7 +2325,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericVarsProlog(CodeGenFunction &CGF, VarTy = Rec.second.FD->getType(); } else { llvm::Value *Ptr = CGF.Builder.CreateInBoundsGEP( - VarAddr.getAddress().getPointer(), + VarAddr.getAddress(CGF).getPointer(), {Bld.getInt32(0), getNVPTXLaneID(CGF)}); VarTy = Rec.second.FD->getType()->castAsArrayTypeUnsafe()->getElementType(); @@ -2325,7 +2333,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericVarsProlog(CodeGenFunction &CGF, Address(Ptr, CGM.getContext().getDeclAlign(Rec.first)), VarTy, AlignmentSource::Decl); } - Rec.second.PrivateAddr = VarAddr.getAddress(); + Rec.second.PrivateAddr = VarAddr.getAddress(CGF); if (!IsInTTDRegion && (WithSPMDCheck || getExecutionMode() == CGOpenMPRuntimeNVPTX::EM_Unknown)) { @@ -2336,10 +2344,10 @@ void CGOpenMPRuntimeNVPTX::emitGenericVarsProlog(CodeGenFunction &CGF, "Secondary glob data must be one per team."); LValue SecVarAddr = CGF.EmitLValueForField(SecBase, SecIt->second.FD); VarAddr.setAddress( - Address(Bld.CreateSelect(IsTTD, SecVarAddr.getPointer(), - VarAddr.getPointer()), + Address(Bld.CreateSelect(IsTTD, SecVarAddr.getPointer(CGF), + VarAddr.getPointer(CGF)), VarAddr.getAlignment())); - Rec.second.PrivateAddr = VarAddr.getAddress(); + Rec.second.PrivateAddr = VarAddr.getAddress(CGF); } Address GlobalPtr = Rec.second.PrivateAddr; Address LocalAddr = CGF.CreateMemTemp(VarTy, Rec.second.FD->getName()); @@ -2351,7 +2359,8 @@ void CGOpenMPRuntimeNVPTX::emitGenericVarsProlog(CodeGenFunction &CGF, if (EscapedParam) { const auto *VD = cast<VarDecl>(Rec.first); CGF.EmitStoreOfScalar(ParValue, VarAddr); - I->getSecond().MappedParams->setVarAddr(CGF, VD, VarAddr.getAddress()); + I->getSecond().MappedParams->setVarAddr(CGF, VD, + VarAddr.getAddress(CGF)); } if (IsTTD) ++SecIt; @@ -2385,7 +2394,7 @@ void CGOpenMPRuntimeNVPTX::emitGenericVarsProlog(CodeGenFunction &CGF, CGM.getContext().getDeclAlign(VD), AlignmentSource::Decl); I->getSecond().MappedParams->setVarAddr(CGF, cast<VarDecl>(VD), - Base.getAddress()); + Base.getAddress(CGF)); I->getSecond().EscapedVariableLengthDeclsAddrs.emplace_back(GlobalRecValue); } I->getSecond().MappedParams->apply(CGF); @@ -2646,7 +2655,7 @@ void CGOpenMPRuntimeNVPTX::emitNonSPMDParallelCall( }; if (IfCond) { - emitOMPIfClause(CGF, IfCond, LNParallelGen, SeqGen); + emitIfClause(CGF, IfCond, LNParallelGen, SeqGen); } else { CodeGenFunction::RunCleanupsScope Scope(CGF); RegionCodeGenTy ThenRCG(LNParallelGen); @@ -3689,7 +3698,8 @@ static llvm::Value *emitListToGlobalCopyFunction( const FieldDecl *FD = VarFieldMap.lookup(VD); LValue GlobLVal = CGF.EmitLValueForField( CGF.MakeNaturalAlignAddrLValue(BufferArrPtr, StaticTy), FD); - llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(GlobLVal.getPointer(), Idxs); + llvm::Value *BufferPtr = + Bld.CreateInBoundsGEP(GlobLVal.getPointer(CGF), Idxs); GlobLVal.setAddress(Address(BufferPtr, GlobLVal.getAlignment())); switch (CGF.getEvaluationKind(Private->getType())) { case TEK_Scalar: { @@ -3786,7 +3796,8 @@ static llvm::Value *emitListToGlobalReduceFunction( const FieldDecl *FD = VarFieldMap.lookup(VD); LValue GlobLVal = CGF.EmitLValueForField( CGF.MakeNaturalAlignAddrLValue(BufferArrPtr, StaticTy), FD); - llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(GlobLVal.getPointer(), Idxs); + llvm::Value *BufferPtr = + Bld.CreateInBoundsGEP(GlobLVal.getPointer(CGF), Idxs); llvm::Value *Ptr = CGF.EmitCastToVoidPtr(BufferPtr); CGF.EmitStoreOfScalar(Ptr, Elem, /*Volatile=*/false, C.VoidPtrTy); if ((*IPriv)->getType()->isVariablyModifiedType()) { @@ -3890,7 +3901,8 @@ static llvm::Value *emitGlobalToListCopyFunction( const FieldDecl *FD = VarFieldMap.lookup(VD); LValue GlobLVal = CGF.EmitLValueForField( CGF.MakeNaturalAlignAddrLValue(BufferArrPtr, StaticTy), FD); - llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(GlobLVal.getPointer(), Idxs); + llvm::Value *BufferPtr = + Bld.CreateInBoundsGEP(GlobLVal.getPointer(CGF), Idxs); GlobLVal.setAddress(Address(BufferPtr, GlobLVal.getAlignment())); switch (CGF.getEvaluationKind(Private->getType())) { case TEK_Scalar: { @@ -3986,7 +3998,8 @@ static llvm::Value *emitGlobalToListReduceFunction( const FieldDecl *FD = VarFieldMap.lookup(VD); LValue GlobLVal = CGF.EmitLValueForField( CGF.MakeNaturalAlignAddrLValue(BufferArrPtr, StaticTy), FD); - llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(GlobLVal.getPointer(), Idxs); + llvm::Value *BufferPtr = + Bld.CreateInBoundsGEP(GlobLVal.getPointer(CGF), Idxs); llvm::Value *Ptr = CGF.EmitCastToVoidPtr(BufferPtr); CGF.EmitStoreOfScalar(Ptr, Elem, /*Volatile=*/false, C.VoidPtrTy); if ((*IPriv)->getType()->isVariablyModifiedType()) { @@ -4309,7 +4322,7 @@ void CGOpenMPRuntimeNVPTX::emitReduction( Address Elem = CGF.Builder.CreateConstArrayGEP(ReductionList, Idx); CGF.Builder.CreateStore( CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - CGF.EmitLValue(RHSExprs[I]).getPointer(), CGF.VoidPtrTy), + CGF.EmitLValue(RHSExprs[I]).getPointer(CGF), CGF.VoidPtrTy), Elem); if ((*IPriv)->getType()->isVariablyModifiedType()) { // Store array size. @@ -4891,7 +4904,7 @@ void CGOpenMPRuntimeNVPTX::adjustTargetSpecificDataForLambdas( if (VD->getType().getCanonicalType()->isReferenceType()) VDAddr = CGF.EmitLoadOfReferenceLValue(VDAddr, VD->getType().getCanonicalType()) - .getAddress(); + .getAddress(CGF); CGF.EmitStoreOfScalar(VDAddr.getPointer(), VarLVal); } } @@ -4953,7 +4966,8 @@ void CGOpenMPRuntimeNVPTX::checkArchForUnifiedAddressing( const OMPRequiresDecl *D) { for (const OMPClause *Clause : D->clauselists()) { if (Clause->getClauseKind() == OMPC_unified_shared_memory) { - switch (getCudaArch(CGM)) { + CudaArch Arch = getCudaArch(CGM); + switch (Arch) { case CudaArch::SM_20: case CudaArch::SM_21: case CudaArch::SM_30: @@ -4965,10 +4979,14 @@ void CGOpenMPRuntimeNVPTX::checkArchForUnifiedAddressing( case CudaArch::SM_53: case CudaArch::SM_60: case CudaArch::SM_61: - case CudaArch::SM_62: - CGM.Error(Clause->getBeginLoc(), - "Target architecture does not support unified addressing"); + case CudaArch::SM_62: { + SmallString<256> Buffer; + llvm::raw_svector_ostream Out(Buffer); + Out << "Target architecture " << CudaArchToString(Arch) + << " does not support unified addressing"; + CGM.Error(Clause->getBeginLoc(), Out.str()); return; + } case CudaArch::SM_70: case CudaArch::SM_72: case CudaArch::SM_75: diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h index 0f78627c95e6..4159af0a622f 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h +++ b/clang/lib/CodeGen/CGOpenMPRuntimeNVPTX.h @@ -212,7 +212,7 @@ public: /// Emit call to void __kmpc_push_proc_bind(ident_t *loc, kmp_int32 /// global_tid, int proc_bind) to generate code for 'proc_bind' clause. virtual void emitProcBindClause(CodeGenFunction &CGF, - OpenMPProcBindClauseKind ProcBind, + llvm::omp::ProcBindKind ProcBind, SourceLocation Loc) override; /// Emits call to void __kmpc_push_num_threads(ident_t *loc, kmp_int32 diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index bb2629f89d3d..138459c68dbf 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -10,10 +10,11 @@ // //===----------------------------------------------------------------------===// -#include "CodeGenFunction.h" #include "CGDebugInfo.h" +#include "CodeGenFunction.h" #include "CodeGenModule.h" #include "TargetInfo.h" +#include "clang/AST/Attr.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/PrettyStackTrace.h" @@ -221,6 +222,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) { case Stmt::OMPParallelForSimdDirectiveClass: EmitOMPParallelForSimdDirective(cast<OMPParallelForSimdDirective>(*S)); break; + case Stmt::OMPParallelMasterDirectiveClass: + EmitOMPParallelMasterDirective(cast<OMPParallelMasterDirective>(*S)); + break; case Stmt::OMPParallelSectionsDirectiveClass: EmitOMPParallelSectionsDirective(cast<OMPParallelSectionsDirective>(*S)); break; @@ -292,6 +296,10 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) { EmitOMPParallelMasterTaskLoopDirective( cast<OMPParallelMasterTaskLoopDirective>(*S)); break; + case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass: + EmitOMPParallelMasterTaskLoopSimdDirective( + cast<OMPParallelMasterTaskLoopSimdDirective>(*S)); + break; case Stmt::OMPDistributeDirectiveClass: EmitOMPDistributeDirective(cast<OMPDistributeDirective>(*S)); break; @@ -554,8 +562,7 @@ void CodeGenFunction::EmitLabel(const LabelDecl *D) { // Emit debug info for labels. if (CGDebugInfo *DI = getDebugInfo()) { - if (CGM.getCodeGenOpts().getDebugInfo() >= - codegenoptions::LimitedDebugInfo) { + if (CGM.getCodeGenOpts().hasReducedDebugInfo()) { DI->setLocation(D->getLocation()); DI->EmitLabel(D, Builder); } @@ -1830,15 +1837,15 @@ CodeGenFunction::EmitAsmInputLValue(const TargetInfo::ConstraintInfo &Info, Ty = llvm::IntegerType::get(getLLVMContext(), Size); Ty = llvm::PointerType::getUnqual(Ty); - Arg = Builder.CreateLoad(Builder.CreateBitCast(InputValue.getAddress(), - Ty)); + Arg = Builder.CreateLoad( + Builder.CreateBitCast(InputValue.getAddress(*this), Ty)); } else { - Arg = InputValue.getPointer(); + Arg = InputValue.getPointer(*this); ConstraintStr += '*'; } } } else { - Arg = InputValue.getPointer(); + Arg = InputValue.getPointer(*this); ConstraintStr += '*'; } @@ -2087,8 +2094,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { LargestVectorWidth = std::max((uint64_t)LargestVectorWidth, VT->getPrimitiveSizeInBits().getFixedSize()); } else { - ArgTypes.push_back(Dest.getAddress().getType()); - Args.push_back(Dest.getPointer()); + ArgTypes.push_back(Dest.getAddress(*this).getType()); + Args.push_back(Dest.getPointer(*this)); Constraints += "=*"; Constraints += OutputConstraint; ReadOnly = ReadNone = false; @@ -2330,7 +2337,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // ResultTypeRequiresCast.size() elements of RegResults. if ((i < ResultTypeRequiresCast.size()) && ResultTypeRequiresCast[i]) { unsigned Size = getContext().getTypeSize(ResultRegQualTys[i]); - Address A = Builder.CreateBitCast(Dest.getAddress(), + Address A = Builder.CreateBitCast(Dest.getAddress(*this), ResultRegTypes[i]->getPointerTo()); QualType Ty = getContext().getIntTypeForBitwidth(Size, /*Signed*/ false); if (Ty.isNull()) { @@ -2383,14 +2390,14 @@ CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S, CapturedRegionKind K) { delete CGF.CapturedStmtInfo; // Emit call to the helper function. - EmitCallOrInvoke(F, CapStruct.getPointer()); + EmitCallOrInvoke(F, CapStruct.getPointer(*this)); return F; } Address CodeGenFunction::GenerateCapturedStmtArgument(const CapturedStmt &S) { LValue CapStruct = InitCapturedStruct(S); - return CapStruct.getAddress(); + return CapStruct.getAddress(*this); } /// Creates the outlined function for a CapturedStmt. diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 6ece69d51daf..dc3899f0e4ea 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -15,11 +15,16 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "TargetInfo.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtOpenMP.h" -#include "clang/AST/DeclOpenMP.h" +#include "clang/Basic/PrettyStackTrace.h" +#include "llvm/Frontend/OpenMP/OMPIRBuilder.h" using namespace clang; using namespace CodeGen; +using namespace llvm::omp; namespace { /// Lexical scope for OpenMP executable constructs, that handles correct codegen @@ -76,7 +81,7 @@ public: InlinedShareds.isGlobalVarCaptured(VD)), VD->getType().getNonReferenceType(), VK_LValue, C.getLocation()); InlinedShareds.addPrivate(VD, [&CGF, &DRE]() -> Address { - return CGF.EmitLValue(&DRE).getAddress(); + return CGF.EmitLValue(&DRE).getAddress(CGF); }); } } @@ -146,7 +151,8 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope { const Stmt *Body = S.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers(); for (unsigned Cnt = 0; Cnt < S.getCollapsedNumber(); ++Cnt) { - Body = Body->IgnoreContainers(); + Body = OMPLoopDirective::tryToFindNextInnerLoop( + Body, /*TryImperfectlyNestedLoops=*/true); if (auto *For = dyn_cast<ForStmt>(Body)) { Body = For->getBody(); } else { @@ -230,7 +236,7 @@ public: VD->getType().getNonReferenceType(), VK_LValue, C.getLocation()); InlinedShareds.addPrivate(VD, [&CGF, &DRE]() -> Address { - return CGF.EmitLValue(&DRE).getAddress(); + return CGF.EmitLValue(&DRE).getAddress(CGF); }); } } @@ -323,7 +329,7 @@ void CodeGenFunction::GenerateOpenMPCapturedVars( CapturedVars.push_back(CV); } else { assert(CurCap->capturesVariable() && "Expected capture by reference."); - CapturedVars.push_back(EmitLValue(*I).getAddress().getPointer()); + CapturedVars.push_back(EmitLValue(*I).getAddress(*this).getPointer()); } } } @@ -334,11 +340,11 @@ static Address castValueFromUintptr(CodeGenFunction &CGF, SourceLocation Loc, ASTContext &Ctx = CGF.getContext(); llvm::Value *CastedPtr = CGF.EmitScalarConversion( - AddrLV.getAddress().getPointer(), Ctx.getUIntPtrType(), + AddrLV.getAddress(CGF).getPointer(), Ctx.getUIntPtrType(), Ctx.getPointerType(DstType), Loc); Address TmpAddr = CGF.MakeNaturalAlignAddrLValue(CastedPtr, Ctx.getPointerType(DstType)) - .getAddress(); + .getAddress(CGF); return TmpAddr; } @@ -517,7 +523,7 @@ static llvm::Function *emitOutlinedFunctionPrologue( } else if (I->capturesVariable()) { const VarDecl *Var = I->getCapturedVar(); QualType VarTy = Var->getType(); - Address ArgAddr = ArgLVal.getAddress(); + Address ArgAddr = ArgLVal.getAddress(CGF); if (ArgLVal.getType()->isLValueReferenceType()) { ArgAddr = CGF.EmitLoadOfReference(ArgLVal); } else if (!VarTy->isVariablyModifiedType() || !VarTy->isPointerType()) { @@ -539,12 +545,12 @@ static llvm::Function *emitOutlinedFunctionPrologue( ? castValueFromUintptr( CGF, I->getLocation(), FD->getType(), Args[Cnt]->getName(), ArgLVal) - : ArgLVal.getAddress()}}); + : ArgLVal.getAddress(CGF)}}); } else { // If 'this' is captured, load it into CXXThisValue. assert(I->capturesThis()); CXXThisValue = CGF.EmitLoadOfScalar(ArgLVal, I->getLocation()); - LocalAddrs.insert({Args[Cnt], {nullptr, ArgLVal.getAddress()}}); + LocalAddrs.insert({Args[Cnt], {nullptr, ArgLVal.getAddress(CGF)}}); } ++Cnt; ++I; @@ -561,8 +567,7 @@ CodeGenFunction::GenerateOpenMPCapturedStmtFunction(const CapturedStmt &S) { const CapturedDecl *CD = S.getCapturedDecl(); // Build the argument list. bool NeedWrapperFunction = - getDebugInfo() && - CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo; + getDebugInfo() && CGM.getCodeGenOpts().hasReducedDebugInfo(); FunctionArgList Args; llvm::MapVector<const Decl *, std::pair<const VarDecl *, Address>> LocalAddrs; llvm::DenseMap<const Decl *, std::pair<const Expr *, llvm::Value *>> VLASizes; @@ -828,8 +833,8 @@ bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D, EmitAggregateAssign(Dest, OriginalLVal, Type); } else { EmitOMPAggregateAssign( - Emission.getAllocatedAddress(), OriginalLVal.getAddress(), - Type, + Emission.getAllocatedAddress(), + OriginalLVal.getAddress(*this), Type, [this, VDInit, Init](Address DestElement, Address SrcElement) { // Clean up any temporaries needed by the @@ -847,7 +852,7 @@ bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D, return Emission.getAllocatedAddress(); }); } else { - Address OriginalAddr = OriginalLVal.getAddress(); + Address OriginalAddr = OriginalLVal.getAddress(*this); IsRegistered = PrivateScope.addPrivate( OrigVD, [this, VDInit, OriginalAddr, VD]() { // Emit private VarDecl with copy init. @@ -924,7 +929,7 @@ bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) { "Copyin threadprivates should have been captured!"); DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(VD), true, (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc()); - MasterAddr = EmitLValue(&DRE).getAddress(); + MasterAddr = EmitLValue(&DRE).getAddress(*this); LocalDeclMap.erase(VD); } else { MasterAddr = @@ -933,7 +938,7 @@ bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) { getContext().getDeclAlign(VD)); } // Get the address of the threadprivate variable. - Address PrivateAddr = EmitLValue(*IRef).getAddress(); + Address PrivateAddr = EmitLValue(*IRef).getAddress(*this); if (CopiedVars.size() == 1) { // At first check if current thread is a master thread. If it is, no // need to copy data. @@ -1001,7 +1006,7 @@ bool CodeGenFunction::EmitOMPLastprivateClauseInit( /*RefersToEnclosingVariableOrCapture=*/ CapturedStmtInfo->lookup(OrigVD) != nullptr, (*IRef)->getType(), VK_LValue, (*IRef)->getExprLoc()); - return EmitLValue(&DRE).getAddress(); + return EmitLValue(&DRE).getAddress(*this); }); // Check if the variable is also a firstprivate: in this case IInit is // not generated. Initialization of this variable will happen in codegen @@ -1039,6 +1044,18 @@ void CodeGenFunction::EmitOMPLastprivateClauseFinal( llvm::BasicBlock *ThenBB = nullptr; llvm::BasicBlock *DoneBB = nullptr; if (IsLastIterCond) { + // Emit implicit barrier if at least one lastprivate conditional is found + // and this is not a simd mode. + if (!getLangOpts().OpenMPSimd && + llvm::any_of(D.getClausesOfKind<OMPLastprivateClause>(), + [](const OMPLastprivateClause *C) { + return C->getKind() == OMPC_LASTPRIVATE_conditional; + })) { + CGM.getOpenMPRuntime().emitBarrierCall(*this, D.getBeginLoc(), + OMPD_unknown, + /*EmitChecks=*/false, + /*ForceSimpleCall=*/true); + } ThenBB = createBasicBlock(".omp.lastprivate.then"); DoneBB = createBasicBlock(".omp.lastprivate.done"); Builder.CreateCondBr(IsLastIterCond, ThenBB, DoneBB); @@ -1077,14 +1094,19 @@ void CodeGenFunction::EmitOMPLastprivateClauseFinal( cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl()); const auto *DestVD = cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl()); - // Get the address of the original variable. - Address OriginalAddr = GetAddrOfLocalVar(DestVD); // Get the address of the private variable. Address PrivateAddr = GetAddrOfLocalVar(PrivateVD); if (const auto *RefTy = PrivateVD->getType()->getAs<ReferenceType>()) PrivateAddr = Address(Builder.CreateLoad(PrivateAddr), getNaturalTypeAlignment(RefTy->getPointeeType())); + // Store the last value to the private copy in the last iteration. + if (C->getKind() == OMPC_LASTPRIVATE_conditional) + CGM.getOpenMPRuntime().emitLastprivateConditionalFinalUpdate( + *this, MakeAddrLValue(PrivateAddr, (*IRef)->getType()), PrivateVD, + (*IRef)->getExprLoc()); + // Get the address of the original variable. + Address OriginalAddr = GetAddrOfLocalVar(DestVD); EmitOMPCopy(Type, OriginalAddr, PrivateAddr, DestVD, SrcVD, AssignOp); } ++IRef; @@ -1158,8 +1180,8 @@ void CodeGenFunction::EmitOMPReductionClauseInit( if (isaOMPArraySectionExpr && Type->isVariablyModifiedType()) { // Store the address of the original variable associated with the LHS // implicit variable. - PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() { - return RedCG.getSharedLValue(Count).getAddress(); + PrivateScope.addPrivate(LHSVD, [&RedCG, Count, this]() { + return RedCG.getSharedLValue(Count).getAddress(*this); }); PrivateScope.addPrivate( RHSVD, [this, PrivateVD]() { return GetAddrOfLocalVar(PrivateVD); }); @@ -1167,8 +1189,8 @@ void CodeGenFunction::EmitOMPReductionClauseInit( isa<ArraySubscriptExpr>(IRef)) { // Store the address of the original variable associated with the LHS // implicit variable. - PrivateScope.addPrivate(LHSVD, [&RedCG, Count]() { - return RedCG.getSharedLValue(Count).getAddress(); + PrivateScope.addPrivate(LHSVD, [&RedCG, Count, this]() { + return RedCG.getSharedLValue(Count).getAddress(*this); }); PrivateScope.addPrivate(RHSVD, [this, PrivateVD, RHSVD]() { return Builder.CreateElementBitCast(GetAddrOfLocalVar(PrivateVD), @@ -1178,7 +1200,7 @@ void CodeGenFunction::EmitOMPReductionClauseInit( } else { QualType Type = PrivateVD->getType(); bool IsArray = getContext().getAsArrayType(Type) != nullptr; - Address OriginalAddr = RedCG.getSharedLValue(Count).getAddress(); + Address OriginalAddr = RedCG.getSharedLValue(Count).getAddress(*this); // Store the address of the original variable associated with the LHS // implicit variable. if (IsArray) { @@ -1313,6 +1335,87 @@ static void emitEmptyBoundParameters(CodeGenFunction &, llvm::SmallVectorImpl<llvm::Value *> &) {} void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { + + if (llvm::OpenMPIRBuilder *OMPBuilder = CGM.getOpenMPIRBuilder()) { + // Check if we have any if clause associated with the directive. + llvm::Value *IfCond = nullptr; + if (const auto *C = S.getSingleClause<OMPIfClause>()) + IfCond = EmitScalarExpr(C->getCondition(), + /*IgnoreResultAssign=*/true); + + llvm::Value *NumThreads = nullptr; + if (const auto *NumThreadsClause = S.getSingleClause<OMPNumThreadsClause>()) + NumThreads = EmitScalarExpr(NumThreadsClause->getNumThreads(), + /*IgnoreResultAssign=*/true); + + ProcBindKind ProcBind = OMP_PROC_BIND_default; + if (const auto *ProcBindClause = S.getSingleClause<OMPProcBindClause>()) + ProcBind = ProcBindClause->getProcBindKind(); + + using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; + + // The cleanup callback that finalizes all variabels at the given location, + // thus calls destructors etc. + auto FiniCB = [this](InsertPointTy IP) { + CGBuilderTy::InsertPointGuard IPG(Builder); + assert(IP.getBlock()->end() != IP.getPoint() && + "OpenMP IR Builder should cause terminated block!"); + llvm::BasicBlock *IPBB = IP.getBlock(); + llvm::BasicBlock *DestBB = IPBB->splitBasicBlock(IP.getPoint()); + IPBB->getTerminator()->eraseFromParent(); + Builder.SetInsertPoint(IPBB); + CodeGenFunction::JumpDest Dest = getJumpDestInCurrentScope(DestBB); + EmitBranchThroughCleanup(Dest); + }; + + // Privatization callback that performs appropriate action for + // shared/private/firstprivate/lastprivate/copyin/... variables. + // + // TODO: This defaults to shared right now. + auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, + llvm::Value &Val, llvm::Value *&ReplVal) { + // The next line is appropriate only for variables (Val) with the + // data-sharing attribute "shared". + ReplVal = &Val; + + return CodeGenIP; + }; + + const CapturedStmt *CS = S.getCapturedStmt(OMPD_parallel); + const Stmt *ParallelRegionBodyStmt = CS->getCapturedStmt(); + + auto BodyGenCB = [ParallelRegionBodyStmt, + this](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, + llvm::BasicBlock &ContinuationBB) { + auto OldAllocaIP = AllocaInsertPt; + AllocaInsertPt = &*AllocaIP.getPoint(); + + auto OldReturnBlock = ReturnBlock; + ReturnBlock = getJumpDestInCurrentScope(&ContinuationBB); + + llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); + CodeGenIPBB->splitBasicBlock(CodeGenIP.getPoint()); + llvm::Instruction *CodeGenIPBBTI = CodeGenIPBB->getTerminator(); + CodeGenIPBBTI->removeFromParent(); + + Builder.SetInsertPoint(CodeGenIPBB); + + EmitStmt(ParallelRegionBodyStmt); + + Builder.Insert(CodeGenIPBBTI); + + AllocaInsertPt = OldAllocaIP; + ReturnBlock = OldReturnBlock; + }; + + CGCapturedStmtInfo CGSI(*CS, CR_OpenMP); + CodeGenFunction::CGCapturedStmtRAII CapInfoRAII(*this, &CGSI); + Builder.restoreIP(OMPBuilder->CreateParallel(Builder, BodyGenCB, PrivCB, + FiniCB, IfCond, NumThreads, + ProcBind, S.hasCancel())); + return; + } + // Emit parallel region as a standalone region. auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); @@ -1339,6 +1442,41 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { [](CodeGenFunction &) { return nullptr; }); } +static void emitBody(CodeGenFunction &CGF, const Stmt *S, const Stmt *NextLoop, + int MaxLevel, int Level = 0) { + assert(Level < MaxLevel && "Too deep lookup during loop body codegen."); + const Stmt *SimplifiedS = S->IgnoreContainers(); + if (const auto *CS = dyn_cast<CompoundStmt>(SimplifiedS)) { + PrettyStackTraceLoc CrashInfo( + CGF.getContext().getSourceManager(), CS->getLBracLoc(), + "LLVM IR generation of compound statement ('{}')"); + + // Keep track of the current cleanup stack depth, including debug scopes. + CodeGenFunction::LexicalScope Scope(CGF, S->getSourceRange()); + for (const Stmt *CurStmt : CS->body()) + emitBody(CGF, CurStmt, NextLoop, MaxLevel, Level); + return; + } + if (SimplifiedS == NextLoop) { + if (const auto *For = dyn_cast<ForStmt>(SimplifiedS)) { + S = For->getBody(); + } else { + assert(isa<CXXForRangeStmt>(SimplifiedS) && + "Expected canonical for loop or range-based for loop."); + const auto *CXXFor = cast<CXXForRangeStmt>(SimplifiedS); + CGF.EmitStmt(CXXFor->getLoopVarStmt()); + S = CXXFor->getBody(); + } + if (Level + 1 < MaxLevel) { + NextLoop = OMPLoopDirective::tryToFindNextInnerLoop( + S, /*TryImperfectlyNestedLoops=*/true); + emitBody(CGF, S, NextLoop, MaxLevel, Level + 1); + return; + } + } + CGF.EmitStmt(S); +} + void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D, JumpDest LoopExit) { RunCleanupsScope BodyScope(*this); @@ -1371,20 +1509,12 @@ void CodeGenFunction::EmitOMPLoopBody(const OMPLoopDirective &D, // Emit loop variables for C++ range loops. const Stmt *Body = D.getInnermostCapturedStmt()->getCapturedStmt()->IgnoreContainers(); - for (unsigned Cnt = 0; Cnt < D.getCollapsedNumber(); ++Cnt) { - Body = Body->IgnoreContainers(); - if (auto *For = dyn_cast<ForStmt>(Body)) { - Body = For->getBody(); - } else { - assert(isa<CXXForRangeStmt>(Body) && - "Expected canonical for loop or range-based for loop."); - auto *CXXFor = cast<CXXForRangeStmt>(Body); - EmitStmt(CXXFor->getLoopVarStmt()); - Body = CXXFor->getBody(); - } - } // Emit loop body. - EmitStmt(D.getBody()); + emitBody(*this, Body, + OMPLoopDirective::tryToFindNextInnerLoop( + Body, /*TryImperfectlyNestedLoops=*/true), + D.getCollapsedNumber()); + // The end (updates/cleanups). EmitBlock(Continue.getBlock()); BreakContinueStack.pop_back(); @@ -1500,7 +1630,7 @@ void CodeGenFunction::EmitOMPLinearClauseFinal( DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(OrigVD), CapturedStmtInfo->lookup(OrigVD) != nullptr, (*IC)->getType(), VK_LValue, (*IC)->getExprLoc()); - Address OrigAddr = EmitLValue(&DRE).getAddress(); + Address OrigAddr = EmitLValue(&DRE).getAddress(*this); CodeGenFunction::OMPPrivateScope VarScope(*this); VarScope.addPrivate(OrigVD, [OrigAddr]() { return OrigAddr; }); (void)VarScope.Privatize(); @@ -1570,7 +1700,7 @@ void CodeGenFunction::EmitOMPPrivateLoopCounters( DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(VD), LocalDeclMap.count(VD) || CapturedStmtInfo->lookup(VD), E->getType(), VK_LValue, E->getExprLoc()); - return EmitLValue(&DRE).getAddress(); + return EmitLValue(&DRE).getAddress(*this); }); } else { (void)LoopScope.addPrivate(PrivateVD, [&VarEmission]() { @@ -1733,12 +1863,13 @@ void CodeGenFunction::EmitOMPSimdFinal( } Address OrigAddr = Address::invalid(); if (CED) { - OrigAddr = EmitLValue(CED->getInit()->IgnoreImpCasts()).getAddress(); + OrigAddr = + EmitLValue(CED->getInit()->IgnoreImpCasts()).getAddress(*this); } else { DeclRefExpr DRE(getContext(), const_cast<VarDecl *>(PrivateVD), /*RefersToEnclosingVariableOrCapture=*/false, (*IPC)->getType(), VK_LValue, (*IPC)->getExprLoc()); - OrigAddr = EmitLValue(&DRE).getAddress(); + OrigAddr = EmitLValue(&DRE).getAddress(*this); } OMPPrivateScope VarScope(*this); VarScope.addPrivate(OrigVD, [OrigAddr]() { return OrigAddr; }); @@ -1755,6 +1886,7 @@ void CodeGenFunction::EmitOMPSimdFinal( static void emitOMPLoopBodyWithStopPoint(CodeGenFunction &CGF, const OMPLoopDirective &S, CodeGenFunction::JumpDest LoopExit) { + CGF.CGM.getOpenMPRuntime().initLastprivateConditionalCounter(CGF, S); CGF.EmitOMPLoopBody(S, LoopExit); CGF.EmitStopPoint(&S); } @@ -1767,6 +1899,40 @@ static LValue EmitOMPHelperVar(CodeGenFunction &CGF, return CGF.EmitLValue(Helper); } +static void emitCommonSimdLoop(CodeGenFunction &CGF, const OMPLoopDirective &S, + const RegionCodeGenTy &SimdInitGen, + const RegionCodeGenTy &BodyCodeGen) { + auto &&ThenGen = [&S, &SimdInitGen, &BodyCodeGen](CodeGenFunction &CGF, + PrePostActionTy &) { + CGOpenMPRuntime::NontemporalDeclsRAII NontemporalsRegion(CGF.CGM, S); + CodeGenFunction::OMPLocalDeclMapRAII Scope(CGF); + SimdInitGen(CGF); + + BodyCodeGen(CGF); + }; + auto &&ElseGen = [&BodyCodeGen](CodeGenFunction &CGF, PrePostActionTy &) { + CodeGenFunction::OMPLocalDeclMapRAII Scope(CGF); + CGF.LoopStack.setVectorizeEnable(/*Enable=*/false); + + BodyCodeGen(CGF); + }; + const Expr *IfCond = nullptr; + for (const auto *C : S.getClausesOfKind<OMPIfClause>()) { + if (CGF.getLangOpts().OpenMP >= 50 && + (C->getNameModifier() == OMPD_unknown || + C->getNameModifier() == OMPD_simd)) { + IfCond = C->getCondition(); + break; + } + } + if (IfCond) { + CGF.CGM.getOpenMPRuntime().emitIfClause(CGF, IfCond, ThenGen, ElseGen); + } else { + RegionCodeGenTy ThenRCG(ThenGen); + ThenRCG(CGF); + } +} + static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S, PrePostActionTy &Action) { Action.Enter(CGF); @@ -1817,8 +1983,6 @@ static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S, CGF.EmitIgnoredExpr(S.getCalcLastIteration()); } - CGF.EmitOMPSimdInit(S); - emitAlignedClause(CGF, S); (void)CGF.EmitOMPLinearClauseInit(S); { @@ -1827,17 +1991,29 @@ static void emitOMPSimdRegion(CodeGenFunction &CGF, const OMPLoopDirective &S, CGF.EmitOMPLinearClause(S, LoopScope); CGF.EmitOMPPrivateClause(S, LoopScope); CGF.EmitOMPReductionClauseInit(S, LoopScope); + CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion( + CGF, S, CGF.EmitLValue(S.getIterationVariable())); bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); (void)LoopScope.Privatize(); if (isOpenMPTargetExecutionDirective(S.getDirectiveKind())) CGF.CGM.getOpenMPRuntime().adjustTargetSpecificDataForLambdas(CGF, S); - CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), - S.getInc(), - [&S](CodeGenFunction &CGF) { - CGF.EmitOMPLoopBody(S, CodeGenFunction::JumpDest()); - CGF.EmitStopPoint(&S); - }, - [](CodeGenFunction &) {}); + + emitCommonSimdLoop( + CGF, S, + [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPSimdInit(S); + }, + [&S, &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPInnerLoop( + S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), + [&S](CodeGenFunction &CGF) { + CGF.CGM.getOpenMPRuntime().initLastprivateConditionalCounter( + CGF, S); + CGF.EmitOMPLoopBody(S, CodeGenFunction::JumpDest()); + CGF.EmitStopPoint(&S); + }, + [](CodeGenFunction &) {}); + }); CGF.EmitOMPSimdFinal(S, [](CodeGenFunction &) { return nullptr; }); // Emit final copy of the lastprivate variables at the end of loops. if (HasLastprivateClause) @@ -1922,27 +2098,32 @@ void CodeGenFunction::EmitOMPOuterLoop( JumpDest Continue = getJumpDestInCurrentScope("omp.dispatch.inc"); BreakContinueStack.push_back(BreakContinue(LoopExit, Continue)); - // Generate !llvm.loop.parallel metadata for loads and stores for loops - // with dynamic/guided scheduling and without ordered clause. - if (!isOpenMPSimdDirective(S.getDirectiveKind())) - LoopStack.setParallel(!IsMonotonic); - else - EmitOMPSimdInit(S, IsMonotonic); - - SourceLocation Loc = S.getBeginLoc(); - - // when 'distribute' is not combined with a 'for': - // while (idx <= UB) { BODY; ++idx; } - // when 'distribute' is combined with a 'for' - // (e.g. 'distribute parallel for') - // while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; } - EmitOMPInnerLoop( - S, LoopScope.requiresCleanups(), LoopArgs.Cond, LoopArgs.IncExpr, - [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) { - CodeGenLoop(CGF, S, LoopExit); + emitCommonSimdLoop( + *this, S, + [&S, IsMonotonic](CodeGenFunction &CGF, PrePostActionTy &) { + // Generate !llvm.loop.parallel metadata for loads and stores for loops + // with dynamic/guided scheduling and without ordered clause. + if (!isOpenMPSimdDirective(S.getDirectiveKind())) + CGF.LoopStack.setParallel(!IsMonotonic); + else + CGF.EmitOMPSimdInit(S, IsMonotonic); }, - [IVSize, IVSigned, Loc, &CodeGenOrdered](CodeGenFunction &CGF) { - CodeGenOrdered(CGF, Loc, IVSize, IVSigned); + [&S, &LoopArgs, LoopExit, &CodeGenLoop, IVSize, IVSigned, &CodeGenOrdered, + &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) { + SourceLocation Loc = S.getBeginLoc(); + // when 'distribute' is not combined with a 'for': + // while (idx <= UB) { BODY; ++idx; } + // when 'distribute' is combined with a 'for' + // (e.g. 'distribute parallel for') + // while (idx <= UB) { <CodeGen rest of pragma>; idx += ST; } + CGF.EmitOMPInnerLoop( + S, LoopScope.requiresCleanups(), LoopArgs.Cond, LoopArgs.IncExpr, + [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) { + CodeGenLoop(CGF, S, LoopExit); + }, + [IVSize, IVSigned, Loc, &CodeGenOrdered](CodeGenFunction &CGF) { + CodeGenOrdered(CGF, Loc, IVSize, IVSigned); + }); }); EmitBlock(Continue.getBlock()); @@ -2204,14 +2385,16 @@ static void emitDistributeParallelForDistributeInnerBoundParams( const auto &Dir = cast<OMPLoopDirective>(S); LValue LB = CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedLowerBoundVariable())); - llvm::Value *LBCast = CGF.Builder.CreateIntCast( - CGF.Builder.CreateLoad(LB.getAddress()), CGF.SizeTy, /*isSigned=*/false); + llvm::Value *LBCast = + CGF.Builder.CreateIntCast(CGF.Builder.CreateLoad(LB.getAddress(CGF)), + CGF.SizeTy, /*isSigned=*/false); CapturedVars.push_back(LBCast); LValue UB = CGF.EmitLValue(cast<DeclRefExpr>(Dir.getCombinedUpperBoundVariable())); - llvm::Value *UBCast = CGF.Builder.CreateIntCast( - CGF.Builder.CreateLoad(UB.getAddress()), CGF.SizeTy, /*isSigned=*/false); + llvm::Value *UBCast = + CGF.Builder.CreateIntCast(CGF.Builder.CreateLoad(UB.getAddress(CGF)), + CGF.SizeTy, /*isSigned=*/false); CapturedVars.push_back(UBCast); } @@ -2384,6 +2567,8 @@ bool CodeGenFunction::EmitOMPWorksharingLoop( /*ForceSimpleCall=*/true); } EmitOMPPrivateClause(S, LoopScope); + CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion( + *this, S, EmitLValue(S.getIterationVariable())); HasLastprivateClause = EmitOMPLastprivateClauseInit(S, LoopScope); EmitOMPReductionClauseInit(S, LoopScope); EmitOMPPrivateLoopCounters(S, LoopScope); @@ -2431,47 +2616,60 @@ bool CodeGenFunction::EmitOMPWorksharingLoop( /* Chunked */ Chunk != nullptr) || StaticChunkedOne) && !Ordered) { - if (isOpenMPSimdDirective(S.getDirectiveKind())) - EmitOMPSimdInit(S, /*IsMonotonic=*/true); - // OpenMP [2.7.1, Loop Construct, Description, table 2-1] - // When no chunk_size is specified, the iteration space is divided into - // chunks that are approximately equal in size, and at most one chunk is - // distributed to each thread. Note that the size of the chunks is - // unspecified in this case. - CGOpenMPRuntime::StaticRTInput StaticInit( - IVSize, IVSigned, Ordered, IL.getAddress(), LB.getAddress(), - UB.getAddress(), ST.getAddress(), - StaticChunkedOne ? Chunk : nullptr); - RT.emitForStaticInit(*this, S.getBeginLoc(), S.getDirectiveKind(), - ScheduleKind, StaticInit); JumpDest LoopExit = getJumpDestInCurrentScope(createBasicBlock("omp.loop.exit")); - // UB = min(UB, GlobalUB); - if (!StaticChunkedOne) - EmitIgnoredExpr(S.getEnsureUpperBound()); - // IV = LB; - EmitIgnoredExpr(S.getInit()); - // For unchunked static schedule generate: - // - // while (idx <= UB) { - // BODY; - // ++idx; - // } - // - // For static schedule with chunk one: - // - // while (IV <= PrevUB) { - // BODY; - // IV += ST; - // } - EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), - StaticChunkedOne ? S.getCombinedParForInDistCond() : S.getCond(), - StaticChunkedOne ? S.getDistInc() : S.getInc(), - [&S, LoopExit](CodeGenFunction &CGF) { - CGF.EmitOMPLoopBody(S, LoopExit); - CGF.EmitStopPoint(&S); + emitCommonSimdLoop( + *this, S, + [&S](CodeGenFunction &CGF, PrePostActionTy &) { + if (isOpenMPSimdDirective(S.getDirectiveKind())) + CGF.EmitOMPSimdInit(S, /*IsMonotonic=*/true); }, - [](CodeGenFunction &) {}); + [IVSize, IVSigned, Ordered, IL, LB, UB, ST, StaticChunkedOne, Chunk, + &S, ScheduleKind, LoopExit, + &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) { + // OpenMP [2.7.1, Loop Construct, Description, table 2-1] + // When no chunk_size is specified, the iteration space is divided + // into chunks that are approximately equal in size, and at most + // one chunk is distributed to each thread. Note that the size of + // the chunks is unspecified in this case. + CGOpenMPRuntime::StaticRTInput StaticInit( + IVSize, IVSigned, Ordered, IL.getAddress(CGF), + LB.getAddress(CGF), UB.getAddress(CGF), ST.getAddress(CGF), + StaticChunkedOne ? Chunk : nullptr); + CGF.CGM.getOpenMPRuntime().emitForStaticInit( + CGF, S.getBeginLoc(), S.getDirectiveKind(), ScheduleKind, + StaticInit); + // UB = min(UB, GlobalUB); + if (!StaticChunkedOne) + CGF.EmitIgnoredExpr(S.getEnsureUpperBound()); + // IV = LB; + CGF.EmitIgnoredExpr(S.getInit()); + // For unchunked static schedule generate: + // + // while (idx <= UB) { + // BODY; + // ++idx; + // } + // + // For static schedule with chunk one: + // + // while (IV <= PrevUB) { + // BODY; + // IV += ST; + // } + CGF.EmitOMPInnerLoop( + S, LoopScope.requiresCleanups(), + StaticChunkedOne ? S.getCombinedParForInDistCond() + : S.getCond(), + StaticChunkedOne ? S.getDistInc() : S.getInc(), + [&S, LoopExit](CodeGenFunction &CGF) { + CGF.CGM.getOpenMPRuntime() + .initLastprivateConditionalCounter(CGF, S); + CGF.EmitOMPLoopBody(S, LoopExit); + CGF.EmitStopPoint(&S); + }, + [](CodeGenFunction &) {}); + }); EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. auto &&CodeGen = [&S](CodeGenFunction &CGF) { @@ -2487,9 +2685,9 @@ bool CodeGenFunction::EmitOMPWorksharingLoop( ScheduleKind.M2 == OMPC_SCHEDULE_MODIFIER_monotonic; // Emit the outer loop, which requests its work chunk [LB..UB] from // runtime and runs the inner loop to process it. - const OMPLoopArguments LoopArguments(LB.getAddress(), UB.getAddress(), - ST.getAddress(), IL.getAddress(), - Chunk, EUB); + const OMPLoopArguments LoopArguments( + LB.getAddress(*this), UB.getAddress(*this), ST.getAddress(*this), + IL.getAddress(*this), Chunk, EUB); EmitOMPForOuterLoop(ScheduleKind, IsMonotonic, S, LoopScope, Ordered, LoopArguments, CGDispatchBounds); } @@ -2649,6 +2847,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { // break; // } // .omp.sections.exit: + CGF.CGM.getOpenMPRuntime().initLastprivateConditionalCounter(CGF, S); llvm::BasicBlock *ExitBB = CGF.createBasicBlock(".omp.sections.exit"); llvm::SwitchInst *SwitchStmt = CGF.Builder.CreateSwitch(CGF.EmitLoadOfScalar(IV, S.getBeginLoc()), @@ -2683,6 +2882,7 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { /*ForceSimpleCall=*/true); } CGF.EmitOMPPrivateClause(S, LoopScope); + CGOpenMPRuntime::LastprivateConditionalRAII LPCRegion(CGF, S, IV); HasLastprivates = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); CGF.EmitOMPReductionClauseInit(S, LoopScope); (void)LoopScope.Privatize(); @@ -2693,8 +2893,8 @@ void CodeGenFunction::EmitSections(const OMPExecutableDirective &S) { OpenMPScheduleTy ScheduleKind; ScheduleKind.Schedule = OMPC_SCHEDULE_static; CGOpenMPRuntime::StaticRTInput StaticInit( - /*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(), - LB.getAddress(), UB.getAddress(), ST.getAddress()); + /*IVSize=*/32, /*IVSigned=*/true, /*Ordered=*/false, IL.getAddress(CGF), + LB.getAddress(CGF), UB.getAddress(CGF), ST.getAddress(CGF)); CGF.CGM.getOpenMPRuntime().emitForStaticInit( CGF, S.getBeginLoc(), S.getDirectiveKind(), ScheduleKind, StaticInit); // UB = min(UB, GlobalUB); @@ -2809,13 +3009,17 @@ void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) { } } -void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) { +static void emitMaster(CodeGenFunction &CGF, const OMPExecutableDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { Action.Enter(CGF); CGF.EmitStmt(S.getInnermostCapturedStmt()->getCapturedStmt()); }; + CGF.CGM.getOpenMPRuntime().emitMasterRegion(CGF, CodeGen, S.getBeginLoc()); +} + +void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) { OMPLexicalScope Scope(*this, S, OMPD_unknown); - CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc()); + emitMaster(*this, S); } void CodeGenFunction::EmitOMPCriticalDirective(const OMPCriticalDirective &S) { @@ -2859,6 +3063,35 @@ void CodeGenFunction::EmitOMPParallelForSimdDirective( emitEmptyBoundParameters); } +void CodeGenFunction::EmitOMPParallelMasterDirective( + const OMPParallelMasterDirective &S) { + // Emit directive as a combined directive that consists of two implicit + // directives: 'parallel' with 'master' directive. + auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { + Action.Enter(CGF); + OMPPrivateScope PrivateScope(CGF); + bool Copyins = CGF.EmitOMPCopyinClause(S); + (void)CGF.EmitOMPFirstprivateClause(S, PrivateScope); + if (Copyins) { + // Emit implicit barrier to synchronize threads and avoid data races on + // propagation master's thread values of threadprivate variables to local + // instances of that variables of all other implicit threads. + CGF.CGM.getOpenMPRuntime().emitBarrierCall( + CGF, S.getBeginLoc(), OMPD_unknown, /*EmitChecks=*/false, + /*ForceSimpleCall=*/true); + } + CGF.EmitOMPPrivateClause(S, PrivateScope); + CGF.EmitOMPReductionClauseInit(S, PrivateScope); + (void)PrivateScope.Privatize(); + emitMaster(CGF, S); + CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_parallel); + }; + emitCommonOMPParallelDirective(*this, S, OMPD_master, CodeGen, + emitEmptyBoundParameters); + emitPostUpdateForReductionClause(*this, S, + [](CodeGenFunction &) { return nullptr; }); +} + void CodeGenFunction::EmitOMPParallelSectionsDirective( const OMPParallelSectionsDirective &S) { // Emit directive as a combined directive that consists of two implicit @@ -3028,7 +3261,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( Pair.second->getType(), VK_LValue, Pair.second->getExprLoc()); Scope.addPrivate(Pair.first, [&CGF, &DRE]() { - return CGF.EmitLValue(&DRE).getAddress(); + return CGF.EmitLValue(&DRE).getAddress(CGF); }); } for (const auto &Pair : PrivatePtrs) { @@ -3125,7 +3358,8 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( S, *I, *PartId, *TaskT, S.getDirectiveKind(), CodeGen, Data.Tied, Data.NumberOfParts); OMPLexicalScope Scope(*this, S, llvm::None, - !isOpenMPParallelDirective(S.getDirectiveKind())); + !isOpenMPParallelDirective(S.getDirectiveKind()) && + !isOpenMPSimdDirective(S.getDirectiveKind())); TaskGen(*this, OutlinedFn, Data); } @@ -3483,11 +3717,9 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S, if (RT.isStaticNonchunked(ScheduleKind, /* Chunked */ Chunk != nullptr) || StaticChunked) { - if (isOpenMPSimdDirective(S.getDirectiveKind())) - EmitOMPSimdInit(S, /*IsMonotonic=*/true); CGOpenMPRuntime::StaticRTInput StaticInit( - IVSize, IVSigned, /* Ordered = */ false, IL.getAddress(), - LB.getAddress(), UB.getAddress(), ST.getAddress(), + IVSize, IVSigned, /* Ordered = */ false, IL.getAddress(*this), + LB.getAddress(*this), UB.getAddress(*this), ST.getAddress(*this), StaticChunked ? Chunk : nullptr); RT.emitDistributeStaticInit(*this, S.getBeginLoc(), ScheduleKind, StaticInit); @@ -3534,18 +3766,28 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S, // IV = LB; // } // - EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), Cond, IncExpr, - [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) { - CodeGenLoop(CGF, S, LoopExit); - }, - [&S, StaticChunked](CodeGenFunction &CGF) { - if (StaticChunked) { - CGF.EmitIgnoredExpr(S.getCombinedNextLowerBound()); - CGF.EmitIgnoredExpr(S.getCombinedNextUpperBound()); - CGF.EmitIgnoredExpr(S.getCombinedEnsureUpperBound()); - CGF.EmitIgnoredExpr(S.getCombinedInit()); - } - }); + emitCommonSimdLoop( + *this, S, + [&S](CodeGenFunction &CGF, PrePostActionTy &) { + if (isOpenMPSimdDirective(S.getDirectiveKind())) + CGF.EmitOMPSimdInit(S, /*IsMonotonic=*/true); + }, + [&S, &LoopScope, Cond, IncExpr, LoopExit, &CodeGenLoop, + StaticChunked](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPInnerLoop( + S, LoopScope.requiresCleanups(), Cond, IncExpr, + [&S, LoopExit, &CodeGenLoop](CodeGenFunction &CGF) { + CodeGenLoop(CGF, S, LoopExit); + }, + [&S, StaticChunked](CodeGenFunction &CGF) { + if (StaticChunked) { + CGF.EmitIgnoredExpr(S.getCombinedNextLowerBound()); + CGF.EmitIgnoredExpr(S.getCombinedNextUpperBound()); + CGF.EmitIgnoredExpr(S.getCombinedEnsureUpperBound()); + CGF.EmitIgnoredExpr(S.getCombinedInit()); + } + }); + }); EmitBlock(LoopExit.getBlock()); // Tell the runtime we are done. RT.emitForStaticFinish(*this, S.getBeginLoc(), S.getDirectiveKind()); @@ -3553,8 +3795,8 @@ void CodeGenFunction::EmitOMPDistributeLoop(const OMPLoopDirective &S, // Emit the outer loop, which requests its work chunk [LB..UB] from // runtime and runs the inner loop to process it. const OMPLoopArguments LoopArguments = { - LB.getAddress(), UB.getAddress(), ST.getAddress(), IL.getAddress(), - Chunk}; + LB.getAddress(*this), UB.getAddress(*this), ST.getAddress(*this), + IL.getAddress(*this), Chunk}; EmitOMPDistributeOuterLoop(ScheduleKind, S, LoopScope, LoopArguments, CodeGenLoop); } @@ -3754,11 +3996,11 @@ static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X, // expression is simple and atomic is allowed for the given type for the // target platform. if (BO == BO_Comma || !Update.isScalar() || - !Update.getScalarVal()->getType()->isIntegerTy() || - !X.isSimple() || (!isa<llvm::ConstantInt>(Update.getScalarVal()) && - (Update.getScalarVal()->getType() != - X.getAddress().getElementType())) || - !X.getAddress().getElementType()->isIntegerTy() || + !Update.getScalarVal()->getType()->isIntegerTy() || !X.isSimple() || + (!isa<llvm::ConstantInt>(Update.getScalarVal()) && + (Update.getScalarVal()->getType() != + X.getAddress(CGF).getElementType())) || + !X.getAddress(CGF).getElementType()->isIntegerTy() || !Context.getTargetInfo().hasBuiltinAtomic( Context.getTypeSize(X.getType()), Context.toBits(X.getAlignment()))) return std::make_pair(false, RValue::get(nullptr)); @@ -3830,11 +4072,11 @@ static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X, llvm::Value *UpdateVal = Update.getScalarVal(); if (auto *IC = dyn_cast<llvm::ConstantInt>(UpdateVal)) { UpdateVal = CGF.Builder.CreateIntCast( - IC, X.getAddress().getElementType(), + IC, X.getAddress(CGF).getElementType(), X.getType()->hasSignedIntegerRepresentation()); } llvm::Value *Res = - CGF.Builder.CreateAtomicRMW(RMWOp, X.getPointer(), UpdateVal, AO); + CGF.Builder.CreateAtomicRMW(RMWOp, X.getPointer(CGF), UpdateVal, AO); return std::make_pair(true, RValue::get(Res)); } @@ -4074,6 +4316,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind, case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + case OMPC_nontemporal: llvm_unreachable("Clause is not allowed in 'omp atomic'."); } } @@ -4489,7 +4732,8 @@ void CodeGenFunction::EmitOMPTeamsDistributeParallelForSimdDirective( CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false); CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); }; - emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen); + emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for_simd, + CodeGen); emitPostUpdateForReductionClause(*this, S, [](CodeGenFunction &) { return nullptr; }); } @@ -4612,6 +4856,19 @@ void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) { break; } } + if (llvm::OpenMPIRBuilder *OMPBuilder = CGM.getOpenMPIRBuilder()) { + // TODO: This check is necessary as we only generate `omp parallel` through + // the OpenMPIRBuilder for now. + if (S.getCancelRegion() == OMPD_parallel) { + llvm::Value *IfCondition = nullptr; + if (IfCond) + IfCondition = EmitScalarExpr(IfCond, + /*IgnoreResultAssign=*/true); + return Builder.restoreIP( + OMPBuilder->CreateCancel(Builder, IfCondition, S.getCancelRegion())); + } + } + CGM.getOpenMPRuntime().emitCancelCall(*this, S.getBeginLoc(), IfCond, S.getCancelRegion()); } @@ -5017,8 +5274,7 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) { CGF.incrementProfileCounter(&S); } - if (isOpenMPSimdDirective(S.getDirectiveKind())) - CGF.EmitOMPSimdInit(S); + (void)CGF.EmitOMPLinearClauseInit(S); OMPPrivateScope LoopScope(CGF); // Emit helper vars inits. @@ -5036,6 +5292,7 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) { mapParam(CGF, cast<DeclRefExpr>(S.getIsLastIterVariable()), *LIP, LoopScope); CGF.EmitOMPPrivateLoopCounters(S, LoopScope); + CGF.EmitOMPLinearClause(S, LoopScope); bool HasLastprivateClause = CGF.EmitOMPLastprivateClauseInit(S, LoopScope); (void)LoopScope.Privatize(); // Emit the loop iteration variable. @@ -5053,13 +5310,24 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) { CGF.EmitIgnoredExpr(S.getCalcLastIteration()); } - CGF.EmitOMPInnerLoop(S, LoopScope.requiresCleanups(), S.getCond(), - S.getInc(), - [&S](CodeGenFunction &CGF) { - CGF.EmitOMPLoopBody(S, JumpDest()); - CGF.EmitStopPoint(&S); - }, - [](CodeGenFunction &) {}); + { + OMPLexicalScope Scope(CGF, S, OMPD_taskloop, /*EmitPreInitStmt=*/false); + emitCommonSimdLoop( + CGF, S, + [&S](CodeGenFunction &CGF, PrePostActionTy &) { + if (isOpenMPSimdDirective(S.getDirectiveKind())) + CGF.EmitOMPSimdInit(S); + }, + [&S, &LoopScope](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPInnerLoop( + S, LoopScope.requiresCleanups(), S.getCond(), S.getInc(), + [&S](CodeGenFunction &CGF) { + CGF.EmitOMPLoopBody(S, CodeGenFunction::JumpDest()); + CGF.EmitStopPoint(&S); + }, + [](CodeGenFunction &) {}); + }); + } // Emit: if (PreCond) - end. if (ContBlock) { CGF.EmitBranch(ContBlock); @@ -5073,6 +5341,11 @@ void CodeGenFunction::EmitOMPTaskLoopBasedDirective(const OMPLoopDirective &S) { CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false, (*LIP)->getType(), S.getBeginLoc()))); } + CGF.EmitOMPLinearClauseFinal(S, [LIP, &S](CodeGenFunction &CGF) { + return CGF.Builder.CreateIsNotNull( + CGF.EmitLoadOfScalar(CGF.GetAddrOfLocalVar(*LIP), /*Volatile=*/false, + (*LIP)->getType(), S.getBeginLoc())); + }); }; auto &&TaskGen = [&S, SharedsTy, CapturedStruct, IfCond](CodeGenFunction &CGF, llvm::Function *OutlinedFn, @@ -5108,6 +5381,7 @@ void CodeGenFunction::EmitOMPTaskLoopDirective(const OMPTaskLoopDirective &S) { void CodeGenFunction::EmitOMPTaskLoopSimdDirective( const OMPTaskLoopSimdDirective &S) { + OMPLexicalScope Scope(*this, S); EmitOMPTaskLoopBasedDirective(S); } @@ -5127,7 +5401,7 @@ void CodeGenFunction::EmitOMPMasterTaskLoopSimdDirective( Action.Enter(CGF); EmitOMPTaskLoopBasedDirective(S); }; - OMPLexicalScope Scope(*this, S, llvm::None, /*EmitPreInitStmt=*/false); + OMPLexicalScope Scope(*this, S); CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc()); } @@ -5147,6 +5421,22 @@ void CodeGenFunction::EmitOMPParallelMasterTaskLoopDirective( emitEmptyBoundParameters); } +void CodeGenFunction::EmitOMPParallelMasterTaskLoopSimdDirective( + const OMPParallelMasterTaskLoopSimdDirective &S) { + auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) { + auto &&TaskLoopCodeGen = [&S](CodeGenFunction &CGF, + PrePostActionTy &Action) { + Action.Enter(CGF); + CGF.EmitOMPTaskLoopBasedDirective(S); + }; + OMPLexicalScope Scope(CGF, S, OMPD_parallel, /*EmitPreInitStmt=*/false); + CGM.getOpenMPRuntime().emitMasterRegion(CGF, TaskLoopCodeGen, + S.getBeginLoc()); + }; + emitCommonOMPParallelDirective(*this, S, OMPD_master_taskloop_simd, CodeGen, + emitEmptyBoundParameters); +} + // Generate the instructions for '#pragma omp target update' directive. void CodeGenFunction::EmitOMPTargetUpdateDirective( const OMPTargetUpdateDirective &S) { @@ -5180,11 +5470,11 @@ void CodeGenFunction::EmitSimpleOMPExecutableDirective( OMPPrivateScope LoopGlobals(CGF); if (const auto *LD = dyn_cast<OMPLoopDirective>(&D)) { for (const Expr *E : LD->counters()) { - const auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()); + const auto *VD = cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl()); if (!VD->hasLocalStorage() && !CGF.LocalDeclMap.count(VD)) { LValue GlobLVal = CGF.EmitLValue(E); LoopGlobals.addPrivate( - VD, [&GlobLVal]() { return GlobLVal.getAddress(); }); + VD, [&GlobLVal, &CGF]() { return GlobLVal.getAddress(CGF); }); } if (isa<OMPCapturedExprDecl>(VD)) { // Emit only those that were not explicitly referenced in clauses. diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index f9f25e7e57ad..59631e802373 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -13,6 +13,7 @@ #include "CGCXXABI.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" +#include "clang/AST/Attr.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/CodeGenOptions.h" @@ -335,7 +336,7 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::FunctionCallee Callee, for (const ParmVarDecl *PD : MD->parameters()) EmitDelegateCallArg(CallArgs, PD, SourceLocation()); - const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); + const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); #ifndef NDEBUG const CGFunctionInfo &CallFnInfo = CGM.getTypes().arrangeCXXMethodCall( @@ -675,7 +676,12 @@ void CodeGenVTables::addVTableComponent( // Method is acceptable, continue processing as usual. } - auto getSpecialVirtualFn = [&](StringRef name) { + auto getSpecialVirtualFn = [&](StringRef name) -> llvm::Constant * { + // For NVPTX devices in OpenMP emit special functon as null pointers, + // otherwise linking ends up with unresolved references. + if (CGM.getLangOpts().OpenMP && CGM.getLangOpts().OpenMPIsDevice && + CGM.getTriple().isNVPTX()) + return llvm::ConstantPointerNull::get(CGM.Int8PtrTy); llvm::FunctionType *fnTy = llvm::FunctionType::get(CGM.VoidTy, /*isVarArg=*/false); llvm::Constant *fn = cast<llvm::Constant>( diff --git a/clang/lib/CodeGen/CGValue.h b/clang/lib/CodeGen/CGValue.h index 71f95abe488a..9fd07bdb187d 100644 --- a/clang/lib/CodeGen/CGValue.h +++ b/clang/lib/CodeGen/CGValue.h @@ -29,6 +29,7 @@ namespace llvm { namespace clang { namespace CodeGen { class AggValueSlot; + class CodeGenFunction; struct CGBitFieldInfo; /// RValue - This trivial value class is used to represent the result of an @@ -319,11 +320,13 @@ public: void setBaseInfo(LValueBaseInfo Info) { BaseInfo = Info; } // simple lvalue - llvm::Value *getPointer() const { + llvm::Value *getPointer(CodeGenFunction &CGF) const { assert(isSimple()); return V; } - Address getAddress() const { return Address(getPointer(), getAlignment()); } + Address getAddress(CodeGenFunction &CGF) const { + return Address(getPointer(CGF), getAlignment()); + } void setAddress(Address address) { assert(isSimple()); V = address.getPointer(); @@ -427,8 +430,8 @@ public: return R; } - RValue asAggregateRValue() const { - return RValue::getAggregate(getAddress(), isVolatileQualified()); + RValue asAggregateRValue(CodeGenFunction &CGF) const { + return RValue::getAggregate(getAddress(CGF), isVolatileQualified()); } }; @@ -536,14 +539,12 @@ public: return AV; } - static AggValueSlot forLValue(const LValue &LV, - IsDestructed_t isDestructed, - NeedsGCBarriers_t needsGC, - IsAliased_t isAliased, - Overlap_t mayOverlap, - IsZeroed_t isZeroed = IsNotZeroed, - IsSanitizerChecked_t isChecked = IsNotSanitizerChecked) { - return forAddr(LV.getAddress(), LV.getQuals(), isDestructed, needsGC, + static AggValueSlot + forLValue(const LValue &LV, CodeGenFunction &CGF, IsDestructed_t isDestructed, + NeedsGCBarriers_t needsGC, IsAliased_t isAliased, + Overlap_t mayOverlap, IsZeroed_t isZeroed = IsNotZeroed, + IsSanitizerChecked_t isChecked = IsNotSanitizerChecked) { + return forAddr(LV.getAddress(CGF), LV.getQuals(), isDestructed, needsGC, isAliased, mayOverlap, isZeroed, isChecked); } diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index 87bda4a0fc2c..7065e78f19a2 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -82,6 +82,24 @@ namespace clang { BackendConsumer *BackendCon; }; + static void reportOptRecordError(Error E, DiagnosticsEngine &Diags, + const CodeGenOptions CodeGenOpts) { + handleAllErrors( + std::move(E), + [&](const RemarkSetupFileError &E) { + Diags.Report(diag::err_cannot_open_file) + << CodeGenOpts.OptRecordFile << E.message(); + }, + [&](const RemarkSetupPatternError &E) { + Diags.Report(diag::err_drv_optimization_remark_pattern) + << E.message() << CodeGenOpts.OptRecordPasses; + }, + [&](const RemarkSetupFormatError &E) { + Diags.Report(diag::err_drv_optimization_remark_format) + << CodeGenOpts.OptRecordFormat; + }); + } + class BackendConsumer : public ASTConsumer { using LinkModule = CodeGenAction::LinkModule; @@ -133,6 +151,29 @@ namespace clang { FrontendTimesIsEnabled = TimePasses; llvm::TimePassesIsEnabled = TimePasses; } + + // This constructor is used in installing an empty BackendConsumer + // to use the clang diagnostic handler for IR input files. It avoids + // initializing the OS field. + BackendConsumer(BackendAction Action, DiagnosticsEngine &Diags, + const HeaderSearchOptions &HeaderSearchOpts, + const PreprocessorOptions &PPOpts, + const CodeGenOptions &CodeGenOpts, + const TargetOptions &TargetOpts, + const LangOptions &LangOpts, bool TimePasses, + SmallVector<LinkModule, 4> LinkModules, LLVMContext &C, + CoverageSourceInfo *CoverageInfo = nullptr) + : Diags(Diags), Action(Action), HeaderSearchOpts(HeaderSearchOpts), + CodeGenOpts(CodeGenOpts), TargetOpts(TargetOpts), LangOpts(LangOpts), + Context(nullptr), + LLVMIRGeneration("irgen", "LLVM IR Generation Time"), + LLVMIRGenerationRefCount(0), + Gen(CreateLLVMCodeGen(Diags, "", HeaderSearchOpts, PPOpts, + CodeGenOpts, C, CoverageInfo)), + LinkModules(std::move(LinkModules)) { + FrontendTimesIsEnabled = TimePasses; + llvm::TimePassesIsEnabled = TimePasses; + } llvm::Module *getModule() const { return Gen->GetModule(); } std::unique_ptr<llvm::Module> takeModule() { return std::unique_ptr<llvm::Module>(Gen->ReleaseModule()); @@ -231,7 +272,7 @@ namespace clang { void HandleTranslationUnit(ASTContext &C) override { { - llvm::TimeTraceScope TimeScope("Frontend", StringRef("")); + llvm::TimeTraceScope TimeScope("Frontend"); PrettyStackTraceString CrashInfo("Per-file LLVM IR generation"); if (FrontendTimesIsEnabled) { LLVMIRGenerationRefCount += 1; @@ -268,29 +309,16 @@ namespace clang { CodeGenOpts, this)); Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr = - setupOptimizationRemarks(Ctx, CodeGenOpts.OptRecordFile, - CodeGenOpts.OptRecordPasses, - CodeGenOpts.OptRecordFormat, - CodeGenOpts.DiagnosticsWithHotness, - CodeGenOpts.DiagnosticsHotnessThreshold); + setupOptimizationRemarks( + Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses, + CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness, + CodeGenOpts.DiagnosticsHotnessThreshold); if (Error E = OptRecordFileOrErr.takeError()) { - handleAllErrors( - std::move(E), - [&](const RemarkSetupFileError &E) { - Diags.Report(diag::err_cannot_open_file) - << CodeGenOpts.OptRecordFile << E.message(); - }, - [&](const RemarkSetupPatternError &E) { - Diags.Report(diag::err_drv_optimization_remark_pattern) - << E.message() << CodeGenOpts.OptRecordPasses; - }, - [&](const RemarkSetupFormatError &E) { - Diags.Report(diag::err_drv_optimization_remark_format) - << CodeGenOpts.OptRecordFormat; - }); + reportOptRecordError(std::move(E), Diags, CodeGenOpts); return; } + std::unique_ptr<llvm::ToolOutputFile> OptRecordFile = std::move(*OptRecordFileOrErr); @@ -331,6 +359,10 @@ namespace clang { Gen->CompleteTentativeDefinition(D); } + void CompleteExternalDeclaration(VarDecl *D) override { + Gen->CompleteExternalDeclaration(D); + } + void AssignInheritanceModel(CXXRecordDecl *RD) override { Gen->AssignInheritanceModel(RD); } @@ -607,10 +639,20 @@ void BackendConsumer::UnsupportedDiagHandler( StringRef Filename; unsigned Line, Column; bool BadDebugInfo = false; - FullSourceLoc Loc = - getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); + FullSourceLoc Loc; + std::string Msg; + raw_string_ostream MsgStream(Msg); - Diags.Report(Loc, diag::err_fe_backend_unsupported) << D.getMessage().str(); + // Context will be nullptr for IR input files, we will construct the diag + // message from llvm::DiagnosticInfoUnsupported. + if (Context != nullptr) { + Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); + MsgStream << D.getMessage(); + } else { + DiagnosticPrinterRawOStream DP(MsgStream); + D.print(DP); + } + Diags.Report(Loc, diag::err_fe_backend_unsupported) << MsgStream.str(); if (BadDebugInfo) // If we were not able to translate the file:line:col information @@ -626,10 +668,21 @@ void BackendConsumer::MisExpectDiagHandler( StringRef Filename; unsigned Line, Column; bool BadDebugInfo = false; - FullSourceLoc Loc = - getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); + FullSourceLoc Loc; + std::string Msg; + raw_string_ostream MsgStream(Msg); + DiagnosticPrinterRawOStream DP(MsgStream); - Diags.Report(Loc, diag::warn_profile_data_misexpect) << D.getMsg().str(); + // Context will be nullptr for IR input files, we will construct the diag + // message from llvm::DiagnosticInfoMisExpect. + if (Context != nullptr) { + Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); + MsgStream << D.getMsg(); + } else { + DiagnosticPrinterRawOStream DP(MsgStream); + D.print(DP); + } + Diags.Report(Loc, diag::warn_profile_data_misexpect) << MsgStream.str(); if (BadDebugInfo) // If we were not able to translate the file:line:col information @@ -649,12 +702,19 @@ void BackendConsumer::EmitOptimizationMessage( StringRef Filename; unsigned Line, Column; bool BadDebugInfo = false; - FullSourceLoc Loc = - getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); - + FullSourceLoc Loc; std::string Msg; raw_string_ostream MsgStream(Msg); - MsgStream << D.getMsg(); + + // Context will be nullptr for IR input files, we will construct the remark + // message from llvm::DiagnosticInfoOptimizationBase. + if (Context != nullptr) { + Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); + MsgStream << D.getMsg(); + } else { + DiagnosticPrinterRawOStream DP(MsgStream); + D.print(DP); + } if (D.getHotness()) MsgStream << " (hotness: " << *D.getHotness() << ")"; @@ -1046,6 +1106,8 @@ void CodeGenAction::ExecuteAction() { if (getCurrentFileKind().getLanguage() == Language::LLVM_IR) { BackendAction BA = static_cast<BackendAction>(Act); CompilerInstance &CI = getCompilerInstance(); + auto &CodeGenOpts = CI.getCodeGenOpts(); + auto &Diagnostics = CI.getDiagnostics(); std::unique_ptr<raw_pwrite_stream> OS = GetOutputStream(CI, getCurrentFile(), BA); if (BA != Backend_EmitNothing && !OS) @@ -1064,23 +1126,49 @@ void CodeGenAction::ExecuteAction() { const TargetOptions &TargetOpts = CI.getTargetOpts(); if (TheModule->getTargetTriple() != TargetOpts.Triple) { - CI.getDiagnostics().Report(SourceLocation(), - diag::warn_fe_override_module) + Diagnostics.Report(SourceLocation(), + diag::warn_fe_override_module) << TargetOpts.Triple; TheModule->setTargetTriple(TargetOpts.Triple); } - EmbedBitcode(TheModule.get(), CI.getCodeGenOpts(), + EmbedBitcode(TheModule.get(), CodeGenOpts, MainFile->getMemBufferRef()); LLVMContext &Ctx = TheModule->getContext(); Ctx.setInlineAsmDiagnosticHandler(BitcodeInlineAsmDiagHandler, - &CI.getDiagnostics()); + &Diagnostics); + + // Set clang diagnostic handler. To do this we need to create a fake + // BackendConsumer. + BackendConsumer Result(BA, CI.getDiagnostics(), CI.getHeaderSearchOpts(), + CI.getPreprocessorOpts(), CI.getCodeGenOpts(), + CI.getTargetOpts(), CI.getLangOpts(), + CI.getFrontendOpts().ShowTimers, + std::move(LinkModules), *VMContext, nullptr); + Ctx.setDiagnosticHandler( + std::make_unique<ClangDiagnosticHandler>(CodeGenOpts, &Result)); - EmitBackendOutput(CI.getDiagnostics(), CI.getHeaderSearchOpts(), - CI.getCodeGenOpts(), TargetOpts, CI.getLangOpts(), + Expected<std::unique_ptr<llvm::ToolOutputFile>> OptRecordFileOrErr = + setupOptimizationRemarks( + Ctx, CodeGenOpts.OptRecordFile, CodeGenOpts.OptRecordPasses, + CodeGenOpts.OptRecordFormat, CodeGenOpts.DiagnosticsWithHotness, + CodeGenOpts.DiagnosticsHotnessThreshold); + + if (Error E = OptRecordFileOrErr.takeError()) { + reportOptRecordError(std::move(E), Diagnostics, CodeGenOpts); + return; + } + std::unique_ptr<llvm::ToolOutputFile> OptRecordFile = + std::move(*OptRecordFileOrErr); + + EmitBackendOutput(Diagnostics, CI.getHeaderSearchOpts(), CodeGenOpts, + TargetOpts, CI.getLangOpts(), CI.getTarget().getDataLayout(), TheModule.get(), BA, std::move(OS)); + + if (OptRecordFile) + OptRecordFile->keep(); return; } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 3f9a52ab7638..2bf94f697e01 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -12,9 +12,9 @@ #include "CodeGenFunction.h" #include "CGBlocks.h" -#include "CGCleanup.h" #include "CGCUDARuntime.h" #include "CGCXXABI.h" +#include "CGCleanup.h" #include "CGDebugInfo.h" #include "CGOpenMPRuntime.h" #include "CodeGenModule.h" @@ -22,6 +22,7 @@ #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/StmtCXX.h" @@ -33,6 +34,8 @@ #include "clang/Frontend/FrontendDiagnostic.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" +#include "llvm/IR/FPEnv.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Operator.h" @@ -87,6 +90,7 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) FMF.setAllowReassoc(); } Builder.setFastMathFlags(FMF); + SetFPModel(); } CodeGenFunction::~CodeGenFunction() { @@ -102,6 +106,51 @@ CodeGenFunction::~CodeGenFunction() { CGM.getOpenMPRuntime().functionFinished(*this); } +// Map the LangOption for rounding mode into +// the corresponding enum in the IR. +static llvm::fp::RoundingMode ToConstrainedRoundingMD( + LangOptions::FPRoundingModeKind Kind) { + + switch (Kind) { + case LangOptions::FPR_ToNearest: return llvm::fp::rmToNearest; + case LangOptions::FPR_Downward: return llvm::fp::rmDownward; + case LangOptions::FPR_Upward: return llvm::fp::rmUpward; + case LangOptions::FPR_TowardZero: return llvm::fp::rmTowardZero; + case LangOptions::FPR_Dynamic: return llvm::fp::rmDynamic; + } + llvm_unreachable("Unsupported FP RoundingMode"); +} + +// Map the LangOption for exception behavior into +// the corresponding enum in the IR. +static llvm::fp::ExceptionBehavior ToConstrainedExceptMD( + LangOptions::FPExceptionModeKind Kind) { + + switch (Kind) { + case LangOptions::FPE_Ignore: return llvm::fp::ebIgnore; + case LangOptions::FPE_MayTrap: return llvm::fp::ebMayTrap; + case LangOptions::FPE_Strict: return llvm::fp::ebStrict; + } + llvm_unreachable("Unsupported FP Exception Behavior"); +} + +void CodeGenFunction::SetFPModel() { + auto fpRoundingMode = ToConstrainedRoundingMD( + getLangOpts().getFPRoundingMode()); + auto fpExceptionBehavior = ToConstrainedExceptMD( + getLangOpts().getFPExceptionMode()); + + if (fpExceptionBehavior == llvm::fp::ebIgnore && + fpRoundingMode == llvm::fp::rmToNearest) + // Constrained intrinsics are not used. + ; + else { + Builder.setIsFPConstrained(true); + Builder.setDefaultConstrainedRounding(fpRoundingMode); + Builder.setDefaultConstrainedExcept(fpExceptionBehavior); + } +} + CharUnits CodeGenFunction::getNaturalPointeeTypeAlignment(QualType T, LValueBaseInfo *BaseInfo, TBAAAccessInfo *TBAAInfo) { @@ -329,9 +378,15 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { if (HasCleanups) { // Make sure the line table doesn't jump back into the body for // the ret after it's been at EndLoc. - if (CGDebugInfo *DI = getDebugInfo()) + Optional<ApplyDebugLocation> AL; + if (CGDebugInfo *DI = getDebugInfo()) { if (OnlySimpleReturnStmts) DI->EmitLocation(Builder, EndLoc); + else + // We may not have a valid end location. Try to apply it anyway, and + // fall back to an artificial location if needed. + AL = ApplyDebugLocation::CreateDefaultArtificial(*this, EndLoc); + } PopCleanupBlocks(PrologueCleanupDepth); } @@ -606,6 +661,13 @@ void CodeGenFunction::markAsIgnoreThreadCheckingAtRuntime(llvm::Function *Fn) { } } +/// Check if the return value of this function requires sanitization. +bool CodeGenFunction::requiresReturnValueCheck() const { + return requiresReturnValueNullabilityCheck() || + (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) && CurCodeDecl && + CurCodeDecl->getAttr<ReturnsNonNullAttr>()); +} + static bool matchesStlAllocatorFn(const Decl *D, const ASTContext &Ctx) { auto *MD = dyn_cast_or_null<CXXMethodDecl>(D); if (!MD || !MD->getDeclName().getAsIdentifierInfo() || @@ -635,8 +697,7 @@ static llvm::Constant *getPrologueSignature(CodeGenModule &CGM, return CGM.getTargetCodeGenInfo().getUBSanFunctionSignature(CGM); } -void CodeGenFunction::StartFunction(GlobalDecl GD, - QualType RetTy, +void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, llvm::Function *Fn, const CGFunctionInfo &FnInfo, const FunctionArgList &Args, @@ -738,8 +799,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, FD->getBody()->getStmtClass() == Stmt::CoroutineBodyStmtClass) SanOpts.Mask &= ~SanitizerKind::Null; - // Apply xray attributes to the function (as a string, for now) if (D) { + // Apply xray attributes to the function (as a string, for now) if (const auto *XRayAttr = D->getAttr<XRayInstrumentAttr>()) { if (CGM.getCodeGenOpts().XRayInstrumentationBundle.has( XRayInstrKind::Function)) { @@ -758,12 +819,25 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, "xray-instruction-threshold", llvm::itostr(CGM.getCodeGenOpts().XRayInstructionThreshold)); } + + if (const auto *Attr = D->getAttr<PatchableFunctionEntryAttr>()) { + // Attr->getStart is currently ignored. + Fn->addFnAttr("patchable-function-entry", + std::to_string(Attr->getCount())); + } else if (unsigned Count = CGM.getCodeGenOpts().PatchableFunctionEntryCount) { + Fn->addFnAttr("patchable-function-entry", + std::to_string(Count)); + } } // Add no-jump-tables value. Fn->addFnAttr("no-jump-tables", llvm::toStringRef(CGM.getCodeGenOpts().NoUseJumpTables)); + // Add no-inline-line-tables value. + if (CGM.getCodeGenOpts().NoInlineLineTables) + Fn->addFnAttr("no-inline-line-tables"); + // Add profile-sample-accurate value. if (CGM.getCodeGenOpts().ProfileSampleAccurate) Fn->addFnAttr("profile-sample-accurate"); @@ -820,6 +894,10 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, if (FD->isMain()) Fn->addFnAttr(llvm::Attribute::NoRecurse); + if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) + if (FD->usesFPIntrin()) + Fn->addFnAttr(llvm::Attribute::StrictFP); + // If a custom alignment is used, force realigning to this alignment on // any main function which certainly will need it. if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D)) @@ -889,9 +967,30 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, Fn->addFnAttr("instrument-function-entry-inlined", getTarget().getMCountName()); } + if (CGM.getCodeGenOpts().MNopMCount) { + if (!CGM.getCodeGenOpts().CallFEntry) + CGM.getDiags().Report(diag::err_opt_not_valid_without_opt) + << "-mnop-mcount" << "-mfentry"; + Fn->addFnAttr("mnop-mcount"); + } + + if (CGM.getCodeGenOpts().RecordMCount) { + if (!CGM.getCodeGenOpts().CallFEntry) + CGM.getDiags().Report(diag::err_opt_not_valid_without_opt) + << "-mrecord-mcount" << "-mfentry"; + Fn->addFnAttr("mrecord-mcount"); + } } } + if (CGM.getCodeGenOpts().PackedStack) { + if (getContext().getTargetInfo().getTriple().getArch() != + llvm::Triple::systemz) + CGM.getDiags().Report(diag::err_opt_not_valid_on_target) + << "-mpacked-stack"; + Fn->addFnAttr("packed-stack"); + } + if (RetTy->isVoidType()) { // Void type; nothing to return. ReturnValue = Address::invalid(); @@ -963,7 +1062,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, LValue ThisFieldLValue = EmitLValueForLambdaField(LambdaThisCaptureField); if (!LambdaThisCaptureField->getType()->isPointerType()) { // If the enclosing object was captured by value, just use its address. - CXXThisValue = ThisFieldLValue.getAddress().getPointer(); + CXXThisValue = ThisFieldLValue.getAddress(*this).getPointer(); } else { // Load the lvalue pointed to by the field, since '*this' was captured // by reference. @@ -2000,18 +2099,18 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { Address CodeGenFunction::EmitVAListRef(const Expr* E) { if (getContext().getBuiltinVaListType()->isArrayType()) return EmitPointerWithAlignment(E); - return EmitLValue(E).getAddress(); + return EmitLValue(E).getAddress(*this); } Address CodeGenFunction::EmitMSVAListRef(const Expr *E) { - return EmitLValue(E).getAddress(); + return EmitLValue(E).getAddress(*this); } void CodeGenFunction::EmitDeclRefExprDbgValue(const DeclRefExpr *E, const APValue &Init) { assert(Init.hasValue() && "Invalid DeclRefExpr initializer!"); if (CGDebugInfo *Dbg = getDebugInfo()) - if (CGM.getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) + if (CGM.getCodeGenOpts().hasReducedDebugInfo()) Dbg->EmitGlobalVariable(E->getDecl(), Init); } @@ -2153,7 +2252,7 @@ static bool hasRequiredFeatures(const SmallVectorImpl<StringRef> &ReqFeatures, // Now build up the set of caller features and verify that all the required // features are there. llvm::StringMap<bool> CallerFeatureMap; - CGM.getFunctionFeatureMap(CallerFeatureMap, GlobalDecl().getWithDecl(FD)); + CGM.getContext().getFunctionFeatureMap(CallerFeatureMap, FD); // If we have at least one of the features in the feature list return // true, otherwise return false. @@ -2210,16 +2309,18 @@ void CodeGenFunction::checkTargetFeatures(SourceLocation Loc, << TargetDecl->getDeclName() << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID); - } else if (TargetDecl->hasAttr<TargetAttr>() || - TargetDecl->hasAttr<CPUSpecificAttr>()) { + } else if (!TargetDecl->isMultiVersion() && + TargetDecl->hasAttr<TargetAttr>()) { // Get the required features for the callee. const TargetAttr *TD = TargetDecl->getAttr<TargetAttr>(); - TargetAttr::ParsedTargetAttr ParsedAttr = CGM.filterFunctionTargetAttrs(TD); + ParsedTargetAttr ParsedAttr = + CGM.getContext().filterFunctionTargetAttrs(TD); SmallVector<StringRef, 1> ReqFeatures; llvm::StringMap<bool> CalleeFeatureMap; - CGM.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl); + CGM.getContext().getFunctionFeatureMap(CalleeFeatureMap, + GlobalDecl(TargetDecl)); for (const auto &F : ParsedAttr.Features) { if (F[0] == '+' && CalleeFeatureMap.lookup(F.substr(1))) @@ -2286,10 +2387,7 @@ static void CreateMultiVersionResolverReturn(CodeGenModule &CGM, void CodeGenFunction::EmitMultiVersionResolver( llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) { - assert((getContext().getTargetInfo().getTriple().getArch() == - llvm::Triple::x86 || - getContext().getTargetInfo().getTriple().getArch() == - llvm::Triple::x86_64) && + assert(getContext().getTargetInfo().getTriple().isX86() && "Only implemented for x86 targets"); bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc(); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 99bc85ba3773..3d8bc93eb965 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -75,6 +75,7 @@ class ObjCAtTryStmt; class ObjCAtThrowStmt; class ObjCAtSynchronizedStmt; class ObjCAutoreleasePoolStmt; +class ReturnsNonNullAttr; namespace analyze_os_log { class OSLogBufferLayout; @@ -947,6 +948,19 @@ public: } }; + /// Save/restore original map of previously emitted local vars in case when we + /// need to duplicate emission of the same code several times in the same + /// function for OpenMP code. + class OMPLocalDeclMapRAII { + CodeGenFunction &CGF; + DeclMapTy SavedMap; + + public: + OMPLocalDeclMapRAII(CodeGenFunction &CGF) + : CGF(CGF), SavedMap(CGF.LocalDeclMap) {} + ~OMPLocalDeclMapRAII() { SavedMap.swap(CGF.LocalDeclMap); } + }; + /// Takes the old cleanup stack size and emits the cleanup blocks /// that have been added. void @@ -1262,7 +1276,7 @@ private: CancelExit(OpenMPDirectiveKind Kind, JumpDest ExitBlock, JumpDest ContBlock) : Kind(Kind), ExitBlock(ExitBlock), ContBlock(ContBlock) {} - OpenMPDirectiveKind Kind = OMPD_unknown; + OpenMPDirectiveKind Kind = llvm::omp::OMPD_unknown; /// true if the exit block has been emitted already by the special /// emitExit() call, false if the default codegen is used. bool HasBeenEmitted = false; @@ -1584,11 +1598,7 @@ private: Address ReturnLocation = Address::invalid(); /// Check if the return value of this function requires sanitization. - bool requiresReturnValueCheck() const { - return requiresReturnValueNullabilityCheck() || - (SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) && - CurCodeDecl && CurCodeDecl->getAttr<ReturnsNonNullAttr>()); - } + bool requiresReturnValueCheck() const; llvm::BasicBlock *TerminateLandingPad = nullptr; llvm::BasicBlock *TerminateHandler = nullptr; @@ -3132,6 +3142,7 @@ public: void EmitOMPParallelForDirective(const OMPParallelForDirective &S); void EmitOMPParallelForSimdDirective(const OMPParallelForSimdDirective &S); void EmitOMPParallelSectionsDirective(const OMPParallelSectionsDirective &S); + void EmitOMPParallelMasterDirective(const OMPParallelMasterDirective &S); void EmitOMPTaskDirective(const OMPTaskDirective &S); void EmitOMPTaskyieldDirective(const OMPTaskyieldDirective &S); void EmitOMPBarrierDirective(const OMPBarrierDirective &S); @@ -3160,6 +3171,8 @@ public: EmitOMPMasterTaskLoopSimdDirective(const OMPMasterTaskLoopSimdDirective &S); void EmitOMPParallelMasterTaskLoopDirective( const OMPParallelMasterTaskLoopDirective &S); + void EmitOMPParallelMasterTaskLoopSimdDirective( + const OMPParallelMasterTaskLoopSimdDirective &S); void EmitOMPDistributeDirective(const OMPDistributeDirective &S); void EmitOMPDistributeParallelForDirective( const OMPDistributeParallelForDirective &S); @@ -3718,6 +3731,11 @@ public: /// Emit IR for __builtin_os_log_format. RValue emitBuiltinOSLogFormat(const CallExpr &E); + /// Emit IR for __builtin_is_aligned. + RValue EmitBuiltinIsAligned(const CallExpr *E); + /// Emit IR for __builtin_align_up/__builtin_align_down. + RValue EmitBuiltinAlignTo(const CallExpr *E, bool AlignUp); + llvm::Function *generateBuiltinOSLogHelperFunction( const analyze_os_log::OSLogBufferLayout &Layout, CharUnits BufferAlignment); @@ -3726,14 +3744,19 @@ public: /// EmitTargetBuiltinExpr - Emit the given builtin call. Returns 0 if the call /// is unhandled by the current target. - llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E); + llvm::Value *EmitTargetBuiltinExpr(unsigned BuiltinID, const CallExpr *E, + ReturnValueSlot ReturnValue); llvm::Value *EmitAArch64CompareBuiltinExpr(llvm::Value *Op, llvm::Type *Ty, const llvm::CmpInst::Predicate Fp, const llvm::CmpInst::Predicate Ip, const llvm::Twine &Name = ""); llvm::Value *EmitARMBuiltinExpr(unsigned BuiltinID, const CallExpr *E, + ReturnValueSlot ReturnValue, llvm::Triple::ArchType Arch); + llvm::Value *EmitARMMVEBuiltinExpr(unsigned BuiltinID, const CallExpr *E, + ReturnValueSlot ReturnValue, + llvm::Triple::ArchType Arch); llvm::Value *EmitCommonNeonBuiltinExpr(unsigned BuiltinID, unsigned LLVMIntrinsic, @@ -4149,6 +4172,9 @@ public: /// point operation, expressed as the maximum relative error in ulp. void SetFPAccuracy(llvm::Value *Val, float Accuracy); + /// SetFPModel - Control floating point behavior via fp-model settings. + void SetFPModel(); + private: llvm::MDNode *getRangeForLoadFromType(QualType Ty); void EmitReturnOfRValue(RValue RV, QualType Ty); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index b05a58848e82..57beda26677c 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -47,6 +47,7 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Frontend/OpenMP/OMPIRBuilder.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Intrinsics.h" @@ -55,6 +56,7 @@ #include "llvm/IR/ProfileSummary.h" #include "llvm/ProfileData/InstrProfReader.h" #include "llvm/Support/CodeGen.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" @@ -72,6 +74,7 @@ static const char AnnotationSection[] = "llvm.metadata"; static CGCXXABI *createCXXABI(CodeGenModule &CGM) { switch (CGM.getTarget().getCXXABI().getKind()) { + case TargetCXXABI::Fuchsia: case TargetCXXABI::GenericAArch64: case TargetCXXABI::GenericARM: case TargetCXXABI::iOS: @@ -216,6 +219,14 @@ void CodeGenModule::createOpenMPRuntime() { OpenMPRuntime.reset(new CGOpenMPRuntime(*this)); break; } + + // The OpenMP-IR-Builder should eventually replace the above runtime codegens + // but we are not there yet so they both reside in CGModule for now and the + // OpenMP-IR-Builder is opt-in only. + if (LangOpts.OpenMPIRBuilder) { + OMPBuilder.reset(new llvm::OpenMPIRBuilder(TheModule)); + OMPBuilder->initialize(); + } } void CodeGenModule::createCUDARuntime() { @@ -469,9 +480,7 @@ void CodeGenModule::Release() { CodeGenOpts.NumRegisterParameters); if (CodeGenOpts.DwarfVersion) { - // We actually want the latest version when there are conflicts. - // We can change from Warning to Latest if such mode is supported. - getModule().addModuleFlag(llvm::Module::Warning, "Dwarf Version", + getModule().addModuleFlag(llvm::Module::Max, "Dwarf Version", CodeGenOpts.DwarfVersion); } if (CodeGenOpts.EmitCodeView) { @@ -482,8 +491,11 @@ void CodeGenModule::Release() { getModule().addModuleFlag(llvm::Module::Warning, "CodeViewGHash", 1); } if (CodeGenOpts.ControlFlowGuard) { - // We want function ID tables for Control Flow Guard. - getModule().addModuleFlag(llvm::Module::Warning, "cfguardtable", 1); + // Function ID tables and checks for Control Flow Guard (cfguard=2). + getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 2); + } else if (CodeGenOpts.ControlFlowGuardNoChecks) { + // Function ID tables for Control Flow Guard (cfguard=1). + getModule().addModuleFlag(llvm::Module::Warning, "cfguard", 1); } if (CodeGenOpts.OptimizationLevel > 0 && CodeGenOpts.StrictVTablePointers) { // We don't support LTO with 2 with different StrictVTablePointers @@ -813,7 +825,7 @@ static bool shouldAssumeDSOLocal(const CodeGenModule &CGM, const auto &CGOpts = CGM.getCodeGenOpts(); llvm::Reloc::Model RM = CGOpts.RelocationModel; const auto &LOpts = CGM.getLangOpts(); - if (RM != llvm::Reloc::Static && !LOpts.PIE && !LOpts.OpenMPIsDevice) + if (RM != llvm::Reloc::Static && !LOpts.PIE) return false; // A definition cannot be preempted from an executable. @@ -954,7 +966,7 @@ static void AppendTargetMangling(const CodeGenModule &CGM, Out << '.'; const TargetInfo &Target = CGM.getTarget(); - TargetAttr::ParsedTargetAttr Info = + ParsedTargetAttr Info = Attr->parse([&Target](StringRef LHS, StringRef RHS) { // Multiversioning doesn't allow "no-${feature}", so we can // only have "+" prefixes here. @@ -1511,16 +1523,15 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, !CodeGenOpts.DisableO0ImplyOptNone && CodeGenOpts.OptimizationLevel == 0; // We can't add optnone in the following cases, it won't pass the verifier. ShouldAddOptNone &= !D->hasAttr<MinSizeAttr>(); - ShouldAddOptNone &= !F->hasFnAttribute(llvm::Attribute::AlwaysInline); ShouldAddOptNone &= !D->hasAttr<AlwaysInlineAttr>(); - if (ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) { + // Add optnone, but do so only if the function isn't always_inline. + if ((ShouldAddOptNone || D->hasAttr<OptimizeNoneAttr>()) && + !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) { B.addAttribute(llvm::Attribute::OptimizeNone); // OptimizeNone implies noinline; we should not be inlining such functions. B.addAttribute(llvm::Attribute::NoInline); - assert(!F->hasFnAttribute(llvm::Attribute::AlwaysInline) && - "OptimizeNone and AlwaysInline on same function!"); // We still need to handle naked functions even though optnone subsumes // much of their semantics. @@ -1536,7 +1547,8 @@ void CodeGenModule::SetLLVMFunctionAttributesForDefinition(const Decl *D, B.addAttribute(llvm::Attribute::NoInline); } else if (D->hasAttr<NoDuplicateAttr>()) { B.addAttribute(llvm::Attribute::NoDuplicate); - } else if (D->hasAttr<NoInlineAttr>()) { + } else if (D->hasAttr<NoInlineAttr>() && !F->hasFnAttribute(llvm::Attribute::AlwaysInline)) { + // Add noinline if the function isn't always_inline. B.addAttribute(llvm::Attribute::NoInline); } else if (D->hasAttr<AlwaysInlineAttr>() && !F->hasFnAttribute(llvm::Attribute::NoInline)) { @@ -1664,7 +1676,7 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD, bool AddedAttr = false; if (TD || SD) { llvm::StringMap<bool> FeatureMap; - getFunctionFeatureMap(FeatureMap, GD); + getContext().getFunctionFeatureMap(FeatureMap, GD); // Produce the canonical string for this set of features. for (const llvm::StringMap<bool>::value_type &Entry : FeatureMap) @@ -1675,7 +1687,7 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD, // get and parse the target attribute so we can get the cpu for // the function. if (TD) { - TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse(); + ParsedTargetAttr ParsedAttr = TD->parse(); if (ParsedAttr.Architecture != "" && getTarget().isValidCPUName(ParsedAttr.Architecture)) TargetCPU = ParsedAttr.Architecture; @@ -1828,6 +1840,11 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, else if (const auto *SA = FD->getAttr<SectionAttr>()) F->setSection(SA->getName()); + if (FD->isInlineBuiltinDeclaration()) { + F->addAttribute(llvm::AttributeList::FunctionIndex, + llvm::Attribute::NoBuiltin); + } + if (FD->isReplaceableGlobalAllocationFunction()) { // A replaceable global allocation function does not act like a builtin by // default, only if it is invoked by a new-expression or delete-expression. @@ -1930,6 +1947,8 @@ void CodeGenModule::AppendLinkerOptions(StringRef Opts) { void CodeGenModule::AddDetectMismatch(StringRef Name, StringRef Value) { llvm::SmallString<32> Opt; getTargetCodeGenInfo().getDetectMismatchOption(Name, Value, Opt); + if (Opt.empty()) + return; auto *MDOpts = llvm::MDString::get(getLLVMContext(), Opt); LinkerOptionsMetadata.push_back(llvm::MDNode::get(getLLVMContext(), MDOpts)); } @@ -2207,9 +2226,15 @@ llvm::Constant *CodeGenModule::EmitAnnotateAttr(llvm::GlobalValue *GV, *UnitGV = EmitAnnotationUnit(L), *LineNoCst = EmitAnnotationLineNo(L); + llvm::Constant *ASZeroGV = GV; + if (GV->getAddressSpace() != 0) { + ASZeroGV = llvm::ConstantExpr::getAddrSpaceCast( + GV, GV->getValueType()->getPointerTo(0)); + } + // Create the ConstantStruct for the global annotation. llvm::Constant *Fields[4] = { - llvm::ConstantExpr::getBitCast(GV, Int8PtrTy), + llvm::ConstantExpr::getBitCast(ASZeroGV, Int8PtrTy), llvm::ConstantExpr::getBitCast(AnnoGV, Int8PtrTy), llvm::ConstantExpr::getBitCast(UnitGV, Int8PtrTy), LineNoCst @@ -3332,8 +3357,14 @@ GetRuntimeFunctionDecl(ASTContext &C, StringRef Name) { /// type and name. llvm::FunctionCallee CodeGenModule::CreateRuntimeFunction(llvm::FunctionType *FTy, StringRef Name, - llvm::AttributeList ExtraAttrs, - bool Local) { + llvm::AttributeList ExtraAttrs, bool Local, + bool AssumeConvergent) { + if (AssumeConvergent) { + ExtraAttrs = + ExtraAttrs.addAttribute(VMContext, llvm::AttributeList::FunctionIndex, + llvm::Attribute::Convergent); + } + llvm::Constant *C = GetOrCreateLLVMFunction(Name, FTy, GlobalDecl(), /*ForVTable=*/false, /*DontDefer=*/false, /*IsThunk=*/false, @@ -3564,6 +3595,9 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, } } + if (GV->isDeclaration()) + getTargetCodeGenInfo().setTargetAttributes(D, GV, *this); + LangAS ExpectedAS = D ? D->getType().getAddressSpace() : (LangOpts.OpenCL ? LangAS::opencl_global : LangAS::Default); @@ -3573,9 +3607,6 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName, return getTargetCodeGenInfo().performAddrSpaceCast(*this, GV, AddrSpace, ExpectedAS, Ty); - if (GV->isDeclaration()) - getTargetCodeGenInfo().setTargetAttributes(D, GV, *this); - return GV; } @@ -3704,6 +3735,10 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) { EmitGlobalVarDefinition(D); } +void CodeGenModule::EmitExternalDeclaration(const VarDecl *D) { + EmitExternalVarDeclaration(D); +} + CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const { return Context.toCharUnitsFromBits( getDataLayout().getTypeStoreSizeInBits(Ty)); @@ -4083,10 +4118,23 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) - if (getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) + if (getCodeGenOpts().hasReducedDebugInfo()) DI->EmitGlobalVariable(GV, D); } +void CodeGenModule::EmitExternalVarDeclaration(const VarDecl *D) { + if (CGDebugInfo *DI = getModuleDebugInfo()) + if (getCodeGenOpts().hasReducedDebugInfo()) { + QualType ASTTy = D->getType(); + llvm::Type *Ty = getTypes().ConvertTypeForMem(D->getType()); + llvm::PointerType *PTy = + llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy)); + llvm::Constant *GV = GetOrCreateLLVMGlobal(D->getName(), PTy, D); + DI->EmitExternalVariable( + cast<llvm::GlobalVariable>(GV->stripPointerCasts()), D); + } +} + static bool isVarDeclStrongDefinition(const ASTContext &Context, CodeGenModule &CGM, const VarDecl *D, bool NoCommon) { @@ -4999,7 +5047,7 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary( // If we're not materializing a subobject of the temporary, keep the // cv-qualifiers from the type of the MaterializeTemporaryExpr. QualType MaterializedType = Init->getType(); - if (Init == E->GetTemporaryExpr()) + if (Init == E->getSubExpr()) MaterializedType = E->getType(); CharUnits Align = getContext().getTypeAlignInChars(MaterializedType); @@ -5022,7 +5070,7 @@ ConstantAddress CodeGenModule::GetAddrOfGlobalTemporary( // temporary. Note that this might have a different value from the value // computed by evaluating the initializer if the surrounding constant // expression modifies the temporary. - Value = getContext().getMaterializedTemporaryValue(E, false); + Value = E->getOrCreateValue(false); } // Try evaluating it now, it might have a constant initializer. @@ -5102,11 +5150,12 @@ void CodeGenModule::EmitObjCPropertyImplementations(const // we want, that just indicates if the decl came from a // property. What we want to know is if the method is defined in // this implementation. - if (!D->getInstanceMethod(PD->getGetterName())) + auto *Getter = PID->getGetterMethodDecl(); + if (!Getter || Getter->isSynthesizedAccessorStub()) CodeGenFunction(*this).GenerateObjCGetter( - const_cast<ObjCImplementationDecl *>(D), PID); - if (!PD->isReadOnly() && - !D->getInstanceMethod(PD->getSetterName())) + const_cast<ObjCImplementationDecl *>(D), PID); + auto *Setter = PID->getSetterMethodDecl(); + if (!PD->isReadOnly() && (!Setter || Setter->isSynthesizedAccessorStub())) CodeGenFunction(*this).GenerateObjCSetter( const_cast<ObjCImplementationDecl *>(D), PID); } @@ -5143,12 +5192,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { if (needsDestructMethod(D)) { IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); - ObjCMethodDecl *DTORMethod = - ObjCMethodDecl::Create(getContext(), D->getLocation(), D->getLocation(), - cxxSelector, getContext().VoidTy, nullptr, D, - /*isInstance=*/true, /*isVariadic=*/false, - /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, - /*isDefined=*/false, ObjCMethodDecl::Required); + ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create( + getContext(), D->getLocation(), D->getLocation(), cxxSelector, + getContext().VoidTy, nullptr, D, + /*isInstance=*/true, /*isVariadic=*/false, + /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(DTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, DTORMethod, false); D->setHasDestructors(true); @@ -5163,17 +5213,13 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { IdentifierInfo *II = &getContext().Idents.get(".cxx_construct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); // The constructor returns 'self'. - ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create(getContext(), - D->getLocation(), - D->getLocation(), - cxxSelector, - getContext().getObjCIdType(), - nullptr, D, /*isInstance=*/true, - /*isVariadic=*/false, - /*isPropertyAccessor=*/true, - /*isImplicitlyDeclared=*/true, - /*isDefined=*/false, - ObjCMethodDecl::Required); + ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create( + getContext(), D->getLocation(), D->getLocation(), cxxSelector, + getContext().getObjCIdType(), nullptr, D, /*isInstance=*/true, + /*isVariadic=*/false, + /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, ObjCMethodDecl::Required); D->addInstanceMethod(CTORMethod); CodeGenFunction(*this).GenerateObjCCtorDtorMethod(D, CTORMethod, true); D->setHasNonZeroConstructors(true); @@ -5182,9 +5228,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { // EmitLinkageSpec - Emit all declarations in a linkage spec. void CodeGenModule::EmitLinkageSpec(const LinkageSpecDecl *LSD) { if (LSD->getLanguage() != LinkageSpecDecl::lang_c && - LSD->getLanguage() != LinkageSpecDecl::lang_cxx && - LSD->getLanguage() != LinkageSpecDecl::lang_cxx_11 && - LSD->getLanguage() != LinkageSpecDecl::lang_cxx_14) { + LSD->getLanguage() != LinkageSpecDecl::lang_cxx) { ErrorUnsupported(LSD, "linkage spec"); return; } @@ -5327,7 +5371,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { ObjCRuntime->GenerateClass(OMD); // Emit global variable debug information. if (CGDebugInfo *DI = getModuleDebugInfo()) - if (getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) + if (getCodeGenOpts().hasReducedDebugInfo()) DI->getOrCreateInterfaceType(getContext().getObjCInterfaceType( OMD->getClassInterface()), OMD->getLocation()); break; @@ -5851,58 +5895,6 @@ void CodeGenModule::AddVTableTypeMetadata(llvm::GlobalVariable *VTable, } } -TargetAttr::ParsedTargetAttr CodeGenModule::filterFunctionTargetAttrs(const TargetAttr *TD) { - assert(TD != nullptr); - TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse(); - - ParsedAttr.Features.erase( - llvm::remove_if(ParsedAttr.Features, - [&](const std::string &Feat) { - return !Target.isValidFeatureName( - StringRef{Feat}.substr(1)); - }), - ParsedAttr.Features.end()); - return ParsedAttr; -} - - -// Fills in the supplied string map with the set of target features for the -// passed in function. -void CodeGenModule::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, - GlobalDecl GD) { - StringRef TargetCPU = Target.getTargetOpts().CPU; - const FunctionDecl *FD = GD.getDecl()->getAsFunction(); - if (const auto *TD = FD->getAttr<TargetAttr>()) { - TargetAttr::ParsedTargetAttr ParsedAttr = filterFunctionTargetAttrs(TD); - - // Make a copy of the features as passed on the command line into the - // beginning of the additional features from the function to override. - ParsedAttr.Features.insert(ParsedAttr.Features.begin(), - Target.getTargetOpts().FeaturesAsWritten.begin(), - Target.getTargetOpts().FeaturesAsWritten.end()); - - if (ParsedAttr.Architecture != "" && - Target.isValidCPUName(ParsedAttr.Architecture)) - TargetCPU = ParsedAttr.Architecture; - - // Now populate the feature map, first with the TargetCPU which is either - // the default or a new one from the target attribute string. Then we'll use - // the passed in features (FeaturesAsWritten) along with the new ones from - // the attribute. - Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, - ParsedAttr.Features); - } else if (const auto *SD = FD->getAttr<CPUSpecificAttr>()) { - llvm::SmallVector<StringRef, 32> FeaturesTmp; - Target.getCPUSpecificCPUDispatchFeatures( - SD->getCPUName(GD.getMultiVersionIndex())->getName(), FeaturesTmp); - std::vector<std::string> Features(FeaturesTmp.begin(), FeaturesTmp.end()); - Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, Features); - } else { - Target.initFeatureMap(FeatureMap, getDiags(), TargetCPU, - Target.getTargetOpts().Features); - } -} - llvm::SanitizerStatReport &CodeGenModule::getSanStats() { if (!SanStats) SanStats = std::make_unique<llvm::SanitizerStatReport>(&getModule()); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 73f81adae35f..115e754bb392 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -17,7 +17,6 @@ #include "CodeGenTypeCache.h" #include "CodeGenTypes.h" #include "SanitizerMetadata.h" -#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclOpenMP.h" @@ -45,6 +44,7 @@ class GlobalValue; class DataLayout; class FunctionType; class LLVMContext; +class OpenMPIRBuilder; class IndexedInstrProfReader; } @@ -77,6 +77,9 @@ class AnnotateAttr; class CXXDestructorDecl; class Module; class CoverageSourceInfo; +class TargetAttr; +class InitSegAttr; +struct ParsedTargetAttr; namespace CodeGen { @@ -319,6 +322,7 @@ private: std::unique_ptr<CGObjCRuntime> ObjCRuntime; std::unique_ptr<CGOpenCLRuntime> OpenCLRuntime; std::unique_ptr<CGOpenMPRuntime> OpenMPRuntime; + std::unique_ptr<llvm::OpenMPIRBuilder> OMPBuilder; std::unique_ptr<CGCUDARuntime> CUDARuntime; std::unique_ptr<CGDebugInfo> DebugInfo; std::unique_ptr<ObjCEntrypoints> ObjCData; @@ -523,18 +527,18 @@ private: int GlobalUniqueCount; } Block; + GlobalDecl initializedGlobalDecl; + + /// @} + /// void @llvm.lifetime.start(i64 %size, i8* nocapture <ptr>) llvm::Function *LifetimeStartFn = nullptr; /// void @llvm.lifetime.end(i64 %size, i8* nocapture <ptr>) llvm::Function *LifetimeEndFn = nullptr; - GlobalDecl initializedGlobalDecl; - std::unique_ptr<SanitizerMetadata> SanitizerMD; - /// @} - llvm::MapVector<const Decl *, bool> DeferredEmptyCoverageMappingDecls; std::unique_ptr<CoverageMappingModuleGen> CoverageMapping; @@ -585,6 +589,9 @@ public: return *OpenMPRuntime; } + /// Return a pointer to the configured OpenMPIRBuilder, if any. + llvm::OpenMPIRBuilder *getOpenMPIRBuilder() { return OMPBuilder.get(); } + /// Return a reference to the configured CUDA runtime. CGCUDARuntime &getCUDARuntime() { assert(CUDARuntime != nullptr); @@ -1027,11 +1034,22 @@ public: } /// Create or return a runtime function declaration with the specified type - /// and name. + /// and name. If \p AssumeConvergent is true, the call will have the + /// convergent attribute added. llvm::FunctionCallee CreateRuntimeFunction(llvm::FunctionType *Ty, StringRef Name, llvm::AttributeList ExtraAttrs = llvm::AttributeList(), - bool Local = false); + bool Local = false, bool AssumeConvergent = false); + + /// Create or return a runtime function declaration with the specified type + /// and name. This will automatically add the convergent attribute to the + /// function declaration. + llvm::FunctionCallee CreateConvergentRuntimeFunction( + llvm::FunctionType *Ty, StringRef Name, + llvm::AttributeList ExtraAttrs = llvm::AttributeList(), + bool Local = false) { + return CreateRuntimeFunction(Ty, Name, ExtraAttrs, Local, true); + } /// Create a new runtime global variable with the specified type and name. llvm::Constant *CreateRuntimeVariable(llvm::Type *Ty, @@ -1139,19 +1157,13 @@ public: /// It's up to you to ensure that this is safe. void AddDefaultFnAttrs(llvm::Function &F); - /// Parses the target attributes passed in, and returns only the ones that are - /// valid feature names. - TargetAttr::ParsedTargetAttr filterFunctionTargetAttrs(const TargetAttr *TD); - - // Fills in the supplied string map with the set of target features for the - // passed in function. - void getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap, GlobalDecl GD); - StringRef getMangledName(GlobalDecl GD); StringRef getBlockMangledName(GlobalDecl GD, const BlockDecl *BD); void EmitTentativeDefinition(const VarDecl *D); + void EmitExternalDeclaration(const VarDecl *D); + void EmitVTable(CXXRecordDecl *Class); void RefreshTypeCacheForClass(const CXXRecordDecl *Class); @@ -1387,6 +1399,7 @@ private: void EmitMultiVersionFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV); void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false); + void EmitExternalVarDeclaration(const VarDecl *D); void EmitAliasDefinition(GlobalDecl GD); void emitIFuncDefinition(GlobalDecl GD); void emitCPUDispatchDefinition(GlobalDecl GD); diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp index e525abe979e3..bad796bf92dc 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -17,6 +17,7 @@ #include "clang/AST/StmtVisitor.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Endian.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MD5.h" @@ -166,7 +167,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> { bool TraverseBlockExpr(BlockExpr *BE) { return true; } bool TraverseLambdaExpr(LambdaExpr *LE) { // Traverse the captures, but not the body. - for (const auto &C : zip(LE->captures(), LE->capture_inits())) + for (auto C : zip(LE->captures(), LE->capture_inits())) TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C)); return true; } diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index 09de9591de7e..7d730cb1ed15 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -78,17 +78,18 @@ llvm::MDNode *CodeGenTBAA::getChar() { static bool TypeHasMayAlias(QualType QTy) { // Tagged types have declarations, and therefore may have attributes. - if (const TagType *TTy = dyn_cast<TagType>(QTy)) - return TTy->getDecl()->hasAttr<MayAliasAttr>(); + if (auto *TD = QTy->getAsTagDecl()) + if (TD->hasAttr<MayAliasAttr>()) + return true; - // Typedef types have declarations, and therefore may have attributes. - if (const TypedefType *TTy = dyn_cast<TypedefType>(QTy)) { - if (TTy->getDecl()->hasAttr<MayAliasAttr>()) + // Also look for may_alias as a declaration attribute on a typedef. + // FIXME: We should follow GCC and model may_alias as a type attribute + // rather than as a declaration attribute. + while (auto *TT = QTy->getAs<TypedefType>()) { + if (TT->getDecl()->hasAttr<MayAliasAttr>()) return true; - // Also, their underlying types may have relevant attributes. - return TypeHasMayAlias(TTy->desugar()); + QTy = TT->desugar(); } - return false; } diff --git a/clang/lib/CodeGen/ConstantEmitter.h b/clang/lib/CodeGen/ConstantEmitter.h index 59a19730f4eb..121acbac4fa9 100644 --- a/clang/lib/CodeGen/ConstantEmitter.h +++ b/clang/lib/CodeGen/ConstantEmitter.h @@ -23,7 +23,7 @@ namespace CodeGen { class ConstantEmitter { public: CodeGenModule &CGM; - CodeGenFunction *CGF; + CodeGenFunction *const CGF; private: bool Abstract = false; diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index a6f6e38d5f14..bdecff39c88f 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1114,8 +1114,8 @@ struct CounterCoverageMappingBuilder // Make a region for the body of the switch. If the body starts with // a case, that case will reuse this region; otherwise, this covers // the unreachable code at the beginning of the switch body. - size_t Index = - pushRegion(Counter::getZero(), getStart(CS->body_front())); + size_t Index = pushRegion(Counter::getZero(), getStart(CS)); + getRegion().setGap(true); for (const auto *Child : CS->children()) Visit(Child); @@ -1278,6 +1278,13 @@ std::string getCoverageSection(const CodeGenModule &CGM) { CGM.getContext().getTargetInfo().getTriple().getObjectFormat()); } +std::string normalizeFilename(StringRef Filename) { + llvm::SmallString<256> Path(Filename); + llvm::sys::fs::make_absolute(Path); + llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); + return Path.str().str(); +} + } // end anonymous namespace static void dump(llvm::raw_ostream &OS, StringRef FunctionName, @@ -1310,24 +1317,6 @@ static void dump(llvm::raw_ostream &OS, StringRef FunctionName, } } -CoverageMappingModuleGen::CoverageMappingModuleGen( - CodeGenModule &CGM, CoverageSourceInfo &SourceInfo) - : CGM(CGM), SourceInfo(SourceInfo), FunctionRecordTy(nullptr) { - // Honor -fdebug-compilation-dir in paths in coverage data. Otherwise, use the - // regular working directory when normalizing paths. - if (!CGM.getCodeGenOpts().DebugCompilationDir.empty()) - CWD = CGM.getCodeGenOpts().DebugCompilationDir; - else - llvm::sys::fs::current_path(CWD); -} - -std::string CoverageMappingModuleGen::normalizeFilename(StringRef Filename) { - llvm::SmallString<256> Path(Filename); - llvm::sys::fs::make_absolute(CWD, Path); - llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true); - return Path.str().str(); -} - void CoverageMappingModuleGen::addFunctionMappingRecord( llvm::GlobalVariable *NamePtr, StringRef NameValue, uint64_t FuncHash, const std::string &CoverageMapping, bool IsUsed) { diff --git a/clang/lib/CodeGen/CoverageMappingGen.h b/clang/lib/CodeGen/CoverageMappingGen.h index 2bdc00e25668..3bf51f590479 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.h +++ b/clang/lib/CodeGen/CoverageMappingGen.h @@ -54,14 +54,10 @@ class CoverageMappingModuleGen { std::vector<llvm::Constant *> FunctionNames; llvm::StructType *FunctionRecordTy; std::vector<std::string> CoverageMappings; - SmallString<256> CWD; - - /// Make the filename absolute, remove dots, and normalize slashes to local - /// path style. - std::string normalizeFilename(StringRef Filename); public: - CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo); + CoverageMappingModuleGen(CodeGenModule &CGM, CoverageSourceInfo &SourceInfo) + : CGM(CGM), SourceInfo(SourceInfo), FunctionRecordTy(nullptr) {} CoverageSourceInfo &getSourceInfo() const { return SourceInfo; diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index 8f9b16470b64..b5b8702c551e 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -24,10 +24,11 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "TargetInfo.h" -#include "clang/CodeGen/ConstantInitBuilder.h" +#include "clang/AST/Attr.h" #include "clang/AST/Mangle.h" -#include "clang/AST/Type.h" #include "clang/AST/StmtCXX.h" +#include "clang/AST/Type.h" +#include "clang/CodeGen/ConstantInitBuilder.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/Instructions.h" @@ -487,6 +488,19 @@ public: bool shouldRTTIBeUnique() const override { return false; } }; +class FuchsiaCXXABI final : public ItaniumCXXABI { +public: + explicit FuchsiaCXXABI(CodeGen::CodeGenModule &CGM) + : ItaniumCXXABI(CGM) {} + +private: + bool HasThisReturn(GlobalDecl GD) const override { + return isa<CXXConstructorDecl>(GD.getDecl()) || + (isa<CXXDestructorDecl>(GD.getDecl()) && + GD.getDtorType() != Dtor_Deleting); + } +}; + class WebAssemblyCXXABI final : public ItaniumCXXABI { public: explicit WebAssemblyCXXABI(CodeGen::CodeGenModule &CGM) @@ -516,6 +530,9 @@ CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) { case TargetCXXABI::iOS64: return new iOS64CXXABI(CGM); + case TargetCXXABI::Fuchsia: + return new FuchsiaCXXABI(CGM); + // Note that AArch64 uses the generic ItaniumCXXABI class since it doesn't // include the other 32-bit ARM oddities: constructor/destructor return values // and array cookies. @@ -2406,7 +2423,7 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF, } void CodeGenModule::registerGlobalDtorsWithAtExit() { - for (const auto I : DtorsUsingAtExit) { + for (const auto &I : DtorsUsingAtExit) { int Priority = I.first; const llvm::TinyPtrVector<llvm::Function *> &Dtors = I.second; @@ -2529,6 +2546,9 @@ ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD, llvm::Function::Create(FnTy, getThreadLocalWrapperLinkage(VD, CGM), WrapperName.str(), &CGM.getModule()); + if (CGM.supportsCOMDAT() && Wrapper->isWeakForLinker()) + Wrapper->setComdat(CGM.getModule().getOrInsertComdat(Wrapper->getName())); + CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, Wrapper); // Always resolve references to the wrapper at link time. @@ -2667,7 +2687,9 @@ void ItaniumCXXABI::EmitThreadLocalInitFuncs( if (Init) { Init->setVisibility(Var->getVisibility()); - Init->setDSOLocal(Var->isDSOLocal()); + // Don't mark an extern_weak function DSO local on windows. + if (!CGM.getTriple().isOSWindows() || !Init->hasExternalWeakLinkage()) + Init->setDSOLocal(Var->isDSOLocal()); } llvm::LLVMContext &Context = CGM.getModule().getContext(); diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 2d8b538bc2ee..aff46135705a 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -19,11 +19,13 @@ #include "CodeGenModule.h" #include "CodeGenTypes.h" #include "TargetInfo.h" -#include "clang/CodeGen/ConstantInitBuilder.h" +#include "clang/AST/Attr.h" +#include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/VTableBuilder.h" +#include "clang/CodeGen/ConstantInitBuilder.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSet.h" #include "llvm/IR/Intrinsics.h" @@ -619,6 +621,9 @@ private: llvm::Function *EmitVirtualMemPtrThunk(const CXXMethodDecl *MD, const MethodVFTableLocation &ML); + llvm::Constant *EmitMemberDataPointer(const CXXRecordDecl *RD, + CharUnits offset); + public: llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT) override; @@ -1339,6 +1344,13 @@ void MicrosoftCXXABI::EmitCXXDestructors(const CXXDestructorDecl *D) { // The TU defining a dtor is only guaranteed to emit a base destructor. All // other destructor variants are delegating thunks. CGM.EmitGlobal(GlobalDecl(D, Dtor_Base)); + + // If the class is dllexported, emit the complete (vbase) destructor wherever + // the base dtor is emitted. + // FIXME: To match MSVC, this should only be done when the class is exported + // with -fdllexport-inlines enabled. + if (D->getParent()->getNumVBases() > 0 && D->hasAttr<DLLExportAttr>()) + CGM.EmitGlobal(GlobalDecl(D, Dtor_Complete)); } CharUnits @@ -2601,27 +2613,27 @@ bool MicrosoftCXXABI::isZeroInitializable(const MemberPointerType *MPT) { // we can't zero initialize. The field offset is sometimes also -1 if 0 is a // valid field offset. const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); - MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); - return (!MSInheritanceAttr::hasVBTableOffsetField(Inheritance) && + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + return (!inheritanceModelHasVBTableOffsetField(Inheritance) && RD->nullFieldOffsetIsZero()); } llvm::Type * MicrosoftCXXABI::ConvertMemberPointerType(const MemberPointerType *MPT) { const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); - MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); llvm::SmallVector<llvm::Type *, 4> fields; if (MPT->isMemberFunctionPointer()) fields.push_back(CGM.VoidPtrTy); // FunctionPointerOrVirtualThunk else fields.push_back(CGM.IntTy); // FieldOffset - if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(), - Inheritance)) + if (inheritanceModelHasNVOffsetField(MPT->isMemberFunctionPointer(), + Inheritance)) fields.push_back(CGM.IntTy); - if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) + if (inheritanceModelHasVBPtrOffsetField(Inheritance)) fields.push_back(CGM.IntTy); - if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) + if (inheritanceModelHasVBTableOffsetField(Inheritance)) fields.push_back(CGM.IntTy); // VirtualBaseAdjustmentOffset if (fields.size() == 1) @@ -2634,7 +2646,7 @@ GetNullMemberPointerFields(const MemberPointerType *MPT, llvm::SmallVectorImpl<llvm::Constant *> &fields) { assert(fields.empty()); const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); - MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); if (MPT->isMemberFunctionPointer()) { // FunctionPointerOrVirtualThunk fields.push_back(llvm::Constant::getNullValue(CGM.VoidPtrTy)); @@ -2645,12 +2657,12 @@ GetNullMemberPointerFields(const MemberPointerType *MPT, fields.push_back(getAllOnesInt()); // FieldOffset } - if (MSInheritanceAttr::hasNVOffsetField(MPT->isMemberFunctionPointer(), - Inheritance)) + if (inheritanceModelHasNVOffsetField(MPT->isMemberFunctionPointer(), + Inheritance)) fields.push_back(getZeroInt()); - if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) + if (inheritanceModelHasVBPtrOffsetField(Inheritance)) fields.push_back(getZeroInt()); - if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) + if (inheritanceModelHasVBTableOffsetField(Inheritance)) fields.push_back(getAllOnesInt()); } @@ -2671,21 +2683,21 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField, const CXXRecordDecl *RD, CharUnits NonVirtualBaseAdjustment, unsigned VBTableIndex) { - MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); // Single inheritance class member pointer are represented as scalars instead // of aggregates. - if (MSInheritanceAttr::hasOnlyOneField(IsMemberFunction, Inheritance)) + if (inheritanceModelHasOnlyOneField(IsMemberFunction, Inheritance)) return FirstField; llvm::SmallVector<llvm::Constant *, 4> fields; fields.push_back(FirstField); - if (MSInheritanceAttr::hasNVOffsetField(IsMemberFunction, Inheritance)) + if (inheritanceModelHasNVOffsetField(IsMemberFunction, Inheritance)) fields.push_back(llvm::ConstantInt::get( CGM.IntTy, NonVirtualBaseAdjustment.getQuantity())); - if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) { + if (inheritanceModelHasVBPtrOffsetField(Inheritance)) { CharUnits Offs = CharUnits::Zero(); if (VBTableIndex) Offs = getContext().getASTRecordLayout(RD).getVBPtrOffset(); @@ -2693,7 +2705,7 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField, } // The rest of the fields are adjusted by conversions to a more derived class. - if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) + if (inheritanceModelHasVBTableOffsetField(Inheritance)) fields.push_back(llvm::ConstantInt::get(CGM.IntTy, VBTableIndex)); return llvm::ConstantStruct::getAnon(fields); @@ -2702,9 +2714,13 @@ MicrosoftCXXABI::EmitFullMemberPointer(llvm::Constant *FirstField, llvm::Constant * MicrosoftCXXABI::EmitMemberDataPointer(const MemberPointerType *MPT, CharUnits offset) { - const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); + return EmitMemberDataPointer(MPT->getMostRecentCXXRecordDecl(), offset); +} + +llvm::Constant *MicrosoftCXXABI::EmitMemberDataPointer(const CXXRecordDecl *RD, + CharUnits offset) { if (RD->getMSInheritanceModel() == - MSInheritanceAttr::Keyword_virtual_inheritance) + MSInheritanceModel::Virtual) offset -= getContext().getOffsetOfBaseWithVBPtr(RD); llvm::Constant *FirstField = llvm::ConstantInt::get(CGM.IntTy, offset.getQuantity()); @@ -2726,8 +2742,17 @@ llvm::Constant *MicrosoftCXXABI::EmitMemberPointer(const APValue &MP, if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(MPD)) { C = EmitMemberFunctionPointer(MD); } else { + // For a pointer to data member, start off with the offset of the field in + // the class in which it was declared, and convert from there if necessary. + // For indirect field decls, get the outermost anonymous field and use the + // parent class. CharUnits FieldOffset = Ctx.toCharUnitsFromBits(Ctx.getFieldOffset(MPD)); - C = EmitMemberDataPointer(DstTy, FieldOffset); + const FieldDecl *FD = dyn_cast<FieldDecl>(MPD); + if (!FD) + FD = cast<FieldDecl>(*cast<IndirectFieldDecl>(MPD)->chain_begin()); + const CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getParent()); + RD = RD->getMostRecentNonInjectedDecl(); + C = EmitMemberDataPointer(RD, FieldOffset); } if (!MemberPointerPath.empty()) { @@ -2801,7 +2826,7 @@ MicrosoftCXXABI::EmitMemberFunctionPointer(const CXXMethodDecl *MD) { if (VBTableIndex == 0 && RD->getMSInheritanceModel() == - MSInheritanceAttr::Keyword_virtual_inheritance) + MSInheritanceModel::Virtual) NonVirtualBaseAdjustment -= getContext().getOffsetOfBaseWithVBPtr(RD); // The rest of the fields are common with data member pointers. @@ -2837,9 +2862,9 @@ MicrosoftCXXABI::EmitMemberPointerComparison(CodeGenFunction &CGF, // If this is a single field member pointer (single inheritance), this is a // single icmp. const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); - MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); - if (MSInheritanceAttr::hasOnlyOneField(MPT->isMemberFunctionPointer(), - Inheritance)) + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); + if (inheritanceModelHasOnlyOneField(MPT->isMemberFunctionPointer(), + Inheritance)) return Builder.CreateICmp(Eq, L, R); // Compare the first field. @@ -3039,7 +3064,7 @@ llvm::Value *MicrosoftCXXABI::EmitMemberDataPointerAddress( CGF.ConvertTypeForMem(MPT->getPointeeType())->getPointerTo(AS); CGBuilderTy &Builder = CGF.Builder; const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl(); - MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); // Extract the fields we need, regardless of model. We'll apply them if we // have them. @@ -3050,9 +3075,9 @@ llvm::Value *MicrosoftCXXABI::EmitMemberDataPointerAddress( // We need to extract values. unsigned I = 0; FieldOffset = Builder.CreateExtractValue(MemPtr, I++); - if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) + if (inheritanceModelHasVBPtrOffsetField(Inheritance)) VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++); - if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) + if (inheritanceModelHasVBTableOffsetField(Inheritance)) VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++); } @@ -3147,8 +3172,8 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion( CGBuilderTy &Builder) { const CXXRecordDecl *SrcRD = SrcTy->getMostRecentCXXRecordDecl(); const CXXRecordDecl *DstRD = DstTy->getMostRecentCXXRecordDecl(); - MSInheritanceAttr::Spelling SrcInheritance = SrcRD->getMSInheritanceModel(); - MSInheritanceAttr::Spelling DstInheritance = DstRD->getMSInheritanceModel(); + MSInheritanceModel SrcInheritance = SrcRD->getMSInheritanceModel(); + MSInheritanceModel DstInheritance = DstRD->getMSInheritanceModel(); bool IsFunc = SrcTy->isMemberFunctionPointer(); bool IsConstant = isa<llvm::Constant>(Src); @@ -3157,15 +3182,15 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion( llvm::Value *NonVirtualBaseAdjustment = getZeroInt(); llvm::Value *VirtualBaseAdjustmentOffset = getZeroInt(); llvm::Value *VBPtrOffset = getZeroInt(); - if (!MSInheritanceAttr::hasOnlyOneField(IsFunc, SrcInheritance)) { + if (!inheritanceModelHasOnlyOneField(IsFunc, SrcInheritance)) { // We need to extract values. unsigned I = 0; FirstField = Builder.CreateExtractValue(Src, I++); - if (MSInheritanceAttr::hasNVOffsetField(IsFunc, SrcInheritance)) + if (inheritanceModelHasNVOffsetField(IsFunc, SrcInheritance)) NonVirtualBaseAdjustment = Builder.CreateExtractValue(Src, I++); - if (MSInheritanceAttr::hasVBPtrOffsetField(SrcInheritance)) + if (inheritanceModelHasVBPtrOffsetField(SrcInheritance)) VBPtrOffset = Builder.CreateExtractValue(Src, I++); - if (MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance)) + if (inheritanceModelHasVBTableOffsetField(SrcInheritance)) VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(Src, I++); } @@ -3184,7 +3209,7 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion( // adjustment to normalize the member pointer. llvm::Value *SrcVBIndexEqZero = Builder.CreateICmpEQ(VirtualBaseAdjustmentOffset, getZeroInt()); - if (SrcInheritance == MSInheritanceAttr::Keyword_virtual_inheritance) { + if (SrcInheritance == MSInheritanceModel::Virtual) { if (int64_t SrcOffsetToFirstVBase = getContext().getOffsetOfBaseWithVBPtr(SrcRD).getQuantity()) { llvm::Value *UndoSrcAdjustment = Builder.CreateSelect( @@ -3218,8 +3243,8 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion( // Update the vbindex to an appropriate value in the destination because // SrcRD's vbtable might not be a strict prefix of the one in DstRD. llvm::Value *DstVBIndexEqZero = SrcVBIndexEqZero; - if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance) && - MSInheritanceAttr::hasVBTableOffsetField(SrcInheritance)) { + if (inheritanceModelHasVBTableOffsetField(DstInheritance) && + inheritanceModelHasVBTableOffsetField(SrcInheritance)) { if (llvm::GlobalVariable *VDispMap = getAddrOfVirtualDisplacementMap(SrcRD, DstRD)) { llvm::Value *VBIndex = Builder.CreateExactUDiv( @@ -3242,7 +3267,7 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion( // Set the VBPtrOffset to zero if the vbindex is zero. Otherwise, initialize // it to the offset of the vbptr. - if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance)) { + if (inheritanceModelHasVBPtrOffsetField(DstInheritance)) { llvm::Value *DstVBPtrOffset = llvm::ConstantInt::get( CGM.IntTy, getContext().getASTRecordLayout(DstRD).getVBPtrOffset().getQuantity()); @@ -3253,7 +3278,7 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion( // Likewise, apply a similar adjustment so that dereferencing the member // pointer correctly accounts for the distance between the start of the first // virtual base and the top of the MDC. - if (DstInheritance == MSInheritanceAttr::Keyword_virtual_inheritance) { + if (DstInheritance == MSInheritanceModel::Virtual) { if (int64_t DstOffsetToFirstVBase = getContext().getOffsetOfBaseWithVBPtr(DstRD).getQuantity()) { llvm::Value *DoDstAdjustment = Builder.CreateSelect( @@ -3266,17 +3291,17 @@ llvm::Value *MicrosoftCXXABI::EmitNonNullMemberPointerConversion( // Recompose dst from the null struct and the adjusted fields from src. llvm::Value *Dst; - if (MSInheritanceAttr::hasOnlyOneField(IsFunc, DstInheritance)) { + if (inheritanceModelHasOnlyOneField(IsFunc, DstInheritance)) { Dst = FirstField; } else { Dst = llvm::UndefValue::get(ConvertMemberPointerType(DstTy)); unsigned Idx = 0; Dst = Builder.CreateInsertValue(Dst, FirstField, Idx++); - if (MSInheritanceAttr::hasNVOffsetField(IsFunc, DstInheritance)) + if (inheritanceModelHasNVOffsetField(IsFunc, DstInheritance)) Dst = Builder.CreateInsertValue(Dst, NonVirtualBaseAdjustment, Idx++); - if (MSInheritanceAttr::hasVBPtrOffsetField(DstInheritance)) + if (inheritanceModelHasVBPtrOffsetField(DstInheritance)) Dst = Builder.CreateInsertValue(Dst, VBPtrOffset, Idx++); - if (MSInheritanceAttr::hasVBTableOffsetField(DstInheritance)) + if (inheritanceModelHasVBTableOffsetField(DstInheritance)) Dst = Builder.CreateInsertValue(Dst, VirtualBaseAdjustmentOffset, Idx++); } return Dst; @@ -3332,7 +3357,7 @@ CGCallee MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer( CGM.getTypes().arrangeCXXMethodType(RD, FPT, /*FD=*/nullptr)); CGBuilderTy &Builder = CGF.Builder; - MSInheritanceAttr::Spelling Inheritance = RD->getMSInheritanceModel(); + MSInheritanceModel Inheritance = RD->getMSInheritanceModel(); // Extract the fields we need, regardless of model. We'll apply them if we // have them. @@ -3344,11 +3369,11 @@ CGCallee MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer( // We need to extract values. unsigned I = 0; FunctionPointer = Builder.CreateExtractValue(MemPtr, I++); - if (MSInheritanceAttr::hasNVOffsetField(MPT, Inheritance)) + if (inheritanceModelHasNVOffsetField(MPT, Inheritance)) NonVirtualBaseAdjustment = Builder.CreateExtractValue(MemPtr, I++); - if (MSInheritanceAttr::hasVBPtrOffsetField(Inheritance)) + if (inheritanceModelHasVBPtrOffsetField(Inheritance)) VBPtrOffset = Builder.CreateExtractValue(MemPtr, I++); - if (MSInheritanceAttr::hasVBTableOffsetField(Inheritance)) + if (inheritanceModelHasVBTableOffsetField(Inheritance)) VirtualBaseAdjustmentOffset = Builder.CreateExtractValue(MemPtr, I++); } diff --git a/clang/lib/CodeGen/ModuleBuilder.cpp b/clang/lib/CodeGen/ModuleBuilder.cpp index 4154f6ebe736..01093cf20c18 100644 --- a/clang/lib/CodeGen/ModuleBuilder.cpp +++ b/clang/lib/CodeGen/ModuleBuilder.cpp @@ -290,6 +290,10 @@ namespace { Builder->EmitTentativeDefinition(D); } + void CompleteExternalDeclaration(VarDecl *D) override { + Builder->EmitExternalDeclaration(D); + } + void HandleVTable(CXXRecordDecl *RD) override { if (Diags.hasErrorOccurred()) return; diff --git a/clang/lib/CodeGen/SanitizerMetadata.cpp b/clang/lib/CodeGen/SanitizerMetadata.cpp index ebc9cd5529bc..24ae6c6e362f 100644 --- a/clang/lib/CodeGen/SanitizerMetadata.cpp +++ b/clang/lib/CodeGen/SanitizerMetadata.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "SanitizerMetadata.h" #include "CodeGenModule.h" +#include "clang/AST/Attr.h" #include "clang/AST/Type.h" #include "llvm/ADT/StringRef.h" #include "llvm/IR/Constants.h" diff --git a/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index c2c7b8bf653b..682ef18da73b 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/lib/CodeGen/TargetInfo.cpp @@ -17,10 +17,12 @@ #include "CGCXXABI.h" #include "CGValue.h" #include "CodeGenFunction.h" +#include "clang/AST/Attr.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/CodeGenOptions.h" #include "clang/CodeGen/CGFunctionInfo.h" #include "clang/CodeGen/SwiftCallingConv.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" @@ -28,7 +30,7 @@ #include "llvm/IR/DataLayout.h" #include "llvm/IR/Type.h" #include "llvm/Support/raw_ostream.h" -#include <algorithm> // std::sort +#include <algorithm> // std::sort using namespace clang; using namespace CodeGen; @@ -778,6 +780,12 @@ public: B.addAttribute("wasm-import-name", Attr->getImportName()); Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); } + if (const auto *Attr = FD->getAttr<WebAssemblyExportNameAttr>()) { + llvm::Function *Fn = cast<llvm::Function>(GV); + llvm::AttrBuilder B; + B.addAttribute("wasm-export-name", Attr->getExportName()); + Fn->addAttributes(llvm::AttributeList::FunctionIndex, B); + } } if (auto *FD = dyn_cast_or_null<FunctionDecl>(D)) { @@ -989,11 +997,13 @@ static ABIArgInfo getDirectX86Hva(llvm::Type* T = nullptr) { /// Similar to llvm::CCState, but for Clang. struct CCState { - CCState(unsigned CC) : CC(CC), FreeRegs(0), FreeSSERegs(0) {} + CCState(CGFunctionInfo &FI) + : IsPreassigned(FI.arg_size()), CC(FI.getCallingConvention()) {} - unsigned CC; - unsigned FreeRegs; - unsigned FreeSSERegs; + llvm::SmallBitVector IsPreassigned; + unsigned CC = CallingConv::CC_C; + unsigned FreeRegs = 0; + unsigned FreeSSERegs = 0; }; enum { @@ -1064,8 +1074,7 @@ class X86_32ABIInfo : public SwiftABIInfo { void addFieldToArgStruct(SmallVector<llvm::Type *, 6> &FrameFields, CharUnits &StackOffset, ABIArgInfo &Info, QualType Type) const; - void computeVectorCallArgs(CGFunctionInfo &FI, CCState &State, - bool &UsedInAlloca) const; + void runVectorCallFirstPass(CGFunctionInfo &FI, CCState &State) const; public: @@ -1180,6 +1189,10 @@ static void rewriteInputConstraintReferences(unsigned FirstIn, if (NumDollars % 2 != 0 && Pos < AsmString.size()) { // We have an operand reference. size_t DigitStart = Pos; + if (AsmString[DigitStart] == '{') { + OS << '{'; + ++DigitStart; + } size_t DigitEnd = AsmString.find_first_not_of("0123456789", DigitStart); if (DigitEnd == std::string::npos) DigitEnd = AsmString.size(); @@ -1225,7 +1238,7 @@ void X86_32TargetCodeGenInfo::addReturnRegisterOutputs( ResultTruncRegTypes.push_back(CoerceTy); // Coerce the integer by bitcasting the return slot pointer. - ReturnSlot.setAddress(CGF.Builder.CreateBitCast(ReturnSlot.getAddress(), + ReturnSlot.setAddress(CGF.Builder.CreateBitCast(ReturnSlot.getAddress(CGF), CoerceTy->getPointerTo())); ResultRegDests.push_back(ReturnSlot); @@ -1629,9 +1642,38 @@ bool X86_32ABIInfo::shouldPrimitiveUseInReg(QualType Ty, CCState &State) const { return true; } +void X86_32ABIInfo::runVectorCallFirstPass(CGFunctionInfo &FI, CCState &State) const { + // Vectorcall x86 works subtly different than in x64, so the format is + // a bit different than the x64 version. First, all vector types (not HVAs) + // are assigned, with the first 6 ending up in the [XYZ]MM0-5 registers. + // This differs from the x64 implementation, where the first 6 by INDEX get + // registers. + // In the second pass over the arguments, HVAs are passed in the remaining + // vector registers if possible, or indirectly by address. The address will be + // passed in ECX/EDX if available. Any other arguments are passed according to + // the usual fastcall rules. + MutableArrayRef<CGFunctionInfoArgInfo> Args = FI.arguments(); + for (int I = 0, E = Args.size(); I < E; ++I) { + const Type *Base = nullptr; + uint64_t NumElts = 0; + const QualType &Ty = Args[I].type; + if ((Ty->isVectorType() || Ty->isBuiltinType()) && + isHomogeneousAggregate(Ty, Base, NumElts)) { + if (State.FreeSSERegs >= NumElts) { + State.FreeSSERegs -= NumElts; + Args[I].info = ABIArgInfo::getDirect(); + State.IsPreassigned.set(I); + } + } + } +} + ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, CCState &State) const { // FIXME: Set alignment on indirect arguments. + bool IsFastCall = State.CC == llvm::CallingConv::X86_FastCall; + bool IsRegCall = State.CC == llvm::CallingConv::X86_RegCall; + bool IsVectorCall = State.CC == llvm::CallingConv::X86_VectorCall; Ty = useFirstFieldIfTransparentUnion(Ty); @@ -1651,11 +1693,16 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, // to other targets. const Type *Base = nullptr; uint64_t NumElts = 0; - if (State.CC == llvm::CallingConv::X86_RegCall && + if ((IsRegCall || IsVectorCall) && isHomogeneousAggregate(Ty, Base, NumElts)) { - if (State.FreeSSERegs >= NumElts) { State.FreeSSERegs -= NumElts; + + // Vectorcall passes HVAs directly and does not flatten them, but regcall + // does. + if (IsVectorCall) + return getDirectX86Hva(); + if (Ty->isBuiltinType() || Ty->isVectorType()) return ABIArgInfo::getDirect(); return ABIArgInfo::getExpand(); @@ -1697,10 +1744,7 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, if (getContext().getTypeSize(Ty) <= 4 * 32 && (!IsMCUABI || State.FreeRegs == 0) && canExpandIndirectArgument(Ty)) return ABIArgInfo::getExpandWithPadding( - State.CC == llvm::CallingConv::X86_FastCall || - State.CC == llvm::CallingConv::X86_VectorCall || - State.CC == llvm::CallingConv::X86_RegCall, - PaddingType); + IsFastCall || IsVectorCall || IsRegCall, PaddingType); return getIndirectResult(Ty, true, State); } @@ -1739,60 +1783,8 @@ ABIArgInfo X86_32ABIInfo::classifyArgumentType(QualType Ty, return ABIArgInfo::getDirect(); } -void X86_32ABIInfo::computeVectorCallArgs(CGFunctionInfo &FI, CCState &State, - bool &UsedInAlloca) const { - // Vectorcall x86 works subtly different than in x64, so the format is - // a bit different than the x64 version. First, all vector types (not HVAs) - // are assigned, with the first 6 ending up in the YMM0-5 or XMM0-5 registers. - // This differs from the x64 implementation, where the first 6 by INDEX get - // registers. - // After that, integers AND HVAs are assigned Left to Right in the same pass. - // Integers are passed as ECX/EDX if one is available (in order). HVAs will - // first take up the remaining YMM/XMM registers. If insufficient registers - // remain but an integer register (ECX/EDX) is available, it will be passed - // in that, else, on the stack. - for (auto &I : FI.arguments()) { - // First pass do all the vector types. - const Type *Base = nullptr; - uint64_t NumElts = 0; - const QualType& Ty = I.type; - if ((Ty->isVectorType() || Ty->isBuiltinType()) && - isHomogeneousAggregate(Ty, Base, NumElts)) { - if (State.FreeSSERegs >= NumElts) { - State.FreeSSERegs -= NumElts; - I.info = ABIArgInfo::getDirect(); - } else { - I.info = classifyArgumentType(Ty, State); - } - UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca); - } - } - - for (auto &I : FI.arguments()) { - // Second pass, do the rest! - const Type *Base = nullptr; - uint64_t NumElts = 0; - const QualType& Ty = I.type; - bool IsHva = isHomogeneousAggregate(Ty, Base, NumElts); - - if (IsHva && !Ty->isVectorType() && !Ty->isBuiltinType()) { - // Assign true HVAs (non vector/native FP types). - if (State.FreeSSERegs >= NumElts) { - State.FreeSSERegs -= NumElts; - I.info = getDirectX86Hva(); - } else { - I.info = getIndirectResult(Ty, /*ByVal=*/false, State); - } - } else if (!IsHva) { - // Assign all Non-HVAs, so this will exclude Vector/FP args. - I.info = classifyArgumentType(Ty, State); - UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca); - } - } -} - void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const { - CCState State(FI.getCallingConvention()); + CCState State(FI); if (IsMCUABI) State.FreeRegs = 3; else if (State.CC == llvm::CallingConv::X86_FastCall) @@ -1824,15 +1816,20 @@ void X86_32ABIInfo::computeInfo(CGFunctionInfo &FI) const { if (FI.isChainCall()) ++State.FreeRegs; + // For vectorcall, do a first pass over the arguments, assigning FP and vector + // arguments to XMM registers as available. + if (State.CC == llvm::CallingConv::X86_VectorCall) + runVectorCallFirstPass(FI, State); + bool UsedInAlloca = false; - if (State.CC == llvm::CallingConv::X86_VectorCall) { - computeVectorCallArgs(FI, State, UsedInAlloca); - } else { - // If not vectorcall, revert to normal behavior. - for (auto &I : FI.arguments()) { - I.info = classifyArgumentType(I.type, State); - UsedInAlloca |= (I.info.getKind() == ABIArgInfo::InAlloca); - } + MutableArrayRef<CGFunctionInfoArgInfo> Args = FI.arguments(); + for (int I = 0, E = Args.size(); I < E; ++I) { + // Skip arguments that have already been assigned. + if (State.IsPreassigned.test(I)) + continue; + + Args[I].info = classifyArgumentType(Args[I].type, State); + UsedInAlloca |= (Args[I].info.getKind() == ABIArgInfo::InAlloca); } // If we needed to use inalloca for any argument, do a second pass and rewrite @@ -4991,7 +4988,7 @@ private: ABIKind getABIKind() const { return Kind; } bool isDarwinPCS() const { return Kind == DarwinPCS; } - ABIArgInfo classifyReturnType(QualType RetTy) const; + ABIArgInfo classifyReturnType(QualType RetTy, bool IsVariadic) const; ABIArgInfo classifyArgumentType(QualType RetTy) const; bool isHomogeneousAggregateBaseType(QualType Ty) const override; bool isHomogeneousAggregateSmallEnough(const Type *Ty, @@ -5001,7 +4998,8 @@ private: void computeInfo(CGFunctionInfo &FI) const override { if (!::classifyReturnType(getCXXABI(), FI, *this)) - FI.getReturnInfo() = classifyReturnType(FI.getReturnType()); + FI.getReturnInfo() = + classifyReturnType(FI.getReturnType(), FI.isVariadic()); for (auto &it : FI.arguments()) it.info = classifyArgumentType(it.type); @@ -5055,23 +5053,38 @@ public: const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(D); if (!FD) return; - llvm::Function *Fn = cast<llvm::Function>(GV); - auto Kind = CGM.getCodeGenOpts().getSignReturnAddress(); - if (Kind != CodeGenOptions::SignReturnAddressScope::None) { + CodeGenOptions::SignReturnAddressScope Scope = CGM.getCodeGenOpts().getSignReturnAddress(); + CodeGenOptions::SignReturnAddressKeyValue Key = CGM.getCodeGenOpts().getSignReturnAddressKey(); + bool BranchTargetEnforcement = CGM.getCodeGenOpts().BranchTargetEnforcement; + if (const auto *TA = FD->getAttr<TargetAttr>()) { + ParsedTargetAttr Attr = TA->parse(); + if (!Attr.BranchProtection.empty()) { + TargetInfo::BranchProtectionInfo BPI; + StringRef Error; + (void)CGM.getTarget().validateBranchProtection(Attr.BranchProtection, + BPI, Error); + assert(Error.empty()); + Scope = BPI.SignReturnAddr; + Key = BPI.SignKey; + BranchTargetEnforcement = BPI.BranchTargetEnforcement; + } + } + + auto *Fn = cast<llvm::Function>(GV); + if (Scope != CodeGenOptions::SignReturnAddressScope::None) { Fn->addFnAttr("sign-return-address", - Kind == CodeGenOptions::SignReturnAddressScope::All + Scope == CodeGenOptions::SignReturnAddressScope::All ? "all" : "non-leaf"); - auto Key = CGM.getCodeGenOpts().getSignReturnAddressKey(); Fn->addFnAttr("sign-return-address-key", Key == CodeGenOptions::SignReturnAddressKeyValue::AKey ? "a_key" : "b_key"); } - if (CGM.getCodeGenOpts().BranchTargetEnforcement) + if (BranchTargetEnforcement) Fn->addFnAttr("branch-target-enforcement"); } }; @@ -5184,23 +5197,24 @@ ABIArgInfo AArch64ABIInfo::classifyArgumentType(QualType Ty) const { Alignment = getContext().getTypeUnadjustedAlign(Ty); Alignment = Alignment < 128 ? 64 : 128; } else { - Alignment = getContext().getTypeAlign(Ty); + Alignment = std::max(getContext().getTypeAlign(Ty), + (unsigned)getTarget().getPointerWidth(0)); } - Size = llvm::alignTo(Size, 64); // round up to multiple of 8 bytes + Size = llvm::alignTo(Size, Alignment); // We use a pair of i64 for 16-byte aggregate with 8-byte alignment. // For aggregates with 16-byte alignment, we use i128. - if (Alignment < 128 && Size == 128) { - llvm::Type *BaseTy = llvm::Type::getInt64Ty(getVMContext()); - return ABIArgInfo::getDirect(llvm::ArrayType::get(BaseTy, Size / 64)); - } - return ABIArgInfo::getDirect(llvm::IntegerType::get(getVMContext(), Size)); + llvm::Type *BaseTy = llvm::Type::getIntNTy(getVMContext(), Alignment); + return ABIArgInfo::getDirect( + Size == Alignment ? BaseTy + : llvm::ArrayType::get(BaseTy, Size / Alignment)); } return getNaturalAlignIndirect(Ty, /*ByVal=*/false); } -ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const { +ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy, + bool IsVariadic) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); @@ -5224,7 +5238,9 @@ ABIArgInfo AArch64ABIInfo::classifyReturnType(QualType RetTy) const { const Type *Base = nullptr; uint64_t Members = 0; - if (isHomogeneousAggregate(RetTy, Base, Members)) + if (isHomogeneousAggregate(RetTy, Base, Members) && + !(getTarget().getTriple().getArch() == llvm::Triple::aarch64_32 && + IsVariadic)) // Homogeneous Floating-point Aggregates (HFAs) are returned directly. return ABIArgInfo::getDirect(); @@ -5259,6 +5275,14 @@ bool AArch64ABIInfo::isIllegalVectorType(QualType Ty) const { // NumElements should be power of 2. if (!llvm::isPowerOf2_32(NumElements)) return true; + + // arm64_32 has to be compatible with the ARM logic here, which allows huge + // vectors for some reason. + llvm::Triple Triple = getTarget().getTriple(); + if (Triple.getArch() == llvm::Triple::aarch64_32 && + Triple.isOSBinFormatMachO()) + return Size <= 32; + return Size != 64 && (Size != 128 || NumElements == 1); } return false; @@ -5550,7 +5574,8 @@ Address AArch64ABIInfo::EmitDarwinVAArg(Address VAListAddr, QualType Ty, if (!isAggregateTypeForABI(Ty) && !isIllegalVectorType(Ty)) return EmitVAArgInstr(CGF, VAListAddr, Ty, ABIArgInfo::getDirect()); - CharUnits SlotSize = CharUnits::fromQuantity(8); + uint64_t PointerSize = getTarget().getPointerWidth(0) / 8; + CharUnits SlotSize = CharUnits::fromQuantity(PointerSize); // Empty records are ignored for parameter passing purposes. if (isEmptyRecord(getContext(), Ty, true)) { @@ -7555,7 +7580,7 @@ public: bool shouldUseInReg(QualType Ty, CCState &State) const; void computeInfo(CGFunctionInfo &FI) const override { - CCState State(FI.getCallingConvention()); + CCState State(FI); // Lanai uses 4 registers to pass arguments unless the function has the // regparm attribute set. if (FI.getHasRegParm()) { @@ -7685,6 +7710,42 @@ private: bool isHomogeneousAggregateSmallEnough(const Type *Base, uint64_t Members) const override; + // Coerce HIP pointer arguments from generic pointers to global ones. + llvm::Type *coerceKernelArgumentType(llvm::Type *Ty, unsigned FromAS, + unsigned ToAS) const { + // Structure types. + if (auto STy = dyn_cast<llvm::StructType>(Ty)) { + SmallVector<llvm::Type *, 8> EltTys; + bool Changed = false; + for (auto T : STy->elements()) { + auto NT = coerceKernelArgumentType(T, FromAS, ToAS); + EltTys.push_back(NT); + Changed |= (NT != T); + } + // Skip if there is no change in element types. + if (!Changed) + return STy; + if (STy->hasName()) + return llvm::StructType::create( + EltTys, (STy->getName() + ".coerce").str(), STy->isPacked()); + return llvm::StructType::get(getVMContext(), EltTys, STy->isPacked()); + } + // Arrary types. + if (auto ATy = dyn_cast<llvm::ArrayType>(Ty)) { + auto T = ATy->getElementType(); + auto NT = coerceKernelArgumentType(T, FromAS, ToAS); + // Skip if there is no change in that element type. + if (NT == T) + return ATy; + return llvm::ArrayType::get(NT, ATy->getNumElements()); + } + // Single value types. + if (Ty->isPointerTy() && Ty->getPointerAddressSpace() == FromAS) + return llvm::PointerType::get( + cast<llvm::PointerType>(Ty)->getElementType(), ToAS); + return Ty; + } + public: explicit AMDGPUABIInfo(CodeGen::CodeGenTypes &CGT) : DefaultABIInfo(CGT) {} @@ -7694,6 +7755,8 @@ public: ABIArgInfo classifyArgumentType(QualType Ty, unsigned &NumRegsLeft) const; void computeInfo(CGFunctionInfo &FI) const override; + Address EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const override; }; bool AMDGPUABIInfo::isHomogeneousAggregateBaseType(QualType Ty) const { @@ -7757,6 +7820,11 @@ void AMDGPUABIInfo::computeInfo(CGFunctionInfo &FI) const { } } +Address AMDGPUABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, + QualType Ty) const { + llvm_unreachable("AMDGPU does not support varargs"); +} + ABIArgInfo AMDGPUABIInfo::classifyReturnType(QualType RetTy) const { if (isAggregateTypeForABI(RetTy)) { // Records with non-trivial destructors/copy-constructors should not be @@ -7805,14 +7873,22 @@ ABIArgInfo AMDGPUABIInfo::classifyKernelArgumentType(QualType Ty) const { // TODO: Can we omit empty structs? - // Coerce single element structs to its element. + llvm::Type *LTy = nullptr; if (const Type *SeltTy = isSingleElementStruct(Ty, getContext())) - return ABIArgInfo::getDirect(CGT.ConvertType(QualType(SeltTy, 0))); + LTy = CGT.ConvertType(QualType(SeltTy, 0)); + + if (getContext().getLangOpts().HIP) { + if (!LTy) + LTy = CGT.ConvertType(Ty); + LTy = coerceKernelArgumentType( + LTy, /*FromAS=*/getContext().getTargetAddressSpace(LangAS::Default), + /*ToAS=*/getContext().getTargetAddressSpace(LangAS::cuda_device)); + } // If we set CanBeFlattened to true, CodeGen will expand the struct to its // individual elements, which confuses the Clover OpenCL backend; therefore we // have to set it to false here. Other args of getDirect() are just defaults. - return ABIArgInfo::getDirect(nullptr, 0, nullptr, false); + return ABIArgInfo::getDirect(LTy, 0, nullptr, false); } ABIArgInfo AMDGPUABIInfo::classifyArgumentType(QualType Ty, @@ -7982,8 +8058,11 @@ void AMDGPUTargetCodeGenInfo::setTargetAttributes( } else assert(Max == 0 && "Max must be zero"); } else if (IsOpenCLKernel || IsHIPKernel) { - // By default, restrict the maximum size to 256. - F->addFnAttr("amdgpu-flat-work-group-size", "1,256"); + // By default, restrict the maximum size to a value specified by + // --gpu-max-threads-per-block=n or its default value. + std::string AttrVal = + std::string("1,") + llvm::utostr(M.getLangOpts().GPUMaxThreadsPerBlock); + F->addFnAttr("amdgpu-flat-work-group-size", AttrVal); } if (const auto *Attr = FD->getAttr<AMDGPUWavesPerEUAttr>()) { @@ -8477,7 +8556,7 @@ private: } void computeInfo(CGFunctionInfo &FI) const override { - CCState State(FI.getCallingConvention()); + CCState State(FI); // ARC uses 8 registers to pass arguments. State.FreeRegs = 8; @@ -9284,11 +9363,21 @@ void RISCVABIInfo::computeInfo(CGFunctionInfo &FI) const { FI.getReturnInfo() = classifyReturnType(RetTy); // IsRetIndirect is true if classifyArgumentType indicated the value should - // be passed indirect or if the type size is greater than 2*xlen. e.g. fp128 - // is passed direct in LLVM IR, relying on the backend lowering code to - // rewrite the argument list and pass indirectly on RV32. - bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect || - getContext().getTypeSize(RetTy) > (2 * XLen); + // be passed indirect, or if the type size is a scalar greater than 2*XLen + // and not a complex type with elements <= FLen. e.g. fp128 is passed direct + // in LLVM IR, relying on the backend lowering code to rewrite the argument + // list and pass indirectly on RV32. + bool IsRetIndirect = FI.getReturnInfo().getKind() == ABIArgInfo::Indirect; + if (!IsRetIndirect && RetTy->isScalarType() && + getContext().getTypeSize(RetTy) > (2 * XLen)) { + if (RetTy->isComplexType() && FLen) { + QualType EltTy = RetTy->getAs<ComplexType>()->getElementType(); + IsRetIndirect = getContext().getTypeSize(EltTy) > FLen; + } else { + // This is a normal scalar > 2*XLen, such as fp128 on RV32. + IsRetIndirect = true; + } + } // We must track the number of GPRs used in order to conform to the RISC-V // ABI, as integer scalars passed in registers should have signext/zeroext @@ -9722,6 +9811,7 @@ const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { return SetCGInfo(new AVRTargetCodeGenInfo(Types)); case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: { AArch64ABIInfo::ABIKind Kind = AArch64ABIInfo::AAPCS; if (getTarget().getABI() == "darwinpcs") diff --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp index f2a3074d1e70..06707fefc9d0 100644 --- a/clang/lib/Driver/Distro.cpp +++ b/clang/lib/Driver/Distro.cpp @@ -13,11 +13,28 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/ADT/Triple.h" using namespace clang::driver; using namespace clang; -static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { +static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS, + const llvm::Triple &TargetOrHost) { + // If we don't target Linux, no need to check the distro. This saves a few + // OS calls. + if (!TargetOrHost.isOSLinux()) + return Distro::UnknownDistro; + + // If the host is not running Linux, and we're backed by a real file system, + // no need to check the distro. This is the case where someone is + // cross-compiling from BSD or Windows to Linux, and it would be meaningless + // to try to figure out the "distro" of the non-Linux host. + IntrusiveRefCntPtr<llvm::vfs::FileSystem> RealFS = + llvm::vfs::getRealFileSystem(); + llvm::Triple HostTriple(llvm::sys::getProcessTriple()); + if (!HostTriple.isOSLinux() && &VFS == RealFS.get()) + return Distro::UnknownDistro; + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = VFS.getBufferForFile("/etc/lsb-release"); if (File) { @@ -52,6 +69,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { .Case("cosmic", Distro::UbuntuCosmic) .Case("disco", Distro::UbuntuDisco) .Case("eoan", Distro::UbuntuEoan) + .Case("focal", Distro::UbuntuFocal) .Default(Distro::UnknownDistro); if (Version != Distro::UnknownDistro) return Version; @@ -148,4 +166,5 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) { return Distro::UnknownDistro; } -Distro::Distro(llvm::vfs::FileSystem &VFS) : DistroVal(DetectDistro(VFS)) {} +Distro::Distro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost) + : DistroVal(DetectDistro(VFS, TargetOrHost)) {} diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index f6016b43b692..e718b8366df0 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -8,6 +8,7 @@ #include "clang/Driver/Driver.h" #include "InputInfo.h" +#include "ToolChains/AIX.h" #include "ToolChains/AMDGPU.h" #include "ToolChains/AVR.h" #include "ToolChains/Ananas.h" @@ -177,6 +178,7 @@ void Driver::setDriverModeFromOption(StringRef Opt) { .Case("g++", GXXMode) .Case("cpp", CPPMode) .Case("cl", CLMode) + .Case("flang", FlangMode) .Default(None)) Mode = *M; else @@ -290,10 +292,6 @@ phases::ID Driver::getFinalPhase(const DerivedArgList &DAL, (PhaseArg = DAL.getLastArg(options::OPT_emit_ast))) { FinalPhase = phases::Compile; - // clang interface stubs - } else if ((PhaseArg = DAL.getLastArg(options::OPT_emit_interface_stubs))) { - FinalPhase = phases::IfsMerge; - // -S only runs up to the backend. } else if ((PhaseArg = DAL.getLastArg(options::OPT_S))) { FinalPhase = phases::Backend; @@ -539,6 +537,17 @@ static llvm::Triple computeTargetTriple(const Driver &D, } } + // If target is RISC-V adjust the target triple according to + // provided architecture name + A = Args.getLastArg(options::OPT_march_EQ); + if (A && Target.isRISCV()) { + StringRef ArchName = A->getValue(); + if (ArchName.startswith_lower("rv32")) + Target.setArch(llvm::Triple::riscv32); + else if (ArchName.startswith_lower("rv64")) + Target.setArch(llvm::Triple::riscv64); + } + return Target; } @@ -735,7 +744,7 @@ static bool searchForFile(SmallVectorImpl<char> &FilePath, ArrayRef<std::string> Dirs, StringRef FileName) { SmallString<128> WPath; - for (const StringRef &Dir : Dirs) { + for (const std::string &Dir : Dirs) { if (Dir.empty()) continue; WPath.clear(); @@ -1981,8 +1990,9 @@ void Driver::BuildUniversalActions(Compilation &C, const ToolChain &TC, // Handle debug info queries. Arg *A = Args.getLastArg(options::OPT_g_Group); - if (A && !A->getOption().matches(options::OPT_g0) && - !A->getOption().matches(options::OPT_gstabs) && + bool enablesDebugInfo = A && !A->getOption().matches(options::OPT_g0) && + !A->getOption().matches(options::OPT_gstabs); + if ((enablesDebugInfo || willEmitRemarks(Args)) && ContainsCompileOrAssembleAction(Actions.back())) { // Add a 'dsymutil' step if necessary, when debug info is enabled and we @@ -3489,6 +3499,68 @@ void Driver::BuildActions(Compilation &C, DerivedArgList &Args, Actions.push_back( C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image)); + if (Args.hasArg(options::OPT_emit_interface_stubs)) { + llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> PhaseList; + if (Args.hasArg(options::OPT_c)) { + llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> CompilePhaseList; + types::getCompilationPhases(types::TY_IFS_CPP, CompilePhaseList); + llvm::copy_if(CompilePhaseList, std::back_inserter(PhaseList), + [&](phases::ID Phase) { return Phase <= phases::Compile; }); + } else { + types::getCompilationPhases(types::TY_IFS_CPP, PhaseList); + } + + ActionList MergerInputs; + + for (auto &I : Inputs) { + types::ID InputType = I.first; + const Arg *InputArg = I.second; + + // Currently clang and the llvm assembler do not support generating symbol + // stubs from assembly, so we skip the input on asm files. For ifs files + // we rely on the normal pipeline setup in the pipeline setup code above. + if (InputType == types::TY_IFS || InputType == types::TY_PP_Asm || + InputType == types::TY_Asm) + continue; + + Action *Current = C.MakeAction<InputAction>(*InputArg, InputType); + + for (auto Phase : PhaseList) { + switch (Phase) { + default: + llvm_unreachable( + "IFS Pipeline can only consist of Compile followed by IfsMerge."); + case phases::Compile: { + // Only IfsMerge (llvm-ifs) can handle .o files by looking for ifs + // files where the .o file is located. The compile action can not + // handle this. + if (InputType == types::TY_Object) + break; + + Current = C.MakeAction<CompileJobAction>(Current, types::TY_IFS_CPP); + break; + } + case phases::IfsMerge: { + assert(Phase == PhaseList.back() && + "merging must be final compilation step."); + MergerInputs.push_back(Current); + Current = nullptr; + break; + } + } + } + + // If we ended with something, add to the output list. + if (Current) + Actions.push_back(Current); + } + + // Add an interface stubs merge action if necessary. + if (!MergerInputs.empty()) + Actions.push_back( + C.MakeAction<IfsMergeJobAction>(MergerInputs, types::TY_Image)); + } + // If --print-supported-cpus, -mcpu=? or -mtune=? is specified, build a custom // Compile phase that prints out supported cpu models and quits. if (Arg *A = Args.getLastArg(options::OPT_print_supported_cpus)) { @@ -3590,8 +3662,6 @@ Action *Driver::ConstructPhaseAction( return C.MakeAction<CompileJobAction>(Input, types::TY_ModuleFile); if (Args.hasArg(options::OPT_verify_pch)) return C.MakeAction<VerifyPCHJobAction>(Input, types::TY_Nothing); - if (Args.hasArg(options::OPT_emit_interface_stubs)) - return C.MakeAction<CompileJobAction>(Input, types::TY_IFS_CPP); return C.MakeAction<CompileJobAction>(Input, types::TY_LLVM_BC); } case phases::Backend: { @@ -3620,11 +3690,29 @@ void Driver::BuildJobs(Compilation &C) const { Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); // It is an error to provide a -o option if we are making multiple output - // files. + // files. There are exceptions: + // + // IfsMergeJob: when generating interface stubs enabled we want to be able to + // generate the stub file at the same time that we generate the real + // library/a.out. So when a .o, .so, etc are the output, with clang interface + // stubs there will also be a .ifs and .ifso at the same location. + // + // CompileJob of type TY_IFS_CPP: when generating interface stubs is enabled + // and -c is passed, we still want to be able to generate a .ifs file while + // we are also generating .o files. So we allow more than one output file in + // this case as well. + // if (FinalOutput) { unsigned NumOutputs = 0; + unsigned NumIfsOutputs = 0; for (const Action *A : C.getActions()) - if (A->getType() != types::TY_Nothing) + if (A->getType() != types::TY_Nothing && + !(A->getKind() == Action::IfsMergeJobClass || + (A->getType() == clang::driver::types::TY_IFS_CPP && + A->getKind() == clang::driver::Action::CompileJobClass && + 0 == NumIfsOutputs++) || + (A->getKind() == Action::BindArchClass && A->getInputs().size() && + A->getInputs().front()->getKind() == Action::IfsMergeJobClass))) ++NumOutputs; if (NumOutputs > 1) { @@ -4699,6 +4787,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args, auto &TC = ToolChains[Target.str()]; if (!TC) { switch (Target.getOS()) { + case llvm::Triple::AIX: + TC = std::make_unique<toolchains::AIX>(*this, Target, Args); + break; case llvm::Triple::Haiku: TC = std::make_unique<toolchains::Haiku>(*this, Target, Args); break; @@ -4872,6 +4963,19 @@ bool Driver::ShouldUseClangCompiler(const JobAction &JA) const { return true; } +bool Driver::ShouldUseFlangCompiler(const JobAction &JA) const { + // Say "no" if there is not exactly one input of a type flang understands. + if (JA.size() != 1 || + !types::isFortran((*JA.input_begin())->getType())) + return false; + + // And say "no" if this is not a kind of action flang understands. + if (!isa<PreprocessJobAction>(JA) && !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA)) + return false; + + return true; +} + /// GetReleaseVersion - Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the /// grouped values as integers. Numbers which are not provided are set to 0. /// @@ -4957,3 +5061,26 @@ Driver::getIncludeExcludeOptionFlagMasks(bool IsClCompatMode) const { bool clang::driver::isOptimizationLevelFast(const ArgList &Args) { return Args.hasFlag(options::OPT_Ofast, options::OPT_O_Group, false); } + +bool clang::driver::willEmitRemarks(const ArgList &Args) { + // -fsave-optimization-record enables it. + if (Args.hasFlag(options::OPT_fsave_optimization_record, + options::OPT_fno_save_optimization_record, false)) + return true; + + // -fsave-optimization-record=<format> enables it as well. + if (Args.hasFlag(options::OPT_fsave_optimization_record_EQ, + options::OPT_fno_save_optimization_record, false)) + return true; + + // -foptimization-record-file alone enables it too. + if (Args.hasFlag(options::OPT_foptimization_record_file_EQ, + options::OPT_fno_save_optimization_record, false)) + return true; + + // -foptimization-record-passes alone enables it too. + if (Args.hasFlag(options::OPT_foptimization_record_passes_EQ, + options::OPT_fno_save_optimization_record, false)) + return true; + return false; +} diff --git a/clang/lib/Driver/Job.cpp b/clang/lib/Driver/Job.cpp index 0a95e49694f9..d57c3a1cdbb8 100644 --- a/clang/lib/Driver/Job.cpp +++ b/clang/lib/Driver/Job.cpp @@ -19,8 +19,10 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/CrashRecoveryContext.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Path.h" +#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> @@ -313,15 +315,46 @@ void Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { Environment.push_back(nullptr); } -int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, - std::string *ErrMsg, bool *ExecutionFailed) const { +void Command::PrintFileNames() const { if (PrintInputFilenames) { for (const char *Arg : InputFilenames) llvm::outs() << llvm::sys::path::filename(Arg) << "\n"; llvm::outs().flush(); } +} + +int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, + std::string *ErrMsg, bool *ExecutionFailed) const { + PrintFileNames(); - SmallVector<const char*, 128> Argv; + SmallVector<const char *, 128> Argv; + if (ResponseFile == nullptr) { + Argv.push_back(Executable); + Argv.append(Arguments.begin(), Arguments.end()); + Argv.push_back(nullptr); + } else { + // If the command is too large, we need to put arguments in a response file. + std::string RespContents; + llvm::raw_string_ostream SS(RespContents); + + // Write file contents and build the Argv vector + writeResponseFile(SS); + buildArgvForResponseFile(Argv); + Argv.push_back(nullptr); + SS.flush(); + + // Save the response file in the appropriate encoding + if (std::error_code EC = writeFileWithEncoding( + ResponseFile, RespContents, Creator.getResponseFileEncoding())) { + if (ErrMsg) + *ErrMsg = EC.message(); + if (ExecutionFailed) + *ExecutionFailed = true; + // Return -1 by convention (see llvm/include/llvm/Support/Program.h) to + // indicate the requested executable cannot be started. + return -1; + } + } Optional<ArrayRef<StringRef>> Env; std::vector<StringRef> ArgvVectorStorage; @@ -332,42 +365,51 @@ int Command::Execute(ArrayRef<llvm::Optional<StringRef>> Redirects, Env = makeArrayRef(ArgvVectorStorage); } - if (ResponseFile == nullptr) { - Argv.push_back(Executable); - Argv.append(Arguments.begin(), Arguments.end()); - Argv.push_back(nullptr); + auto Args = llvm::toStringRefArray(Argv.data()); + return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects, + /*secondsToWait*/ 0, + /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); +} - auto Args = llvm::toStringRefArray(Argv.data()); - return llvm::sys::ExecuteAndWait( - Executable, Args, Env, Redirects, /*secondsToWait*/ 0, - /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); - } +void CC1Command::Print(raw_ostream &OS, const char *Terminator, bool Quote, + CrashReportInfo *CrashInfo) const { + OS << " (in-process)"; + Command::Print(OS, Terminator, Quote, CrashInfo); +} - // We need to put arguments in a response file (command is too large) - // Open stream to store the response file contents - std::string RespContents; - llvm::raw_string_ostream SS(RespContents); +int CC1Command::Execute(ArrayRef<llvm::Optional<StringRef>> /*Redirects*/, + std::string *ErrMsg, bool *ExecutionFailed) const { + PrintFileNames(); - // Write file contents and build the Argv vector - writeResponseFile(SS); - buildArgvForResponseFile(Argv); + SmallVector<const char *, 128> Argv; + Argv.push_back(getExecutable()); + Argv.append(getArguments().begin(), getArguments().end()); Argv.push_back(nullptr); - SS.flush(); - // Save the response file in the appropriate encoding - if (std::error_code EC = writeFileWithEncoding( - ResponseFile, RespContents, Creator.getResponseFileEncoding())) { - if (ErrMsg) - *ErrMsg = EC.message(); - if (ExecutionFailed) - *ExecutionFailed = true; - return -1; + // This flag simply indicates that the program couldn't start, which isn't + // applicable here. + if (ExecutionFailed) + *ExecutionFailed = false; + + llvm::CrashRecoveryContext CRC; + CRC.DumpStackAndCleanupOnFailure = true; + + const void *PrettyState = llvm::SavePrettyStackState(); + const Driver &D = getCreator().getToolChain().getDriver(); + + int R = 0; + // Enter ExecuteCC1Tool() instead of starting up a new process + if (!CRC.RunSafely([&]() { R = D.CC1Main(Argv); })) { + llvm::RestorePrettyStackState(PrettyState); + return CRC.RetCode; } + return R; +} - auto Args = llvm::toStringRefArray(Argv.data()); - return llvm::sys::ExecuteAndWait(Executable, Args, Env, Redirects, - /*secondsToWait*/ 0, - /*memoryLimit*/ 0, ErrMsg, ExecutionFailed); +void CC1Command::setEnvironment(llvm::ArrayRef<const char *> NewEnvironment) { + // We don't support set a new environment when calling into ExecuteCC1Tool() + llvm_unreachable( + "The CC1Command doesn't support changing the environment vars!"); } FallbackCommand::FallbackCommand(const Action &Source_, const Tool &Creator_, diff --git a/clang/lib/Driver/OptionUtils.cpp b/clang/lib/Driver/OptionUtils.cpp new file mode 100644 index 000000000000..1f36ffc03cab --- /dev/null +++ b/clang/lib/Driver/OptionUtils.cpp @@ -0,0 +1,47 @@ +//===--- OptionUtils.cpp - Utilities for command line arguments -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticDriver.h" +#include "clang/Driver/OptionUtils.h" +#include "llvm/Option/ArgList.h" + +using namespace clang; +using namespace llvm::opt; + +namespace { +template <typename IntTy> +IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, + IntTy Default, DiagnosticsEngine *Diags, + unsigned Base) { + IntTy Res = Default; + if (Arg *A = Args.getLastArg(Id)) { + if (StringRef(A->getValue()).getAsInteger(Base, Res)) { + if (Diags) + Diags->Report(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(); + } + } + return Res; +} +} // namespace + +namespace clang { + +int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, + DiagnosticsEngine *Diags, unsigned Base) { + return getLastArgIntValueImpl<int>(Args, Id, Default, Diags, Base); +} + +uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, + uint64_t Default, DiagnosticsEngine *Diags, + unsigned Base) { + return getLastArgIntValueImpl<uint64_t>(Args, Id, Default, Diags, Base); +} + +} // namespace clang diff --git a/clang/lib/Driver/SanitizerArgs.cpp b/clang/lib/Driver/SanitizerArgs.cpp index cc6c5e6ef438..ac9a294ee3fa 100644 --- a/clang/lib/Driver/SanitizerArgs.cpp +++ b/clang/lib/Driver/SanitizerArgs.cpp @@ -141,7 +141,7 @@ static void addDefaultBlacklists(const Driver &D, SanitizerMask Kinds, clang::SmallString<64> Path(D.ResourceDir); llvm::sys::path::append(Path, "share", BL.File); - if (llvm::sys::fs::exists(Path)) + if (D.getVFS().exists(Path)) BlacklistFiles.push_back(Path.str()); else if (BL.Mask == SanitizerKind::CFI) // If cfi_blacklist.txt cannot be found in the resource dir, driver @@ -557,29 +557,35 @@ SanitizerArgs::SanitizerArgs(const ToolChain &TC, // Setup blacklist files. // Add default blacklist from resource directory. - addDefaultBlacklists(D, Kinds, BlacklistFiles); + addDefaultBlacklists(D, Kinds, SystemBlacklistFiles); // Parse -f(no-)sanitize-blacklist options. for (const auto *Arg : Args) { if (Arg->getOption().matches(options::OPT_fsanitize_blacklist)) { Arg->claim(); std::string BLPath = Arg->getValue(); - if (llvm::sys::fs::exists(BLPath)) { - BlacklistFiles.push_back(BLPath); - ExtraDeps.push_back(BLPath); + if (D.getVFS().exists(BLPath)) { + UserBlacklistFiles.push_back(BLPath); } else { D.Diag(clang::diag::err_drv_no_such_file) << BLPath; } } else if (Arg->getOption().matches(options::OPT_fno_sanitize_blacklist)) { Arg->claim(); - BlacklistFiles.clear(); - ExtraDeps.clear(); + UserBlacklistFiles.clear(); + SystemBlacklistFiles.clear(); } } // Validate blacklists format. { std::string BLError; std::unique_ptr<llvm::SpecialCaseList> SCL( - llvm::SpecialCaseList::create(BlacklistFiles, BLError)); + llvm::SpecialCaseList::create(UserBlacklistFiles, D.getVFS(), BLError)); + if (!SCL.get()) + D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; + } + { + std::string BLError; + std::unique_ptr<llvm::SpecialCaseList> SCL(llvm::SpecialCaseList::create( + SystemBlacklistFiles, D.getVFS(), BLError)); if (!SCL.get()) D.Diag(clang::diag::err_drv_malformed_sanitizer_blacklist) << BLError; } @@ -952,15 +958,15 @@ void SanitizerArgs::addArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, CmdArgs.push_back( Args.MakeArgString("-fsanitize-trap=" + toString(TrapSanitizers))); - for (const auto &BLPath : BlacklistFiles) { + for (const auto &BLPath : UserBlacklistFiles) { SmallString<64> BlacklistOpt("-fsanitize-blacklist="); BlacklistOpt += BLPath; CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); } - for (const auto &Dep : ExtraDeps) { - SmallString<64> ExtraDepOpt("-fdepfile-entry="); - ExtraDepOpt += Dep; - CmdArgs.push_back(Args.MakeArgString(ExtraDepOpt)); + for (const auto &BLPath : SystemBlacklistFiles) { + SmallString<64> BlacklistOpt("-fsanitize-system-blacklist="); + BlacklistOpt += BLPath; + CmdArgs.push_back(Args.MakeArgString(BlacklistOpt)); } if (MsanTrackOrigins) diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 357a5106ab39..3ebbd30195b3 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -11,6 +11,7 @@ #include "ToolChains/Arch/ARM.h" #include "ToolChains/Clang.h" #include "ToolChains/InterfaceStubs.h" +#include "ToolChains/Flang.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/Sanitizers.h" #include "clang/Config/config.h" @@ -67,7 +68,8 @@ static ToolChain::RTTIMode CalculateRTTIMode(const ArgList &Args, } // -frtti is default, except for the PS4 CPU. - return (Triple.isPS4CPU()) ? ToolChain::RM_Disabled : ToolChain::RM_Enabled; + return (Triple.isPS4CPU() || Triple.isNVPTX()) ? ToolChain::RM_Disabled + : ToolChain::RM_Enabled; } ToolChain::ToolChain(const Driver &D, const llvm::Triple &T, @@ -151,6 +153,7 @@ static const DriverSuffix *FindDriverSuffix(StringRef ProgName, size_t &Pos) { {"cpp", "--driver-mode=cpp"}, {"cl", "--driver-mode=cl"}, {"++", "--driver-mode=g++"}, + {"flang", "--driver-mode=flang"}, }; for (size_t i = 0; i < llvm::array_lengthof(DriverSuffixes); ++i) { @@ -254,6 +257,12 @@ Tool *ToolChain::getClang() const { return Clang.get(); } +Tool *ToolChain::getFlang() const { + if (!Flang) + Flang.reset(new tools::Flang(*this)); + return Flang.get(); +} + Tool *ToolChain::buildAssembler() const { return new tools::ClangAs(*this); } @@ -493,6 +502,7 @@ bool ToolChain::needsGCovInstrumentation(const llvm::opt::ArgList &Args) { } Tool *ToolChain::SelectTool(const JobAction &JA) const { + if (D.IsFlangMode() && getDriver().ShouldUseFlangCompiler(JA)) return getFlang(); if (getDriver().ShouldUseClangCompiler(JA)) return getClang(); Action::ActionClass AC = JA.getKind(); if (AC == Action::AssembleJobClass && useIntegratedAs()) @@ -541,7 +551,15 @@ std::string ToolChain::GetLinkerPath() const { } types::ID ToolChain::LookupTypeForExtension(StringRef Ext) const { - return types::lookupTypeForExtension(Ext); + types::ID id = types::lookupTypeForExtension(Ext); + + // Flang always runs the preprocessor and has no notion of "preprocessed + // fortran". Here, TY_PP_Fortran is coerced to TY_Fortran to avoid treating + // them differently. + if (D.IsFlangMode() && id == types::TY_PP_Fortran) + id = types::TY_Fortran; + + return id; } bool ToolChain::HasNativeLLVMSupport() const { @@ -620,6 +638,8 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args, Triple.setArchName("arm64"); return Triple.getTriple(); } + case llvm::Triple::aarch64_32: + return getTripleString(); case llvm::Triple::arm: case llvm::Triple::armeb: case llvm::Triple::thumb: @@ -831,7 +851,7 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs, /*static*/ void ToolChain::addSystemIncludes(const ArgList &DriverArgs, ArgStringList &CC1Args, ArrayRef<StringRef> Paths) { - for (const auto Path : Paths) { + for (const auto &Path : Paths) { CC1Args.push_back("-internal-isystem"); CC1Args.push_back(DriverArgs.MakeArgString(Path)); } diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp new file mode 100644 index 000000000000..6fbff61f7656 --- /dev/null +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -0,0 +1,159 @@ +//===--- AIX.cpp - AIX ToolChain Implementations ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "AIX.h" +#include "Arch/PPC.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" + +using AIX = clang::driver::toolchains::AIX; +using namespace clang::driver; +using namespace clang::driver::tools; + +using namespace llvm::opt; + +void aix::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + const bool IsArch32Bit = getToolChain().getTriple().isArch32Bit(); + const bool IsArch64Bit = getToolChain().getTriple().isArch64Bit(); + // Only support 32 and 64 bit. + if (!IsArch32Bit && !IsArch64Bit) + llvm_unreachable("Unsupported bit width value."); + + // Specify the mode in which the as(1) command operates. + if (IsArch32Bit) { + CmdArgs.push_back("-a32"); + } else { + // Must be 64-bit, otherwise asserted already. + CmdArgs.push_back("-a64"); + } + + // Accept an undefined symbol as an extern so that an error message is not + // displayed. Otherwise, undefined symbols are flagged with error messages. + // FIXME: This should be removed when the assembly generation from the + // compiler is able to write externs properly. + CmdArgs.push_back("-u"); + + // Accept any mixture of instructions. + // On Power for AIX and Linux, this behaviour matches that of GCC for both the + // user-provided assembler source case and the compiler-produced assembler + // source case. Yet XL with user-provided assembler source would not add this. + CmdArgs.push_back("-many"); + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + // Specify assembler output file. + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + // Specify assembler input file. + // The system assembler on AIX takes exactly one input file. The driver is + // expected to invoke as(1) separately for each assembler source input file. + if (Inputs.size() != 1) + llvm_unreachable("Invalid number of input files."); + const InputInfo &II = Inputs[0]; + assert((II.isFilename() || II.isNothing()) && "Invalid input."); + if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void aix::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, const ArgList &Args, + const char *LinkingOutput) const { + const AIX &ToolChain = static_cast<const AIX &>(getToolChain()); + ArgStringList CmdArgs; + + const bool IsArch32Bit = ToolChain.getTriple().isArch32Bit(); + const bool IsArch64Bit = ToolChain.getTriple().isArch64Bit(); + // Only support 32 and 64 bit. + if (!(IsArch32Bit || IsArch64Bit)) + llvm_unreachable("Unsupported bit width value."); + + // Force static linking when "-static" is present. + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("-bnso"); + + // Specify linker output file. + assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } + + // Set linking mode (i.e., 32/64-bit) and the address of + // text and data sections based on arch bit width. + if (IsArch32Bit) { + CmdArgs.push_back("-b32"); + CmdArgs.push_back("-bpT:0x10000000"); + CmdArgs.push_back("-bpD:0x20000000"); + } else { + // Must be 64-bit, otherwise asserted already. + CmdArgs.push_back("-b64"); + CmdArgs.push_back("-bpT:0x100000000"); + CmdArgs.push_back("-bpD:0x110000000"); + } + + auto getCrt0Basename = [&Args, IsArch32Bit] { + // Enable gprofiling when "-pg" is specified. + if (Args.hasArg(options::OPT_pg)) + return IsArch32Bit ? "gcrt0.o" : "gcrt0_64.o"; + // Enable profiling when "-p" is specified. + else if (Args.hasArg(options::OPT_p)) + return IsArch32Bit ? "mcrt0.o" : "mcrt0_64.o"; + else + return IsArch32Bit ? "crt0.o" : "crt0_64.o"; + }; + + if (!Args.hasArg(options::OPT_nostdlib)) { + CmdArgs.push_back( + Args.MakeArgString(ToolChain.GetFilePath(getCrt0Basename()))); + } + + // Specify linker input file(s). + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + // Add directory to library search path. + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + // Support POSIX threads if "-pthreads" or "-pthread" is present. + if (Args.hasArg(options::OPT_pthreads, options::OPT_pthread)) + CmdArgs.push_back("-lpthreads"); + + CmdArgs.push_back("-lc"); + } + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// AIX - AIX tool chain which can call as(1) and ld(1) directly. +AIX::AIX(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : ToolChain(D, Triple, Args) { + getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); +} + +auto AIX::buildAssembler() const -> Tool * { return new aix::Assembler(*this); } + +auto AIX::buildLinker() const -> Tool * { return new aix::Linker(*this); } diff --git a/clang/lib/Driver/ToolChains/AIX.h b/clang/lib/Driver/ToolChains/AIX.h new file mode 100644 index 000000000000..69b948bc0ea8 --- /dev/null +++ b/clang/lib/Driver/ToolChains/AIX.h @@ -0,0 +1,75 @@ +//===--- AIX.h - AIX ToolChain Implementations ------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AIX_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AIX_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// aix -- Directly call system default assembler and linker. +namespace aix { + +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("aix::Assembler", "assembler", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: + Linker(const ToolChain &TC) : Tool("aix::Linker", "linker", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // end namespace aix + +} // end namespace tools +} // end namespace driver +} // end namespace clang + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY AIX : public ToolChain { +public: + AIX(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool isPICDefault() const override { return true; } + bool isPIEDefault() const override { return false; } + bool isPICDefaultForced() const override { return true; } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AIX_H diff --git a/clang/lib/Driver/ToolChains/AMDGPU.h b/clang/lib/Driver/ToolChains/AMDGPU.h index 5585cc534861..f4c78bea5cc9 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.h +++ b/clang/lib/Driver/ToolChains/AMDGPU.h @@ -55,7 +55,7 @@ protected: public: AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args); - unsigned GetDefaultDwarfVersion() const override { return 5; } + unsigned GetDefaultDwarfVersion() const override { return 4; } bool IsIntegratedAssemblerDefault() const override { return true; } bool IsMathErrnoDefault() const override { return false; } diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 3a5fe6ddeaed..9c27504dccf5 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -43,10 +43,11 @@ std::string aarch64::getAArch64TargetCPU(const ArgList &Args, else if (CPU.size()) return CPU; - // Make sure we pick "cyclone" if -arch is used or when targetting a Darwin - // OS. + // Make sure we pick the appropriate Apple CPU if -arch is used or when + // targetting a Darwin OS. if (Args.getLastArg(options::OPT_arch) || Triple.isOSDarwin()) - return "cyclone"; + return Triple.getArch() == llvm::Triple::aarch64_32 ? "apple-s4" + : "apple-a7"; return "generic"; } @@ -139,7 +140,7 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, // Handle CPU name is 'native'. if (MtuneLowerCase == "native") MtuneLowerCase = llvm::sys::getHostCPUName(); - if (MtuneLowerCase == "cyclone") { + if (MtuneLowerCase == "cyclone" || MtuneLowerCase.find("apple") == 0) { Features.push_back("+zcm"); Features.push_back("+zcz"); } diff --git a/clang/lib/Driver/ToolChains/Arch/ARM.cpp b/clang/lib/Driver/ToolChains/Arch/ARM.cpp index 68a57310ad40..a1923e731489 100644 --- a/clang/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/clang/lib/Driver/ToolChains/Arch/ARM.cpp @@ -63,12 +63,13 @@ static void getARMHWDivFeatures(const Driver &D, const Arg *A, } // Handle -mfpu=. -static void getARMFPUFeatures(const Driver &D, const Arg *A, - const ArgList &Args, StringRef FPU, - std::vector<StringRef> &Features) { +static unsigned getARMFPUFeatures(const Driver &D, const Arg *A, + const ArgList &Args, StringRef FPU, + std::vector<StringRef> &Features) { unsigned FPUID = llvm::ARM::parseFPU(FPU); if (!llvm::ARM::getFPUFeatures(FPUID, Features)) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); + return FPUID; } // Decode ARM features from string like +[no]featureA+[no]featureB+... @@ -388,18 +389,20 @@ void arm::getARMTargetFeatures(const ToolChain &TC, checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, ExtensionFeatures, Triple); // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. + unsigned FPUID = llvm::ARM::FK_INVALID; const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ); if (WaFPU) { if (FPUArg) D.Diag(clang::diag::warn_drv_unused_argument) << FPUArg->getAsString(Args); - getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6), - Features); + (void)getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6), + Features); } else if (FPUArg) { - getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); + FPUID = getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features); } else if (Triple.isAndroid() && getARMSubArchVersionNumber(Triple) >= 7) { const char *AndroidFPU = "neon"; - if (!llvm::ARM::getFPUFeatures(llvm::ARM::parseFPU(AndroidFPU), Features)) + FPUID = llvm::ARM::parseFPU(AndroidFPU); + if (!llvm::ARM::getFPUFeatures(FPUID, Features)) D.Diag(clang::diag::err_drv_clang_unsupported) << std::string("-mfpu=") + AndroidFPU; } @@ -454,21 +457,21 @@ fp16_fml_fallthrough: if (ABI == arm::FloatABI::Soft) { llvm::ARM::getFPUFeatures(llvm::ARM::FK_NONE, Features); - // Disable all features relating to hardware FP. - // FIXME: Disabling fpregs should be enough all by itself, since all - // the other FP features are dependent on it. However - // there is currently no easy way to test this in clang, so for - // now just be explicit and disable all known dependent features - // as well. - for (std::string Feature : { - "vfp2", "vfp2sp", - "vfp3", "vfp3sp", "vfp3d16", "vfp3d16sp", - "vfp4", "vfp4sp", "vfp4d16", "vfp4d16sp", - "fp-armv8", "fp-armv8sp", "fp-armv8d16", "fp-armv8d16sp", - "fullfp16", "neon", "crypto", "dotprod", "fp16fml", - "mve", "mve.fp", - "fp64", "d32", "fpregs"}) - Features.push_back(Args.MakeArgString("-" + Feature)); + // Disable all features relating to hardware FP, not already disabled by the + // above call. + Features.insert(Features.end(), {"-neon", "-crypto", "-dotprod", "-fp16fml", + "-mve", "-mve.fp", "-fpregs"}); + } else if (FPUID == llvm::ARM::FK_NONE) { + // -mfpu=none is *very* similar to -mfloat-abi=soft, only that it should not + // disable MVE-I. + Features.insert(Features.end(), + {"-neon", "-crypto", "-dotprod", "-fp16fml", "-mve.fp"}); + // Even though we remove MVE-FP, we still need to check if it was originally + // present among the requested extensions, because it implies MVE-I, which + // should not be disabled by -mfpu-none. + if (!llvm::is_contained(Features, "+mve") && + !llvm::is_contained(Features, "+mve.fp")) + Features.emplace_back("-fpregs"); } // En/disable crc code generation. diff --git a/clang/lib/Driver/ToolChains/Arch/PPC.cpp b/clang/lib/Driver/ToolChains/Arch/PPC.cpp index 3e02e57e0f6c..f1baadaebf41 100644 --- a/clang/lib/Driver/ToolChains/Arch/PPC.cpp +++ b/clang/lib/Driver/ToolChains/Arch/PPC.cpp @@ -53,10 +53,12 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) { .Case("7450", "7450") .Case("G4+", "g4+") .Case("750", "750") + .Case("8548", "e500") .Case("970", "970") .Case("G5", "g5") .Case("a2", "a2") .Case("a2q", "a2q") + .Case("e500", "e500") .Case("e500mc", "e500mc") .Case("e5500", "e5500") .Case("power3", "pwr3") @@ -68,6 +70,7 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) { .Case("power7", "pwr7") .Case("power8", "pwr8") .Case("power9", "pwr9") + .Case("future", "future") .Case("pwr3", "pwr3") .Case("pwr4", "pwr4") .Case("pwr5", "pwr5") @@ -101,6 +104,9 @@ const char *ppc::getPPCAsmModeForCPU(StringRef Name) { void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<StringRef> &Features) { + if (Triple.getSubArch() == llvm::Triple::PPCSubArch_spe) + Features.push_back("+spe"); + handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group); ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args); diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp index 624788a5874e..8c343b8693f3 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.cpp +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.cpp @@ -357,16 +357,75 @@ static bool getArchFeatures(const Driver &D, StringRef MArch, void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<StringRef> &Features) { - llvm::Optional<StringRef> MArch; - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) - MArch = A->getValue(); - else if (Triple.getOS() == llvm::Triple::Linux) - // RISC-V Linux defaults to rv{32,64}gc. - MArch = Triple.getArch() == llvm::Triple::riscv32 ? "rv32gc" : "rv64gc"; + StringRef MArch = getRISCVArch(Args, Triple); - if (MArch.hasValue() && !getArchFeatures(D, *MArch, Features, Args)) + if (!getArchFeatures(D, MArch, Features, Args)) return; + // Handle features corresponding to "-ffixed-X" options + if (Args.hasArg(options::OPT_ffixed_x1)) + Features.push_back("+reserve-x1"); + if (Args.hasArg(options::OPT_ffixed_x2)) + Features.push_back("+reserve-x2"); + if (Args.hasArg(options::OPT_ffixed_x3)) + Features.push_back("+reserve-x3"); + if (Args.hasArg(options::OPT_ffixed_x4)) + Features.push_back("+reserve-x4"); + if (Args.hasArg(options::OPT_ffixed_x5)) + Features.push_back("+reserve-x5"); + if (Args.hasArg(options::OPT_ffixed_x6)) + Features.push_back("+reserve-x6"); + if (Args.hasArg(options::OPT_ffixed_x7)) + Features.push_back("+reserve-x7"); + if (Args.hasArg(options::OPT_ffixed_x8)) + Features.push_back("+reserve-x8"); + if (Args.hasArg(options::OPT_ffixed_x9)) + Features.push_back("+reserve-x9"); + if (Args.hasArg(options::OPT_ffixed_x10)) + Features.push_back("+reserve-x10"); + if (Args.hasArg(options::OPT_ffixed_x11)) + Features.push_back("+reserve-x11"); + if (Args.hasArg(options::OPT_ffixed_x12)) + Features.push_back("+reserve-x12"); + if (Args.hasArg(options::OPT_ffixed_x13)) + Features.push_back("+reserve-x13"); + if (Args.hasArg(options::OPT_ffixed_x14)) + Features.push_back("+reserve-x14"); + if (Args.hasArg(options::OPT_ffixed_x15)) + Features.push_back("+reserve-x15"); + if (Args.hasArg(options::OPT_ffixed_x16)) + Features.push_back("+reserve-x16"); + if (Args.hasArg(options::OPT_ffixed_x17)) + Features.push_back("+reserve-x17"); + if (Args.hasArg(options::OPT_ffixed_x18)) + Features.push_back("+reserve-x18"); + if (Args.hasArg(options::OPT_ffixed_x19)) + Features.push_back("+reserve-x19"); + if (Args.hasArg(options::OPT_ffixed_x20)) + Features.push_back("+reserve-x20"); + if (Args.hasArg(options::OPT_ffixed_x21)) + Features.push_back("+reserve-x21"); + if (Args.hasArg(options::OPT_ffixed_x22)) + Features.push_back("+reserve-x22"); + if (Args.hasArg(options::OPT_ffixed_x23)) + Features.push_back("+reserve-x23"); + if (Args.hasArg(options::OPT_ffixed_x24)) + Features.push_back("+reserve-x24"); + if (Args.hasArg(options::OPT_ffixed_x25)) + Features.push_back("+reserve-x25"); + if (Args.hasArg(options::OPT_ffixed_x26)) + Features.push_back("+reserve-x26"); + if (Args.hasArg(options::OPT_ffixed_x27)) + Features.push_back("+reserve-x27"); + if (Args.hasArg(options::OPT_ffixed_x28)) + Features.push_back("+reserve-x28"); + if (Args.hasArg(options::OPT_ffixed_x29)) + Features.push_back("+reserve-x29"); + if (Args.hasArg(options::OPT_ffixed_x30)) + Features.push_back("+reserve-x30"); + if (Args.hasArg(options::OPT_ffixed_x31)) + Features.push_back("+reserve-x31"); + // -mrelax is default, unless -mno-relax is specified. if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true)) Features.push_back("+relax"); @@ -391,12 +450,132 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) { Triple.getArch() == llvm::Triple::riscv64) && "Unexpected triple"); + // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not + // configured using `--with-abi=`, then the logic for the default choice is + // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We + // deviate from GCC's default only on baremetal targets (UnknownOS) where + // neither `-march` nor `-mabi` is specified. + // + // The logic uses the following, in order: + // 1. Explicit choices using `--with-abi=` + // 2. A default based on `--with-arch=`, if provided + // 3. A default based on the target triple's arch + // + // The logic in config.gcc is a little circular but it is not inconsistent. + // + // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=` + // and `-mabi=` respectively instead. + + // 1. If `-mabi=` is specified, use it. if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) return A->getValue(); - // RISC-V Linux defaults to ilp32d/lp64d - if (Triple.getOS() == llvm::Triple::Linux) - return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32d" : "lp64d"; - else - return Triple.getArch() == llvm::Triple::riscv32 ? "ilp32" : "lp64"; + // 2. Choose a default based on `-march=` + // + // rv32g | rv32*d -> ilp32d + // rv32e -> ilp32e + // rv32* -> ilp32 + // rv64g | rv64*d -> lp64d + // rv64* -> lp64 + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { + StringRef MArch = A->getValue(); + + if (MArch.startswith_lower("rv32")) { + // FIXME: parse `March` to find `D` extension properly + if (MArch.substr(4).contains_lower("d") || + MArch.startswith_lower("rv32g")) + return "ilp32d"; + else if (MArch.startswith_lower("rv32e")) + return "ilp32e"; + else + return "ilp32"; + } else if (MArch.startswith_lower("rv64")) { + // FIXME: parse `March` to find `D` extension properly + if (MArch.substr(4).contains_lower("d") || + MArch.startswith_lower("rv64g")) + return "lp64d"; + else + return "lp64"; + } + } + + // 3. Choose a default based on the triple + // + // We deviate from GCC's defaults here: + // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only. + // - On all other OSs we use the double floating point calling convention. + if (Triple.getArch() == llvm::Triple::riscv32) { + if (Triple.getOS() == llvm::Triple::UnknownOS) + return "ilp32"; + else + return "ilp32d"; + } else { + if (Triple.getOS() == llvm::Triple::UnknownOS) + return "lp64"; + else + return "lp64d"; + } +} + +StringRef riscv::getRISCVArch(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple) { + assert((Triple.getArch() == llvm::Triple::riscv32 || + Triple.getArch() == llvm::Triple::riscv64) && + "Unexpected triple"); + + // GCC's logic around choosing a default `-march=` is complex. If GCC is not + // configured using `--with-arch=`, then the logic for the default choice is + // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We + // deviate from GCC's default only on baremetal targets (UnknownOS) where + // neither `-march` nor `-mabi` is specified. + // + // The logic uses the following, in order: + // 1. Explicit choices using `--with-arch=` + // 2. A default based on `--with-abi=`, if provided + // 3. A default based on the target triple's arch + // + // The logic in config.gcc is a little circular but it is not inconsistent. + // + // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=` + // and `-mabi=` respectively instead. + // + // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc` + // instead of `rv{XLEN}gc` though they are (currently) equivalent. + + // 1. If `-march=` is specified, use it. + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + return A->getValue(); + + // 2. Choose a default based on `-mabi=` + // + // ilp32e -> rv32e + // ilp32 | ilp32f | ilp32d -> rv32imafdc + // lp64 | lp64f | lp64d -> rv64imafdc + if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { + StringRef MABI = A->getValue(); + + if (MABI.equals_lower("ilp32e")) + return "rv32e"; + else if (MABI.startswith_lower("ilp32")) + return "rv32imafdc"; + else if (MABI.startswith_lower("lp64")) + return "rv64imafdc"; + } + + // 3. Choose a default based on the triple + // + // We deviate from GCC's defaults here: + // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac` + // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`) + if (Triple.getArch() == llvm::Triple::riscv32) { + if (Triple.getOS() == llvm::Triple::UnknownOS) + return "rv32imac"; + else + return "rv32imafdc"; + } else { + if (Triple.getOS() == llvm::Triple::UnknownOS) + return "rv64imac"; + else + return "rv64imafdc"; + } } diff --git a/clang/lib/Driver/ToolChains/Arch/RISCV.h b/clang/lib/Driver/ToolChains/Arch/RISCV.h index 10eaf3c897b6..d4a519cdab34 100644 --- a/clang/lib/Driver/ToolChains/Arch/RISCV.h +++ b/clang/lib/Driver/ToolChains/Arch/RISCV.h @@ -24,6 +24,8 @@ void getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple, std::vector<llvm::StringRef> &Features); StringRef getRISCVABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); +StringRef getRISCVArch(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); } // end namespace riscv } // namespace tools } // end namespace driver diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp index ca60b85cf8a0..2b77d59fdc66 100644 --- a/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.cpp @@ -9,15 +9,27 @@ #include "SystemZ.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" +#include "llvm/Support/Host.h" using namespace clang::driver; using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; -const char *systemz::getSystemZTargetCPU(const ArgList &Args) { - if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) - return A->getValue(); +std::string systemz::getSystemZTargetCPU(const ArgList &Args) { + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { + llvm::StringRef CPUName = A->getValue(); + + if (CPUName == "native") { + std::string CPU = llvm::sys::getHostCPUName(); + if (!CPU.empty() && CPU != "generic") + return CPU; + else + return ""; + } + + return CPUName; + } return "z10"; } diff --git a/clang/lib/Driver/ToolChains/Arch/SystemZ.h b/clang/lib/Driver/ToolChains/Arch/SystemZ.h index 11d77fa01cc8..77dcbc47be5c 100644 --- a/clang/lib/Driver/ToolChains/Arch/SystemZ.h +++ b/clang/lib/Driver/ToolChains/Arch/SystemZ.h @@ -11,6 +11,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Option/Option.h" +#include <string> #include <vector> namespace clang { @@ -18,7 +19,7 @@ namespace driver { namespace tools { namespace systemz { -const char *getSystemZTargetCPU(const llvm::opt::ArgList &Args); +std::string getSystemZTargetCPU(const llvm::opt::ArgList &Args); void getSystemZTargetFeatures(const llvm::opt::ArgList &Args, std::vector<llvm::StringRef> &Features); diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index d2b97bf6ad71..d1e0c8253b79 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -63,8 +63,7 @@ const char *x86::getX86TargetCPU(const ArgList &Args, // Select the default CPU if none was given (or detection failed). - if (Triple.getArch() != llvm::Triple::x86_64 && - Triple.getArch() != llvm::Triple::x86) + if (!Triple.isX86()) return nullptr; // This routine is only handling x86 targets. bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 55d631733add..9b3055413e9e 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -302,6 +302,96 @@ static void ParseMPreferVectorWidth(const Driver &D, const ArgList &Args, } } +static void getWebAssemblyTargetFeatures(const ArgList &Args, + std::vector<StringRef> &Features) { + handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); +} + +static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, + const ArgList &Args, ArgStringList &CmdArgs, + bool ForAS) { + const Driver &D = TC.getDriver(); + std::vector<StringRef> Features; + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + mips::getMIPSTargetFeatures(D, Triple, Args, Features); + break; + + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS); + break; + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + ppc::getPPCTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::riscv32: + case llvm::Triple::riscv64: + riscv::getRISCVTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::systemz: + systemz::getSystemZTargetFeatures(Args, Features); + break; + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: + case llvm::Triple::aarch64_be: + aarch64::getAArch64TargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + x86::getX86TargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::hexagon: + hexagon::getHexagonTargetFeatures(D, Args, Features); + break; + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + getWebAssemblyTargetFeatures(Args, Features); + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + sparc::getSparcTargetFeatures(D, Args, Features); + break; + case llvm::Triple::r600: + case llvm::Triple::amdgcn: + amdgpu::getAMDGPUTargetFeatures(D, Args, Features); + break; + case llvm::Triple::msp430: + msp430::getMSP430TargetFeatures(D, Args, Features); + } + + // Find the last of each feature. + llvm::StringMap<unsigned> LastOpt; + for (unsigned I = 0, N = Features.size(); I < N; ++I) { + StringRef Name = Features[I]; + assert(Name[0] == '-' || Name[0] == '+'); + LastOpt[Name.drop_front(1)] = I; + } + + for (unsigned I = 0, N = Features.size(); I < N; ++I) { + // If this feature was overridden, ignore it. + StringRef Name = Features[I]; + llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1)); + assert(LastI != LastOpt.end()); + unsigned Last = LastI->second; + if (Last != I) + continue; + + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back(Name.data()); + } +} + static bool shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, const llvm::Triple &Triple) { @@ -378,15 +468,20 @@ static void addExceptionArgs(const ArgList &Args, types::ID InputType, CmdArgs.push_back("-fexceptions"); } -static bool ShouldDisableAutolink(const ArgList &Args, const ToolChain &TC) { +static bool ShouldEnableAutolink(const ArgList &Args, const ToolChain &TC, + const JobAction &JA) { bool Default = true; if (TC.getTriple().isOSDarwin()) { // The native darwin assembler doesn't support the linker_option directives, // so we disable them if we think the .s file will be passed to it. Default = TC.useIntegratedAs(); } - return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink, - Default); + // The linker_option directives are intended for host compilation. + if (JA.isDeviceOffloading(Action::OFK_Cuda) || + JA.isDeviceOffloading(Action::OFK_HIP)) + Default = false; + return Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink, + Default); } static bool ShouldDisableDwarfDirectory(const ArgList &Args, @@ -443,6 +538,8 @@ static bool useFramePointerForTargetByDefault(const ArgList &Args, case llvm::Triple::ppc64le: case llvm::Triple::riscv32: case llvm::Triple::riscv64: + case llvm::Triple::amdgcn: + case llvm::Triple::r600: return !areOptimizationsEnabled(Args); default: break; @@ -506,9 +603,9 @@ getFramePointerKind(const ArgList &Args, const llvm::Triple &Triple) { bool OmitFP = A && A->getOption().matches(options::OPT_fomit_frame_pointer); bool NoOmitFP = A && A->getOption().matches(options::OPT_fno_omit_frame_pointer); - bool KeepLeaf = - Args.hasFlag(options::OPT_momit_leaf_frame_pointer, - options::OPT_mno_omit_leaf_frame_pointer, Triple.isPS4CPU()); + bool KeepLeaf = Args.hasFlag(options::OPT_momit_leaf_frame_pointer, + options::OPT_mno_omit_leaf_frame_pointer, + Triple.isAArch64() || Triple.isPS4CPU()); if (NoOmitFP || mustUseNonLeafFramePointerForTarget(Triple) || (!OmitFP && useFramePointerForTargetByDefault(Args, Triple))) { if (KeepLeaf) @@ -533,16 +630,33 @@ static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs, /// Add a CC1 and CC1AS option to specify the debug file path prefix map. static void addDebugPrefixMapArg(const Driver &D, const ArgList &Args, ArgStringList &CmdArgs) { - for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) { + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fdebug_prefix_map_EQ)) { StringRef Map = A->getValue(); if (Map.find('=') == StringRef::npos) - D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map; + D.Diag(diag::err_drv_invalid_argument_to_option) + << Map << A->getOption().getName(); else CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); A->claim(); } } +/// Add a CC1 and CC1AS option to specify the macro file path prefix map. +static void addMacroPrefixMapArg(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fmacro_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_option) + << Map << A->getOption().getName(); + else + CmdArgs.push_back(Args.MakeArgString("-fmacro-prefix-map=" + Map)); + A->claim(); + } +} + /// Vectorize at all optimization levels greater than 1 except for -Oz. /// For -Oz the loop vectorizer is disabled, while the slp vectorizer is /// enabled. @@ -802,7 +916,9 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C, if ((Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) && (EmitCovNotes || EmitCovData) && Output.isFilename()) { SmallString<128> OutputFilename; - if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) + if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT__SLASH_Fo)) + OutputFilename = FinalOutput->getValue(); + else if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) OutputFilename = FinalOutput->getValue(); else OutputFilename = llvm::sys::path::filename(Output.getBaseInput()); @@ -883,6 +999,9 @@ static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, case codegenoptions::DebugLineTablesOnly: CmdArgs.push_back("-debug-info-kind=line-tables-only"); break; + case codegenoptions::DebugInfoConstructor: + CmdArgs.push_back("-debug-info-kind=constructor"); + break; case codegenoptions::LimitedDebugInfo: CmdArgs.push_back("-debug-info-kind=limited"); break; @@ -1248,6 +1367,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, // For IAMCU add special include arguments. getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs); } + + addMacroPrefixMapArg(D, Args, CmdArgs); } // FIXME: Move to target hook. @@ -1257,6 +1378,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) { return true; case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: case llvm::Triple::arm: case llvm::Triple::armeb: @@ -1296,6 +1418,116 @@ static bool isNoCommonDefault(const llvm::Triple &Triple) { } } +static bool hasMultipleInvocations(const llvm::Triple &Triple, + const ArgList &Args) { + // Supported only on Darwin where we invoke the compiler multiple times + // followed by an invocation to lipo. + if (!Triple.isOSDarwin()) + return false; + // If more than one "-arch <arch>" is specified, we're targeting multiple + // architectures resulting in a fat binary. + return Args.getAllArgValues(options::OPT_arch).size() > 1; +} + +static bool checkRemarksOptions(const Driver &D, const ArgList &Args, + const llvm::Triple &Triple) { + // When enabling remarks, we need to error if: + // * The remark file is specified but we're targeting multiple architectures, + // which means more than one remark file is being generated. + bool hasMultipleInvocations = ::hasMultipleInvocations(Triple, Args); + bool hasExplicitOutputFile = + Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (hasMultipleInvocations && hasExplicitOutputFile) { + D.Diag(diag::err_drv_invalid_output_with_multiple_archs) + << "-foptimization-record-file"; + return false; + } + return true; +} + +static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, + const llvm::Triple &Triple, + const InputInfo &Input, + const InputInfo &Output, const JobAction &JA) { + StringRef Format = "yaml"; + if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) + Format = A->getValue(); + + CmdArgs.push_back("-opt-record-file"); + + const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (A) { + CmdArgs.push_back(A->getValue()); + } else { + bool hasMultipleArchs = + Triple.isOSDarwin() && // Only supported on Darwin platforms. + Args.getAllArgValues(options::OPT_arch).size() > 1; + + SmallString<128> F; + + if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { + if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) + F = FinalOutput->getValue(); + } else { + if (Format != "yaml" && // For YAML, keep the original behavior. + Triple.isOSDarwin() && // Enable this only on darwin, since it's the only platform supporting .dSYM bundles. + Output.isFilename()) + F = Output.getFilename(); + } + + if (F.empty()) { + // Use the input filename. + F = llvm::sys::path::stem(Input.getBaseInput()); + + // If we're compiling for an offload architecture (i.e. a CUDA device), + // we need to make the file name for the device compilation different + // from the host compilation. + if (!JA.isDeviceOffloading(Action::OFK_None) && + !JA.isDeviceOffloading(Action::OFK_Host)) { + llvm::sys::path::replace_extension(F, ""); + F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(), + Triple.normalize()); + F += "-"; + F += JA.getOffloadingArch(); + } + } + + // If we're having more than one "-arch", we should name the files + // differently so that every cc1 invocation writes to a different file. + // We're doing that by appending "-<arch>" with "<arch>" being the arch + // name from the triple. + if (hasMultipleArchs) { + // First, remember the extension. + SmallString<64> OldExtension = llvm::sys::path::extension(F); + // then, remove it. + llvm::sys::path::replace_extension(F, ""); + // attach -<arch> to it. + F += "-"; + F += Triple.getArchName(); + // put back the extension. + llvm::sys::path::replace_extension(F, OldExtension); + } + + SmallString<32> Extension; + Extension += "opt."; + Extension += Format; + + llvm::sys::path::replace_extension(F, Extension); + CmdArgs.push_back(Args.MakeArgString(F)); + } + + if (const Arg *A = + Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { + CmdArgs.push_back("-opt-record-passes"); + CmdArgs.push_back(A->getValue()); + } + + if (!Format.empty()) { + CmdArgs.push_back("-opt-record-format"); + CmdArgs.push_back(Format.data()); + } +} + namespace { void RenderARMABI(const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs) { @@ -1379,6 +1611,7 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, break; case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: AddAArch64TargetArgs(Args, CmdArgs); CmdArgs.push_back("-fallow-half-arguments-and-returns"); @@ -1432,56 +1665,6 @@ void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, } } -// Parse -mbranch-protection=<protection>[+<protection>]* where -// <protection> ::= standard | none | [bti,pac-ret[+b-key,+leaf]*] -// Returns a triple of (return address signing Scope, signing key, require -// landing pads) -static std::tuple<StringRef, StringRef, bool> -ParseAArch64BranchProtection(const Driver &D, const ArgList &Args, - const Arg *A) { - StringRef Scope = "none"; - StringRef Key = "a_key"; - bool IndirectBranches = false; - - StringRef Value = A->getValue(); - // This maps onto -mbranch-protection=<scope>+<key> - - if (Value.equals("standard")) { - Scope = "non-leaf"; - Key = "a_key"; - IndirectBranches = true; - - } else if (!Value.equals("none")) { - SmallVector<StringRef, 4> BranchProtection; - StringRef(A->getValue()).split(BranchProtection, '+'); - - auto Protection = BranchProtection.begin(); - while (Protection != BranchProtection.end()) { - if (Protection->equals("bti")) - IndirectBranches = true; - else if (Protection->equals("pac-ret")) { - Scope = "non-leaf"; - while (++Protection != BranchProtection.end()) { - // Inner loop as "leaf" and "b-key" options must only appear attached - // to pac-ret. - if (Protection->equals("leaf")) - Scope = "all"; - else if (Protection->equals("b-key")) - Key = "b_key"; - else - break; - } - Protection--; - } else - D.Diag(diag::err_invalid_branch_protection) - << *Protection << A->getAsString(Args); - Protection++; - } - } - - return std::make_tuple(Scope, Key, IndirectBranches); -} - namespace { void RenderAArch64ABI(const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs) { @@ -1553,9 +1736,16 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, << Scope << A->getAsString(Args); Key = "a_key"; IndirectBranches = false; - } else - std::tie(Scope, Key, IndirectBranches) = - ParseAArch64BranchProtection(D, Args, A); + } else { + StringRef Err; + llvm::AArch64::ParsedBranchProtection PBP; + if (!llvm::AArch64::parseBranchProtection(A->getValue(), PBP, Err)) + D.Diag(diag::err_invalid_branch_protection) + << Err << A->getAsString(Args); + Scope = PBP.Scope; + Key = PBP.Key; + IndirectBranches = PBP.BranchTargetEnforcement; + } CmdArgs.push_back( Args.MakeArgString(Twine("-msign-return-address=") + Scope)); @@ -1713,7 +1903,8 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Select the ABI to use. const char *ABIName = nullptr; - if (getToolChain().getTriple().isOSLinux()) + const llvm::Triple &T = getToolChain().getTriple(); + if (T.isOSBinFormatELF()) { switch (getToolChain().getArch()) { case llvm::Triple::ppc64: { // When targeting a processor that supports QPX, or if QPX is @@ -1728,7 +1919,10 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, break; } - ABIName = "elfv1"; + if (T.isMusl() || (T.isOSFreeBSD() && T.getOSMajorVersion() >= 13)) + ABIName = "elfv2"; + else + ABIName = "elfv1"; break; } case llvm::Triple::ppc64le: @@ -1737,6 +1931,7 @@ void Clang::AddPPCTargetArgs(const ArgList &Args, default: break; } + } bool IEEELongDouble = false; for (const Arg *A : Args.filtered(options::OPT_mabi_EQ)) { @@ -1804,12 +1999,75 @@ void Clang::AddSparcTargetArgs(const ArgList &Args, void Clang::AddSystemZTargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - if (Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false)) + bool HasBackchain = Args.hasFlag(options::OPT_mbackchain, + options::OPT_mno_backchain, false); + bool HasPackedStack = Args.hasFlag(options::OPT_mpacked_stack, + options::OPT_mno_packed_stack, false); + if (HasBackchain && HasPackedStack) { + const Driver &D = getToolChain().getDriver(); + D.Diag(diag::err_drv_unsupported_opt) + << Args.getLastArg(options::OPT_mpacked_stack)->getAsString(Args) + + " " + Args.getLastArg(options::OPT_mbackchain)->getAsString(Args); + } + if (HasBackchain) CmdArgs.push_back("-mbackchain"); + if (HasPackedStack) + CmdArgs.push_back("-mpacked-stack"); +} + +static void addX86AlignBranchArgs(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasArg(options::OPT_mbranches_within_32B_boundaries)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-x86-branches-within-32B-boundaries"); + } + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_boundary_EQ)) { + StringRef Value = A->getValue(); + unsigned Boundary; + if (Value.getAsInteger(10, Boundary) || Boundary < 16 || + !llvm::isPowerOf2_64(Boundary)) { + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); + } else { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back( + Args.MakeArgString("-x86-align-branch-boundary=" + Twine(Boundary))); + } + } + if (const Arg *A = Args.getLastArg(options::OPT_malign_branch_EQ)) { + std::string AlignBranch; + for (StringRef T : A->getValues()) { + if (T != "fused" && T != "jcc" && T != "jmp" && T != "call" && + T != "ret" && T != "indirect") + D.Diag(diag::err_drv_invalid_malign_branch_EQ) + << T << "fused, jcc, jmp, call, ret, indirect"; + if (!AlignBranch.empty()) + AlignBranch += '+'; + AlignBranch += T; + } + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch=" + AlignBranch)); + } + if (const Arg *A = + Args.getLastArg(options::OPT_malign_branch_prefix_size_EQ)) { + StringRef Value = A->getValue(); + unsigned PrefixSize; + if (Value.getAsInteger(10, PrefixSize) || PrefixSize > 5) { + D.Diag(diag::err_drv_invalid_argument_to_option) + << Value << A->getOption().getName(); + } else { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-align-branch-prefix-size=" + + Twine(PrefixSize))); + } + } } void Clang::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getDriver(); + addX86AlignBranchArgs(D, Args, CmdArgs); + if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || Args.hasArg(options::OPT_mkernel) || Args.hasArg(options::OPT_fapple_kext)) @@ -1839,10 +2097,10 @@ void Clang::AddX86TargetArgs(const ArgList &Args, CmdArgs.push_back("-mllvm"); CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); } else { - getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) + D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; } - } else if (getToolChain().getDriver().IsCLMode()) { + } else if (D.IsCLMode()) { CmdArgs.push_back("-mllvm"); CmdArgs.push_back("-x86-asm-syntax=intel"); } @@ -2193,6 +2451,12 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } else if (Value == "-fdebug-compilation-dir") { CmdArgs.push_back("-fdebug-compilation-dir"); TakeNextArg = true; + } else if (Value.consume_front("-fdebug-compilation-dir=")) { + // The flag is a -Wa / -Xassembler argument and Options doesn't + // parse the argument, so this isn't automatically aliased to + // -fdebug-compilation-dir (without '=') here. + CmdArgs.push_back("-fdebug-compilation-dir"); + CmdArgs.push_back(Value.data()); } else { D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Value; @@ -2229,9 +2493,18 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, bool AssociativeMath = false; bool ReciprocalMath = false; bool SignedZeros = true; - bool TrappingMath = true; + bool TrappingMath = false; // Implemented via -ffp-exception-behavior + bool TrappingMathPresent = false; // Is trapping-math in args, and not + // overriden by ffp-exception-behavior? + bool RoundingFPMath = false; + bool RoundingMathPresent = false; // Is rounding-math in args? + // -ffp-model values: strict, fast, precise + StringRef FPModel = ""; + // -ffp-exception-behavior options: strict, maytrap, ignore + StringRef FPExceptionBehavior = ""; StringRef DenormalFPMath = ""; StringRef FPContract = ""; + bool StrictFPModel = false; if (const Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { CmdArgs.push_back("-mlimit-float-precision"); @@ -2239,7 +2512,65 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, } for (const Arg *A : Args) { - switch (A->getOption().getID()) { + auto optID = A->getOption().getID(); + bool PreciseFPModel = false; + switch (optID) { + default: + break; + case options::OPT_ffp_model_EQ: { + // If -ffp-model= is seen, reset to fno-fast-math + HonorINFs = true; + HonorNaNs = true; + // Turning *off* -ffast-math restores the toolchain default. + MathErrno = TC.IsMathErrnoDefault(); + AssociativeMath = false; + ReciprocalMath = false; + SignedZeros = true; + // -fno_fast_math restores default denormal and fpcontract handling + DenormalFPMath = ""; + FPContract = ""; + StringRef Val = A->getValue(); + if (OFastEnabled && !Val.equals("fast")) { + // Only -ffp-model=fast is compatible with OFast, ignore. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-model=" + Val) + << "-Ofast"; + break; + } + StrictFPModel = false; + PreciseFPModel = true; + // ffp-model= is a Driver option, it is entirely rewritten into more + // granular options before being passed into cc1. + // Use the gcc option in the switch below. + if (!FPModel.empty() && !FPModel.equals(Val)) { + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-model=" + FPModel) + << Args.MakeArgString("-ffp-model=" + Val); + FPContract = ""; + } + if (Val.equals("fast")) { + optID = options::OPT_ffast_math; + FPModel = Val; + FPContract = "fast"; + } else if (Val.equals("precise")) { + optID = options::OPT_ffp_contract; + FPModel = Val; + FPContract = "fast"; + PreciseFPModel = true; + } else if (Val.equals("strict")) { + StrictFPModel = true; + optID = options::OPT_frounding_math; + FPExceptionBehavior = "strict"; + FPModel = Val; + TrappingMath = true; + } else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + break; + } + } + + switch (optID) { // If this isn't an FP option skip the claim below default: continue; @@ -2256,20 +2587,83 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, case options::OPT_fno_reciprocal_math: ReciprocalMath = false; break; case options::OPT_fsigned_zeros: SignedZeros = true; break; case options::OPT_fno_signed_zeros: SignedZeros = false; break; - case options::OPT_ftrapping_math: TrappingMath = true; break; - case options::OPT_fno_trapping_math: TrappingMath = false; break; + case options::OPT_ftrapping_math: + if (!TrappingMathPresent && !FPExceptionBehavior.empty() && + !FPExceptionBehavior.equals("strict")) + // Warn that previous value of option is overridden. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) + << "-ftrapping-math"; + TrappingMath = true; + TrappingMathPresent = true; + FPExceptionBehavior = "strict"; + break; + case options::OPT_fno_trapping_math: + if (!TrappingMathPresent && !FPExceptionBehavior.empty() && + !FPExceptionBehavior.equals("ignore")) + // Warn that previous value of option is overridden. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) + << "-fno-trapping-math"; + TrappingMath = false; + TrappingMathPresent = true; + FPExceptionBehavior = "ignore"; + break; + + case options::OPT_frounding_math: + RoundingFPMath = true; + RoundingMathPresent = true; + break; + + case options::OPT_fno_rounding_math: + RoundingFPMath = false; + RoundingMathPresent = false; + break; case options::OPT_fdenormal_fp_math_EQ: DenormalFPMath = A->getValue(); break; - // Validate and pass through -fp-contract option. + // Validate and pass through -ffp-contract option. case options::OPT_ffp_contract: { StringRef Val = A->getValue(); - if (Val == "fast" || Val == "on" || Val == "off") + if (PreciseFPModel) { + // -ffp-model=precise enables ffp-contract=fast as a side effect + // the FPContract value has already been set to a string literal + // and the Val string isn't a pertinent value. + ; + } else if (Val.equals("fast") || Val.equals("on") || Val.equals("off")) FPContract = Val; else D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + break; + } + + // Validate and pass through -ffp-model option. + case options::OPT_ffp_model_EQ: + // This should only occur in the error case + // since the optID has been replaced by a more granular + // floating point option. + break; + + // Validate and pass through -ffp-exception-behavior option. + case options::OPT_ffp_exception_behavior_EQ: { + StringRef Val = A->getValue(); + if (!TrappingMathPresent && !FPExceptionBehavior.empty() && + !FPExceptionBehavior.equals(Val)) + // Warn that previous value of option is overridden. + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << Args.MakeArgString("-ffp-exception-behavior=" + FPExceptionBehavior) + << Args.MakeArgString("-ffp-exception-behavior=" + Val); + TrappingMath = TrappingMathPresent = false; + if (Val.equals("ignore") || Val.equals("maytrap")) + FPExceptionBehavior = Val; + else if (Val.equals("strict")) { + FPExceptionBehavior = Val; + TrappingMath = TrappingMathPresent = true; + } else + D.Diag(diag::err_drv_unsupported_option_argument) << A->getOption().getName() << Val; break; } @@ -2288,12 +2682,14 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ReciprocalMath = true; SignedZeros = false; TrappingMath = false; + FPExceptionBehavior = ""; break; case options::OPT_fno_unsafe_math_optimizations: AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; TrappingMath = true; + FPExceptionBehavior = "strict"; // -fno_unsafe_math_optimizations restores default denormal handling DenormalFPMath = ""; break; @@ -2311,6 +2707,7 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, ReciprocalMath = true; SignedZeros = false; TrappingMath = false; + RoundingFPMath = false; // If fast-math is set then set the fp-contract mode to fast. FPContract = "fast"; break; @@ -2324,12 +2721,31 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, AssociativeMath = false; ReciprocalMath = false; SignedZeros = true; - TrappingMath = true; + TrappingMath = false; + RoundingFPMath = false; // -fno_fast_math restores default denormal and fpcontract handling DenormalFPMath = ""; FPContract = ""; break; } + if (StrictFPModel) { + // If -ffp-model=strict has been specified on command line but + // subsequent options conflict then emit warning diagnostic. + if (HonorINFs && HonorNaNs && + !AssociativeMath && !ReciprocalMath && + SignedZeros && TrappingMath && RoundingFPMath && + DenormalFPMath.empty() && FPContract.empty()) + // OK: Current Arg doesn't conflict with -ffp-model=strict + ; + else { + StrictFPModel = false; + FPModel = ""; + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << "-ffp-model=strict" << + ((A->getNumValues() == 0) ? A->getSpelling() + : Args.MakeArgString(A->getSpelling() + A->getValue())); + } + } // If we handled this option claim it A->claim(); @@ -2357,7 +2773,11 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (ReciprocalMath) CmdArgs.push_back("-freciprocal-math"); - if (!TrappingMath) + if (TrappingMath) { + // FP Exception Behavior is also set to strict + assert(FPExceptionBehavior.equals("strict")); + CmdArgs.push_back("-ftrapping-math"); + } else if (TrappingMathPresent) CmdArgs.push_back("-fno-trapping-math"); if (!DenormalFPMath.empty()) @@ -2367,14 +2787,37 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, if (!FPContract.empty()) CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); + if (!RoundingFPMath) + CmdArgs.push_back(Args.MakeArgString("-fno-rounding-math")); + + if (RoundingFPMath && RoundingMathPresent) + CmdArgs.push_back(Args.MakeArgString("-frounding-math")); + + if (!FPExceptionBehavior.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-exception-behavior=" + + FPExceptionBehavior)); + ParseMRecip(D, Args, CmdArgs); // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the // individual features enabled by -ffast-math instead of the option itself as // that's consistent with gcc's behaviour. if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && - ReciprocalMath && !SignedZeros && !TrappingMath) + ReciprocalMath && !SignedZeros && !TrappingMath && !RoundingFPMath) { CmdArgs.push_back("-ffast-math"); + if (FPModel.equals("fast")) { + if (FPContract.equals("fast")) + // All set, do nothing. + ; + else if (FPContract.empty()) + // Enable -ffp-contract=fast + CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); + else + D.Diag(clang::diag::warn_drv_overriding_flag_option) + << "-ffp-model=fast" + << Args.MakeArgString("-ffp-contract=" + FPContract); + } + } // Handle __FINITE_MATH_ONLY__ similarly. if (!HonorINFs && !HonorNaNs) @@ -2423,8 +2866,13 @@ static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork"); } - if (Triple.isOSDarwin()) + if (Triple.isOSDarwin()) { CmdArgs.push_back("-analyzer-checker=osx"); + CmdArgs.push_back( + "-analyzer-checker=security.insecureAPI.decodeValueOfObjCType"); + } + else if (Triple.isOSFuchsia()) + CmdArgs.push_back("-analyzer-checker=fuchsia"); CmdArgs.push_back("-analyzer-checker=deadcode"); @@ -3145,12 +3593,11 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, // This avoids having to monkey around further in cc1 other than to disable // codeview if not running in a Windows environment. Perhaps even that // decision should be made in the driver as well though. - unsigned DWARFVersion = 0; llvm::DebuggerKind DebuggerTuning = TC.getDefaultDebuggerTuning(); bool SplitDWARFInlining = Args.hasFlag(options::OPT_fsplit_dwarf_inlining, - options::OPT_fno_split_dwarf_inlining, true); + options::OPT_fno_split_dwarf_inlining, false); Args.ClaimAllArgs(options::OPT_g_Group); @@ -3198,11 +3645,16 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, } // If a -gdwarf argument appeared, remember it. - if (const Arg *A = - Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, - options::OPT_gdwarf_4, options::OPT_gdwarf_5)) - if (checkDebugInfoOption(A, Args, D, TC)) - DWARFVersion = DwarfVersionNum(A->getSpelling()); + const Arg *GDwarfN = Args.getLastArg( + options::OPT_gdwarf_2, options::OPT_gdwarf_3, options::OPT_gdwarf_4, + options::OPT_gdwarf_5, options::OPT_gdwarf); + bool EmitDwarf = false; + if (GDwarfN) { + if (checkDebugInfoOption(GDwarfN, Args, D, TC)) + EmitDwarf = true; + else + GDwarfN = nullptr; + } if (const Arg *A = Args.getLastArg(options::OPT_gcodeview)) { if (checkDebugInfoOption(A, Args, D, TC)) @@ -3211,18 +3663,36 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, // If the user asked for debug info but did not explicitly specify -gcodeview // or -gdwarf, ask the toolchain for the default format. - if (!EmitCodeView && DWARFVersion == 0 && + if (!EmitCodeView && !EmitDwarf && DebugInfoKind != codegenoptions::NoDebugInfo) { switch (TC.getDefaultDebugFormat()) { case codegenoptions::DIF_CodeView: EmitCodeView = true; break; case codegenoptions::DIF_DWARF: - DWARFVersion = TC.GetDefaultDwarfVersion(); + EmitDwarf = true; break; } } + unsigned DWARFVersion = 0; + unsigned DefaultDWARFVersion = ParseDebugDefaultVersion(TC, Args); + if (EmitDwarf) { + // Start with the platform default DWARF version + DWARFVersion = TC.GetDefaultDwarfVersion(); + assert(DWARFVersion && "toolchain default DWARF version must be nonzero"); + + // If the user specified a default DWARF version, that takes precedence + // over the platform default. + if (DefaultDWARFVersion) + DWARFVersion = DefaultDWARFVersion; + + // Override with a user-specified DWARF version + if (GDwarfN) + if (auto ExplicitVersion = DwarfVersionNum(GDwarfN->getSpelling())) + DWARFVersion = ExplicitVersion; + } + // -gline-directives-only supported only for the DWARF debug info. if (DWARFVersion == 0 && DebugInfoKind == codegenoptions::DebugDirectivesOnly) DebugInfoKind = codegenoptions::NoDebugInfo; @@ -3296,9 +3766,20 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, } } + // Omit inline line tables if requested. + if (Args.hasFlag(options::OPT_gno_inline_line_tables, + options::OPT_ginline_line_tables, false)) { + CmdArgs.push_back("-gno-inline-line-tables"); + } + // Adjust the debug info kind for the given toolchain. TC.adjustDebugInfoKind(DebugInfoKind, Args); + // When emitting remarks, we need at least debug lines in the output. + if (willEmitRemarks(Args) && + DebugInfoKind <= codegenoptions::DebugDirectivesOnly) + DebugInfoKind = codegenoptions::DebugLineTablesOnly; + RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DWARFVersion, DebuggerTuning); @@ -3339,6 +3820,10 @@ static void RenderDebugOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-generate-arange-section"); } + if (Args.hasFlag(options::OPT_fforce_dwarf_frame, + options::OPT_fno_force_dwarf_frame, false)) + CmdArgs.push_back("-fforce-dwarf-frame"); + if (Args.hasFlag(options::OPT_fdebug_types_section, options::OPT_fno_debug_types_section, false)) { if (!T.isOSBinFormatELF()) { @@ -3641,6 +4126,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); } + if (Args.getLastArg(options::OPT_fthin_link_bitcode_EQ)) + Args.AddLastArg(CmdArgs, options::OPT_fthin_link_bitcode_EQ); + if (Args.getLastArg(options::OPT_save_temps_EQ)) Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); @@ -3653,7 +4141,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Disable all llvm IR level optimizations. CmdArgs.push_back("-disable-llvm-passes"); - // Render target options such as -fuse-init-array on modern ELF platforms. + // Render target options. TC.addClangTargetOptions(Args, CmdArgs, JA.getOffloadingDeviceKind()); // reject options that shouldn't be supported in bitcode @@ -3718,6 +4206,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RenderARMABI(Triple, Args, CmdArgs); break; case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: RenderAArch64ABI(Triple, Args, CmdArgs); break; @@ -4009,8 +4498,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, RenderFloatingPointOptions(TC, D, OFastEnabled, Args, CmdArgs); if (Arg *A = Args.getLastArg(options::OPT_LongDouble_Group)) { - if (TC.getArch() == llvm::Triple::x86 || - TC.getArch() == llvm::Triple::x86_64) + if (TC.getTriple().isX86()) A->render(Args, CmdArgs); else if ((TC.getArch() == llvm::Triple::ppc || TC.getTriple().isPPC64()) && (A->getOption().getID() != options::OPT_mlong_double_80)) @@ -4097,6 +4585,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } + if (Arg *A = Args.getLastArg(options::OPT_mtls_size_EQ)) { + StringRef Value = A->getValue(); + unsigned TLSSize = 0; + Value.getAsInteger(10, TLSSize); + if (!Triple.isAArch64() || !Triple.isOSBinFormatELF()) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getOption().getName() << TripleStr; + if (TLSSize != 12 && TLSSize != 24 && TLSSize != 32 && TLSSize != 48) + D.Diag(diag::err_drv_invalid_int_value) + << A->getOption().getName() << Value; + Args.AddLastArg(CmdArgs, options::OPT_mtls_size_EQ); + } + // Add the target cpu std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); if (!CPU.empty()) { @@ -4362,7 +4863,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (ShouldDisableDwarfDirectory(Args, TC)) CmdArgs.push_back("-fno-dwarf-directory-asm"); - if (ShouldDisableAutolink(Args, TC)) + if (!ShouldEnableAutolink(Args, TC, JA)) CmdArgs.push_back("-fno-autolink"); // Add in -fdebug-compilation-dir if necessary. @@ -4394,9 +4895,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_fexperimental_new_constant_interpreter)) CmdArgs.push_back("-fexperimental-new-constant-interpreter"); - if (Args.hasArg(options::OPT_fforce_experimental_new_constant_interpreter)) - CmdArgs.push_back("-fforce-experimental-new-constant-interpreter"); - if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) { CmdArgs.push_back("-fbracket-depth"); CmdArgs.push_back(A->getValue()); @@ -4532,6 +5030,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fnoopenmp-use-tls"); Args.AddLastArg(CmdArgs, options::OPT_fopenmp_simd, options::OPT_fno_openmp_simd); + Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_enable_irbuilder); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_number_of_sm_EQ); Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_cuda_blocks_per_sm_EQ); @@ -4576,11 +5075,50 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, const XRayArgs &XRay = TC.getXRayArgs(); XRay.addArgs(TC, Args, CmdArgs, InputType); - if (TC.SupportsProfiling()) + if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) { + StringRef S0 = A->getValue(), S = S0; + unsigned Size, Start = 0; + if (!Triple.isAArch64() && Triple.getArch() != llvm::Triple::x86 && + Triple.getArch() != llvm::Triple::x86_64) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + else if (S.consumeInteger(10, Size) || + (!S.empty() && (!S.consume_front(",") || + S.consumeInteger(10, Start) || !S.empty()))) + D.Diag(diag::err_drv_invalid_argument_to_option) + << S0 << A->getOption().getName(); + else if (Start) + D.Diag(diag::err_drv_unsupported_fpatchable_function_entry_argument); + else + CmdArgs.push_back(Args.MakeArgString(A->getSpelling() + Twine(Size))); + } + + if (TC.SupportsProfiling()) { Args.AddLastArg(CmdArgs, options::OPT_pg); - if (TC.SupportsProfiling()) - Args.AddLastArg(CmdArgs, options::OPT_mfentry); + llvm::Triple::ArchType Arch = TC.getArch(); + if (Arg *A = Args.getLastArg(options::OPT_mfentry)) { + if (Arch == llvm::Triple::systemz || TC.getTriple().isX86()) + A->render(Args, CmdArgs); + else + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + if (Arg *A = Args.getLastArg(options::OPT_mnop_mcount)) { + if (Arch == llvm::Triple::systemz) + A->render(Args, CmdArgs); + else + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + if (Arg *A = Args.getLastArg(options::OPT_mrecord_mcount)) { + if (Arch == llvm::Triple::systemz) + A->render(Args, CmdArgs); + else + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getAsString(Args) << TripleStr; + } + } if (Args.getLastArg(options::OPT_fapple_kext) || (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType))) @@ -4595,6 +5133,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_ftime_trace_granularity_EQ); Args.AddLastArg(CmdArgs, options::OPT_ftrapv); Args.AddLastArg(CmdArgs, options::OPT_malign_double); + Args.AddLastArg(CmdArgs, options::OPT_fno_temp_file); if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { CmdArgs.push_back("-ftrapv-handler"); @@ -5112,66 +5651,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fapple-pragma-pack"); // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. - if (Args.hasFlag(options::OPT_fsave_optimization_record, - options::OPT_foptimization_record_file_EQ, - options::OPT_fno_save_optimization_record, false) || - Args.hasFlag(options::OPT_fsave_optimization_record_EQ, - options::OPT_fno_save_optimization_record, false) || - Args.hasFlag(options::OPT_foptimization_record_passes_EQ, - options::OPT_fno_save_optimization_record, false)) { - CmdArgs.push_back("-opt-record-file"); - - const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); - if (A) { - CmdArgs.push_back(A->getValue()); - } else { - SmallString<128> F; - - if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { - if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) - F = FinalOutput->getValue(); - } - - if (F.empty()) { - // Use the input filename. - F = llvm::sys::path::stem(Input.getBaseInput()); - - // If we're compiling for an offload architecture (i.e. a CUDA device), - // we need to make the file name for the device compilation different - // from the host compilation. - if (!JA.isDeviceOffloading(Action::OFK_None) && - !JA.isDeviceOffloading(Action::OFK_Host)) { - llvm::sys::path::replace_extension(F, ""); - F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(), - Triple.normalize()); - F += "-"; - F += JA.getOffloadingArch(); - } - } - - std::string Extension = "opt."; - if (const Arg *A = - Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) - Extension += A->getValue(); - else - Extension += "yaml"; - - llvm::sys::path::replace_extension(F, Extension); - CmdArgs.push_back(Args.MakeArgString(F)); - } - - if (const Arg *A = - Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { - CmdArgs.push_back("-opt-record-passes"); - CmdArgs.push_back(A->getValue()); - } - - if (const Arg *A = - Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) { - CmdArgs.push_back("-opt-record-format"); - CmdArgs.push_back(A->getValue()); - } - } + if (willEmitRemarks(Args) && checkRemarksOptions(D, Args, Triple)) + renderRemarksOptions(Args, CmdArgs, Triple, Input, Output, JA); bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports, options::OPT_fno_rewrite_imports, false); @@ -5331,6 +5812,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fcuda-short-ptr"); } + if (IsHIP) + CmdArgs.push_back("-fcuda-allow-variadic-functions"); + // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path // to specify the result of the compile phase on the host, so the meaningful // device declarations can be identified. Also, -fopenmp-is-device is passed @@ -5395,7 +5879,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fwhole-program-vtables"); } - bool DefaultsSplitLTOUnit = WholeProgramVTables || Sanitize.needsLTO(); + bool DefaultsSplitLTOUnit = + (WholeProgramVTables || Sanitize.needsLTO()) && + (D.getLTOMode() == LTOK_Full || TC.canSplitThinLTOUnit()); bool SplitLTOUnit = Args.hasFlag(options::OPT_fsplit_lto_unit, options::OPT_fno_split_lto_unit, DefaultsSplitLTOUnit); @@ -5467,11 +5953,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // We only support -moutline in AArch64 right now. If we're not compiling // for AArch64, emit a warning and ignore the flag. Otherwise, add the // proper mllvm flags. - if (Triple.getArch() != llvm::Triple::aarch64) { + if (Triple.getArch() != llvm::Triple::aarch64 && + Triple.getArch() != llvm::Triple::aarch64_32) { D.Diag(diag::warn_drv_moutline_unsupported_opt) << Triple.getArchName(); } else { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-enable-machine-outliner"); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-enable-machine-outliner"); } } else { // Disable all outlining behaviour. @@ -5485,7 +5972,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, TC.getTriple().isOSBinFormatCOFF()) && !TC.getTriple().isPS4() && !TC.getTriple().isOSNetBSD() && - !Distro(D.getVFS()).IsGentoo() && + !Distro(D.getVFS(), TC.getTriple()).IsGentoo() && !TC.getTriple().isAndroid() && TC.useIntegratedAs())) CmdArgs.push_back("-faddrsig"); @@ -5503,8 +5990,16 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Output.getType() == types::TY_Dependencies) { // Handled with other dependency code. } else if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); + if (Output.getType() == clang::driver::types::TY_IFS_CPP || + Output.getType() == clang::driver::types::TY_IFS) { + SmallString<128> OutputFilename(Output.getFilename()); + llvm::sys::path::replace_extension(OutputFilename, "ifs"); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Args.MakeArgString(OutputFilename)); + } else { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } } else { assert(Output.isNothing() && "Invalid output."); } @@ -5538,6 +6033,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // fails, so that the main compilation's fallback to cl.exe runs. C.addCommand(std::make_unique<ForceSuccessCommand>(JA, *this, Exec, CmdArgs, Inputs)); + } else if (D.CC1Main && !D.CCGenDiagnostics) { + // Invoke the CC1 directly in this process + C.addCommand( + std::make_unique<CC1Command>(JA, *this, Exec, CmdArgs, Inputs)); } else { C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } @@ -5872,8 +6371,7 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, } unsigned VolatileOptionID; - if (getToolChain().getArch() == llvm::Triple::x86_64 || - getToolChain().getArch() == llvm::Triple::x86) + if (getToolChain().getTriple().isX86()) VolatileOptionID = options::OPT__SLASH_volatile_ms; else VolatileOptionID = options::OPT__SLASH_volatile_iso; @@ -5967,26 +6465,19 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, } if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { - SmallVector<StringRef, 1> SplitArgs; - StringRef(A->getValue()).split(SplitArgs, ","); - bool Instrument = false; - bool NoChecks = false; - for (StringRef Arg : SplitArgs) { - if (Arg.equals_lower("cf")) - Instrument = true; - else if (Arg.equals_lower("cf-")) - Instrument = false; - else if (Arg.equals_lower("nochecks")) - NoChecks = true; - else if (Arg.equals_lower("nochecks-")) - NoChecks = false; - else - D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << Arg; - } - // Currently there's no support emitting CFG instrumentation; the flag only - // emits the table of address-taken functions. - if (Instrument || NoChecks) + StringRef GuardArgs = A->getValue(); + // The only valid options are "cf", "cf,nochecks", and "cf-". + if (GuardArgs.equals_lower("cf")) { + // Emit CFG instrumentation and the table of address-taken functions. CmdArgs.push_back("-cfguard"); + } else if (GuardArgs.equals_lower("cf,nochecks")) { + // Emit only the table of address-taken functions. + CmdArgs.push_back("-cfguard-no-checks"); + } else if (GuardArgs.equals_lower("cf-")) { + // Do nothing, but we might want to emit a security warning in future. + } else { + D.Diag(diag::err_drv_invalid_value) << A->getSpelling() << GuardArgs; + } } } @@ -6040,6 +6531,8 @@ void ClangAs::AddMIPSTargetArgs(const ArgList &Args, void ClangAs::AddX86TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { + addX86AlignBranchArgs(getToolChain().getDriver(), Args, CmdArgs); + if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { StringRef Value = A->getValue(); if (Value == "intel" || Value == "att") { @@ -6134,6 +6627,11 @@ void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, if (WantDebug) DwarfVersion = DwarfVersionNum(A->getSpelling()); } + + unsigned DefaultDwarfVersion = ParseDebugDefaultVersion(getToolChain(), Args); + if (DwarfVersion == 0) + DwarfVersion = DefaultDwarfVersion; + if (DwarfVersion == 0) DwarfVersion = getToolChain().GetDefaultDwarfVersion(); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 10743559e048..37ec73468570 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -11,12 +11,8 @@ #include "Arch/ARM.h" #include "Arch/Mips.h" #include "Arch/PPC.h" -#include "Arch/RISCV.h" -#include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "Arch/X86.h" -#include "AMDGPU.h" -#include "MSP430.h" #include "HIP.h" #include "Hexagon.h" #include "InputInfo.h" @@ -257,6 +253,7 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, return ""; case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: return aarch64::getAArch64TargetCPU(Args, T, A); @@ -488,14 +485,6 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, if (!StatsFile.empty()) CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=stats-file=") + StatsFile)); - - getTargetFeatures(ToolChain, ToolChain.getTriple(), Args, CmdArgs, - /* ForAS= */ false, /* ForLTOPlugin= */ true); - - StringRef ABIName = tools::getTargetABI(Args, ToolChain.getTriple()); - if (!ABIName.empty()) - CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=-target-abi=") + ABIName)); } void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, @@ -1138,6 +1127,21 @@ unsigned tools::ParseFunctionAlignment(const ToolChain &TC, return Value ? llvm::Log2_32_Ceil(std::min(Value, 65536u)) : Value; } +unsigned tools::ParseDebugDefaultVersion(const ToolChain &TC, + const ArgList &Args) { + const Arg *A = Args.getLastArg(options::OPT_fdebug_default_version); + + if (!A) + return 0; + + unsigned Value = 0; + if (StringRef(A->getValue()).getAsInteger(10, Value) || Value > 5 || + Value < 2) + TC.getDriver().Diag(diag::err_drv_invalid_int_value) + << A->getAsString(Args) << A->getValue(); + return Value; +} + void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs) { llvm::Reloc::Model RelocationModel; @@ -1205,7 +1209,10 @@ static void AddUnwindLibrary(const ToolChain &TC, const Driver &D, break; } case ToolChain::UNW_CompilerRT: - CmdArgs.push_back("-lunwind"); + if (LGT == LibGccType::StaticLibGcc) + CmdArgs.push_back("-l:libunwind.a"); + else + CmdArgs.push_back("-l:libunwind.so"); break; } @@ -1392,111 +1399,3 @@ void tools::addMultilibFlag(bool Enabled, const char *const Flag, Multilib::flags_list &Flags) { Flags.push_back(std::string(Enabled ? "+" : "-") + Flag); } - -static void getWebAssemblyTargetFeatures(const ArgList &Args, - std::vector<StringRef> &Features) { - handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); -} - -void tools::getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, - const ArgList &Args, ArgStringList &CmdArgs, bool ForAS, - bool ForLTOPlugin) { - - const Driver &D = TC.getDriver(); - std::vector<StringRef> Features; - switch (Triple.getArch()) { - default: - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - mips::getMIPSTargetFeatures(D, Triple, Args, Features); - break; - - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS); - break; - - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - ppc::getPPCTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - riscv::getRISCVTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::systemz: - systemz::getSystemZTargetFeatures(Args, Features); - break; - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - aarch64::getAArch64TargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::x86: - case llvm::Triple::x86_64: - x86::getX86TargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::hexagon: - hexagon::getHexagonTargetFeatures(D, Args, Features); - break; - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - getWebAssemblyTargetFeatures(Args, Features); - break; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - sparc::getSparcTargetFeatures(D, Args, Features); - break; - case llvm::Triple::r600: - case llvm::Triple::amdgcn: - amdgpu::getAMDGPUTargetFeatures(D, Args, Features); - break; - case llvm::Triple::msp430: - msp430::getMSP430TargetFeatures(D, Args, Features); - } - - // Find the last of each feature. - llvm::StringMap<unsigned> LastOpt; - for (unsigned I = 0, N = Features.size(); I < N; ++I) { - StringRef Name = Features[I]; - assert(Name[0] == '-' || Name[0] == '+'); - LastOpt[Name.drop_front(1)] = I; - } - - for (unsigned I = 0, N = Features.size(); I < N; ++I) { - // If this feature was overridden, ignore it. - StringRef Name = Features[I]; - llvm::StringMap<unsigned>::iterator LastI = - LastOpt.find(Name.drop_front(1)); - assert(LastI != LastOpt.end()); - unsigned Last = LastI->second; - if (Last != I) - continue; - if (!ForLTOPlugin) { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back(Name.data()); - } else { - CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=-mattr=") + Name)); - } - } -} - -StringRef tools::getTargetABI(const ArgList &Args, const llvm::Triple &Triple) { - // TODO: Support the other target ABI - switch (Triple.getArch()) { - default: - break; - case llvm::Triple::riscv32: - case llvm::Triple::riscv64: - return tools::riscv::getRISCVABI(Args, Triple); - break; - } - return StringRef(); -} diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index 79468e6b8926..84b9d2cf59b4 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -68,6 +68,9 @@ ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args); unsigned ParseFunctionAlignment(const ToolChain &TC, const llvm::opt::ArgList &Args); +unsigned ParseDebugDefaultVersion(const ToolChain &TC, + const llvm::opt::ArgList &Args); + void AddAssemblerKPIC(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); @@ -118,14 +121,6 @@ SmallString<128> getStatsFileName(const llvm::opt::ArgList &Args, void addMultilibFlag(bool Enabled, const char *const Flag, Multilib::flags_list &Flags); -StringRef getTargetABI(const llvm::opt::ArgList &Args, - const llvm::Triple &Triple); - -void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, bool ForAS, - bool ForLTOPlugin = false); - } // end namespace tools } // end namespace driver } // end namespace clang diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 8c704a3078ad..02871d2ce411 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -115,7 +115,8 @@ CudaInstallationDetector::CudaInstallationDetector( for (const char *Ver : Versions) Candidates.emplace_back(D.SysRoot + "/usr/local/cuda-" + Ver); - if (Distro(D.getVFS()).IsDebian() || Distro(D.getVFS()).IsUbuntu()) + Distro Dist(D.getVFS(), llvm::Triple(llvm::sys::getProcessTriple())); + if (Dist.IsDebian() || Dist.IsUbuntu()) // Special case for Debian to have nvidia-cuda-toolkit work // out of the box. More info on http://bugs.debian.org/882505 Candidates.emplace_back(D.SysRoot + "/usr/lib/cuda"); diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index ee08b8208d93..344a14fe1ea7 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -19,6 +19,7 @@ #include "clang/Driver/SanitizerArgs.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Path.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/TargetParser.h" @@ -57,6 +58,7 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { .Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm) .Cases("armv7s", "xscale", llvm::Triple::arm) .Case("arm64", llvm::Triple::aarch64) + .Case("arm64_32", llvm::Triple::aarch64_32) .Case("r600", llvm::Triple::r600) .Case("amdgcn", llvm::Triple::amdgcn) .Case("nvptx", llvm::Triple::nvptx) @@ -122,8 +124,7 @@ void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, AddMachOArch(Args, CmdArgs); // Use -force_cpusubtype_ALL on x86 by default. - if (getToolChain().getArch() == llvm::Triple::x86 || - getToolChain().getArch() == llvm::Triple::x86_64 || + if (getToolChain().getTriple().isX86() || Args.hasArg(options::OPT_force__cpusubtype__ALL)) CmdArgs.push_back("-force_cpusubtype_ALL"); @@ -334,7 +335,10 @@ void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, Args.AddAllArgs(CmdArgs, options::OPT_init); // Add the deployment target. - MachOTC.addMinVersionArgs(Args, CmdArgs); + if (!Version[0] || Version[0] >= 520) + MachOTC.addPlatformVersionArgs(Args, CmdArgs); + else + MachOTC.addMinVersionArgs(Args, CmdArgs); Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); Args.AddLastArg(CmdArgs, options::OPT_multi__module); @@ -737,7 +741,7 @@ Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) CudaInstallation(D, Triple, Args) {} types::ID MachO::LookupTypeForExtension(StringRef Ext) const { - types::ID Ty = types::lookupTypeForExtension(Ext); + types::ID Ty = ToolChain::LookupTypeForExtension(Ext); // Darwin always preprocesses assembly files (unless -x is used explicitly). if (Ty == types::TY_PP_Asm) @@ -831,6 +835,9 @@ StringRef MachO::getMachOArchName(const ArgList &Args) const { default: return getDefaultUniversalArchName(); + case llvm::Triple::aarch64_32: + return "arm64_32"; + case llvm::Triple::aarch64: return "arm64"; @@ -1061,7 +1068,6 @@ StringRef Darwin::getPlatformFamily() const { StringRef Darwin::getSDKName(StringRef isysroot) { // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk - llvm::sys::path::const_iterator SDKDir; auto BeginSDK = llvm::sys::path::begin(isysroot); auto EndSDK = llvm::sys::path::end(isysroot); for (auto IT = BeginSDK; IT != EndSDK; ++IT) { @@ -1110,6 +1116,19 @@ static void addExportedSymbol(ArgStringList &CmdArgs, const char *Symbol) { CmdArgs.push_back(Symbol); } +/// Add a sectalign directive for \p Segment and \p Section to the maximum +/// expected page size for Darwin. +/// +/// On iPhone 6+ the max supported page size is 16K. On macOS, the max is 4K. +/// Use a common alignment constant (16K) for now, and reduce the alignment on +/// macOS if it proves important. +static void addSectalignToPage(const ArgList &Args, ArgStringList &CmdArgs, + StringRef Segment, StringRef Section) { + for (const char *A : {"-sectalign", Args.MakeArgString(Segment), + Args.MakeArgString(Section), "0x4000"}) + CmdArgs.push_back(A); +} + void Darwin::addProfileRTLibs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!needsProfileRT(Args)) return; @@ -1117,11 +1136,13 @@ void Darwin::addProfileRTLibs(const ArgList &Args, AddLinkRuntimeLib(Args, CmdArgs, "profile", RuntimeLinkOptions(RLO_AlwaysLink | RLO_FirstLink)); + bool ForGCOV = needsGCovInstrumentation(Args); + // If we have a symbol export directive and we're linking in the profile // runtime, automatically export symbols necessary to implement some of the // runtime's functionality. if (hasExportSymbolDirective(Args)) { - if (needsGCovInstrumentation(Args)) { + if (ForGCOV) { addExportedSymbol(CmdArgs, "___gcov_flush"); addExportedSymbol(CmdArgs, "_flush_fn_list"); addExportedSymbol(CmdArgs, "_writeout_fn_list"); @@ -1131,6 +1152,24 @@ void Darwin::addProfileRTLibs(const ArgList &Args, } addExportedSymbol(CmdArgs, "_lprofDirMode"); } + + // Align __llvm_prf_{cnts,data} sections to the maximum expected page + // alignment. This allows profile counters to be mmap()'d to disk. Note that + // it's not enough to just page-align __llvm_prf_cnts: the following section + // must also be page-aligned so that its data is not clobbered by mmap(). + // + // The section alignment is only needed when continuous profile sync is + // enabled, but this is expected to be the default in Xcode. Specifying the + // extra alignment also allows the same binary to be used with/without sync + // enabled. + if (!ForGCOV) { + for (auto IPSK : {llvm::IPSK_cnts, llvm::IPSK_data}) { + addSectalignToPage( + Args, CmdArgs, "__DATA", + llvm::getInstrProfSectionName(IPSK, llvm::Triple::MachO, + /*AddSegmentInfo=*/false)); + } + } } void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args, @@ -1493,8 +1532,8 @@ getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, Targets[Darwin::TvOS] = ""; } else { // Don't allow conflicts in any other platform. - int FirstTarget = llvm::array_lengthof(Targets); - for (int I = 0; I != llvm::array_lengthof(Targets); ++I) { + unsigned FirstTarget = llvm::array_lengthof(Targets); + for (unsigned I = 0; I != llvm::array_lengthof(Targets); ++I) { if (Targets[I].empty()) continue; if (FirstTarget == llvm::array_lengthof(Targets)) @@ -1607,7 +1646,7 @@ inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain, if (MachOArchName == "armv7" || MachOArchName == "armv7s" || MachOArchName == "arm64") OSTy = llvm::Triple::IOS; - else if (MachOArchName == "armv7k") + else if (MachOArchName == "armv7k" || MachOArchName == "arm64_32") OSTy = llvm::Triple::WatchOS; else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && MachOArchName != "armv7em") @@ -1796,9 +1835,7 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { DarwinEnvironmentKind Environment = OSTarget->getEnvironment(); // Recognize iOS targets with an x86 architecture as the iOS simulator. if (Environment == NativeEnvironment && Platform != MacOS && - OSTarget->canInferSimulatorFromArch() && - (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64)) + OSTarget->canInferSimulatorFromArch() && getTriple().isX86()) Environment = Simulator; setTarget(Platform, Environment, Major, Minor, Micro); @@ -2194,8 +2231,7 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, } } - if (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64) + if (getTriple().isX86()) if (!Args.hasArgNoClaim(options::OPT_mtune_EQ)) DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mtune_EQ), "core2"); @@ -2451,7 +2487,7 @@ bool MachO::isPICDefaultForced() const { bool MachO::SupportsProfiling() const { // Profiling instrumentation is only supported on x86. - return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64; + return getTriple().isX86(); } void Darwin::addMinVersionArgs(const ArgList &Args, @@ -2478,6 +2514,45 @@ void Darwin::addMinVersionArgs(const ArgList &Args, CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); } +static const char *getPlatformName(Darwin::DarwinPlatformKind Platform, + Darwin::DarwinEnvironmentKind Environment) { + switch (Platform) { + case Darwin::MacOS: + return "macos"; + case Darwin::IPhoneOS: + if (Environment == Darwin::NativeEnvironment || + Environment == Darwin::Simulator) + return "ios"; + // FIXME: Add macCatalyst support here ("\"mac catalyst\""). + llvm_unreachable("macCatalyst isn't yet supported"); + case Darwin::TvOS: + return "tvos"; + case Darwin::WatchOS: + return "watchos"; + } + llvm_unreachable("invalid platform"); +} + +void Darwin::addPlatformVersionArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + // -platform_version <platform> <target_version> <sdk_version> + // Both the target and SDK version support only up to 3 components. + CmdArgs.push_back("-platform_version"); + std::string PlatformName = getPlatformName(TargetPlatform, TargetEnvironment); + if (TargetEnvironment == Darwin::Simulator) + PlatformName += "-simulator"; + CmdArgs.push_back(Args.MakeArgString(PlatformName)); + VersionTuple TargetVersion = getTargetVersion().withoutBuild(); + CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); + if (SDKInfo) { + VersionTuple SDKVersion = SDKInfo->getVersion().withoutBuild(); + CmdArgs.push_back(Args.MakeArgString(SDKVersion.getAsString())); + } else { + // Use a blank SDK version if it's not present. + CmdArgs.push_back("0.0.0"); + } +} + void Darwin::addStartObjectFileArgs(const ArgList &Args, ArgStringList &CmdArgs) const { // Derived from startfile spec. diff --git a/clang/lib/Driver/ToolChains/Darwin.h b/clang/lib/Driver/ToolChains/Darwin.h index 2dc7c85880f7..1b193a4c4eb9 100644 --- a/clang/lib/Driver/ToolChains/Darwin.h +++ b/clang/lib/Driver/ToolChains/Darwin.h @@ -167,6 +167,10 @@ public: virtual void addMinVersionArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const {} + virtual void addPlatformVersionArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + } + /// On some iOS platforms, kernel and kernel modules were built statically. Is /// this such a target? virtual bool isKernelStatic() const { return false; } @@ -258,6 +262,9 @@ public: return ""; } + // Darwin toolchain uses legacy thin LTO API, which is not + // capable of unit splitting. + bool canSplitThinLTOUnit() const override { return false; } /// } }; @@ -311,6 +318,9 @@ public: void addMinVersionArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; + void addPlatformVersionArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + void addStartObjectFileArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp new file mode 100644 index 000000000000..9b9eb81fa111 --- /dev/null +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -0,0 +1,79 @@ +//===-- Flang.cpp - Flang+LLVM ToolChain Implementations --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + + +#include "Flang.h" +#include "CommonArgs.h" + +#include "clang/Driver/Options.h" + +#include <cassert> + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +void Flang::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const ArgList &Args, const char *LinkingOutput) const { + const auto &TC = getToolChain(); + const llvm::Triple &Triple = TC.getEffectiveTriple(); + const std::string &TripleStr = Triple.getTriple(); + + ArgStringList CmdArgs; + + CmdArgs.push_back("-fc1"); + + CmdArgs.push_back("-triple"); + CmdArgs.push_back(Args.MakeArgString(TripleStr)); + + if (isa<PreprocessJobAction>(JA)) { + CmdArgs.push_back("-E"); + } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) { + if (JA.getType() == types::TY_Nothing) { + CmdArgs.push_back("-fsyntax-only"); + } else if (JA.getType() == types::TY_AST) { + CmdArgs.push_back("-emit-ast"); + } else if (JA.getType() == types::TY_LLVM_IR || + JA.getType() == types::TY_LTO_IR) { + CmdArgs.push_back("-emit-llvm"); + } else if (JA.getType() == types::TY_LLVM_BC || + JA.getType() == types::TY_LTO_BC) { + CmdArgs.push_back("-emit-llvm-bc"); + } else if (JA.getType() == types::TY_PP_Asm) { + CmdArgs.push_back("-S"); + } else { + assert(false && "Unexpected output type!"); + } + } else if (isa<AssembleJobAction>(JA)) { + CmdArgs.push_back("-emit-obj"); + } else { + assert(false && "Unexpected action class for Flang tool."); + } + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + const InputInfo &Input = Inputs[0]; + assert(Input.isFilename() && "Invalid input."); + CmdArgs.push_back(Input.getFilename()); + + const auto& D = C.getDriver(); + const char* Exec = Args.MakeArgString(D.GetProgramPath("flang", TC)); + C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +Flang::Flang(const ToolChain &TC) + : Tool("flang", "flang frontend", TC, RF_Full) {} + +Flang::~Flang() {} diff --git a/clang/lib/Driver/ToolChains/Flang.h b/clang/lib/Driver/ToolChains/Flang.h new file mode 100644 index 000000000000..19e3a8c28f7e --- /dev/null +++ b/clang/lib/Driver/ToolChains/Flang.h @@ -0,0 +1,46 @@ +//===--- Flang.h - Flang Tool and ToolChain Implementations ====-*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/Action.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Compiler.h" + +namespace clang { +namespace driver { + +namespace tools { + +/// Flang compiler tool. +class LLVM_LIBRARY_VISIBILITY Flang : public Tool { +public: + Flang(const ToolChain &TC); + ~Flang() override; + + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedAssembler() const override { return true; } + bool hasIntegratedCPP() const override { return true; } + bool canEmitIR() const override { return true; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + +} // end namespace tools + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FLANG_H diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index 7c891a24ba30..c5c6f530f48c 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -12,6 +12,7 @@ #include "Arch/Sparc.h" #include "CommonArgs.h" #include "clang/Driver/Compilation.h" +#include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" @@ -30,6 +31,7 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { claimNoWarnArgs(Args); ArgStringList CmdArgs; + const auto &D = getToolChain().getDriver(); // When building 32-bit code on FreeBSD/amd64, we have to explicitly // instruct as in the base system to assemble 32-bit code. @@ -103,6 +105,19 @@ void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, } } + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fdebug_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_option) + << Map << A->getOption().getName(); + else { + CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map")); + CmdArgs.push_back(Args.MakeArgString(Map)); + } + A->claim(); + } + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); CmdArgs.push_back("-o"); @@ -155,11 +170,10 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-dynamic-linker"); CmdArgs.push_back("/libexec/ld-elf.so.1"); } - if (ToolChain.getTriple().getOSMajorVersion() >= 9) { - if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || - Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { + const llvm::Triple &T = ToolChain.getTriple(); + if (T.getOSMajorVersion() >= 9) { + if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || T.isX86()) CmdArgs.push_back("--hash-style=both"); - } } CmdArgs.push_back("--enable-new-dtags"); } @@ -397,6 +411,11 @@ void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, } } +void FreeBSD::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + Tool *FreeBSD::buildAssembler() const { return new tools::freebsd::Assembler(*this); } @@ -420,6 +439,8 @@ llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const { bool FreeBSD::HasNativeLLVMSupport() const { return true; } +bool FreeBSD::IsUnwindTablesDefault(const ArgList &Args) const { return true; } + bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } SanitizerMask FreeBSD::getSupportedSanitizers() const { @@ -445,3 +466,12 @@ SanitizerMask FreeBSD::getSupportedSanitizers() const { Res |= SanitizerKind::Memory; return Res; } + +void FreeBSD::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args, + Action::OffloadKind) const { + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, + getTriple().getOSMajorVersion() >= 12)) + CC1Args.push_back("-fno-use-init-array"); +} diff --git a/clang/lib/Driver/ToolChains/FreeBSD.h b/clang/lib/Driver/ToolChains/FreeBSD.h index d17b3808ffac..84bdbfd9a312 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.h +++ b/clang/lib/Driver/ToolChains/FreeBSD.h @@ -64,15 +64,22 @@ public: llvm::opt::ArgStringList &CC1Args) const override; void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; llvm::ExceptionHandling GetExceptionModel( const llvm::opt::ArgList &Args) const override; + bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; unsigned GetDefaultDwarfVersion() const override; // Until dtrace (via CTF) and LLDB can deal with distributed debug info, // FreeBSD defaults to standalone/full debug info. bool GetDefaultStandaloneDebug() const override { return true; } + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; protected: Tool *buildAssembler() const override; diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp index e7d38ff9f227..808d0408d0d4 100644 --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -46,6 +46,9 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); + CmdArgs.push_back("-z"); + CmdArgs.push_back("now"); + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); if (llvm::sys::path::filename(Exec).equals_lower("ld.lld") || llvm::sys::path::stem(Exec).equals_lower("ld.lld")) { @@ -224,7 +227,7 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args, types::ID InputType) const { llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); - return (Triple.getArchName() + "-" + Triple.getOSName()).str(); + return Triple.str(); } Tool *Fuchsia::buildLinker() const { @@ -258,9 +261,9 @@ Fuchsia::GetCXXStdlibType(const ArgList &Args) const { void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs, 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"); + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, true)) + CC1Args.push_back("-fno-use-init-array"); } void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -343,5 +346,17 @@ SanitizerMask Fuchsia::getSupportedSanitizers() const { } SanitizerMask Fuchsia::getDefaultSanitizers() const { - return SanitizerKind::SafeStack; + SanitizerMask Res; + switch (getTriple().getArch()) { + case llvm::Triple::aarch64: + Res |= SanitizerKind::ShadowCallStack; + break; + case llvm::Triple::x86_64: + Res |= SanitizerKind::SafeStack; + break; + default: + // TODO: Enable SafeStack on RISC-V once tested. + break; + } + return Res; } diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index c302a31cd2e1..da197e476621 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -709,11 +709,9 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, StringRef ABIName = riscv::getRISCVABI(Args, getToolChain().getTriple()); CmdArgs.push_back("-mabi"); CmdArgs.push_back(ABIName.data()); - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) { - StringRef MArch = A->getValue(); - CmdArgs.push_back("-march"); - CmdArgs.push_back(MArch.data()); - } + StringRef MArchName = riscv::getRISCVArch(Args, getToolChain().getTriple()); + CmdArgs.push_back("-march"); + CmdArgs.push_back(MArchName.data()); break; } case llvm::Triple::sparc: @@ -864,12 +862,25 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, case llvm::Triple::systemz: { // Always pass an -march option, since our default of z10 is later // than the GNU assembler's default. - StringRef CPUName = systemz::getSystemZTargetCPU(Args); + std::string CPUName = systemz::getSystemZTargetCPU(Args); CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); break; } } + for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ, + options::OPT_fdebug_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_option) + << Map << A->getOption().getName(); + else { + CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map")); + CmdArgs.push_back(Args.MakeArgString(Map)); + } + A->claim(); + } + Args.AddAllArgs(CmdArgs, options::OPT_I); Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); @@ -1393,7 +1404,8 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags); addMultilibFlag(CPUName == "mips64", "march=mips64", Flags); addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" || - CPUName == "mips64r5" || CPUName == "octeon", + CPUName == "mips64r5" || CPUName == "octeon" || + CPUName == "octeon+", "march=mips64r2", Flags); addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags); addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); @@ -1504,9 +1516,65 @@ static bool findMSP430Multilibs(const Driver &D, return false; } +static void findRISCVBareMetalMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + DetectedMultilibs &Result) { + FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); + struct RiscvMultilib { + StringRef march; + StringRef mabi; + }; + // currently only support the set of multilibs like riscv-gnu-toolchain does. + // TODO: support MULTILIB_REUSE + SmallVector<RiscvMultilib, 8> RISCVMultilibSet = { + {"rv32i", "ilp32"}, {"rv32im", "ilp32"}, {"rv32iac", "ilp32"}, + {"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"}, + {"rv64imafdc", "lp64d"}}; + + std::vector<Multilib> Ms; + for (auto Element : RISCVMultilibSet) { + // multilib path rule is ${march}/${mabi} + Ms.emplace_back( + makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi)).str()) + .flag(Twine("+march=", Element.march).str()) + .flag(Twine("+mabi=", Element.mabi).str())); + } + MultilibSet RISCVMultilibs = + MultilibSet() + .Either(ArrayRef<Multilib>(Ms)) + .FilterOut(NonExistent) + .setFilePathsCallback([](const Multilib &M) { + return std::vector<std::string>( + {M.gccSuffix(), + "/../../../../riscv64-unknown-elf/lib" + M.gccSuffix(), + "/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()}); + }); + + + Multilib::flags_list Flags; + llvm::StringSet<> Added_ABIs; + StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); + StringRef MArch = tools::riscv::getRISCVArch(Args, TargetTriple); + for (auto Element : RISCVMultilibSet) { + addMultilibFlag(MArch == Element.march, + Twine("march=", Element.march).str().c_str(), Flags); + if (!Added_ABIs.count(Element.mabi)) { + Added_ABIs.insert(Element.mabi); + addMultilibFlag(ABIName == Element.mabi, + Twine("mabi=", Element.mabi).str().c_str(), Flags); + } + } + + if (RISCVMultilibs.select(Flags, Result.SelectedMultilib)) + Result.Multilibs = RISCVMultilibs; +} + static void findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, StringRef Path, const ArgList &Args, DetectedMultilibs &Result) { + if (TargetTriple.getOS() == llvm::Triple::UnknownOS) + return findRISCVBareMetalMultilibs(D, TargetTriple, Path, Args, Result); FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32"); @@ -2002,7 +2070,9 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes( static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; static const char *const PPCTriples[] = { "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe", - "powerpc-suse-linux", "powerpc-montavista-linuxspe"}; + // On 32-bit PowerPC systems running SUSE Linux, gcc is configured as a + // 64-bit compiler which defaults to "-m32", hence "powerpc64-suse-linux". + "powerpc64-suse-linux", "powerpc-montavista-linuxspe"}; static const char *const PPC64LibDirs[] = {"/lib64", "/lib"}; static const char *const PPC64Triples[] = { "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu", @@ -2545,9 +2615,6 @@ bool Generic_GCC::isPICDefault() const { switch (getArch()) { case llvm::Triple::x86_64: return getTriple().isOSWindows(); - case llvm::Triple::ppc64: - // Big endian PPC is PIC by default - return !getTriple().isOSBinFormatMachO() && !getTriple().isMacOSX(); case llvm::Triple::mips64: case llvm::Triple::mips64el: return true; @@ -2616,19 +2683,49 @@ void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, } } -void -Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - // FIXME: The Linux behavior would probaby be a better approach here. - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/include/c++/v1"); +static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs, + StringRef base) { + std::error_code EC; + int MaxVersion = 0; + std::string MaxVersionString; + for (llvm::vfs::directory_iterator LI = vfs.dir_begin(base, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + int Version; + if (VersionText[0] == 'v' && + !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { + if (Version > MaxVersion) { + MaxVersion = Version; + MaxVersionString = VersionText; + } + } + } + return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; } void -Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - // By default, we don't assume we know where libstdc++ might be installed. - // FIXME: If we have a valid GCCInstallation, use it. +Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const std::string& SysRoot = getDriver().SysRoot; + auto AddIncludePath = [&](std::string Path) { + std::string IncludePath = DetectLibcxxIncludePath(getVFS(), Path); + if (IncludePath.empty() || !getVFS().exists(IncludePath)) + return false; + addSystemInclude(DriverArgs, CC1Args, IncludePath); + return true; + }; + // Android never uses the libc++ headers installed alongside the toolchain, + // which are generally incompatible with the NDK libraries anyway. + if (!getTriple().isAndroid()) + if (AddIncludePath(getDriver().Dir + "/../include/c++")) + return; + // If this is a development, non-installed, clang, libcxx will + // not be found at ../include/c++ but it likely to be found at + // one of the following two locations: + if (AddIncludePath(SysRoot + "/usr/local/include/c++")) + return; + if (AddIncludePath(SysRoot + "/usr/include/c++")) + return; } /// Helper to add the variant paths of a libstdc++ installation. @@ -2664,6 +2761,60 @@ bool Generic_GCC::addLibStdCXXIncludePaths( return true; } +bool +Generic_GCC::addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + // Use GCCInstallation to know where libstdc++ headers are installed. + if (!GCCInstallation.isValid()) + return false; + + // By default, look for the C++ headers in an include directory adjacent to + // the lib directory of the GCC installation. Note that this is expect to be + // equivalent to '/usr/include/c++/X.Y' in almost all cases. + StringRef LibDir = GCCInstallation.getParentLibPath(); + StringRef InstallDir = GCCInstallation.getInstallPath(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + const std::string GCCMultiarchTriple = getMultiarchTriple( + getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); + const std::string TargetMultiarchTriple = + getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); + const GCCVersion &Version = GCCInstallation.getVersion(); + + // The primary search for libstdc++ supports multiarch variants. + if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", + "/c++/" + Version.Text, TripleStr, + GCCMultiarchTriple, TargetMultiarchTriple, + Multilib.includeSuffix(), DriverArgs, CC1Args)) + return true; + + // Otherwise, fall back on a bunch of options which don't use multiarch + // layouts for simplicity. + const std::string LibStdCXXIncludePathCandidates[] = { + // Gentoo is weird and places its headers inside the GCC install, + // so if the first attempt to find the headers fails, try these patterns. + InstallDir.str() + "/include/g++-v" + Version.Text, + InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + + Version.MinorStr, + InstallDir.str() + "/include/g++-v" + Version.MajorStr, + }; + + for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { + if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr, + /*GCCMultiarchTriple*/ "", + /*TargetMultiarchTriple*/ "", + Multilib.includeSuffix(), DriverArgs, CC1Args)) + return true; + } + return false; +} + +void +Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args); +} + llvm::opt::DerivedArgList * Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef, Action::OffloadKind DeviceOffloadKind) const { @@ -2712,23 +2863,7 @@ void Generic_ELF::anchor() {} void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, ArgStringList &CC1Args, Action::OffloadKind) const { - const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); - bool UseInitArrayDefault = - getTriple().getArch() == llvm::Triple::aarch64 || - getTriple().getArch() == llvm::Triple::aarch64_be || - (getTriple().isOSFreeBSD() && - getTriple().getOSMajorVersion() >= 12) || - (getTriple().getOS() == llvm::Triple::Linux && - ((!GCCInstallation.isValid() || !V.isOlderThan(4, 7, 0)) || - getTriple().isAndroid())) || - getTriple().getOS() == llvm::Triple::NaCl || - (getTriple().getVendor() == llvm::Triple::MipsTechnologies && - !getTriple().hasEnvironment()) || - getTriple().getOS() == llvm::Triple::Solaris || - getTriple().getArch() == llvm::Triple::riscv32 || - getTriple().getArch() == llvm::Triple::riscv64; - - if (DriverArgs.hasFlag(options::OPT_fuse_init_array, - options::OPT_fno_use_init_array, UseInitArrayDefault)) - CC1Args.push_back("-fuse-init-array"); + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, true)) + CC1Args.push_back("-fno-use-init-array"); } diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index 3bb38c498b35..083f74c05477 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -300,6 +300,11 @@ protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + virtual std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const + { return TargetTriple.str(); } + /// \name ToolChain Implementation Helper Functions /// @{ @@ -322,6 +327,10 @@ protected: addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const; + bool + addGCCLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, StringRef TargetMultiarchTriple, diff --git a/clang/lib/Driver/ToolChains/HIP.cpp b/clang/lib/Driver/ToolChains/HIP.cpp index ad9384df6a24..f89e648948ab 100644 --- a/clang/lib/Driver/ToolChains/HIP.cpp +++ b/clang/lib/Driver/ToolChains/HIP.cpp @@ -62,6 +62,34 @@ static const char *getOutputFileName(Compilation &C, StringRef Base, } return OutputFileName; } + +static void addOptLevelArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + bool IsLlc = false) { + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + StringRef OOpt = "3"; + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + OOpt = "3"; + else if (A->getOption().matches(options::OPT_O0)) + OOpt = "0"; + else if (A->getOption().matches(options::OPT_O)) { + // Clang and opt support -Os/-Oz; llc only supports -O0, -O1, -O2 and -O3 + // so we map -Os/-Oz to -O2. + // Only clang supports -Og, and maps it to -O1. + // We map anything else to -O2. + OOpt = llvm::StringSwitch<const char *>(A->getValue()) + .Case("1", "1") + .Case("2", "2") + .Case("3", "3") + .Case("s", IsLlc ? "2" : "s") + .Case("z", IsLlc ? "2" : "z") + .Case("g", "1") + .Default("2"); + } + CmdArgs.push_back(Args.MakeArgString("-O" + OOpt)); + } +} } // namespace const char *AMDGCN::Linker::constructLLVMLinkCommand( @@ -93,25 +121,7 @@ const char *AMDGCN::Linker::constructOptCommand( // The input to opt is the output from llvm-link. OptArgs.push_back(InputFileName); // Pass optimization arg to opt. - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - StringRef OOpt = "3"; - if (A->getOption().matches(options::OPT_O4) || - A->getOption().matches(options::OPT_Ofast)) - OOpt = "3"; - else if (A->getOption().matches(options::OPT_O0)) - OOpt = "0"; - else if (A->getOption().matches(options::OPT_O)) { - // -Os, -Oz, and -O(anything else) map to -O2 - OOpt = llvm::StringSwitch<const char *>(A->getValue()) - .Case("1", "1") - .Case("2", "2") - .Case("3", "3") - .Case("s", "2") - .Case("z", "2") - .Default("2"); - } - OptArgs.push_back(Args.MakeArgString("-O" + OOpt)); - } + addOptLevelArgs(Args, OptArgs); OptArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); OptArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); @@ -136,10 +146,15 @@ const char *AMDGCN::Linker::constructLlcCommand( llvm::StringRef OutputFilePrefix, const char *InputFileName, bool OutputIsAsm) const { // Construct llc command. - ArgStringList LlcArgs{ - InputFileName, "-mtriple=amdgcn-amd-amdhsa", - Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj")), - Args.MakeArgString("-mcpu=" + SubArchName)}; + ArgStringList LlcArgs; + // The input to llc is the output from opt. + LlcArgs.push_back(InputFileName); + // Pass optimization arg to llc. + addOptLevelArgs(Args, LlcArgs, /*IsLlc=*/true); + LlcArgs.push_back("-mtriple=amdgcn-amd-amdhsa"); + LlcArgs.push_back(Args.MakeArgString("-mcpu=" + SubArchName)); + LlcArgs.push_back( + Args.MakeArgString(Twine("-filetype=") + (OutputIsAsm ? "asm" : "obj"))); // Extract all the -m options std::vector<llvm::StringRef> Features; @@ -292,6 +307,20 @@ void HIPToolChain::addClangTargetOptions( false)) CC1Args.push_back("-fgpu-rdc"); + StringRef MaxThreadsPerBlock = + DriverArgs.getLastArgValue(options::OPT_gpu_max_threads_per_block_EQ); + if (!MaxThreadsPerBlock.empty()) { + std::string ArgStr = + std::string("--gpu-max-threads-per-block=") + MaxThreadsPerBlock.str(); + CC1Args.push_back(DriverArgs.MakeArgStringRef(ArgStr)); + } + + if (DriverArgs.hasFlag(options::OPT_fgpu_allow_device_init, + options::OPT_fno_gpu_allow_device_init, false)) + CC1Args.push_back("-fgpu-allow-device-init"); + + CC1Args.push_back("-fcuda-allow-variadic-functions"); + // Default to "hidden" visibility, as object level linking will not be // supported for the foreseeable future. if (!DriverArgs.hasArg(options::OPT_fvisibility_EQ, @@ -337,9 +366,8 @@ void HIPToolChain::addClangTargetOptions( else WaveFrontSizeBC = "oclc_wavefrontsize64_off.amdgcn.bc"; - BCLibs.append({"hip.amdgcn.bc", "opencl.amdgcn.bc", "ocml.amdgcn.bc", - "ockl.amdgcn.bc", "oclc_finite_only_off.amdgcn.bc", - FlushDenormalControlBC, + BCLibs.append({"hip.amdgcn.bc", "ocml.amdgcn.bc", "ockl.amdgcn.bc", + "oclc_finite_only_off.amdgcn.bc", FlushDenormalControlBC, "oclc_correctly_rounded_sqrt_on.amdgcn.bc", "oclc_unsafe_math_off.amdgcn.bc", ISAVerBC, WaveFrontSizeBC}); diff --git a/clang/lib/Driver/ToolChains/HIP.h b/clang/lib/Driver/ToolChains/HIP.h index 2d146ce5cc6f..c4f944e458bf 100644 --- a/clang/lib/Driver/ToolChains/HIP.h +++ b/clang/lib/Driver/ToolChains/HIP.h @@ -113,7 +113,7 @@ public: computeMSVCVersion(const Driver *D, const llvm::opt::ArgList &Args) const override; - unsigned GetDefaultDwarfVersion() const override { return 2; } + unsigned GetDefaultDwarfVersion() const override { return 4; } const ToolChain &HostTC; diff --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp index 96cc084e2821..e4d9ea8a70f9 100644 --- a/clang/lib/Driver/ToolChains/Hexagon.cpp +++ b/clang/lib/Driver/ToolChains/Hexagon.cpp @@ -209,7 +209,11 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles); bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); bool UseG0 = false; + const char *Exec = Args.MakeArgString(HTC.GetLinkerPath()); + bool UseLLD = (llvm::sys::path::filename(Exec).equals_lower("ld.lld") || + llvm::sys::path::stem(Exec).equals_lower("ld.lld")); bool UseShared = IsShared && !IsStatic; + StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); //---------------------------------------------------------------------------- // Silence warnings for various options @@ -232,9 +236,10 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, for (const auto &Opt : HTC.ExtraOpts) CmdArgs.push_back(Opt.c_str()); - CmdArgs.push_back("-march=hexagon"); - StringRef CpuVer = toolchains::HexagonToolChain::GetTargetCPUVersion(Args); - CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer)); + if (!UseLLD) { + CmdArgs.push_back("-march=hexagon"); + CmdArgs.push_back(Args.MakeArgString("-mcpu=hexagon" + CpuVer)); + } if (IsShared) { CmdArgs.push_back("-shared"); @@ -574,7 +579,7 @@ const StringRef HexagonToolChain::GetDefaultCPU() { const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { Arg *CpuArg = nullptr; - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ)) + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) CpuArg = A; StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); diff --git a/clang/lib/Driver/ToolChains/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp index 92b0a7f2483f..72166ca9f359 100644 --- a/clang/lib/Driver/ToolChains/Hurd.cpp +++ b/clang/lib/Driver/ToolChains/Hurd.cpp @@ -27,9 +27,9 @@ using tools::addPathIfExists; /// a target-triple directory in the library and header search paths. /// Unfortunately, this triple does not align with the vanilla target triple, /// so we provide a rough mapping here. -static std::string getMultiarchTriple(const Driver &D, - const llvm::Triple &TargetTriple, - StringRef SysRoot) { +std::string Hurd::getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const { if (TargetTriple.getArch() == llvm::Triple::x86) { // We use the existence of '/lib/<triple>' as a directory to detect some // common hurd triples that don't quite match the Clang triple for both @@ -70,6 +70,10 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const std::string OSLibDir = getOSLibDir(Triple, Args); const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); +#ifdef ENABLE_LINKER_BUILD_ID + ExtraOpts.push_back("--build-id"); +#endif + // If we are currently running Clang inside of the requested system root, add // its parent library paths to those searched. // FIXME: It's not clear whether we should use the driver's installed diff --git a/clang/lib/Driver/ToolChains/Hurd.h b/clang/lib/Driver/ToolChains/Hurd.h index a2c3d074e9f9..86c6c3f734dd 100644 --- a/clang/lib/Driver/ToolChains/Hurd.h +++ b/clang/lib/Driver/ToolChains/Hurd.h @@ -36,6 +36,10 @@ public: protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + + std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const override; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp index 6677843b2c53..8f947e79bd1f 100644 --- a/clang/lib/Driver/ToolChains/InterfaceStubs.cpp +++ b/clang/lib/Driver/ToolChains/InterfaceStubs.cpp @@ -9,6 +9,7 @@ #include "InterfaceStubs.h" #include "CommonArgs.h" #include "clang/Driver/Compilation.h" +#include "llvm/Support/Path.h" namespace clang { namespace driver { @@ -21,13 +22,38 @@ void Merger::ConstructJob(Compilation &C, const JobAction &JA, std::string Merger = getToolChain().GetProgramPath(getShortName()); llvm::opt::ArgStringList CmdArgs; CmdArgs.push_back("-action"); - CmdArgs.push_back(Args.getLastArg(options::OPT_emit_merged_ifs) - ? "write-ifs" - : "write-bin"); + const bool WriteBin = !Args.getLastArg(options::OPT_emit_merged_ifs); + CmdArgs.push_back(WriteBin ? "write-bin" : "write-ifs"); CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - for (const auto &Input : Inputs) - CmdArgs.push_back(Input.getFilename()); + + // Normally we want to write to a side-car file ending in ".ifso" so for + // example if `clang -emit-interface-stubs -shared -o libhello.so` were + // invoked then we would like to get libhello.so and libhello.ifso. If the + // stdout stream is given as the output file (ie `-o -`), that is the one + // exception where we will just append to the same filestream as the normal + // output. + SmallString<128> OutputFilename(Output.getFilename()); + if (OutputFilename != "-") { + if (Args.hasArg(options::OPT_shared)) + llvm::sys::path::replace_extension(OutputFilename, + (WriteBin ? "ifso" : "ifs")); + else + OutputFilename += (WriteBin ? ".ifso" : ".ifs"); + } + + CmdArgs.push_back(Args.MakeArgString(OutputFilename.c_str())); + + // Here we append the input files. If the input files are object files, then + // we look for .ifs files present in the same location as the object files. + for (const auto &Input : Inputs) { + if (!Input.isFilename()) + continue; + SmallString<128> InputFilename(Input.getFilename()); + if (Input.getType() == types::TY_Object) + llvm::sys::path::replace_extension(InputFilename, ".ifs"); + CmdArgs.push_back(Args.MakeArgString(InputFilename.c_str())); + } + C.addCommand(std::make_unique<Command>(JA, *this, Args.MakeArgString(Merger), CmdArgs, Inputs)); } diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 087783875ffe..bff1ab1009be 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -37,9 +37,9 @@ using tools::addPathIfExists; /// a target-triple directory in the library and header search paths. /// Unfortunately, this triple does not align with the vanilla target triple, /// so we provide a rough mapping here. -static std::string getMultiarchTriple(const Driver &D, +std::string Linux::getMultiarchTriple(const Driver &D, const llvm::Triple &TargetTriple, - StringRef SysRoot) { + StringRef SysRoot) const { llvm::Triple::EnvironmentType TargetEnvironment = TargetTriple.getEnvironment(); bool IsAndroid = TargetTriple.isAndroid(); @@ -240,7 +240,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) .str()); } - Distro Distro(D.getVFS()); + Distro Distro(D.getVFS(), Triple); if (Distro.IsAlpineLinux() || Triple.isAndroid()) { ExtraOpts.push_back("-z"); @@ -511,7 +511,7 @@ std::string Linux::getDynamicLinker(const ArgList &Args) const { const llvm::Triple::ArchType Arch = getArch(); const llvm::Triple &Triple = getTriple(); - const Distro Distro(getDriver().getVFS()); + const Distro Distro(getDriver().getVFS(), Triple); if (Triple.isAndroid()) return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker"; @@ -865,81 +865,23 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude); } -static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs, - StringRef base) { - std::error_code EC; - int MaxVersion = 0; - std::string MaxVersionString = ""; - for (llvm::vfs::directory_iterator LI = vfs.dir_begin(base, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); - int Version; - if (VersionText[0] == 'v' && - !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { - if (Version > MaxVersion) { - MaxVersion = Version; - MaxVersionString = VersionText; - } - } - } - return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; -} - -void Linux::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - const std::string& SysRoot = computeSysRoot(); - const std::string LibCXXIncludePathCandidates[] = { - DetectLibcxxIncludePath(getVFS(), getDriver().Dir + "/../include/c++"), - // If this is a development, non-installed, clang, libcxx will - // not be found at ../include/c++ but it likely to be found at - // one of the following two locations: - DetectLibcxxIncludePath(getVFS(), SysRoot + "/usr/local/include/c++"), - DetectLibcxxIncludePath(getVFS(), SysRoot + "/usr/include/c++") }; - for (const auto &IncludePath : LibCXXIncludePathCandidates) { - if (IncludePath.empty() || !getVFS().exists(IncludePath)) - continue; - // Use the first candidate that exists. - addSystemInclude(DriverArgs, CC1Args, IncludePath); - return; - } -} - void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { + // Try generic GCC detection first. + if (Generic_GCC::addGCCLibStdCxxIncludePaths(DriverArgs, CC1Args)) + return; + // We need a detected GCC installation on Linux to provide libstdc++'s - // headers. + // headers in odd Linuxish places. if (!GCCInstallation.isValid()) return; - // By default, look for the C++ headers in an include directory adjacent to - // the lib directory of the GCC installation. Note that this is expect to be - // equivalent to '/usr/include/c++/X.Y' in almost all cases. StringRef LibDir = GCCInstallation.getParentLibPath(); - StringRef InstallDir = GCCInstallation.getInstallPath(); StringRef TripleStr = GCCInstallation.getTriple().str(); const Multilib &Multilib = GCCInstallation.getMultilib(); - const std::string GCCMultiarchTriple = getMultiarchTriple( - getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); - const std::string TargetMultiarchTriple = - getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); const GCCVersion &Version = GCCInstallation.getVersion(); - // The primary search for libstdc++ supports multiarch variants. - if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", - "/c++/" + Version.Text, TripleStr, - GCCMultiarchTriple, TargetMultiarchTriple, - Multilib.includeSuffix(), DriverArgs, CC1Args)) - return; - - // Otherwise, fall back on a bunch of options which don't use multiarch - // layouts for simplicity. const std::string LibStdCXXIncludePathCandidates[] = { - // Gentoo is weird and places its headers inside the GCC install, - // so if the first attempt to find the headers fails, try these patterns. - InstallDir.str() + "/include/g++-v" + Version.Text, - InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + - Version.MinorStr, - InstallDir.str() + "/include/g++-v" + Version.MajorStr, // Android standalone toolchain has C++ headers in yet another place. LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, // Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++, diff --git a/clang/lib/Driver/ToolChains/Linux.h b/clang/lib/Driver/ToolChains/Linux.h index 4c61994691c7..f5518eac218a 100644 --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -26,9 +26,6 @@ public: void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; - void addLibCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; void addLibStdCxxIncludePaths( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -52,6 +49,10 @@ public: protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; + + std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) const override; }; } // end namespace toolchains diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index 1d31844bfcc8..4e143f6a5d3f 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -422,6 +422,17 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); + // Control Flow Guard checks + if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { + StringRef GuardArgs = A->getValue(); + if (GuardArgs.equals_lower("cf") || GuardArgs.equals_lower("cf,nochecks")) { + // MSVC doesn't yet support the "nochecks" modifier. + CmdArgs.push_back("-guard:cf"); + } else if (GuardArgs.equals_lower("cf-")) { + CmdArgs.push_back("-guard:cf-"); + } + } + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) { CmdArgs.push_back("-nodefaultlib:vcomp.lib"); @@ -679,6 +690,17 @@ std::unique_ptr<Command> visualstudio::Compiler::GetCommand( : "/Zc:threadSafeInit-"); } + // Control Flow Guard checks + if (Arg *A = Args.getLastArg(options::OPT__SLASH_guard)) { + StringRef GuardArgs = A->getValue(); + if (GuardArgs.equals_lower("cf") || GuardArgs.equals_lower("cf,nochecks")) { + // MSVC doesn't yet support the "nochecks" modifier. + CmdArgs.push_back("/guard:cf"); + } else if (GuardArgs.equals_lower("cf-")) { + CmdArgs.push_back("/guard:cf-"); + } + } + // Pass through all unknown arguments so that the fallback command can see // them too. Args.AddAllArgs(CmdArgs, options::OPT_UNKNOWN); diff --git a/clang/lib/Driver/ToolChains/MinGW.cpp b/clang/lib/Driver/ToolChains/MinGW.cpp index 0d851114c225..8f24384e688b 100644 --- a/clang/lib/Driver/ToolChains/MinGW.cpp +++ b/clang/lib/Driver/ToolChains/MinGW.cpp @@ -160,7 +160,19 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, } CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); + const char *OutputFile = Output.getFilename(); + // GCC implicitly adds an .exe extension if it is given an output file name + // that lacks an extension. However, GCC only does this when actually + // running on windows, not when operating as a cross compiler. As some users + // have come to rely on this behaviour, try to replicate it. +#ifdef _WIN32 + if (!llvm::sys::path::has_extension(OutputFile)) + CmdArgs.push_back(Args.MakeArgString(Twine(OutputFile) + ".exe")); + else + CmdArgs.push_back(OutputFile); +#else + CmdArgs.push_back(OutputFile); +#endif Args.AddAllArgs(CmdArgs, options::OPT_e); // FIXME: add -N, -n flags diff --git a/clang/lib/Driver/ToolChains/NetBSD.cpp b/clang/lib/Driver/ToolChains/NetBSD.cpp index 405142204199..0100a387d6c3 100644 --- a/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -505,7 +505,7 @@ void NetBSD::addClangTargetOptions(const ArgList &DriverArgs, getTriple().getArch() == llvm::Triple::arm || getTriple().getArch() == llvm::Triple::armeb; - if (DriverArgs.hasFlag(options::OPT_fuse_init_array, - options::OPT_fno_use_init_array, UseInitArrayDefault)) - CC1Args.push_back("-fuse-init-array"); + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, UseInitArrayDefault)) + CC1Args.push_back("-fno-use-init-array"); } diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp index e93f5fcc3d81..80343c0394cb 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -267,3 +267,12 @@ Tool *OpenBSD::buildAssembler() const { } Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); } + +void OpenBSD::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args, + Action::OffloadKind) const { + // Support for .init_array is still new (Aug 2016). + if (!DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, false)) + CC1Args.push_back("-fno-use-init-array"); +} diff --git a/clang/lib/Driver/ToolChains/OpenBSD.h b/clang/lib/Driver/ToolChains/OpenBSD.h index c92d109b7c16..9f1ee0f66402 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.h +++ b/clang/lib/Driver/ToolChains/OpenBSD.h @@ -75,6 +75,11 @@ public: SanitizerMask getSupportedSanitizers() const override; + void + addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + Action::OffloadKind DeviceOffloadKind) const override; + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/clang/lib/Driver/ToolChains/PS4CPU.h b/clang/lib/Driver/ToolChains/PS4CPU.h index e9f0891c1194..18852b2808cb 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.h +++ b/clang/lib/Driver/ToolChains/PS4CPU.h @@ -84,6 +84,10 @@ public: SanitizerMask getSupportedSanitizers() const override; + // PS4 toolchain uses legacy thin LTO API, which is not + // capable of unit splitting. + bool canSplitThinLTOUnit() const override { return false; } + protected: Tool *buildAssembler() const override; Tool *buildLinker() const override; diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp index 22dc5117f196..ddc329e3c722 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "RISCVToolchain.h" -#include "Arch/RISCV.h" #include "CommonArgs.h" #include "InputInfo.h" #include "clang/Driver/Compilation.h" @@ -23,29 +22,60 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; +static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, + const Multilib &Multilib, + StringRef InstallPath, + ToolChain::path_list &Paths) { + if (const auto &PathsCallback = Multilibs.filePathsCallback()) + for (const auto &Path : PathsCallback(Multilib)) + addPathIfExists(D, InstallPath + Path, Paths); +} + /// RISCV Toolchain RISCVToolChain::RISCVToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { GCCInstallation.init(Triple, Args); - getFilePaths().push_back(computeSysRoot() + "/lib"); if (GCCInstallation.isValid()) { + Multilibs = GCCInstallation.getMultilibs(); + SelectedMultilib = GCCInstallation.getMultilib(); + path_list &Paths = getFilePaths(); + // Add toolchain/multilib specific file paths. + addMultilibsFilePaths(D, Multilibs, SelectedMultilib, + GCCInstallation.getInstallPath(), Paths); getFilePaths().push_back(GCCInstallation.getInstallPath().str()); - getProgramPaths().push_back( - (GCCInstallation.getParentLibPath() + "/../bin").str()); + ToolChain::path_list &PPaths = getProgramPaths(); + // Multilib cross-compiler GCC installations put ld in a triple-prefixed + // directory off of the parent of the GCC installation. + PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + + GCCInstallation.getTriple().str() + "/bin") + .str()); + PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str()); + } else { + getProgramPaths().push_back(D.Dir); } + getFilePaths().push_back(computeSysRoot() + "/lib"); } Tool *RISCVToolChain::buildLinker() const { return new tools::RISCV::Linker(*this); } +ToolChain::RuntimeLibType RISCVToolChain::GetDefaultRuntimeLibType() const { + return GCCInstallation.isValid() ? + ToolChain::RLT_Libgcc : ToolChain::RLT_CompilerRT; +} + +ToolChain::UnwindLibType +RISCVToolChain::GetUnwindLibType(const llvm::opt::ArgList &Args) const { + return ToolChain::UNW_None; +} + void RISCVToolChain::addClangTargetOptions( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind) const { CC1Args.push_back("-nostdsysteminc"); - CC1Args.push_back("-fuse-init-array"); } void RISCVToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, @@ -74,17 +104,22 @@ std::string RISCVToolChain::computeSysRoot() const { if (!getDriver().SysRoot.empty()) return getDriver().SysRoot; - if (!GCCInstallation.isValid()) - return std::string(); - - StringRef LibDir = GCCInstallation.getParentLibPath(); - StringRef TripleStr = GCCInstallation.getTriple().str(); - std::string SysRootDir = LibDir.str() + "/../" + TripleStr.str(); + SmallString<128> SysRootDir; + if (GCCInstallation.isValid()) { + StringRef LibDir = GCCInstallation.getParentLibPath(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + llvm::sys::path::append(SysRootDir, LibDir, "..", TripleStr); + } else { + // Use the triple as provided to the driver. Unlike the parsed triple + // this has not been normalized to always contain every field. + llvm::sys::path::append(SysRootDir, getDriver().Dir, "..", + getDriver().getTargetTriple()); + } if (!llvm::sys::fs::exists(SysRootDir)) return std::string(); - return SysRootDir; + return SysRootDir.str(); } void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, @@ -99,20 +134,35 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - std::string Linker = getToolChain().GetProgramPath(getShortName()); - - if (D.isUsingLTO()) { - assert(!Inputs.empty() && "Must have at least one input."); - AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0], - D.getLTOMode() == LTOK_Thin); + bool IsRV64 = ToolChain.getArch() == llvm::Triple::riscv64; + CmdArgs.push_back("-m"); + if (IsRV64) { + CmdArgs.push_back("elf64lriscv"); + } else { + CmdArgs.push_back("elf32lriscv"); } + std::string Linker = getToolChain().GetProgramPath(getShortName()); + bool WantCRTs = !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); + const char *crtbegin, *crtend; + auto RuntimeLib = ToolChain.GetRuntimeLibType(Args); + if (RuntimeLib == ToolChain::RLT_Libgcc) { + crtbegin = "crtbegin.o"; + crtend = "crtend.o"; + } else { + assert (RuntimeLib == ToolChain::RLT_CompilerRT); + crtbegin = ToolChain.getCompilerRTArgString(Args, "crtbegin", + ToolChain::FT_Object); + crtend = ToolChain.getCompilerRTArgString(Args, "crtend", + ToolChain::FT_Object); + } + if (WantCRTs) { CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); } Args.AddAllArgs(CmdArgs, options::OPT_L); @@ -133,11 +183,11 @@ void RISCV::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-lc"); CmdArgs.push_back("-lgloss"); CmdArgs.push_back("--end-group"); - CmdArgs.push_back("-lgcc"); + AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); } if (WantCRTs) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); diff --git a/clang/lib/Driver/ToolChains/RISCVToolchain.h b/clang/lib/Driver/ToolChains/RISCVToolchain.h index 673d749d76ff..bb7f64849bcb 100644 --- a/clang/lib/Driver/ToolChains/RISCVToolchain.h +++ b/clang/lib/Driver/ToolChains/RISCVToolchain.h @@ -25,7 +25,9 @@ public: void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args, Action::OffloadKind) const override; - bool HasNativeLLVMSupport() const override { return true; } + RuntimeLibType GetDefaultRuntimeLibType() const override; + UnwindLibType + GetUnwindLibType(const llvm::opt::ArgList &Args) const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 3add913b700f..907f86b8233c 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -8,6 +8,7 @@ #include "WebAssembly.h" #include "CommonArgs.h" +#include "clang/Basic/Version.h" #include "clang/Config/config.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" @@ -90,6 +91,39 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Output.getFilename()); C.addCommand(std::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs)); + + // When optimizing, if wasm-opt is available, run it. + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + auto WasmOptPath = getToolChain().GetProgramPath("wasm-opt"); + if (WasmOptPath != "wasm-opt") { + StringRef OOpt = "s"; + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + OOpt = "4"; + else if (A->getOption().matches(options::OPT_O0)) + OOpt = "0"; + else if (A->getOption().matches(options::OPT_O)) + OOpt = A->getValue(); + + if (OOpt != "0") { + const char *WasmOpt = Args.MakeArgString(WasmOptPath); + ArgStringList CmdArgs; + CmdArgs.push_back(Output.getFilename()); + CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + C.addCommand(std::make_unique<Command>(JA, *this, WasmOpt, CmdArgs, Inputs)); + } + } + } +} + +/// Given a base library directory, append path components to form the +/// LTO directory. +static std::string AppendLTOLibDir(const std::string &Dir) { + // The version allows the path to be keyed to the specific version of + // LLVM in used, as the bitcode format is not stable. + return Dir + "/llvm-lto/" LLVM_VERSION_STRING; } WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, @@ -100,16 +134,24 @@ WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, getProgramPaths().push_back(getDriver().getInstalledDir()); + auto SysRoot = getDriver().SysRoot; if (getTriple().getOS() == llvm::Triple::UnknownOS) { // Theoretically an "unknown" OS should mean no standard libraries, however // it could also mean that a custom set of libraries is in use, so just add // /lib to the search path. Disable multiarch in this case, to discourage // paths containing "unknown" from acquiring meanings. - getFilePaths().push_back(getDriver().SysRoot + "/lib"); + getFilePaths().push_back(SysRoot + "/lib"); } else { const std::string MultiarchTriple = - getMultiarchTriple(getDriver(), Triple, getDriver().SysRoot); - getFilePaths().push_back(getDriver().SysRoot + "/lib/" + MultiarchTriple); + getMultiarchTriple(getDriver(), Triple, SysRoot); + if (D.isUsingLTO()) { + // For LTO, enable use of lto-enabled sysroot libraries too, if available. + // Note that the directory is keyed to the LLVM revision, as LLVM's + // bitcode format is not stable. + auto Dir = AppendLTOLibDir(SysRoot + "/lib/" + MultiarchTriple); + getFilePaths().push_back(Dir); + } + getFilePaths().push_back(SysRoot + "/lib/" + MultiarchTriple); } } @@ -137,9 +179,9 @@ bool WebAssembly::HasNativeLLVMSupport() const { return true; } void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, 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"); + if (!DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, true)) + CC1Args.push_back("-fno-use-init-array"); // '-pthread' implies atomics, bulk-memory, mutable-globals, and sign-ext if (DriverArgs.hasFlag(options::OPT_pthread, options::OPT_no_pthread, @@ -181,6 +223,12 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, getDriver().Diag(diag::err_drv_argument_not_allowed_with) << "-fwasm-exceptions" << "-mno-exception-handling"; + // '-fwasm-exceptions' is not compatible with '-mno-reference-types' + if (DriverArgs.hasFlag(options::OPT_mno_reference_types, + options::OPT_mexception_handing, false)) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << "-fwasm-exceptions" + << "-mno-reference-types"; // '-fwasm-exceptions' is not compatible with // '-mllvm -enable-emscripten-cxx-exceptions' for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { @@ -189,9 +237,11 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, << "-fwasm-exceptions" << "-mllvm -enable-emscripten-cxx-exceptions"; } - // '-fwasm-exceptions' implies exception-handling + // '-fwasm-exceptions' implies exception-handling and reference-types CC1Args.push_back("-target-feature"); CC1Args.push_back("+exception-handling"); + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+reference-types"); } } diff --git a/clang/lib/Driver/Types.cpp b/clang/lib/Driver/Types.cpp index a30710645af3..7d83be2521e7 100644 --- a/clang/lib/Driver/Types.cpp +++ b/clang/lib/Driver/Types.cpp @@ -212,6 +212,16 @@ bool types::isHIP(ID Id) { } } +bool types::isFortran(ID Id) { + switch (Id) { + default: + return false; + + case TY_Fortran: case TY_PP_Fortran: + return true; + } +} + bool types::isSrcFile(ID Id) { return Id != TY_Object && getPreprocessedType(Id) != TY_INVALID; } @@ -320,22 +330,6 @@ void types::getCompilationPhases(const clang::driver::Driver &Driver, llvm::copy_if(PhaseList, std::back_inserter(P), [](phases::ID Phase) { return Phase <= phases::Precompile; }); - // Treat Interface Stubs like its own compilation mode. - else if (DAL.getLastArg(options::OPT_emit_interface_stubs)) { - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> IfsModePhaseList; - llvm::SmallVector<phases::ID, phases::MaxNumberOfPhases> &PL = PhaseList; - phases::ID LastPhase = phases::IfsMerge; - if (Id != types::TY_IFS) { - if (DAL.hasArg(options::OPT_c)) - LastPhase = phases::Compile; - PL = IfsModePhaseList; - types::getCompilationPhases(types::TY_IFS_CPP, PL); - } - llvm::copy_if(PL, std::back_inserter(P), [&](phases::ID Phase) { - return Phase <= LastPhase; - }); - } - // -{fsyntax-only,-analyze,emit-ast} only run up to the compiler. else if (DAL.getLastArg(options::OPT_fsyntax_only) || DAL.getLastArg(options::OPT_print_supported_cpus) || diff --git a/clang/lib/Driver/XRayArgs.cpp b/clang/lib/Driver/XRayArgs.cpp index 16e7c7ecf36b..a2dd63f9eb77 100644 --- a/clang/lib/Driver/XRayArgs.cpp +++ b/clang/lib/Driver/XRayArgs.cpp @@ -70,6 +70,13 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { D.Diag(diag::err_drv_clang_unsupported) << (std::string(XRayInstrumentOption) + " on " + Triple.str()); } + + // Both XRay and -fpatchable-function-entry use + // TargetOpcode::PATCHABLE_FUNCTION_ENTER. + if (Arg *A = Args.getLastArg(options::OPT_fpatchable_function_entry_EQ)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << "-fxray-instrument" << A->getSpelling(); + XRayInstrument = true; if (const Arg *A = Args.getLastArg(options::OPT_fxray_instruction_threshold_, @@ -129,7 +136,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { // are treated as actual dependencies. for (const auto &Filename : Args.getAllArgValues(options::OPT_fxray_always_instrument)) { - if (llvm::sys::fs::exists(Filename)) { + if (D.getVFS().exists(Filename)) { AlwaysInstrumentFiles.push_back(Filename); ExtraDeps.push_back(Filename); } else @@ -138,7 +145,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { for (const auto &Filename : Args.getAllArgValues(options::OPT_fxray_never_instrument)) { - if (llvm::sys::fs::exists(Filename)) { + if (D.getVFS().exists(Filename)) { NeverInstrumentFiles.push_back(Filename); ExtraDeps.push_back(Filename); } else @@ -147,7 +154,7 @@ XRayArgs::XRayArgs(const ToolChain &TC, const ArgList &Args) { for (const auto &Filename : Args.getAllArgValues(options::OPT_fxray_attr_list)) { - if (llvm::sys::fs::exists(Filename)) { + if (D.getVFS().exists(Filename)) { AttrListFiles.push_back(Filename); ExtraDeps.push_back(Filename); } else diff --git a/clang/lib/Format/BreakableToken.cpp b/clang/lib/Format/BreakableToken.cpp index 09ea5473c0c1..cd0eb0b4324a 100644 --- a/clang/lib/Format/BreakableToken.cpp +++ b/clang/lib/Format/BreakableToken.cpp @@ -88,11 +88,11 @@ getCommentSplit(StringRef Text, unsigned ContentStartColumn, StringRef::size_type SpaceOffset = Text.find_last_of(Blanks, MaxSplitBytes); - static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\."); + static const auto kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\."); while (SpaceOffset != StringRef::npos) { // Do not split before a number followed by a dot: this would be interpreted // as a numbered list, which would prevent re-flowing in subsequent passes. - if (kNumberedListRegexp->match(Text.substr(SpaceOffset).ltrim(Blanks))) + if (kNumberedListRegexp.match(Text.substr(SpaceOffset).ltrim(Blanks))) SpaceOffset = Text.find_last_of(Blanks, SpaceOffset); // In JavaScript, some @tags can be followed by {, and machinery that parses // these comments will fail to understand the comment if followed by a line @@ -245,7 +245,7 @@ BreakableStringLiteral::BreakableStringLiteral( BreakableToken::Split BreakableStringLiteral::getSplit( unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, - unsigned ContentStartColumn, llvm::Regex &CommentPragmasRegex) const { + unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const { return getStringSplit(Line.substr(TailOffset), ContentStartColumn, ColumnLimit - Postfix.size(), Style.TabWidth, Encoding); } @@ -271,7 +271,7 @@ unsigned BreakableComment::getLineCount() const { return Lines.size(); } BreakableToken::Split BreakableComment::getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, - llvm::Regex &CommentPragmasRegex) const { + const llvm::Regex &CommentPragmasRegex) const { // Don't break lines matching the comment pragmas regex. if (CommentPragmasRegex.match(Content[LineIndex])) return Split(StringRef::npos, 0); @@ -316,9 +316,9 @@ static bool mayReflowContent(StringRef Content) { // Numbered lists may also start with a number followed by '.' // To avoid issues if a line starts with a number which is actually the end // of a previous line, we only consider numbers with up to 2 digits. - static auto *const kNumberedListRegexp = new llvm::Regex("^[1-9][0-9]?\\. "); + static const auto kNumberedListRegexp = llvm::Regex("^[1-9][0-9]?\\. "); hasSpecialMeaningPrefix = - hasSpecialMeaningPrefix || kNumberedListRegexp->match(Content); + hasSpecialMeaningPrefix || kNumberedListRegexp.match(Content); // Simple heuristic for what to reflow: content should contain at least two // characters and either the first or second character must be @@ -458,7 +458,7 @@ BreakableBlockComment::BreakableBlockComment( BreakableToken::Split BreakableBlockComment::getSplit( unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, - unsigned ContentStartColumn, llvm::Regex &CommentPragmasRegex) const { + unsigned ContentStartColumn, const llvm::Regex &CommentPragmasRegex) const { // Don't break lines matching the comment pragmas regex. if (CommentPragmasRegex.match(Content[LineIndex])) return Split(StringRef::npos, 0); @@ -597,9 +597,8 @@ void BreakableBlockComment::insertBreak(unsigned LineIndex, unsigned TailOffset, PrefixWithTrailingIndent.size()); } -BreakableToken::Split -BreakableBlockComment::getReflowSplit(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const { +BreakableToken::Split BreakableBlockComment::getReflowSplit( + unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const { if (!mayReflow(LineIndex, CommentPragmasRegex)) return Split(StringRef::npos, 0); @@ -706,8 +705,8 @@ BreakableBlockComment::getSplitAfterLastLine(unsigned TailOffset) const { return Split(StringRef::npos, 0); } -bool BreakableBlockComment::mayReflow(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const { +bool BreakableBlockComment::mayReflow( + unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const { // Content[LineIndex] may exclude the indent after the '*' decoration. In that // case, we compute the start of the comment pragma manually. StringRef IndentContent = Content[LineIndex]; @@ -845,7 +844,7 @@ void BreakableLineCommentSection::insertBreak( } BreakableComment::Split BreakableLineCommentSection::getReflowSplit( - unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const { + unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const { if (!mayReflow(LineIndex, CommentPragmasRegex)) return Split(StringRef::npos, 0); @@ -955,7 +954,7 @@ void BreakableLineCommentSection::updateNextToken(LineState &State) const { } bool BreakableLineCommentSection::mayReflow( - unsigned LineIndex, llvm::Regex &CommentPragmasRegex) const { + unsigned LineIndex, const llvm::Regex &CommentPragmasRegex) const { // Line comments have the indent as part of the prefix, so we need to // recompute the start of the line. StringRef IndentContent = Content[LineIndex]; diff --git a/clang/lib/Format/BreakableToken.h b/clang/lib/Format/BreakableToken.h index 72852d59f9c4..a6691300de3b 100644 --- a/clang/lib/Format/BreakableToken.h +++ b/clang/lib/Format/BreakableToken.h @@ -155,7 +155,7 @@ public: /// file. virtual Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, - llvm::Regex &CommentPragmasRegex) const = 0; + const llvm::Regex &CommentPragmasRegex) const = 0; /// Emits the previously retrieved \p Split via \p Whitespaces. virtual void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, @@ -190,7 +190,7 @@ public: /// If the split is not contained within one token, for example when reflowing /// line comments, returns (0, <length>). virtual Split getReflowSplit(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const { + const llvm::Regex &CommentPragmasRegex) const { return Split(StringRef::npos, 0); } @@ -255,7 +255,7 @@ public: Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; void insertBreak(unsigned LineIndex, unsigned TailOffset, Split Split, unsigned ContentIndent, WhitespaceManager &Whitespaces) const override; @@ -298,7 +298,7 @@ public: unsigned getLineCount() const override; Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; void compressWhitespace(unsigned LineIndex, unsigned TailOffset, Split Split, WhitespaceManager &Whitespaces) const override; @@ -309,7 +309,7 @@ protected: // Checks if the content of line LineIndex may be reflown with the previous // line. virtual bool mayReflow(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const = 0; + const llvm::Regex &CommentPragmasRegex) const = 0; // Contains the original text of the lines of the block comment. // @@ -363,7 +363,7 @@ public: Split getSplit(unsigned LineIndex, unsigned TailOffset, unsigned ColumnLimit, unsigned ContentStartColumn, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; unsigned getRangeLength(unsigned LineIndex, unsigned Offset, StringRef::size_type Length, unsigned StartColumn) const override; @@ -375,7 +375,7 @@ public: unsigned ContentIndent, WhitespaceManager &Whitespaces) const override; Split getReflowSplit(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; void reflow(unsigned LineIndex, WhitespaceManager &Whitespaces) const override; bool introducesBreakBeforeToken() const override; @@ -384,7 +384,7 @@ public: Split getSplitAfterLastLine(unsigned TailOffset) const override; bool mayReflow(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; // Contains Javadoc annotations that require additional indent when continued // on multiple lines. @@ -448,14 +448,14 @@ public: unsigned ContentIndent, WhitespaceManager &Whitespaces) const override; Split getReflowSplit(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; void reflow(unsigned LineIndex, WhitespaceManager &Whitespaces) const override; void adaptStartOfLine(unsigned LineIndex, WhitespaceManager &Whitespaces) const override; void updateNextToken(LineState &State) const override; bool mayReflow(unsigned LineIndex, - llvm::Regex &CommentPragmasRegex) const override; + const llvm::Regex &CommentPragmasRegex) const override; private: // OriginalPrefix[i] contains the original prefix of line i, including diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index cd44c0be85f0..f12bca48c630 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -467,6 +467,7 @@ template <> struct MappingTraits<FormatStyle> { Style.ConstructorInitializerIndentWidth); IO.mapOptional("ContinuationIndentWidth", Style.ContinuationIndentWidth); IO.mapOptional("Cpp11BracedListStyle", Style.Cpp11BracedListStyle); + IO.mapOptional("DeriveLineEnding", Style.DeriveLineEnding); IO.mapOptional("DerivePointerAlignment", Style.DerivePointerAlignment); IO.mapOptional("DisableFormat", Style.DisableFormat); IO.mapOptional("ExperimentalAutoDetectBinPacking", @@ -476,6 +477,8 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("IncludeBlocks", Style.IncludeStyle.IncludeBlocks); IO.mapOptional("IncludeCategories", Style.IncludeStyle.IncludeCategories); IO.mapOptional("IncludeIsMainRegex", Style.IncludeStyle.IncludeIsMainRegex); + IO.mapOptional("IncludeIsMainSourceRegex", + Style.IncludeStyle.IncludeIsMainSourceRegex); IO.mapOptional("IndentCaseLabels", Style.IndentCaseLabels); IO.mapOptional("IndentGotoLabels", Style.IndentGotoLabels); IO.mapOptional("IndentPPDirectives", Style.IndentPPDirectives); @@ -534,16 +537,21 @@ template <> struct MappingTraits<FormatStyle> { IO.mapOptional("SpacesBeforeTrailingComments", Style.SpacesBeforeTrailingComments); IO.mapOptional("SpacesInAngles", Style.SpacesInAngles); + IO.mapOptional("SpacesInConditionalStatement", + Style.SpacesInConditionalStatement); IO.mapOptional("SpacesInContainerLiterals", Style.SpacesInContainerLiterals); IO.mapOptional("SpacesInCStyleCastParentheses", Style.SpacesInCStyleCastParentheses); IO.mapOptional("SpacesInParentheses", Style.SpacesInParentheses); IO.mapOptional("SpacesInSquareBrackets", Style.SpacesInSquareBrackets); + IO.mapOptional("SpaceBeforeSquareBrackets", + Style.SpaceBeforeSquareBrackets); IO.mapOptional("Standard", Style.Standard); IO.mapOptional("StatementMacros", Style.StatementMacros); IO.mapOptional("TabWidth", Style.TabWidth); IO.mapOptional("TypenameMacros", Style.TypenameMacros); + IO.mapOptional("UseCRLF", Style.UseCRLF); IO.mapOptional("UseTab", Style.UseTab); } }; @@ -760,6 +768,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.ConstructorInitializerIndentWidth = 4; LLVMStyle.ContinuationIndentWidth = 4; LLVMStyle.Cpp11BracedListStyle = true; + LLVMStyle.DeriveLineEnding = true; LLVMStyle.DerivePointerAlignment = false; LLVMStyle.ExperimentalAutoDetectBinPacking = false; LLVMStyle.FixNamespaceComments = true; @@ -790,6 +799,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.PointerAlignment = FormatStyle::PAS_Right; LLVMStyle.SpacesBeforeTrailingComments = 1; LLVMStyle.Standard = FormatStyle::LS_Latest; + LLVMStyle.UseCRLF = false; LLVMStyle.UseTab = FormatStyle::UT_Never; LLVMStyle.ReflowComments = true; LLVMStyle.SpacesInParentheses = false; @@ -807,7 +817,9 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.SpaceBeforeRangeBasedForLoopColon = true; LLVMStyle.SpaceBeforeAssignmentOperators = true; LLVMStyle.SpaceBeforeCpp11BracedList = false; + LLVMStyle.SpaceBeforeSquareBrackets = false; LLVMStyle.SpacesInAngles = false; + LLVMStyle.SpacesInConditionalStatement = false; LLVMStyle.PenaltyBreakAssignment = prec::Assignment; LLVMStyle.PenaltyBreakComment = 300; @@ -1348,7 +1360,11 @@ public: WhitespaceManager Whitespaces( Env.getSourceManager(), Style, - inputUsesCRLF(Env.getSourceManager().getBufferData(Env.getFileID()))); + Style.DeriveLineEnding + ? inputUsesCRLF( + Env.getSourceManager().getBufferData(Env.getFileID()), + Style.UseCRLF) + : Style.UseCRLF); ContinuationIndenter Indenter(Style, Tokens.getKeywords(), Env.getSourceManager(), Whitespaces, Encoding, BinPackInconclusiveFunctions); @@ -1369,8 +1385,10 @@ public: } private: - static bool inputUsesCRLF(StringRef Text) { - return Text.count('\r') * 2 > Text.count('\n'); + static bool inputUsesCRLF(StringRef Text, bool DefaultToCRLF) { + size_t LF = Text.count('\n'); + size_t CR = Text.count('\r') * 2; + return LF == CR ? DefaultToCRLF : CR > LF; } bool @@ -2600,6 +2618,10 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, if (std::error_code EC = FS->makeAbsolute(Path)) return make_string_error(EC.message()); + llvm::SmallVector<std::string, 2> FilesToLookFor; + FilesToLookFor.push_back(".clang-format"); + FilesToLookFor.push_back("_clang-format"); + for (StringRef Directory = Path; !Directory.empty(); Directory = llvm::sys::path::parent_path(Directory)) { @@ -2609,43 +2631,35 @@ llvm::Expected<FormatStyle> getStyle(StringRef StyleName, StringRef FileName, continue; } - SmallString<128> ConfigFile(Directory); - - llvm::sys::path::append(ConfigFile, ".clang-format"); - LLVM_DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n"); + for (const auto &F : FilesToLookFor) { + SmallString<128> ConfigFile(Directory); - Status = FS->status(ConfigFile.str()); - bool FoundConfigFile = - Status && (Status->getType() == llvm::sys::fs::file_type::regular_file); - if (!FoundConfigFile) { - // Try _clang-format too, since dotfiles are not commonly used on Windows. - ConfigFile = Directory; - llvm::sys::path::append(ConfigFile, "_clang-format"); + llvm::sys::path::append(ConfigFile, F); LLVM_DEBUG(llvm::dbgs() << "Trying " << ConfigFile << "...\n"); + Status = FS->status(ConfigFile.str()); - FoundConfigFile = Status && (Status->getType() == - llvm::sys::fs::file_type::regular_file); - } - if (FoundConfigFile) { - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = - FS->getBufferForFile(ConfigFile.str()); - if (std::error_code EC = Text.getError()) - return make_string_error(EC.message()); - if (std::error_code ec = - parseConfiguration(Text.get()->getBuffer(), &Style)) { - if (ec == ParseError::Unsuitable) { - if (!UnsuitableConfigFiles.empty()) - UnsuitableConfigFiles.append(", "); - UnsuitableConfigFiles.append(ConfigFile); - continue; + if (Status && + (Status->getType() == llvm::sys::fs::file_type::regular_file)) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> Text = + FS->getBufferForFile(ConfigFile.str()); + if (std::error_code EC = Text.getError()) + return make_string_error(EC.message()); + if (std::error_code ec = + parseConfiguration(Text.get()->getBuffer(), &Style)) { + if (ec == ParseError::Unsuitable) { + if (!UnsuitableConfigFiles.empty()) + UnsuitableConfigFiles.append(", "); + UnsuitableConfigFiles.append(ConfigFile); + continue; + } + return make_string_error("Error reading " + ConfigFile + ": " + + ec.message()); } - return make_string_error("Error reading " + ConfigFile + ": " + - ec.message()); + LLVM_DEBUG(llvm::dbgs() + << "Using configuration file " << ConfigFile << "\n"); + return Style; } - LLVM_DEBUG(llvm::dbgs() - << "Using configuration file " << ConfigFile << "\n"); - return Style; } } if (!UnsuitableConfigFiles.empty()) diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index b11f36559a8b..e9cd327754ef 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -60,6 +60,8 @@ namespace format { TYPE(JsExponentiationEqual) \ TYPE(JsFatArrow) \ TYPE(JsNonNullAssertion) \ + TYPE(JsNullishCoalescingOperator) \ + TYPE(JsNullPropagatingOperator) \ TYPE(JsPrivateIdentifier) \ TYPE(JsTypeColon) \ TYPE(JsTypeOperator) \ @@ -405,7 +407,7 @@ struct FormatToken { bool isMemberAccess() const { return isOneOf(tok::arrow, tok::period, tok::arrowstar) && !isOneOf(TT_DesignatedInitializerPeriod, TT_TrailingReturnArrow, - TT_LambdaArrow); + TT_LambdaArrow, TT_LeadingJavaAnnotation); } bool isUnaryOperator() const { diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 5d8a77577c0b..ef20ba884fb3 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -100,6 +100,10 @@ void FormatTokenLexer::tryMergePreviousTokens() { static const tok::TokenKind JSExponentiation[] = {tok::star, tok::star}; static const tok::TokenKind JSExponentiationEqual[] = {tok::star, tok::starequal}; + static const tok::TokenKind JSNullPropagatingOperator[] = {tok::question, + tok::period}; + static const tok::TokenKind JSNullishOperator[] = {tok::question, + tok::question}; // FIXME: Investigate what token type gives the correct operator priority. if (tryMergeTokens(JSIdentity, TT_BinaryOperator)) @@ -116,6 +120,14 @@ void FormatTokenLexer::tryMergePreviousTokens() { Tokens.back()->Tok.setKind(tok::starequal); return; } + if (tryMergeTokens(JSNullishOperator, TT_JsNullishCoalescingOperator)) + return; + if (tryMergeTokens(JSNullPropagatingOperator, + TT_JsNullPropagatingOperator)) { + // Treat like a regular "." access. + Tokens.back()->Tok.setKind(tok::period); + return; + } if (tryMergeJSPrivateIdentifier()) return; } diff --git a/clang/lib/Format/NamespaceEndCommentsFixer.cpp b/clang/lib/Format/NamespaceEndCommentsFixer.cpp index 98901cff2681..20b424f86077 100644 --- a/clang/lib/Format/NamespaceEndCommentsFixer.cpp +++ b/clang/lib/Format/NamespaceEndCommentsFixer.cpp @@ -92,24 +92,24 @@ bool validEndComment(const FormatToken *RBraceTok, StringRef NamespaceName, // Matches a valid namespace end comment. // Valid namespace end comments don't need to be edited. - static llvm::Regex *const NamespaceCommentPattern = - new llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" - "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$", - llvm::Regex::IgnoreCase); - static llvm::Regex *const NamespaceMacroCommentPattern = - new llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" - "([a-zA-Z0-9_]+)\\(([a-zA-Z0-9:_]*)\\)\\.? *(\\*/)?$", - llvm::Regex::IgnoreCase); + static const llvm::Regex NamespaceCommentPattern = + llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" + "namespace( +([a-zA-Z0-9:_]+))?\\.? *(\\*/)?$", + llvm::Regex::IgnoreCase); + static const llvm::Regex NamespaceMacroCommentPattern = + llvm::Regex("^/[/*] *(end (of )?)? *(anonymous|unnamed)? *" + "([a-zA-Z0-9_]+)\\(([a-zA-Z0-9:_]*)\\)\\.? *(\\*/)?$", + llvm::Regex::IgnoreCase); SmallVector<StringRef, 8> Groups; if (NamespaceTok->is(TT_NamespaceMacro) && - NamespaceMacroCommentPattern->match(Comment->TokenText, &Groups)) { + NamespaceMacroCommentPattern.match(Comment->TokenText, &Groups)) { StringRef NamespaceTokenText = Groups.size() > 4 ? Groups[4] : ""; // The name of the macro must be used. if (NamespaceTokenText != NamespaceTok->TokenText) return false; } else if (NamespaceTok->isNot(tok::kw_namespace) || - !NamespaceCommentPattern->match(Comment->TokenText, &Groups)) { + !NamespaceCommentPattern.match(Comment->TokenText, &Groups)) { // Comment does not match regex. return false; } diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 1ed35597d075..d5d394e61926 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -950,9 +950,9 @@ private: if (CurrentToken->isOneOf(tok::star, tok::amp)) CurrentToken->Type = TT_PointerOrReference; consumeToken(); - if (CurrentToken && - CurrentToken->Previous->isOneOf(TT_BinaryOperator, TT_UnaryOperator, - tok::comma)) + if (CurrentToken && CurrentToken->Previous->isOneOf( + TT_BinaryOperator, TT_UnaryOperator, tok::comma, + tok::star, tok::arrow, tok::amp, tok::ampamp)) CurrentToken->Previous->Type = TT_OverloadedOperator; } if (CurrentToken) { @@ -1344,12 +1344,80 @@ private: Contexts.back().IsExpression = false; } else if (Current.is(tok::kw_new)) { Contexts.back().CanBeExpression = false; - } else if (Current.isOneOf(tok::semi, tok::exclaim)) { + } else if (Current.is(tok::semi) || + (Current.is(tok::exclaim) && Current.Previous && + !Current.Previous->is(tok::kw_operator))) { // This should be the condition or increment in a for-loop. + // But not operator !() (can't use TT_OverloadedOperator here as its not + // been annotated yet). Contexts.back().IsExpression = true; } } + static FormatToken *untilMatchingParen(FormatToken *Current) { + // Used when `MatchingParen` is not yet established. + int ParenLevel = 0; + while (Current) { + if (Current->is(tok::l_paren)) + ParenLevel++; + if (Current->is(tok::r_paren)) + ParenLevel--; + if (ParenLevel < 1) + break; + Current = Current->Next; + } + return Current; + } + + static bool isDeductionGuide(FormatToken &Current) { + // Look for a deduction guide template<T> A(...) -> A<...>; + if (Current.Previous && Current.Previous->is(tok::r_paren) && + Current.startsSequence(tok::arrow, tok::identifier, tok::less)) { + // Find the TemplateCloser. + FormatToken *TemplateCloser = Current.Next->Next; + int NestingLevel = 0; + while (TemplateCloser) { + // Skip over an expressions in parens A<(3 < 2)>; + if (TemplateCloser->is(tok::l_paren)) { + // No Matching Paren yet so skip to matching paren + TemplateCloser = untilMatchingParen(TemplateCloser); + } + if (TemplateCloser->is(tok::less)) + NestingLevel++; + if (TemplateCloser->is(tok::greater)) + NestingLevel--; + if (NestingLevel < 1) + break; + TemplateCloser = TemplateCloser->Next; + } + // Assuming we have found the end of the template ensure its followed + // with a semi-colon. + if (TemplateCloser && TemplateCloser->Next && + TemplateCloser->Next->is(tok::semi) && + Current.Previous->MatchingParen) { + // Determine if the identifier `A` prior to the A<..>; is the same as + // prior to the A(..) + FormatToken *LeadingIdentifier = + Current.Previous->MatchingParen->Previous; + + // Differentiate a deduction guide by seeing the + // > of the template prior to the leading identifier. + if (LeadingIdentifier) { + FormatToken *PriorLeadingIdentifier = LeadingIdentifier->Previous; + // Skip back past explicit decoration + if (PriorLeadingIdentifier && + PriorLeadingIdentifier->is(tok::kw_explicit)) + PriorLeadingIdentifier = PriorLeadingIdentifier->Previous; + + return (PriorLeadingIdentifier && + PriorLeadingIdentifier->is(TT_TemplateCloser) && + LeadingIdentifier->TokenText == Current.Next->TokenText); + } + } + } + return false; + } + void determineTokenType(FormatToken &Current) { if (!Current.is(TT_Unknown)) // The token type is already known. @@ -1397,6 +1465,10 @@ private: !Current.Previous->is(tok::kw_operator)) { // not auto operator->() -> xxx; Current.Type = TT_TrailingReturnArrow; + + } else if (isDeductionGuide(Current)) { + // Deduction guides trailing arrow " A(...) -> A<T>;". + Current.Type = TT_TrailingReturnArrow; } else if (Current.isOneOf(tok::star, tok::amp, tok::ampamp)) { Current.Type = determineStarAmpUsage(Current, Contexts.back().CanBeExpression && @@ -1757,7 +1829,8 @@ private: // Use heuristics to recognize unary operators. if (PrevToken->isOneOf(tok::equal, tok::l_paren, tok::comma, tok::l_square, tok::question, tok::colon, tok::kw_return, - tok::kw_case, tok::at, tok::l_brace, tok::kw_throw)) + tok::kw_case, tok::at, tok::l_brace, tok::kw_throw, + tok::kw_co_return, tok::kw_co_yield)) return TT_UnaryOperator; // There can't be two consecutive binary operators. @@ -2087,11 +2160,22 @@ static bool isFunctionDeclarationName(const FormatToken &Current, continue; if (Next->isOneOf(tok::kw_new, tok::kw_delete)) { // For 'new[]' and 'delete[]'. - if (Next->Next && Next->Next->is(tok::l_square) && Next->Next->Next && - Next->Next->Next->is(tok::r_square)) + if (Next->Next && + Next->Next->startsSequence(tok::l_square, tok::r_square)) Next = Next->Next->Next; continue; } + if (Next->startsSequence(tok::l_square, tok::r_square)) { + // For operator[](). + Next = Next->Next; + continue; + } + if ((Next->isSimpleTypeSpecifier() || Next->is(tok::identifier)) && + Next->Next && Next->Next->isOneOf(tok::star, tok::amp, tok::ampamp)) { + // For operator void*(), operator char*(), operator Foo*(). + Next = Next->Next; + continue; + } break; } @@ -2508,6 +2592,13 @@ bool TokenAnnotator::spaceRequiredBeforeParens(const FormatToken &Right) const { Right.ParameterCount > 0); } +/// Returns \c true if the token is followed by a boolean condition, \c false +/// otherwise. +static bool isKeywordWithCondition(const FormatToken &Tok) { + return Tok.isOneOf(tok::kw_if, tok::kw_for, tok::kw_while, tok::kw_switch, + tok::kw_constexpr); +} + bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left, const FormatToken &Right) { @@ -2526,6 +2617,15 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, (Left.is(tok::l_brace) && Left.BlockKind != BK_Block && Right.is(tok::r_brace) && Right.BlockKind != BK_Block)) return Style.SpaceInEmptyParentheses; + if (Style.SpacesInConditionalStatement) { + if (Left.is(tok::l_paren) && Left.Previous && + isKeywordWithCondition(*Left.Previous)) + return true; + if (Right.is(tok::r_paren) && Right.MatchingParen && + Right.MatchingParen->Previous && + isKeywordWithCondition(*Right.MatchingParen->Previous)) + return true; + } if (Left.is(tok::l_paren) || Right.is(tok::r_paren)) return (Right.is(TT_CastRParen) || (Left.MatchingParen && Left.MatchingParen->is(TT_CastRParen))) @@ -2567,7 +2667,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return Left.Tok.isLiteral() || (Left.is(tok::identifier) && Left.Previous && Left.Previous->is(tok::kw_case)); if (Left.is(tok::l_square) && Right.is(tok::amp)) - return false; + return Style.SpacesInSquareBrackets; if (Right.is(TT_PointerOrReference)) { if (Left.is(tok::r_paren) && Line.MightBeFunctionDecl) { if (!Left.MatchingParen) @@ -2605,6 +2705,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, tok::l_square)); if (Right.is(tok::star) && Left.is(tok::l_paren)) return false; + if (Right.isOneOf(tok::star, tok::amp, tok::ampamp) && + (Left.is(tok::identifier) || Left.isSimpleTypeSpecifier()) && + Left.Previous && Left.Previous->is(tok::kw_operator)) + // Space between the type and the * + // operator void*(), operator char*(), operator Foo*() dependant + // on PointerAlignment style. + return (Style.PointerAlignment != FormatStyle::PAS_Left); const auto SpaceRequiredForArrayInitializerLSquare = [](const FormatToken &LSquareTok, const FormatStyle &Style) { return Style.SpacesInContainerLiterals || @@ -2634,7 +2741,9 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, !Right.isOneOf(TT_ObjCMethodExpr, TT_LambdaLSquare, TT_DesignatedInitializerLSquare, TT_StructuredBindingLSquare, TT_AttributeSquare) && - !Left.isOneOf(tok::numeric_constant, TT_DictLiteral)) + !Left.isOneOf(tok::numeric_constant, TT_DictLiteral) && + !(!Left.is(tok::r_square) && Style.SpaceBeforeSquareBrackets && + Right.is(TT_ArraySubscriptLSquare))) return false; if (Left.is(tok::l_brace) && Right.is(tok::r_brace)) return !Left.Children.empty(); // No spaces in "{}". @@ -2906,14 +3015,18 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, return true; } if (Left.is(TT_UnaryOperator)) { - // The alternative operators for ~ and ! are "compl" and "not". - // If they are used instead, we do not want to combine them with - // the token to the right, unless that is a left paren. if (!Right.is(tok::l_paren)) { + // The alternative operators for ~ and ! are "compl" and "not". + // If they are used instead, we do not want to combine them with + // the token to the right, unless that is a left paren. if (Left.is(tok::exclaim) && Left.TokenText == "not") return true; if (Left.is(tok::tilde) && Left.TokenText == "compl") return true; + // Lambda captures allow for a lone &, so "&]" needs to be properly + // handled. + if (Left.is(tok::amp) && Right.is(tok::r_square)) + return Style.SpacesInSquareBrackets; } return (Style.SpaceAfterLogicalNot && Left.is(tok::exclaim)) || Right.is(TT_BinaryOperator); @@ -2947,7 +3060,8 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, // The identifier might actually be a macro name such as ALWAYS_INLINE. If // this turns out to be too lenient, add analysis of the identifier itself. return Right.WhitespaceRange.getBegin() != Right.WhitespaceRange.getEnd(); - if (Right.is(tok::coloncolon) && !Left.isOneOf(tok::l_brace, tok::comment)) + if (Right.is(tok::coloncolon) && + !Left.isOneOf(tok::l_brace, tok::comment, tok::l_paren)) return (Left.is(TT_TemplateOpener) && Style.Standard < FormatStyle::LS_Cpp11) || !(Left.isOneOf(tok::l_paren, tok::r_paren, tok::l_square, diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index 8b8d357d9cbe..fec85f1174da 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -326,6 +326,19 @@ private: FormatStyle::BWACS_Always) ? tryMergeSimpleBlock(I, E, Limit) : 0; + } else if (I[1]->First->is(tok::l_brace) && + TheLine->First->isOneOf(tok::kw_else, tok::kw_catch) && + Style.BraceWrapping.AfterControlStatement == + FormatStyle::BWACS_MultiLine) { + // This case if different from the upper BWACS_MultiLine processing + // in that a preceding r_brace is not on the same line as else/catch + // most likely because of BeforeElse/BeforeCatch set to true. + // If the line length doesn't fit ColumnLimit, leave l_brace on the + // next line to respect the BWACS_MultiLine. + return (Style.ColumnLimit == 0 || + TheLine->Last->TotalLength <= Style.ColumnLimit) + ? 1 + : 0; } // Try to merge either empty or one-line block if is precedeed by control // statement token diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index bbe05602f6da..ead6b4743207 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -466,7 +466,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { (NextTok->is(tok::semi) && (!ExpectClassBody || LBraceStack.size() != 1)) || (NextTok->isBinaryOperator() && !NextIsObjCMethod); - if (NextTok->is(tok::l_square)) { + if (!Style.isCSharp() && NextTok->is(tok::l_square)) { // We can have an array subscript after a braced init // list, but C++11 attributes are expected after blocks. NextTok = Tokens->getNextToken(); @@ -2498,9 +2498,10 @@ bool UnwrappedLineParser::isOnNewLine(const FormatToken &FormatTok) { // Checks if \p FormatTok is a line comment that continues the line comment // section on \p Line. -static bool continuesLineCommentSection(const FormatToken &FormatTok, - const UnwrappedLine &Line, - llvm::Regex &CommentPragmasRegex) { +static bool +continuesLineCommentSection(const FormatToken &FormatTok, + const UnwrappedLine &Line, + const llvm::Regex &CommentPragmasRegex) { if (Line.Tokens.empty()) return false; diff --git a/clang/lib/Frontend/ASTUnit.cpp b/clang/lib/Frontend/ASTUnit.cpp index f5e291b7fe17..b3264952ff47 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -61,7 +61,7 @@ #include "clang/Serialization/ASTWriter.h" #include "clang/Serialization/ContinuousRangeMap.h" #include "clang/Serialization/InMemoryModuleCache.h" -#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFile.h" #include "clang/Serialization/PCHContainerOperations.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -1457,7 +1457,7 @@ void ASTUnit::transferASTDataFromCompilerInstance(CompilerInstance &CI) { CI.setFileManager(nullptr); if (CI.hasTarget()) Target = &CI.getTarget(); - Reader = CI.getModuleManager(); + Reader = CI.getASTReader(); HadModuleLoaderFatalFailure = CI.hadModuleLoaderFatalFailure(); } diff --git a/clang/lib/Frontend/ChainedIncludesSource.cpp b/clang/lib/Frontend/ChainedIncludesSource.cpp index 29fee7246d14..dec281529b9e 100644 --- a/clang/lib/Frontend/ChainedIncludesSource.cpp +++ b/clang/lib/Frontend/ChainedIncludesSource.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/Builtins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index c409c07ff133..688f21dd0908 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -75,7 +75,7 @@ void CompilerInstance::setInvocation( bool CompilerInstance::shouldBuildGlobalModuleIndex() const { return (BuildGlobalModuleIndex || - (ModuleManager && ModuleManager->isGlobalIndexUnavailable() && + (TheASTReader && TheASTReader->isGlobalIndexUnavailable() && getFrontendOpts().GenerateGlobalModuleIndex)) && !ModuleBuildFailed; } @@ -135,13 +135,13 @@ std::unique_ptr<Sema> CompilerInstance::takeSema() { return std::move(TheSema); } -IntrusiveRefCntPtr<ASTReader> CompilerInstance::getModuleManager() const { - return ModuleManager; +IntrusiveRefCntPtr<ASTReader> CompilerInstance::getASTReader() const { + return TheASTReader; } void CompilerInstance::setModuleManager(IntrusiveRefCntPtr<ASTReader> Reader) { assert(ModuleCache.get() == &Reader->getModuleManager().getModuleCache() && "Expected ASTReader to use the same PCM cache"); - ModuleManager = std::move(Reader); + TheASTReader = std::move(Reader); } std::shared_ptr<ModuleDependencyCollector> @@ -380,7 +380,7 @@ void CompilerInstance::createPreprocessor(TranslationUnitKind TUKind) { const PreprocessorOptions &PPOpts = getPreprocessorOpts(); // The module manager holds a reference to the old preprocessor (if any). - ModuleManager.reset(); + TheASTReader.reset(); // Create the Preprocessor. HeaderSearch *HeaderInfo = @@ -494,7 +494,7 @@ void CompilerInstance::createPCHExternalASTSource( StringRef Path, bool DisablePCHValidation, bool AllowPCHWithCompilerErrors, void *DeserializationListener, bool OwnDeserializationListener) { bool Preamble = getPreprocessorOpts().PrecompiledPreambleBytes.first != 0; - ModuleManager = createPCHExternalASTSource( + TheASTReader = createPCHExternalASTSource( Path, getHeaderSearchOpts().Sysroot, DisablePCHValidation, AllowPCHWithCompilerErrors, getPreprocessor(), getModuleCache(), getASTContext(), getPCHContainerReader(), @@ -672,7 +672,7 @@ CompilerInstance::createDefaultOutputFile(bool Binary, StringRef InFile, StringRef Extension) { return createOutputFile(getFrontendOpts().OutputFile, Binary, /*RemoveFileOnSignal=*/true, InFile, Extension, - /*UseTemporary=*/true); + getFrontendOpts().UseTemporary); } std::unique_ptr<raw_pwrite_stream> CompilerInstance::createNullOutputFile() { @@ -917,8 +917,9 @@ bool CompilerInstance::ExecuteAction(FrontendAction &Act) { if (!hasTarget()) return false; - // Create TargetInfo for the other side of CUDA and OpenMP compilation. - if ((getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) && + // Create TargetInfo for the other side of CUDA/OpenMP/SYCL compilation. + if ((getLangOpts().CUDA || getLangOpts().OpenMPIsDevice || + getLangOpts().SYCLIsDevice) && !getFrontendOpts().AuxTriple.empty()) { auto TO = std::make_shared<TargetOptions>(); TO->Triple = llvm::Triple::normalize(getFrontendOpts().AuxTriple); @@ -1179,13 +1180,12 @@ static const FileEntry *getPublicModuleMap(const FileEntry *File, return nullptr; } -/// Compile a module file for the given module, using the options -/// provided by the importing compiler instance. Returns true if the module -/// was built without errors. -static bool compileModuleImpl(CompilerInstance &ImportingInstance, - SourceLocation ImportLoc, - Module *Module, - StringRef ModuleFileName) { +/// Compile a module file for the given module in a separate compiler instance, +/// using the options provided by the importing compiler instance. Returns true +/// if the module was built without errors. +static bool compileModule(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, Module *Module, + StringRef ModuleFileName) { InputKind IK(getLanguageFromOptions(ImportingInstance.getLangOpts()), InputKind::ModuleMap); @@ -1245,10 +1245,17 @@ static bool compileModuleImpl(CompilerInstance &ImportingInstance, return Result; } -static bool compileAndLoadModule(CompilerInstance &ImportingInstance, - SourceLocation ImportLoc, - SourceLocation ModuleNameLoc, Module *Module, - StringRef ModuleFileName) { +/// Compile a module in a separate compiler instance and read the AST, +/// returning true if the module compiles without errors. +/// +/// Uses a lock file manager and exponential backoff to reduce the chances that +/// multiple instances will compete to create the same module. On timeout, +/// deletes the lock file in order to avoid deadlock from crashing processes or +/// bugs in the lock file manager. +static bool compileModuleAndReadAST(CompilerInstance &ImportingInstance, + SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, + Module *Module, StringRef ModuleFileName) { DiagnosticsEngine &Diags = ImportingInstance.getDiagnostics(); auto diagnoseBuildFailure = [&] { @@ -1276,8 +1283,8 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance, LLVM_FALLTHROUGH; case llvm::LockFileManager::LFS_Owned: // We're responsible for building the module ourselves. - if (!compileModuleImpl(ImportingInstance, ModuleNameLoc, Module, - ModuleFileName)) { + if (!compileModule(ImportingInstance, ModuleNameLoc, Module, + ModuleFileName)) { diagnoseBuildFailure(); return false; } @@ -1307,7 +1314,7 @@ static bool compileAndLoadModule(CompilerInstance &ImportingInstance, // Try to read the module file, now that we've compiled it. ASTReader::ASTReadResult ReadResult = - ImportingInstance.getModuleManager()->ReadAST( + ImportingInstance.getASTReader()->ReadAST( ModuleFileName, serialization::MK_ImplicitModule, ImportLoc, ModuleLoadCapabilities); @@ -1471,52 +1478,52 @@ static void pruneModuleCache(const HeaderSearchOptions &HSOpts) { } } -void CompilerInstance::createModuleManager() { - if (!ModuleManager) { - if (!hasASTContext()) - createASTContext(); +void CompilerInstance::createASTReader() { + if (TheASTReader) + return; - // If we're implicitly building modules but not currently recursively - // building a module, check whether we need to prune the module cache. - if (getSourceManager().getModuleBuildStack().empty() && - !getPreprocessor().getHeaderSearchInfo().getModuleCachePath().empty() && - getHeaderSearchOpts().ModuleCachePruneInterval > 0 && - getHeaderSearchOpts().ModuleCachePruneAfter > 0) { - pruneModuleCache(getHeaderSearchOpts()); - } + if (!hasASTContext()) + createASTContext(); - HeaderSearchOptions &HSOpts = getHeaderSearchOpts(); - std::string Sysroot = HSOpts.Sysroot; - const PreprocessorOptions &PPOpts = getPreprocessorOpts(); - std::unique_ptr<llvm::Timer> ReadTimer; - if (FrontendTimerGroup) - ReadTimer = std::make_unique<llvm::Timer>("reading_modules", - "Reading modules", - *FrontendTimerGroup); - ModuleManager = new ASTReader( - getPreprocessor(), getModuleCache(), &getASTContext(), - getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions, - Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation, - /*AllowASTWithCompilerErrors=*/false, - /*AllowConfigurationMismatch=*/false, - HSOpts.ModulesValidateSystemHeaders, - HSOpts.ValidateASTInputFilesContent, - getFrontendOpts().UseGlobalModuleIndex, std::move(ReadTimer)); - if (hasASTConsumer()) { - ModuleManager->setDeserializationListener( - getASTConsumer().GetASTDeserializationListener()); - getASTContext().setASTMutationListener( - getASTConsumer().GetASTMutationListener()); - } - getASTContext().setExternalSource(ModuleManager); - if (hasSema()) - ModuleManager->InitializeSema(getSema()); - if (hasASTConsumer()) - ModuleManager->StartTranslationUnit(&getASTConsumer()); + // If we're implicitly building modules but not currently recursively + // building a module, check whether we need to prune the module cache. + if (getSourceManager().getModuleBuildStack().empty() && + !getPreprocessor().getHeaderSearchInfo().getModuleCachePath().empty() && + getHeaderSearchOpts().ModuleCachePruneInterval > 0 && + getHeaderSearchOpts().ModuleCachePruneAfter > 0) { + pruneModuleCache(getHeaderSearchOpts()); + } - for (auto &Listener : DependencyCollectors) - Listener->attachToASTReader(*ModuleManager); + HeaderSearchOptions &HSOpts = getHeaderSearchOpts(); + std::string Sysroot = HSOpts.Sysroot; + const PreprocessorOptions &PPOpts = getPreprocessorOpts(); + std::unique_ptr<llvm::Timer> ReadTimer; + if (FrontendTimerGroup) + ReadTimer = std::make_unique<llvm::Timer>("reading_modules", + "Reading modules", + *FrontendTimerGroup); + TheASTReader = new ASTReader( + getPreprocessor(), getModuleCache(), &getASTContext(), + getPCHContainerReader(), getFrontendOpts().ModuleFileExtensions, + Sysroot.empty() ? "" : Sysroot.c_str(), PPOpts.DisablePCHValidation, + /*AllowASTWithCompilerErrors=*/false, + /*AllowConfigurationMismatch=*/false, HSOpts.ModulesValidateSystemHeaders, + HSOpts.ValidateASTInputFilesContent, + getFrontendOpts().UseGlobalModuleIndex, std::move(ReadTimer)); + if (hasASTConsumer()) { + TheASTReader->setDeserializationListener( + getASTConsumer().GetASTDeserializationListener()); + getASTContext().setASTMutationListener( + getASTConsumer().GetASTMutationListener()); } + getASTContext().setExternalSource(TheASTReader); + if (hasSema()) + TheASTReader->InitializeSema(getSema()); + if (hasASTConsumer()) + TheASTReader->StartTranslationUnit(&getASTConsumer()); + + for (auto &Listener : DependencyCollectors) + Listener->attachToASTReader(*TheASTReader); } bool CompilerInstance::loadModuleFile(StringRef FileName) { @@ -1541,12 +1548,9 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { } void registerAll() { - for (auto *II : LoadedModules) { - CI.KnownModules[II] = CI.getPreprocessor() - .getHeaderSearchInfo() - .getModuleMap() - .findModule(II->getName()); - } + ModuleMap &MM = CI.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + for (auto *II : LoadedModules) + MM.cacheModuleLoad(*II, MM.findModule(II->getName())); LoadedModules.clear(); } @@ -1576,8 +1580,8 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { }; // If we don't already have an ASTReader, create one now. - if (!ModuleManager) - createModuleManager(); + if (!TheASTReader) + createASTReader(); // If -Wmodule-file-config-mismatch is mapped as an error or worse, allow the // ASTReader to diagnose it, since it can produce better errors that we can. @@ -1588,11 +1592,11 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { auto Listener = std::make_unique<ReadModuleNames>(*this); auto &ListenerRef = *Listener; - ASTReader::ListenerScope ReadModuleNamesListener(*ModuleManager, + ASTReader::ListenerScope ReadModuleNamesListener(*TheASTReader, std::move(Listener)); // Try to load the module file. - switch (ModuleManager->ReadAST( + switch (TheASTReader->ReadAST( FileName, serialization::MK_ExplicitModule, SourceLocation(), ConfigMismatchIsRecoverable ? ASTReader::ARR_ConfigurationMismatch : 0)) { case ASTReader::Success: @@ -1615,6 +1619,220 @@ bool CompilerInstance::loadModuleFile(StringRef FileName) { } } +namespace { +enum ModuleSource { + MS_ModuleNotFound, + MS_ModuleCache, + MS_PrebuiltModulePath, + MS_ModuleBuildPragma +}; +} // end namespace + +/// Select a source for loading the named module and compute the filename to +/// load it from. +static ModuleSource +selectModuleSource(Module *M, StringRef ModuleName, std::string &ModuleFilename, + const std::map<std::string, std::string> &BuiltModules, + HeaderSearch &HS) { + assert(ModuleFilename.empty() && "Already has a module source?"); + + // Check to see if the module has been built as part of this compilation + // via a module build pragma. + auto BuiltModuleIt = BuiltModules.find(ModuleName); + if (BuiltModuleIt != BuiltModules.end()) { + ModuleFilename = BuiltModuleIt->second; + return MS_ModuleBuildPragma; + } + + // Try to load the module from the prebuilt module path. + const HeaderSearchOptions &HSOpts = HS.getHeaderSearchOpts(); + if (!HSOpts.PrebuiltModuleFiles.empty() || + !HSOpts.PrebuiltModulePaths.empty()) { + ModuleFilename = HS.getPrebuiltModuleFileName(ModuleName); + if (!ModuleFilename.empty()) + return MS_PrebuiltModulePath; + } + + // Try to load the module from the module cache. + if (M) { + ModuleFilename = HS.getCachedModuleFileName(M); + return MS_ModuleCache; + } + + return MS_ModuleNotFound; +} + +ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST( + StringRef ModuleName, SourceLocation ImportLoc, + SourceLocation ModuleNameLoc, bool IsInclusionDirective) { + // Search for a module with the given name. + HeaderSearch &HS = PP->getHeaderSearchInfo(); + Module *M = HS.lookupModule(ModuleName, true, !IsInclusionDirective); + + // Select the source and filename for loading the named module. + std::string ModuleFilename; + ModuleSource Source = + selectModuleSource(M, ModuleName, ModuleFilename, BuiltModules, HS); + if (Source == MS_ModuleNotFound) { + // We can't find a module, error out here. + getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) + << ModuleName << SourceRange(ImportLoc, ModuleNameLoc); + ModuleBuildFailed = true; + // FIXME: Why is this not cached? + return ModuleLoadResult::OtherUncachedFailure; + } + if (ModuleFilename.empty()) { + if (M && M->HasIncompatibleModuleFile) { + // We tried and failed to load a module file for this module. Fall + // back to textual inclusion for its headers. + return ModuleLoadResult::ConfigMismatch; + } + + getDiagnostics().Report(ModuleNameLoc, diag::err_module_build_disabled) + << ModuleName; + ModuleBuildFailed = true; + // FIXME: Why is this not cached? + return ModuleLoadResult::OtherUncachedFailure; + } + + // Create an ASTReader on demand. + if (!getASTReader()) + createASTReader(); + + // Time how long it takes to load the module. + llvm::Timer Timer; + if (FrontendTimerGroup) + Timer.init("loading." + ModuleFilename, "Loading " + ModuleFilename, + *FrontendTimerGroup); + llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); + llvm::TimeTraceScope TimeScope("Module Load", ModuleName); + + // Try to load the module file. If we are not trying to load from the + // module cache, we don't know how to rebuild modules. + unsigned ARRFlags = Source == MS_ModuleCache + ? ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing + : Source == MS_PrebuiltModulePath + ? 0 + : ASTReader::ARR_ConfigurationMismatch; + switch (getASTReader()->ReadAST(ModuleFilename, + Source == MS_PrebuiltModulePath + ? serialization::MK_PrebuiltModule + : Source == MS_ModuleBuildPragma + ? serialization::MK_ExplicitModule + : serialization::MK_ImplicitModule, + ImportLoc, ARRFlags)) { + case ASTReader::Success: { + if (M) + return M; + assert(Source != MS_ModuleCache && + "missing module, but file loaded from cache"); + + // A prebuilt module is indexed as a ModuleFile; the Module does not exist + // until the first call to ReadAST. Look it up now. + M = HS.lookupModule(ModuleName, true, !IsInclusionDirective); + + // Check whether M refers to the file in the prebuilt module path. + if (M && M->getASTFile()) + if (auto ModuleFile = FileMgr->getFile(ModuleFilename)) + if (*ModuleFile == M->getASTFile()) + return M; + + ModuleBuildFailed = true; + getDiagnostics().Report(ModuleNameLoc, diag::err_module_prebuilt) + << ModuleName; + return ModuleLoadResult(); + } + + case ASTReader::OutOfDate: + case ASTReader::Missing: + // The most interesting case. + break; + + case ASTReader::ConfigurationMismatch: + if (Source == MS_PrebuiltModulePath) + // FIXME: We shouldn't be setting HadFatalFailure below if we only + // produce a warning here! + getDiagnostics().Report(SourceLocation(), + diag::warn_module_config_mismatch) + << ModuleFilename; + // Fall through to error out. + LLVM_FALLTHROUGH; + case ASTReader::VersionMismatch: + case ASTReader::HadErrors: + // FIXME: Should this set ModuleBuildFailed = true? + ModuleLoader::HadFatalFailure = true; + // FIXME: The ASTReader will already have complained, but can we shoehorn + // that diagnostic information into a more useful form? + return ModuleLoadResult(); + + case ASTReader::Failure: + // FIXME: Should this set ModuleBuildFailed = true? + ModuleLoader::HadFatalFailure = true; + return ModuleLoadResult(); + } + + // ReadAST returned Missing or OutOfDate. + if (Source != MS_ModuleCache) { + // We don't know the desired configuration for this module and don't + // necessarily even have a module map. Since ReadAST already produces + // diagnostics for these two cases, we simply error out here. + ModuleBuildFailed = true; + return ModuleLoadResult(); + } + + // The module file is missing or out-of-date. Build it. + assert(M && "missing module, but trying to compile for cache"); + + // Check whether there is a cycle in the module graph. + ModuleBuildStack ModPath = getSourceManager().getModuleBuildStack(); + ModuleBuildStack::iterator Pos = ModPath.begin(), PosEnd = ModPath.end(); + for (; Pos != PosEnd; ++Pos) { + if (Pos->first == ModuleName) + break; + } + + if (Pos != PosEnd) { + SmallString<256> CyclePath; + for (; Pos != PosEnd; ++Pos) { + CyclePath += Pos->first; + CyclePath += " -> "; + } + CyclePath += ModuleName; + + getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle) + << ModuleName << CyclePath; + // FIXME: Should this set ModuleBuildFailed = true? + // FIXME: Why is this not cached? + return ModuleLoadResult::OtherUncachedFailure; + } + + // Check whether we have already attempted to build this module (but + // failed). + if (getPreprocessorOpts().FailedModules && + getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) { + getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built) + << ModuleName << SourceRange(ImportLoc, ModuleNameLoc); + ModuleBuildFailed = true; + // FIXME: Why is this not cached? + return ModuleLoadResult::OtherUncachedFailure; + } + + // Try to compile and then read the AST. + if (!compileModuleAndReadAST(*this, ImportLoc, ModuleNameLoc, M, + ModuleFilename)) { + assert(getDiagnostics().hasErrorOccurred() && + "undiagnosed error in compileModuleAndReadAST"); + if (getPreprocessorOpts().FailedModules) + getPreprocessorOpts().FailedModules->addFailed(ModuleName); + ModuleBuildFailed = true; + // FIXME: Why is this not cached? + return ModuleLoadResult::OtherUncachedFailure; + } + + // Okay, we've rebuilt and now loaded the module. + return M; +} + ModuleLoadResult CompilerInstance::loadModule(SourceLocation ImportLoc, ModuleIdPath Path, @@ -1630,19 +1848,17 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, if (ImportLoc.isValid() && LastModuleImportLoc == ImportLoc) { // Make the named module visible. if (LastModuleImportResult && ModuleName != getLangOpts().CurrentModule) - ModuleManager->makeModuleVisible(LastModuleImportResult, Visibility, - ImportLoc); + TheASTReader->makeModuleVisible(LastModuleImportResult, Visibility, + ImportLoc); return LastModuleImportResult; } - clang::Module *Module = nullptr; - // If we don't already have information on this module, load the module now. - llvm::DenseMap<const IdentifierInfo *, clang::Module *>::iterator Known - = KnownModules.find(Path[0].first); - if (Known != KnownModules.end()) { - // Retrieve the cached top-level module. - Module = Known->second; + Module *Module = nullptr; + ModuleMap &MM = getPreprocessor().getHeaderSearchInfo().getModuleMap(); + if (auto MaybeModule = MM.getCachedModuleLoad(*Path[0].first)) { + // Use the cached result, which may be nullptr. + Module = *MaybeModule; } else if (ModuleName == getLangOpts().CurrentModule) { // This is the module we're building. Module = PP->getHeaderSearchInfo().lookupModule( @@ -1656,198 +1872,23 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, // ModuleBuildFailed = true; // return ModuleLoadResult(); //} - Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first; + MM.cacheModuleLoad(*Path[0].first, Module); } else { - // Search for a module with the given name. - Module = PP->getHeaderSearchInfo().lookupModule(ModuleName, true, - !IsInclusionDirective); - HeaderSearchOptions &HSOpts = - PP->getHeaderSearchInfo().getHeaderSearchOpts(); - - std::string ModuleFileName; - enum ModuleSource { - ModuleNotFound, ModuleCache, PrebuiltModulePath, ModuleBuildPragma - } Source = ModuleNotFound; - - // Check to see if the module has been built as part of this compilation - // via a module build pragma. - auto BuiltModuleIt = BuiltModules.find(ModuleName); - if (BuiltModuleIt != BuiltModules.end()) { - ModuleFileName = BuiltModuleIt->second; - Source = ModuleBuildPragma; - } - - // Try to load the module from the prebuilt module path. - if (Source == ModuleNotFound && (!HSOpts.PrebuiltModuleFiles.empty() || - !HSOpts.PrebuiltModulePaths.empty())) { - ModuleFileName = - PP->getHeaderSearchInfo().getPrebuiltModuleFileName(ModuleName); - if (!ModuleFileName.empty()) - Source = PrebuiltModulePath; - } - - // Try to load the module from the module cache. - if (Source == ModuleNotFound && Module) { - ModuleFileName = PP->getHeaderSearchInfo().getCachedModuleFileName(Module); - Source = ModuleCache; - } - - if (Source == ModuleNotFound) { - // We can't find a module, error out here. - getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_found) - << ModuleName << SourceRange(ImportLoc, ModuleNameLoc); - ModuleBuildFailed = true; - return ModuleLoadResult(); - } - - if (ModuleFileName.empty()) { - if (Module && Module->HasIncompatibleModuleFile) { - // We tried and failed to load a module file for this module. Fall - // back to textual inclusion for its headers. - return ModuleLoadResult::ConfigMismatch; - } - - getDiagnostics().Report(ModuleNameLoc, diag::err_module_build_disabled) - << ModuleName; - ModuleBuildFailed = true; - return ModuleLoadResult(); - } - - // If we don't already have an ASTReader, create one now. - if (!ModuleManager) - createModuleManager(); - - llvm::Timer Timer; - if (FrontendTimerGroup) - Timer.init("loading." + ModuleFileName, "Loading " + ModuleFileName, - *FrontendTimerGroup); - llvm::TimeRegion TimeLoading(FrontendTimerGroup ? &Timer : nullptr); - llvm::TimeTraceScope TimeScope("Module Load", ModuleName); - - // Try to load the module file. If we are not trying to load from the - // module cache, we don't know how to rebuild modules. - unsigned ARRFlags = Source == ModuleCache ? - ASTReader::ARR_OutOfDate | ASTReader::ARR_Missing : - Source == PrebuiltModulePath ? - 0 : - ASTReader::ARR_ConfigurationMismatch; - switch (ModuleManager->ReadAST(ModuleFileName, - Source == PrebuiltModulePath - ? serialization::MK_PrebuiltModule - : Source == ModuleBuildPragma - ? serialization::MK_ExplicitModule - : serialization::MK_ImplicitModule, - ImportLoc, ARRFlags)) { - case ASTReader::Success: { - if (Source != ModuleCache && !Module) { - Module = PP->getHeaderSearchInfo().lookupModule(ModuleName, true, - !IsInclusionDirective); - auto ModuleFile = FileMgr->getFile(ModuleFileName); - if (!Module || !Module->getASTFile() || - !ModuleFile || (*ModuleFile != Module->getASTFile())) { - // Error out if Module does not refer to the file in the prebuilt - // module path. - getDiagnostics().Report(ModuleNameLoc, diag::err_module_prebuilt) - << ModuleName; - ModuleBuildFailed = true; - KnownModules[Path[0].first] = nullptr; - return ModuleLoadResult(); - } - } - break; - } - - case ASTReader::OutOfDate: - case ASTReader::Missing: { - if (Source != ModuleCache) { - // We don't know the desired configuration for this module and don't - // necessarily even have a module map. Since ReadAST already produces - // diagnostics for these two cases, we simply error out here. - ModuleBuildFailed = true; - KnownModules[Path[0].first] = nullptr; - return ModuleLoadResult(); - } - - // The module file is missing or out-of-date. Build it. - assert(Module && "missing module file"); - // Check whether there is a cycle in the module graph. - ModuleBuildStack ModPath = getSourceManager().getModuleBuildStack(); - ModuleBuildStack::iterator Pos = ModPath.begin(), PosEnd = ModPath.end(); - for (; Pos != PosEnd; ++Pos) { - if (Pos->first == ModuleName) - break; - } - - if (Pos != PosEnd) { - SmallString<256> CyclePath; - for (; Pos != PosEnd; ++Pos) { - CyclePath += Pos->first; - CyclePath += " -> "; - } - CyclePath += ModuleName; - - getDiagnostics().Report(ModuleNameLoc, diag::err_module_cycle) - << ModuleName << CyclePath; - return ModuleLoadResult(); - } - - // Check whether we have already attempted to build this module (but - // failed). - if (getPreprocessorOpts().FailedModules && - getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) { - getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built) - << ModuleName - << SourceRange(ImportLoc, ModuleNameLoc); - ModuleBuildFailed = true; - return ModuleLoadResult(); - } - - // Try to compile and then load the module. - if (!compileAndLoadModule(*this, ImportLoc, ModuleNameLoc, Module, - ModuleFileName)) { - assert(getDiagnostics().hasErrorOccurred() && - "undiagnosed error in compileAndLoadModule"); - if (getPreprocessorOpts().FailedModules) - getPreprocessorOpts().FailedModules->addFailed(ModuleName); - KnownModules[Path[0].first] = nullptr; - ModuleBuildFailed = true; - return ModuleLoadResult(); - } - - // Okay, we've rebuilt and now loaded the module. - break; - } - - case ASTReader::ConfigurationMismatch: - if (Source == PrebuiltModulePath) - // FIXME: We shouldn't be setting HadFatalFailure below if we only - // produce a warning here! - getDiagnostics().Report(SourceLocation(), - diag::warn_module_config_mismatch) - << ModuleFileName; - // Fall through to error out. - LLVM_FALLTHROUGH; - case ASTReader::VersionMismatch: - case ASTReader::HadErrors: - ModuleLoader::HadFatalFailure = true; - // FIXME: The ASTReader will already have complained, but can we shoehorn - // that diagnostic information into a more useful form? - KnownModules[Path[0].first] = nullptr; - return ModuleLoadResult(); - - case ASTReader::Failure: - ModuleLoader::HadFatalFailure = true; - // Already complained, but note now that we failed. - KnownModules[Path[0].first] = nullptr; - ModuleBuildFailed = true; - return ModuleLoadResult(); - } - - // Cache the result of this top-level module lookup for later. - Known = KnownModules.insert(std::make_pair(Path[0].first, Module)).first; + ModuleLoadResult Result = findOrCompileModuleAndReadAST( + ModuleName, ImportLoc, ModuleNameLoc, IsInclusionDirective); + // FIXME: Can we pull 'ModuleBuildFailed = true' out of the return + // sequences for findOrCompileModuleAndReadAST and do it here (as long as + // the result is not a config mismatch)? See FIXMEs there. + if (!Result.isNormal()) + return Result; + Module = Result; + MM.cacheModuleLoad(*Path[0].first, Module); + if (!Module) + return Module; } - // If we never found the module, fail. + // If we never found the module, fail. Otherwise, verify the module and link + // it up. if (!Module) return ModuleLoadResult(); @@ -1967,7 +2008,7 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, return ModuleLoadResult(); } - ModuleManager->makeModuleVisible(Module, Visibility, ImportLoc); + TheASTReader->makeModuleVisible(Module, Visibility, ImportLoc); } // Check for any configuration macros that have changed. @@ -1988,9 +2029,9 @@ CompilerInstance::loadModule(SourceLocation ImportLoc, return LastModuleImportResult; } -void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc, - StringRef ModuleName, - StringRef Source) { +void CompilerInstance::createModuleFromSource(SourceLocation ImportLoc, + StringRef ModuleName, + StringRef Source) { // Avoid creating filenames with special characters. SmallString<128> CleanModuleName(ModuleName); for (auto &C : CleanModuleName) @@ -2044,27 +2085,27 @@ void CompilerInstance::loadModuleFromSource(SourceLocation ImportLoc, void CompilerInstance::makeModuleVisible(Module *Mod, Module::NameVisibilityKind Visibility, SourceLocation ImportLoc) { - if (!ModuleManager) - createModuleManager(); - if (!ModuleManager) + if (!TheASTReader) + createASTReader(); + if (!TheASTReader) return; - ModuleManager->makeModuleVisible(Mod, Visibility, ImportLoc); + TheASTReader->makeModuleVisible(Mod, Visibility, ImportLoc); } GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex( SourceLocation TriggerLoc) { if (getPreprocessor().getHeaderSearchInfo().getModuleCachePath().empty()) return nullptr; - if (!ModuleManager) - createModuleManager(); + if (!TheASTReader) + createASTReader(); // Can't do anything if we don't have the module manager. - if (!ModuleManager) + if (!TheASTReader) return nullptr; // Get an existing global index. This loads it if not already // loaded. - ModuleManager->loadGlobalIndex(); - GlobalModuleIndex *GlobalIndex = ModuleManager->getGlobalIndex(); + TheASTReader->loadGlobalIndex(); + GlobalModuleIndex *GlobalIndex = TheASTReader->getGlobalIndex(); // If the global index doesn't exist, create it. if (!GlobalIndex && shouldBuildGlobalModuleIndex() && hasFileManager() && hasPreprocessor()) { @@ -2080,9 +2121,9 @@ GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex( consumeError(std::move(Err)); return nullptr; } - ModuleManager->resetForReload(); - ModuleManager->loadGlobalIndex(); - GlobalIndex = ModuleManager->getGlobalIndex(); + TheASTReader->resetForReload(); + TheASTReader->loadGlobalIndex(); + GlobalIndex = TheASTReader->getGlobalIndex(); } // For finding modules needing to be imported for fixit messages, // we need to make the global index cover all modules, so we do that here. @@ -2111,9 +2152,9 @@ GlobalModuleIndex *CompilerInstance::loadGlobalModuleIndex( consumeError(std::move(Err)); return nullptr; } - ModuleManager->resetForReload(); - ModuleManager->loadGlobalIndex(); - GlobalIndex = ModuleManager->getGlobalIndex(); + TheASTReader->resetForReload(); + TheASTReader->loadGlobalIndex(); + GlobalIndex = TheASTReader->getGlobalIndex(); } HaveFullGlobalModuleIndex = true; } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 665695ec3b18..e1e59565083b 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -334,7 +334,7 @@ static bool ParseAnalyzerArgs(AnalyzerOptions &Opts, ArgList &Args, StringRef CheckerAndPackageList = A->getValue(); SmallVector<StringRef, 16> CheckersAndPackages; CheckerAndPackageList.split(CheckersAndPackages, ","); - for (const StringRef CheckerOrPackage : CheckersAndPackages) + for (const StringRef &CheckerOrPackage : CheckersAndPackages) Opts.CheckersAndPackages.emplace_back(CheckerOrPackage, IsEnabled); } @@ -476,7 +476,7 @@ static void parseAnalyzerConfigs(AnalyzerOptions &AnOpts, SmallVector<StringRef, 16> CheckersAndPackages; AnOpts.RawSilencedCheckersAndPackages.split(CheckersAndPackages, ";"); - for (const StringRef CheckerOrPackage : CheckersAndPackages) { + for (const StringRef &CheckerOrPackage : CheckersAndPackages) { if (Diags) { bool IsChecker = CheckerOrPackage.contains('.'); bool IsValidName = @@ -607,7 +607,7 @@ static void parseXRayInstrumentationBundle(StringRef FlagName, StringRef Bundle, XRayInstrSet &S) { llvm::SmallVector<StringRef, 2> BundleParts; llvm::SplitString(Bundle, BundleParts, ","); - for (const auto B : BundleParts) { + for (const auto &B : BundleParts) { auto Mask = parseXRayInstrValue(B); if (Mask == XRayInstrKind::None) if (B != "none") @@ -731,6 +731,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, llvm::StringSwitch<unsigned>(A->getValue()) .Case("line-tables-only", codegenoptions::DebugLineTablesOnly) .Case("line-directives-only", codegenoptions::DebugDirectivesOnly) + .Case("constructor", codegenoptions::DebugInfoConstructor) .Case("limited", codegenoptions::LimitedDebugInfo) .Case("standalone", codegenoptions::FullDebugInfo) .Default(~0U); @@ -769,6 +770,9 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.DebugFwdTemplateParams = Args.hasArg(OPT_debug_forward_template_params); Opts.EmbedSource = Args.hasArg(OPT_gembed_source); + Opts.ForceDwarfFrameSection = + Args.hasFlag(OPT_fforce_dwarf_frame, OPT_fno_force_dwarf_frame, false); + for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) Opts.DebugPrefixMap.insert(StringRef(Arg).split('=')); @@ -784,8 +788,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, llvm::Triple::arm, llvm::Triple::armeb}; llvm::Triple T(TargetOpts.Triple); - if (Opts.OptimizationLevel > 0 && - Opts.getDebugInfo() >= codegenoptions::LimitedDebugInfo && + if (Opts.OptimizationLevel > 0 && Opts.hasReducedDebugInfo() && llvm::is_contained(DebugEntryValueArchs, T.getArch())) Opts.EnableDebugEntryValues = Args.hasArg(OPT_femit_debug_entry_values); @@ -806,6 +809,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.RecordCommandLine = Args.getLastArgValue(OPT_record_command_line); Opts.MergeAllConstants = Args.hasArg(OPT_fmerge_all_constants); Opts.NoCommon = Args.hasArg(OPT_fno_common); + Opts.NoInlineLineTables = Args.hasArg(OPT_gno_inline_line_tables); Opts.NoImplicitFloat = Args.hasArg(OPT_no_implicit_float); Opts.OptimizeSize = getOptimizationLevelSize(Args); Opts.SimplifyLibCalls = !(Args.hasArg(OPT_fno_builtin) || @@ -949,7 +953,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, << Args.getLastArg(OPT_mthread_model)->getAsString(Args) << Opts.ThreadModel; Opts.TrapFuncName = Args.getLastArgValue(OPT_ftrap_function_EQ); - Opts.UseInitArray = Args.hasArg(OPT_fuse_init_array); + Opts.UseInitArray = !Args.hasArg(OPT_fno_use_init_array); Opts.FunctionSections = Args.hasFlag(OPT_ffunction_sections, OPT_fno_function_sections, false); @@ -1003,6 +1007,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, Opts.MainFileName = Args.getLastArgValue(OPT_main_file_name); Opts.VerifyModule = !Args.hasArg(OPT_disable_llvm_verifier); + Opts.ControlFlowGuardNoChecks = Args.hasArg(OPT_cfguard_no_checks); Opts.ControlFlowGuard = Args.hasArg(OPT_cfguard); Opts.DisableGCov = Args.hasArg(OPT_test_coverage); @@ -1096,8 +1101,13 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, parseXRayInstrumentationBundle("-fxray-instrumentation-bundle=", A, Args, Diags, Opts.XRayInstrumentationBundle); + Opts.PatchableFunctionEntryCount = + getLastArgIntValue(Args, OPT_fpatchable_function_entry_EQ, 0, Diags); Opts.InstrumentForProfiling = Args.hasArg(OPT_pg); Opts.CallFEntry = Args.hasArg(OPT_mfentry); + Opts.MNopMCount = Args.hasArg(OPT_mnop_mcount); + Opts.RecordMCount = Args.hasArg(OPT_mrecord_mcount); + Opts.PackedStack = Args.hasArg(OPT_mpacked_stack); Opts.EmitOpenCLArgMetadata = Args.hasArg(OPT_cl_kernel_arg_info); if (const Arg *A = Args.getLastArg(OPT_fcf_protection_EQ)) { @@ -1258,15 +1268,12 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK, } } + Opts.TLSSize = getLastArgIntValue(Args, OPT_mtls_size_EQ, 0, Diags); + if (Arg *A = Args.getLastArg(OPT_fdenormal_fp_math_EQ)) { StringRef Val = A->getValue(); - if (Val == "ieee") - Opts.FPDenormalMode = "ieee"; - else if (Val == "preserve-sign") - Opts.FPDenormalMode = "preserve-sign"; - else if (Val == "positive-zero") - Opts.FPDenormalMode = "positive-zero"; - else + Opts.FPDenormalMode = llvm::parseDenormalFPAttribute(Val); + if (Opts.FPDenormalMode == llvm::DenormalMode::Invalid) Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; } @@ -1441,7 +1448,26 @@ static void ParseDependencyOutputArgs(DependencyOutputOptions &Opts, // Add sanitizer blacklists as extra dependencies. // They won't be discovered by the regular preprocessor, so // we let make / ninja to know about this implicit dependency. - Opts.ExtraDeps = Args.getAllArgValues(OPT_fdepfile_entry); + if (!Args.hasArg(OPT_fno_sanitize_blacklist)) { + for (const auto *A : Args.filtered(OPT_fsanitize_blacklist)) { + StringRef Val = A->getValue(); + if (Val.find('=') == StringRef::npos) + Opts.ExtraDeps.push_back(Val); + } + if (Opts.IncludeSystemHeaders) { + for (const auto *A : Args.filtered(OPT_fsanitize_system_blacklist)) { + StringRef Val = A->getValue(); + if (Val.find('=') == StringRef::npos) + Opts.ExtraDeps.push_back(Val); + } + } + } + + // Propagate the extra dependencies. + for (const auto *A : Args.filtered(OPT_fdepfile_entry)) { + Opts.ExtraDeps.push_back(A->getValue()); + } + // Only the -fmodule-file=<file> form. for (const auto *A : Args.filtered(OPT_fmodule_file)) { StringRef Val = A->getValue(); @@ -1866,6 +1892,7 @@ static InputKind ParseFrontendArgs(FrontendOptions &Opts, ArgList &Args, Opts.ModulesEmbedFiles = Args.getAllArgValues(OPT_fmodules_embed_file_EQ); Opts.ModulesEmbedAllFiles = Args.hasArg(OPT_fmodules_embed_all_files); Opts.IncludeTimestamps = !Args.hasArg(OPT_fno_pch_timestamp); + Opts.UseTemporary = !Args.hasArg(OPT_fno_temp_file); Opts.CodeCompleteOpts.IncludeMacros = Args.hasArg(OPT_code_completion_macros); @@ -2528,7 +2555,20 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.CUDADeviceApproxTranscendentals = 1; Opts.GPURelocatableDeviceCode = Args.hasArg(OPT_fgpu_rdc); + if (Args.hasArg(OPT_fgpu_allow_device_init)) { + if (Opts.HIP) + Opts.GPUAllowDeviceInit = 1; + else + Diags.Report(diag::warn_ignored_hip_only_option) + << Args.getLastArg(OPT_fgpu_allow_device_init)->getAsString(Args); + } Opts.HIPUseNewLaunchAPI = Args.hasArg(OPT_fhip_new_launch_api); + if (Opts.HIP) + Opts.GPUMaxThreadsPerBlock = getLastArgIntValue( + Args, OPT_gpu_max_threads_per_block_EQ, Opts.GPUMaxThreadsPerBlock); + else if (Args.hasArg(OPT_gpu_max_threads_per_block_EQ)) + Diags.Report(diag::warn_ignored_hip_only_option) + << Args.getLastArg(OPT_gpu_max_threads_per_block_EQ)->getAsString(Args); if (Opts.ObjC) { if (Arg *arg = Args.getLastArg(OPT_fobjc_runtime_EQ)) { @@ -2689,7 +2729,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, OPT_fno_dollars_in_identifiers, Opts.DollarIdents); Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings); - Opts.VtorDispMode = getLastArgIntValue(Args, OPT_vtordisp_mode_EQ, 1, Diags); + Opts.setVtorDispMode( + MSVtorDispMode(getLastArgIntValue(Args, OPT_vtordisp_mode_EQ, 1, Diags))); Opts.Borland = Args.hasArg(OPT_fborland_extensions); Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings); Opts.ConstStrings = Args.hasFlag(OPT_fconst_strings, OPT_fno_const_strings, @@ -2749,6 +2790,9 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.BlocksRuntimeOptional = Args.hasArg(OPT_fblocks_runtime_optional); Opts.Coroutines = Opts.CPlusPlus2a || Args.hasArg(OPT_fcoroutines_ts); + Opts.ConvergentFunctions = Opts.OpenCL || (Opts.CUDA && Opts.CUDAIsDevice) || + Args.hasArg(OPT_fconvergent_functions); + Opts.DoubleSquareBracketAttributes = Args.hasFlag(OPT_fdouble_square_bracket_attributes, OPT_fno_double_square_bracket_attributes, @@ -2823,8 +2867,6 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, getLastArgIntValue(Args, OPT_fconstexpr_steps, 1048576, Diags); Opts.EnableNewConstInterp = Args.hasArg(OPT_fexperimental_new_constant_interpreter); - Opts.ForceNewConstInterp = - Args.hasArg(OPT_fforce_experimental_new_constant_interpreter); Opts.BracketDepth = getLastArgIntValue(Args, OPT_fbracket_depth, 256, Diags); Opts.DelayedTemplateParsing = Args.hasArg(OPT_fdelayed_template_parsing); Opts.NumLargeByValueCopy = @@ -2951,7 +2993,7 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Arch != llvm::Triple::x86; emitError |= (DefaultCC == LangOptions::DCC_VectorCall || DefaultCC == LangOptions::DCC_RegCall) && - !(Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64); + !T.isX86(); if (emitError) Diags.Report(diag::err_drv_argument_not_allowed_with) << A->getSpelling() << T.getTriple(); @@ -2985,6 +3027,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.OpenMP && !Args.hasArg(options::OPT_fnoopenmp_use_tls); Opts.OpenMPIsDevice = Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_is_device); + Opts.OpenMPIRBuilder = + Opts.OpenMP && Args.hasArg(options::OPT_fopenmp_enable_irbuilder); bool IsTargetSpecified = Opts.OpenMPIsDevice || Args.hasArg(options::OPT_fopenmp_targets_EQ); @@ -3041,7 +3085,8 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, llvm::Triple TT(A->getValue(i)); if (TT.getArch() == llvm::Triple::UnknownArch || - !(TT.getArch() == llvm::Triple::ppc || + !(TT.getArch() == llvm::Triple::aarch64 || + TT.getArch() == llvm::Triple::ppc || TT.getArch() == llvm::Triple::ppc64 || TT.getArch() == llvm::Triple::ppc64le || TT.getArch() == llvm::Triple::nvptx || @@ -3116,6 +3161,34 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; } + LangOptions::FPRoundingModeKind FPRM = LangOptions::FPR_ToNearest; + if (Args.hasArg(OPT_frounding_math)) { + FPRM = LangOptions::FPR_Dynamic; + } + Opts.setFPRoundingMode(FPRM); + + if (Args.hasArg(OPT_ftrapping_math)) { + Opts.setFPExceptionMode(LangOptions::FPE_Strict); + } + + if (Args.hasArg(OPT_fno_trapping_math)) { + Opts.setFPExceptionMode(LangOptions::FPE_Ignore); + } + + LangOptions::FPExceptionModeKind FPEB = LangOptions::FPE_Ignore; + if (Arg *A = Args.getLastArg(OPT_ffp_exception_behavior_EQ)) { + StringRef Val = A->getValue(); + if (Val.equals("ignore")) + FPEB = LangOptions::FPE_Ignore; + else if (Val.equals("maytrap")) + FPEB = LangOptions::FPE_MayTrap; + else if (Val.equals("strict")) + FPEB = LangOptions::FPE_Strict; + else + Diags.Report(diag::err_drv_invalid_value) << A->getAsString(Args) << Val; + } + Opts.setFPExceptionMode(FPEB); + Opts.RetainCommentsFromSystemHeaders = Args.hasArg(OPT_fretain_comments_from_system_headers); @@ -3151,6 +3224,11 @@ static void ParseLangArgs(LangOptions &Opts, ArgList &Args, InputKind IK, Opts.SanitizeAddressFieldPadding = getLastArgIntValue(Args, OPT_fsanitize_address_field_padding, 0, Diags); Opts.SanitizerBlacklistFiles = Args.getAllArgValues(OPT_fsanitize_blacklist); + std::vector<std::string> systemBlacklists = + Args.getAllArgValues(OPT_fsanitize_system_blacklist); + Opts.SanitizerBlacklistFiles.insert(Opts.SanitizerBlacklistFiles.end(), + systemBlacklists.begin(), + systemBlacklists.end()); // -fxray-instrument Opts.XRayInstrument = @@ -3279,6 +3357,9 @@ static void ParsePreprocessorArgs(PreprocessorOptions &Opts, ArgList &Args, for (const auto *A : Args.filtered(OPT_error_on_deserialized_pch_decl)) Opts.DeserializedPCHDeclsToErrorOn.insert(A->getValue()); + for (const auto &A : Args.getAllArgValues(OPT_fmacro_prefix_map_EQ)) + Opts.MacroPrefixMap.insert(StringRef(A).split('=')); + if (const Arg *A = Args.getLastArg(OPT_preamble_bytes_EQ)) { StringRef Value(A->getValue()); size_t Comma = Value.find(','); @@ -3645,35 +3726,8 @@ std::string CompilerInvocation::getModuleHash() const { return llvm::APInt(64, code).toString(36, /*Signed=*/false); } -template<typename IntTy> -static IntTy getLastArgIntValueImpl(const ArgList &Args, OptSpecifier Id, - IntTy Default, - DiagnosticsEngine *Diags) { - IntTy Res = Default; - if (Arg *A = Args.getLastArg(Id)) { - if (StringRef(A->getValue()).getAsInteger(10, Res)) { - if (Diags) - Diags->Report(diag::err_drv_invalid_int_value) << A->getAsString(Args) - << A->getValue(); - } - } - return Res; -} - namespace clang { -// Declared in clang/Frontend/Utils.h. -int getLastArgIntValue(const ArgList &Args, OptSpecifier Id, int Default, - DiagnosticsEngine *Diags) { - return getLastArgIntValueImpl<int>(Args, Id, Default, Diags); -} - -uint64_t getLastArgUInt64Value(const ArgList &Args, OptSpecifier Id, - uint64_t Default, - DiagnosticsEngine *Diags) { - return getLastArgIntValueImpl<uint64_t>(Args, Id, Default, Diags); -} - IntrusiveRefCntPtr<llvm::vfs::FileSystem> createVFSFromCompilerInvocation(const CompilerInvocation &CI, DiagnosticsEngine &Diags) { diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp index ab62b633cda3..18c4814bbd5c 100644 --- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -26,7 +26,8 @@ using namespace llvm::opt; std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine( ArrayRef<const char *> ArgList, IntrusiveRefCntPtr<DiagnosticsEngine> Diags, - IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, bool ShouldRecoverOnErorrs) { + IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, bool ShouldRecoverOnErorrs, + std::vector<std::string> *CC1Args) { if (!Diags.get()) { // No diagnostics engine was provided, so create our own diagnostics object // with the default options. @@ -89,6 +90,8 @@ std::unique_ptr<CompilerInvocation> clang::createInvocationFromCommandLine( } const ArgStringList &CCArgs = Cmd.getArguments(); + if (CC1Args) + *CC1Args = {CCArgs.begin(), CCArgs.end()}; auto CI = std::make_unique<CompilerInvocation>(); if (!CompilerInvocation::CreateFromArgs(*CI, CCArgs, *Diags) && !ShouldRecoverOnErorrs) diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index b3b7976f8f3e..934d17b3c925 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -10,6 +10,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclGroup.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/LangStandard.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" @@ -870,9 +871,9 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, // extended by an external source. if (CI.getLangOpts().Modules || !CI.hasASTContext() || !CI.getASTContext().getExternalSource()) { - CI.createModuleManager(); - CI.getModuleManager()->setDeserializationListener(DeserialListener, - DeleteDeserialListener); + CI.createASTReader(); + CI.getASTReader()->setDeserializationListener(DeserialListener, + DeleteDeserialListener); } } @@ -891,7 +892,7 @@ bool FrontendAction::BeginSourceFile(CompilerInstance &CI, } else { // FIXME: If this is a problem, recover from it by creating a multiplex // source. - assert((!CI.getLangOpts().Modules || CI.getModuleManager()) && + assert((!CI.getLangOpts().Modules || CI.getASTReader()) && "modules enabled but created an external source that " "doesn't support modules"); } diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 4d47c768ad3c..8574d0a7e813 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -140,7 +140,7 @@ GeneratePCHAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile, std::unique_ptr<raw_pwrite_stream> OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true, /*RemoveFileOnSignal=*/false, InFile, - /*Extension=*/"", /*UseTemporary=*/true); + /*Extension=*/"", CI.getFrontendOpts().UseTemporary); if (!OS) return nullptr; @@ -413,6 +413,8 @@ private: return "ExceptionSpecInstantiation"; case CodeSynthesisContext::DeclaringSpecialMember: return "DeclaringSpecialMember"; + case CodeSynthesisContext::DeclaringImplicitEqualityComparison: + return "DeclaringImplicitEqualityComparison"; case CodeSynthesisContext::DefiningSynthesizedFunction: return "DefiningSynthesizedFunction"; case CodeSynthesisContext::RewritingOperatorAsSpaceship: @@ -423,6 +425,10 @@ private: return "ConstraintsCheck"; case CodeSynthesisContext::ConstraintSubstitution: return "ConstraintSubstitution"; + case CodeSynthesisContext::ConstraintNormalization: + return "ConstraintNormalization"; + case CodeSynthesisContext::ParameterMappingSubstitution: + return "ParameterMappingSubstitution"; } return ""; } diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index c27c33c530f6..2c7e3a56c043 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -484,6 +484,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, LangOpts.CPlusPlus2a ? "201907L" : LangOpts.CPlusPlus17 ? "201603L" : LangOpts.CPlusPlus14 ? "201304L" : "200704"); + Builder.defineMacro("__cpp_constexpr_in_decltype", "201711L"); Builder.defineMacro("__cpp_range_based_for", LangOpts.CPlusPlus17 ? "201603L" : "200907"); Builder.defineMacro("__cpp_static_assert", @@ -506,8 +507,10 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, if (LangOpts.CPlusPlus14) { Builder.defineMacro("__cpp_binary_literals", "201304L"); Builder.defineMacro("__cpp_digit_separators", "201309L"); - Builder.defineMacro("__cpp_init_captures", "201304L"); - Builder.defineMacro("__cpp_generic_lambdas", "201304L"); + Builder.defineMacro("__cpp_init_captures", + LangOpts.CPlusPlus2a ? "201803L" : "201304L"); + Builder.defineMacro("__cpp_generic_lambdas", + LangOpts.CPlusPlus2a ? "201707L" : "201304L"); Builder.defineMacro("__cpp_decltype_auto", "201304L"); Builder.defineMacro("__cpp_return_type_deduction", "201304L"); Builder.defineMacro("__cpp_aggregate_nsdmi", "201304L"); @@ -523,7 +526,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_noexcept_function_type", "201510L"); Builder.defineMacro("__cpp_capture_star_this", "201603L"); Builder.defineMacro("__cpp_if_constexpr", "201606L"); - Builder.defineMacro("__cpp_deduction_guides", "201703L"); + Builder.defineMacro("__cpp_deduction_guides", "201703L"); // (not latest) Builder.defineMacro("__cpp_template_auto", "201606L"); // (old name) Builder.defineMacro("__cpp_namespace_attributes", "201411L"); Builder.defineMacro("__cpp_enumerator_attributes", "201411L"); @@ -531,7 +534,8 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_variadic_using", "201611L"); Builder.defineMacro("__cpp_aggregate_bases", "201603L"); Builder.defineMacro("__cpp_structured_bindings", "201606L"); - Builder.defineMacro("__cpp_nontype_template_args", "201411L"); + Builder.defineMacro("__cpp_nontype_template_args", + "201411L"); // (not latest) Builder.defineMacro("__cpp_fold_expressions", "201603L"); Builder.defineMacro("__cpp_guaranteed_copy_elision", "201606L"); Builder.defineMacro("__cpp_nontype_template_parameter_auto", "201606L"); @@ -543,9 +547,17 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, // C++20 features. if (LangOpts.CPlusPlus2a) { + //Builder.defineMacro("__cpp_aggregate_paren_init", "201902L"); + //Builder.defineMacro("__cpp_concepts", "201907L"); Builder.defineMacro("__cpp_conditional_explicit", "201806L"); + //Builder.defineMacro("__cpp_consteval", "201811L"); Builder.defineMacro("__cpp_constexpr_dynamic_alloc", "201907L"); Builder.defineMacro("__cpp_constinit", "201907L"); + //Builder.defineMacro("__cpp_coroutines", "201902L"); + Builder.defineMacro("__cpp_designated_initializers", "201707L"); + Builder.defineMacro("__cpp_impl_three_way_comparison", "201907L"); + //Builder.defineMacro("__cpp_modules", "201907L"); + //Builder.defineMacro("__cpp_using_enum", "201907L"); } if (LangOpts.Char8) Builder.defineMacro("__cpp_char8_t", "201811L"); @@ -1124,7 +1136,8 @@ void clang::InitializePreprocessor( if (InitOpts.UsePredefines) { // FIXME: This will create multiple definitions for most of the predefined // macros. This is not the right way to handle this. - if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice) && PP.getAuxTargetInfo()) + if ((LangOpts.CUDA || LangOpts.OpenMPIsDevice || LangOpts.SYCLIsDevice) && + PP.getAuxTargetInfo()) InitializePredefinedMacros(*PP.getAuxTargetInfo(), LangOpts, FEOpts, PP.getPreprocessorOpts(), Builder); diff --git a/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp b/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp index 0b28b78de3b1..7241081d6cc0 100644 --- a/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp +++ b/clang/lib/Frontend/InterfaceStubFunctionsConsumer.cpp @@ -52,11 +52,16 @@ class InterfaceStubFunctionsConsumer : public ASTConsumer { if (!isVisible(ND)) return true; - if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) + if (const VarDecl *VD = dyn_cast<VarDecl>(ND)) { + if (const auto *Parent = VD->getParentFunctionOrMethod()) + if (isa<BlockDecl>(Parent) || isa<CXXMethodDecl>(Parent)) + return true; + if ((VD->getStorageClass() == StorageClass::SC_Extern) || (VD->getStorageClass() == StorageClass::SC_Static && VD->getParentFunctionOrMethod() == nullptr)) return true; + } if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { if (FD->isInlined() && !isa<CXXMethodDecl>(FD) && @@ -182,8 +187,36 @@ class InterfaceStubFunctionsConsumer : public ASTConsumer { case Decl::Kind::Enum: case Decl::Kind::EnumConstant: case Decl::Kind::TemplateTypeParm: + case Decl::Kind::NonTypeTemplateParm: + case Decl::Kind::CXXConversion: + case Decl::Kind::UnresolvedUsingValue: + case Decl::Kind::Using: + case Decl::Kind::UsingShadow: + case Decl::Kind::TypeAliasTemplate: + case Decl::Kind::TypeAlias: + case Decl::Kind::VarTemplate: + case Decl::Kind::VarTemplateSpecialization: + case Decl::Kind::UsingDirective: + case Decl::Kind::TemplateTemplateParm: + case Decl::Kind::ClassTemplatePartialSpecialization: + case Decl::Kind::IndirectField: + case Decl::Kind::ConstructorUsingShadow: + case Decl::Kind::CXXDeductionGuide: + case Decl::Kind::NamespaceAlias: + case Decl::Kind::UnresolvedUsingTypename: return true; - case Decl::Kind::Var: + case Decl::Kind::Var: { + // Bail on any VarDecl that either has no named symbol. + if (!ND->getIdentifier()) + return true; + const auto *VD = cast<VarDecl>(ND); + // Bail on any VarDecl that is a dependent or templated type. + if (VD->isTemplated() || VD->getType()->isDependentType()) + return true; + if (WriteNamedDecl(ND, Symbols, RDO)) + return true; + break; + } case Decl::Kind::ParmVar: case Decl::Kind::CXXMethod: case Decl::Kind::CXXConstructor: @@ -251,14 +284,16 @@ public: for (const NamedDecl *ND : v.NamedDecls) HandleNamedDecl(ND, Symbols, FromTU); - auto writeIfsV1 = - [this](const llvm::Triple &T, const MangledSymbols &Symbols, - const ASTContext &context, StringRef Format, - raw_ostream &OS) -> void { + auto writeIfsV1 = [this](const llvm::Triple &T, + const MangledSymbols &Symbols, + const ASTContext &context, StringRef Format, + raw_ostream &OS) -> void { OS << "--- !" << Format << "\n"; OS << "IfsVersion: 1.0\n"; OS << "Triple: " << T.str() << "\n"; - OS << "ObjectFileFormat: " << "ELF" << "\n"; // TODO: For now, just ELF. + OS << "ObjectFileFormat: " + << "ELF" + << "\n"; // TODO: For now, just ELF. OS << "Symbols:\n"; for (const auto &E : Symbols) { const MangledSymbol &Symbol = E.second; diff --git a/clang/lib/Frontend/MultiplexConsumer.cpp b/clang/lib/Frontend/MultiplexConsumer.cpp index 04e896296c95..5abbb3a235b4 100644 --- a/clang/lib/Frontend/MultiplexConsumer.cpp +++ b/clang/lib/Frontend/MultiplexConsumer.cpp @@ -322,6 +322,11 @@ void MultiplexConsumer::CompleteTentativeDefinition(VarDecl *D) { Consumer->CompleteTentativeDefinition(D); } +void MultiplexConsumer::CompleteExternalDeclaration(VarDecl *D) { + for (auto &Consumer : Consumers) + Consumer->CompleteExternalDeclaration(D); +} + void MultiplexConsumer::AssignInheritanceModel(CXXRecordDecl *RD) { for (auto &Consumer : Consumers) Consumer->AssignInheritanceModel(RD); diff --git a/clang/lib/Frontend/PrecompiledPreamble.cpp b/clang/lib/Frontend/PrecompiledPreamble.cpp index ced32c670288..0e5a8e504dc5 100644 --- a/clang/lib/Frontend/PrecompiledPreamble.cpp +++ b/clang/lib/Frontend/PrecompiledPreamble.cpp @@ -535,21 +535,15 @@ PrecompiledPreamble::TempPCHFile::CreateNewPreamblePCHFile() { // FIXME: This is a hack so that we can override the preamble file during // crash-recovery testing, which is the only case where the preamble files // are not necessarily cleaned up. - const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE"); - if (TmpFile) - return TempPCHFile::createFromCustomPath(TmpFile); - return TempPCHFile::createInSystemTempDir("preamble", "pch"); -} + if (const char *TmpFile = ::getenv("CINDEXTEST_PREAMBLE_FILE")) + return TempPCHFile(TmpFile); -llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> -PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix, - StringRef Suffix) { llvm::SmallString<64> File; // Using a version of createTemporaryFile with a file descriptor guarantees // that we would never get a race condition in a multi-threaded setting // (i.e., multiple threads getting the same temporary path). int FD; - auto EC = llvm::sys::fs::createTemporaryFile(Prefix, Suffix, FD, File); + auto EC = llvm::sys::fs::createTemporaryFile("preamble", "pch", FD, File); if (EC) return EC; // We only needed to make sure the file exists, close the file right away. @@ -557,11 +551,6 @@ PrecompiledPreamble::TempPCHFile::createInSystemTempDir(const Twine &Prefix, return TempPCHFile(std::move(File).str()); } -llvm::ErrorOr<PrecompiledPreamble::TempPCHFile> -PrecompiledPreamble::TempPCHFile::createFromCustomPath(const Twine &Path) { - return TempPCHFile(Path.str()); -} - PrecompiledPreamble::TempPCHFile::TempPCHFile(std::string FilePath) : FilePath(std::move(FilePath)) { TemporaryFiles::getInstance().addFile(*this->FilePath); diff --git a/clang/lib/Frontend/Rewrite/FrontendActions.cpp b/clang/lib/Frontend/Rewrite/FrontendActions.cpp index 549b86edebcd..aaffbde3309b 100644 --- a/clang/lib/Frontend/Rewrite/FrontendActions.cpp +++ b/clang/lib/Frontend/Rewrite/FrontendActions.cpp @@ -21,7 +21,7 @@ #include "clang/Rewrite/Frontend/FixItRewriter.h" #include "clang/Rewrite/Frontend/Rewriters.h" #include "clang/Serialization/ASTReader.h" -#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFile.h" #include "clang/Serialization/ModuleManager.h" #include "llvm/ADT/DenseSet.h" #include "llvm/Support/CrashRecoveryContext.h" @@ -220,7 +220,7 @@ public: return; serialization::ModuleFile *MF = - CI.getModuleManager()->getModuleManager().lookup(*File); + CI.getASTReader()->getModuleManager().lookup(*File); assert(MF && "missing module file for loaded module?"); // Not interested in PCH / preambles. @@ -293,8 +293,8 @@ bool RewriteIncludesAction::BeginSourceFileAction(CompilerInstance &CI) { // If we're rewriting imports, set up a listener to track when we import // module files. if (CI.getPreprocessorOutputOpts().RewriteImports) { - CI.createModuleManager(); - CI.getModuleManager()->addListener( + CI.createASTReader(); + CI.getASTReader()->addListener( std::make_unique<RewriteImportsListener>(CI, OutputStream)); } diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp index 45495065ada6..831f95e8c6be 100644 --- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -908,9 +908,9 @@ RewriteModernObjC::getIvarAccessString(ObjCIvarDecl *D) { static bool mustSynthesizeSetterGetterMethod(ObjCImplementationDecl *IMP, ObjCPropertyDecl *PD, bool getter) { - return getter ? !IMP->getInstanceMethod(PD->getGetterName()) - : !IMP->getInstanceMethod(PD->getSetterName()); - + auto *OMD = IMP->getInstanceMethod(getter ? PD->getGetterName() + : PD->getSetterName()); + return !OMD || OMD->isSynthesizedAccessorStub(); } void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, @@ -952,7 +952,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, "id objc_getProperty(id, SEL, long, bool);\n"; } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getGetterMethodDecl(), Getr); + PID->getGetterMethodDecl(), Getr); Getr += "{ "; // Synthesize an explicit cast to gain access to the ivar. // See objc-act.c:objc_synthesize_new_getter() for details. @@ -960,7 +960,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) Getr += "typedef "; const FunctionType *FPRetType = nullptr; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr, + RewriteTypeIntoString(PID->getGetterMethodDecl()->getReturnType(), Getr, FPRetType); Getr += " _TYPE"; if (FPRetType) { @@ -1012,7 +1012,7 @@ void RewriteModernObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getSetterMethodDecl(), Setr); + PID->getSetterMethodDecl(), Setr); Setr += "{ "; // Synthesize an explicit cast to initialize the ivar. // See objc-act.c:objc_synthesize_new_setter() for details. @@ -1346,6 +1346,8 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) { InsertText(CID->getBeginLoc(), "// "); for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -1357,6 +1359,8 @@ void RewriteModernObjC::RewriteImplementationDecl(Decl *OID) { } for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -7031,12 +7035,12 @@ void RewriteModernObjC::RewriteObjCClassMetaData(ObjCImplementationDecl *IDecl, ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) if (mustSynthesizeSetterGetterMethod(IDecl, PD, true /*getter*/)) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) if (mustSynthesizeSetterGetterMethod(IDecl, PD, false /*setter*/)) InstanceMethods.push_back(Setter); } @@ -7281,11 +7285,11 @@ void RewriteModernObjC::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *IDecl, ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) InstanceMethods.push_back(Setter); } diff --git a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp index 6a22da178fbc..0cb7592b9982 100644 --- a/clang/lib/Frontend/Rewrite/RewriteObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteObjC.cpp @@ -786,8 +786,9 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, if (!OID) return; + unsigned Attributes = PD->getPropertyAttributes(); - if (!PD->getGetterMethodDecl()->isDefined()) { + if (PID->getGetterMethodDecl() && !PID->getGetterMethodDecl()->isDefined()) { bool GenGetProperty = !(Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) && (Attributes & (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_copy)); @@ -799,7 +800,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, "id objc_getProperty(id, SEL, long, bool);\n"; } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getGetterMethodDecl(), Getr); + PID->getGetterMethodDecl(), Getr); Getr += "{ "; // Synthesize an explicit cast to gain access to the ivar. // See objc-act.c:objc_synthesize_new_getter() for details. @@ -807,7 +808,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, // return objc_getProperty(self, _cmd, offsetof(ClassDecl, OID), 1) Getr += "typedef "; const FunctionType *FPRetType = nullptr; - RewriteTypeIntoString(PD->getGetterMethodDecl()->getReturnType(), Getr, + RewriteTypeIntoString(PID->getGetterMethodDecl()->getReturnType(), Getr, FPRetType); Getr += " _TYPE"; if (FPRetType) { @@ -843,7 +844,8 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, InsertText(onePastSemiLoc, Getr); } - if (PD->isReadOnly() || PD->getSetterMethodDecl()->isDefined()) + if (PD->isReadOnly() || !PID->getSetterMethodDecl() || + PID->getSetterMethodDecl()->isDefined()) return; // Generate the 'setter' function. @@ -858,7 +860,7 @@ void RewriteObjC::RewritePropertyImplDecl(ObjCPropertyImplDecl *PID, } RewriteObjCMethodDecl(OID->getContainingInterface(), - PD->getSetterMethodDecl(), Setr); + PID->getSetterMethodDecl(), Setr); Setr += "{ "; // Synthesize an explicit cast to initialize the ivar. // See objc-act.c:objc_synthesize_new_setter() for details. @@ -1168,6 +1170,8 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) { InsertText(IMD ? IMD->getBeginLoc() : CID->getBeginLoc(), "// "); for (auto *OMD : IMD ? IMD->instance_methods() : CID->instance_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -1179,6 +1183,8 @@ void RewriteObjC::RewriteImplementationDecl(Decl *OID) { } for (auto *OMD : IMD ? IMD->class_methods() : CID->class_methods()) { + if (!OMD->getBody()) + continue; std::string ResultStr; RewriteObjCMethodDecl(OMD->getClassInterface(), OMD, ResultStr); SourceLocation LocStart = OMD->getBeginLoc(); @@ -5355,12 +5361,12 @@ void RewriteObjCFragileABI::RewriteObjCClassMetaData(ObjCImplementationDecl *IDe ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) if (!Getter->isDefined()) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) if (!Setter->isDefined()) InstanceMethods.push_back(Setter); } @@ -5633,11 +5639,11 @@ void RewriteObjCFragileABI::RewriteObjCCategoryImplDecl(ObjCCategoryImplDecl *ID ObjCPropertyDecl *PD = Prop->getPropertyDecl(); if (!PD) continue; - if (ObjCMethodDecl *Getter = PD->getGetterMethodDecl()) + if (ObjCMethodDecl *Getter = Prop->getGetterMethodDecl()) InstanceMethods.push_back(Getter); if (PD->isReadOnly()) continue; - if (ObjCMethodDecl *Setter = PD->getSetterMethodDecl()) + if (ObjCMethodDecl *Setter = Prop->getSetterMethodDecl()) InstanceMethods.push_back(Setter); } RewriteObjCMethodsMetaData(InstanceMethods.begin(), InstanceMethods.end(), diff --git a/clang/lib/Frontend/TextDiagnostic.cpp b/clang/lib/Frontend/TextDiagnostic.cpp index 7bb6c5b74d5f..78acaaf9f96e 100644 --- a/clang/lib/Frontend/TextDiagnostic.cpp +++ b/clang/lib/Frontend/TextDiagnostic.cpp @@ -761,11 +761,12 @@ void TextDiagnostic::printDiagnosticMessage(raw_ostream &OS, } void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) { - SmallVector<char, 128> AbsoluteFilename; +#ifdef _WIN32 + SmallString<4096> TmpFilename; +#endif if (DiagOpts->AbsolutePath) { - auto Dir = SM.getFileManager().getDirectory( - llvm::sys::path::parent_path(Filename)); - if (Dir) { + auto File = SM.getFileManager().getFile(Filename); + if (File) { // We want to print a simplified absolute path, i. e. without "dots". // // The hardest part here are the paths like "<part1>/<link>/../<part2>". @@ -781,16 +782,14 @@ void TextDiagnostic::emitFilename(StringRef Filename, const SourceManager &SM) { // on Windows we can just use llvm::sys::path::remove_dots(), because, // on that system, both aforementioned paths point to the same place. #ifdef _WIN32 - SmallString<4096> DirName = (*Dir)->getName(); - llvm::sys::fs::make_absolute(DirName); - llvm::sys::path::native(DirName); - llvm::sys::path::remove_dots(DirName, /* remove_dot_dot */ true); + TmpFilename = (*File)->getName(); + llvm::sys::fs::make_absolute(TmpFilename); + llvm::sys::path::native(TmpFilename); + llvm::sys::path::remove_dots(TmpFilename, /* remove_dot_dot */ true); + Filename = StringRef(TmpFilename.data(), TmpFilename.size()); #else - StringRef DirName = SM.getFileManager().getCanonicalName(*Dir); + Filename = SM.getFileManager().getCanonicalName(*File); #endif - llvm::sys::path::append(AbsoluteFilename, DirName, - llvm::sys::path::filename(Filename)); - Filename = StringRef(AbsoluteFilename.data(), AbsoluteFilename.size()); } } diff --git a/clang/lib/Headers/altivec.h b/clang/lib/Headers/altivec.h index 8352f8f740c2..7e231a2a428e 100644 --- a/clang/lib/Headers/altivec.h +++ b/clang/lib/Headers/altivec.h @@ -14784,7 +14784,7 @@ static __inline__ int __ATTRS_o_ai vec_all_ne(vector bool long long __a, static __inline__ int __ATTRS_o_ai vec_all_ne(vector float __a, vector float __b) { #ifdef __VSX__ - return __builtin_vsx_xvcmpeqdp_p(__CR6_EQ, (vector double)__a, (vector double)__b); + return __builtin_vsx_xvcmpeqsp_p(__CR6_EQ, __a, __b); #else return __builtin_altivec_vcmpeqfp_p(__CR6_EQ, __a, __b); #endif @@ -16364,27 +16364,32 @@ vec_xl(signed long long __offset, unsigned char *__ptr) { static inline __ATTRS_o_ai vector signed short vec_xl(signed long long __offset, signed short *__ptr) { - return *(unaligned_vec_sshort *)(__ptr + __offset); + signed char *__addr = (signed char *)__ptr + __offset; + return *(unaligned_vec_sshort *)__addr; } static inline __ATTRS_o_ai vector unsigned short vec_xl(signed long long __offset, unsigned short *__ptr) { - return *(unaligned_vec_ushort *)(__ptr + __offset); + signed char *__addr = (signed char *)__ptr + __offset; + return *(unaligned_vec_ushort *)__addr; } static inline __ATTRS_o_ai vector signed int vec_xl(signed long long __offset, signed int *__ptr) { - return *(unaligned_vec_sint *)(__ptr + __offset); + signed char *__addr = (signed char *)__ptr + __offset; + return *(unaligned_vec_sint *)__addr; } static inline __ATTRS_o_ai vector unsigned int vec_xl(signed long long __offset, unsigned int *__ptr) { - return *(unaligned_vec_uint *)(__ptr + __offset); + signed char *__addr = (signed char *)__ptr + __offset; + return *(unaligned_vec_uint *)__addr; } static inline __ATTRS_o_ai vector float vec_xl(signed long long __offset, float *__ptr) { - return *(unaligned_vec_float *)(__ptr + __offset); + signed char *__addr = (signed char *)__ptr + __offset; + return *(unaligned_vec_float *)__addr; } #ifdef __VSX__ @@ -16394,17 +16399,20 @@ typedef vector double unaligned_vec_double __attribute__((aligned(1))); static inline __ATTRS_o_ai vector signed long long vec_xl(signed long long __offset, signed long long *__ptr) { - return *(unaligned_vec_sll *)(__ptr + __offset); + signed char *__addr = (signed char *)__ptr + __offset; + return *(unaligned_vec_sll *)__addr; } static inline __ATTRS_o_ai vector unsigned long long vec_xl(signed long long __offset, unsigned long long *__ptr) { - return *(unaligned_vec_ull *)(__ptr + __offset); + signed char *__addr = (signed char *)__ptr + __offset; + return *(unaligned_vec_ull *)__addr; } static inline __ATTRS_o_ai vector double vec_xl(signed long long __offset, double *__ptr) { - return *(unaligned_vec_double *)(__ptr + __offset); + signed char *__addr = (signed char *)__ptr + __offset; + return *(unaligned_vec_double *)__addr; } #endif @@ -16414,12 +16422,14 @@ typedef vector unsigned __int128 unaligned_vec_ui128 __attribute__((aligned(1))); static inline __ATTRS_o_ai vector signed __int128 vec_xl(signed long long __offset, signed __int128 *__ptr) { - return *(unaligned_vec_si128 *)(__ptr + __offset); + signed char *__addr = (signed char *)__ptr + __offset; + return *(unaligned_vec_si128 *)__addr; } static inline __ATTRS_o_ai vector unsigned __int128 vec_xl(signed long long __offset, unsigned __int128 *__ptr) { - return *(unaligned_vec_ui128 *)(__ptr + __offset); + signed char *__addr = (signed char *)__ptr + __offset; + return *(unaligned_vec_ui128 *)__addr; } #endif @@ -16516,50 +16526,58 @@ static inline __ATTRS_o_ai void vec_xst(vector unsigned char __vec, static inline __ATTRS_o_ai void vec_xst(vector signed short __vec, signed long long __offset, signed short *__ptr) { - *(unaligned_vec_sshort *)(__ptr + __offset) = __vec; + signed char *__addr = (signed char *)__ptr + __offset; + *(unaligned_vec_sshort *)__addr = __vec; } static inline __ATTRS_o_ai void vec_xst(vector unsigned short __vec, signed long long __offset, unsigned short *__ptr) { - *(unaligned_vec_ushort *)(__ptr + __offset) = __vec; + signed char *__addr = (signed char *)__ptr + __offset; + *(unaligned_vec_ushort *)__addr = __vec; } static inline __ATTRS_o_ai void vec_xst(vector signed int __vec, signed long long __offset, signed int *__ptr) { - *(unaligned_vec_sint *)(__ptr + __offset) = __vec; + signed char *__addr = (signed char *)__ptr + __offset; + *(unaligned_vec_sint *)__addr = __vec; } static inline __ATTRS_o_ai void vec_xst(vector unsigned int __vec, signed long long __offset, unsigned int *__ptr) { - *(unaligned_vec_uint *)(__ptr + __offset) = __vec; + signed char *__addr = (signed char *)__ptr + __offset; + *(unaligned_vec_uint *)__addr = __vec; } static inline __ATTRS_o_ai void vec_xst(vector float __vec, signed long long __offset, float *__ptr) { - *(unaligned_vec_float *)(__ptr + __offset) = __vec; + signed char *__addr = (signed char *)__ptr + __offset; + *(unaligned_vec_float *)__addr = __vec; } #ifdef __VSX__ static inline __ATTRS_o_ai void vec_xst(vector signed long long __vec, signed long long __offset, signed long long *__ptr) { - *(unaligned_vec_sll *)(__ptr + __offset) = __vec; + signed char *__addr = (signed char *)__ptr + __offset; + *(unaligned_vec_sll *)__addr = __vec; } static inline __ATTRS_o_ai void vec_xst(vector unsigned long long __vec, signed long long __offset, unsigned long long *__ptr) { - *(unaligned_vec_ull *)(__ptr + __offset) = __vec; + signed char *__addr = (signed char *)__ptr + __offset; + *(unaligned_vec_ull *)__addr = __vec; } static inline __ATTRS_o_ai void vec_xst(vector double __vec, signed long long __offset, double *__ptr) { - *(unaligned_vec_double *)(__ptr + __offset) = __vec; + signed char *__addr = (signed char *)__ptr + __offset; + *(unaligned_vec_double *)__addr = __vec; } #endif @@ -16567,13 +16585,15 @@ static inline __ATTRS_o_ai void vec_xst(vector double __vec, static inline __ATTRS_o_ai void vec_xst(vector signed __int128 __vec, signed long long __offset, signed __int128 *__ptr) { - *(unaligned_vec_si128 *)(__ptr + __offset) = __vec; + signed char *__addr = (signed char *)__ptr + __offset; + *(unaligned_vec_si128 *)__addr = __vec; } static inline __ATTRS_o_ai void vec_xst(vector unsigned __int128 __vec, signed long long __offset, unsigned __int128 *__ptr) { - *(unaligned_vec_ui128 *)(__ptr + __offset) = __vec; + signed char *__addr = (signed char *)__ptr + __offset; + *(unaligned_vec_ui128 *)__addr = __vec; } #endif diff --git a/clang/lib/Headers/arm_acle.h b/clang/lib/Headers/arm_acle.h index 0510e6fd809f..596ea03cff2f 100644 --- a/clang/lib/Headers/arm_acle.h +++ b/clang/lib/Headers/arm_acle.h @@ -90,9 +90,11 @@ __swp(uint32_t __x, volatile uint32_t *__p) { #endif /* 8.7 NOP */ +#if !defined(_MSC_VER) || !defined(__aarch64__) static __inline__ void __attribute__((__always_inline__, __nodebug__)) __nop(void) { __builtin_arm_nop(); } +#endif /* 9 DATA-PROCESSING INTRINSICS */ /* 9.2 Miscellaneous data-processing intrinsics */ @@ -139,6 +141,26 @@ __clzll(uint64_t __t) { return __builtin_clzll(__t); } +/* CLS */ +static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__)) +__cls(uint32_t __t) { + return __builtin_arm_cls(__t); +} + +static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__)) +__clsl(unsigned long __t) { +#if __SIZEOF_LONG__ == 4 + return __builtin_arm_cls(__t); +#else + return __builtin_arm_cls64(__t); +#endif +} + +static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__)) +__clsll(uint64_t __t) { + return __builtin_arm_cls64(__t); +} + /* REV */ static __inline__ uint32_t __attribute__((__always_inline__, __nodebug__)) __rev(uint32_t __t) { @@ -609,9 +631,13 @@ __jcvt(double __a) { #define __arm_rsr(sysreg) __builtin_arm_rsr(sysreg) #define __arm_rsr64(sysreg) __builtin_arm_rsr64(sysreg) #define __arm_rsrp(sysreg) __builtin_arm_rsrp(sysreg) +#define __arm_rsrf(sysreg) __builtin_bit_cast(float, __arm_rsr(sysreg)) +#define __arm_rsrf64(sysreg) __builtin_bit_cast(double, __arm_rsr64(sysreg)) #define __arm_wsr(sysreg, v) __builtin_arm_wsr(sysreg, v) #define __arm_wsr64(sysreg, v) __builtin_arm_wsr64(sysreg, v) #define __arm_wsrp(sysreg, v) __builtin_arm_wsrp(sysreg, v) +#define __arm_wsrf(sysreg, v) __arm_wsr(sysreg, __builtin_bit_cast(uint32_t, v)) +#define __arm_wsrf64(sysreg, v) __arm_wsr64(sysreg, __builtin_bit_cast(uint64_t, v)) /* Memory Tagging Extensions (MTE) Intrinsics */ #if __ARM_FEATURE_MEMORY_TAGGING diff --git a/clang/lib/Headers/arm_cmse.h b/clang/lib/Headers/arm_cmse.h new file mode 100644 index 000000000000..ecf50ecc5c8e --- /dev/null +++ b/clang/lib/Headers/arm_cmse.h @@ -0,0 +1,217 @@ +//===---- arm_cmse.h - Arm CMSE support -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef __ARM_CMSE_H +#define __ARM_CMSE_H + +#if (__ARM_FEATURE_CMSE & 0x1) +#include <stddef.h> +#include <stdint.h> + +#define __ARM_CMSE_SECURE_MODE (__ARM_FEATURE_CMSE & 0x2) +#define CMSE_MPU_READWRITE 1 /* checks if readwrite_ok field is set */ +#define CMSE_AU_NONSECURE 2 /* checks if permissions have secure field unset */ +#define CMSE_MPU_UNPRIV 4 /* sets T flag on TT insrtuction */ +#define CMSE_MPU_READ 8 /* checks if read_ok field is set */ +#define CMSE_MPU_NONSECURE 16 /* sets A flag, checks if secure field unset */ +#define CMSE_NONSECURE (CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE) + +#define cmse_check_pointed_object(p, f) \ + cmse_check_address_range((p), sizeof(*(p)), (f)) + +#if defined(__cplusplus) +extern "C" { +#endif + +typedef union { + struct cmse_address_info { +#ifdef __ARM_BIG_ENDIAN + /* __ARM_BIG_ENDIAN */ +#if (__ARM_CMSE_SECURE_MODE) + unsigned idau_region : 8; + unsigned idau_region_valid : 1; + unsigned secure : 1; + unsigned nonsecure_readwrite_ok : 1; + unsigned nonsecure_read_ok : 1; +#else + unsigned : 12; +#endif + unsigned readwrite_ok : 1; + unsigned read_ok : 1; +#if (__ARM_CMSE_SECURE_MODE) + unsigned sau_region_valid : 1; +#else + unsigned : 1; +#endif + unsigned mpu_region_valid : 1; +#if (__ARM_CMSE_SECURE_MODE) + unsigned sau_region : 8; +#else + unsigned : 8; +#endif + unsigned mpu_region : 8; + +#else /* __ARM_LITTLE_ENDIAN */ + unsigned mpu_region : 8; +#if (__ARM_CMSE_SECURE_MODE) + unsigned sau_region : 8; +#else + unsigned : 8; +#endif + unsigned mpu_region_valid : 1; +#if (__ARM_CMSE_SECURE_MODE) + unsigned sau_region_valid : 1; +#else + unsigned : 1; +#endif + unsigned read_ok : 1; + unsigned readwrite_ok : 1; +#if (__ARM_CMSE_SECURE_MODE) + unsigned nonsecure_read_ok : 1; + unsigned nonsecure_readwrite_ok : 1; + unsigned secure : 1; + unsigned idau_region_valid : 1; + unsigned idau_region : 8; +#else + unsigned : 12; +#endif +#endif /*__ARM_LITTLE_ENDIAN */ + } flags; + unsigned value; +} cmse_address_info_t; + +static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) +cmse_TT(void *__p) { + cmse_address_info_t __u; + __u.value = __builtin_arm_cmse_TT(__p); + return __u; +} +static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) +cmse_TTT(void *__p) { + cmse_address_info_t __u; + __u.value = __builtin_arm_cmse_TTT(__p); + return __u; +} + +#if __ARM_CMSE_SECURE_MODE +static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) +cmse_TTA(void *__p) { + cmse_address_info_t __u; + __u.value = __builtin_arm_cmse_TTA(__p); + return __u; +} +static cmse_address_info_t __attribute__((__always_inline__, __nodebug__)) +cmse_TTAT(void *__p) { + cmse_address_info_t __u; + __u.value = __builtin_arm_cmse_TTAT(__p); + return __u; +} +#endif + +#define cmse_TT_fptr(p) cmse_TT(__builtin_bit_cast(void *, (p))) +#define cmse_TTT_fptr(p) cmse_TTT(__builtin_bit_cast(void *, (p))) + +#if __ARM_CMSE_SECURE_MODE +#define cmse_TTA_fptr(p) cmse_TTA(__builtin_bit_cast(void *, (p))) +#define cmse_TTAT_fptr(p) cmse_TTAT(__builtin_bit_cast(void *, (p))) +#endif + +static void *__attribute__((__always_inline__)) +cmse_check_address_range(void *__pb, size_t __s, int __flags) { + uintptr_t __begin = (uintptr_t)__pb; + uintptr_t __end = __begin + __s - 1; + + if (__end < __begin) + return NULL; /* wrap around check */ + + /* Check whether the range crosses a 32-bytes aligned address */ + const int __single_check = (__begin ^ __end) < 0x20u; + + /* execute the right variant of the TT instructions */ + void *__pe = (void *)__end; + cmse_address_info_t __permb, __perme; + switch (__flags & (CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) { + case 0: + __permb = cmse_TT(__pb); + __perme = __single_check ? __permb : cmse_TT(__pe); + break; + case CMSE_MPU_UNPRIV: + __permb = cmse_TTT(__pb); + __perme = __single_check ? __permb : cmse_TTT(__pe); + break; +#if __ARM_CMSE_SECURE_MODE + case CMSE_MPU_NONSECURE: + __permb = cmse_TTA(__pb); + __perme = __single_check ? __permb : cmse_TTA(__pe); + break; + case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE: + __permb = cmse_TTAT(__pb); + __perme = __single_check ? __permb : cmse_TTAT(__pe); + break; +#endif + /* if CMSE_NONSECURE is specified w/o __ARM_CMSE_SECURE_MODE */ + default: + return NULL; + } + + /* check that the range does not cross MPU, SAU, or IDAU region boundaries */ + if (__permb.value != __perme.value) + return NULL; +#if !(__ARM_CMSE_SECURE_MODE) + /* CMSE_AU_NONSECURE is only supported when __ARM_FEATURE_CMSE & 0x2 */ + if (__flags & CMSE_AU_NONSECURE) + return NULL; +#endif + + /* check the permission on the range */ + switch (__flags & ~(CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) { +#if (__ARM_CMSE_SECURE_MODE) + case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE: + case CMSE_MPU_READWRITE | CMSE_AU_NONSECURE: + return __permb.flags.nonsecure_readwrite_ok ? __pb : NULL; + + case CMSE_MPU_READ | CMSE_AU_NONSECURE: + return __permb.flags.nonsecure_read_ok ? __pb : NULL; + + case CMSE_AU_NONSECURE: + return __permb.flags.secure ? NULL : __pb; +#endif + case CMSE_MPU_READ | CMSE_MPU_READWRITE: + case CMSE_MPU_READWRITE: + return __permb.flags.readwrite_ok ? __pb : NULL; + + case CMSE_MPU_READ: + return __permb.flags.read_ok ? __pb : NULL; + + default: + return NULL; + } +} + +#if __ARM_CMSE_SECURE_MODE +static int __attribute__((__always_inline__, __nodebug__)) +cmse_nonsecure_caller(void) { + return !((uintptr_t)__builtin_return_address(0) & 1); +} + +#define cmse_nsfptr_create(p) \ + __builtin_bit_cast(__typeof__(p), \ + (__builtin_bit_cast(uintptr_t, p) & ~(uintptr_t)1)) + +#define cmse_is_nsfptr(p) ((__builtin_bit_cast(uintptr_t, p) & 1) == 0) + +#endif /* __ARM_CMSE_SECURE_MODE */ + +void __attribute__((__noreturn__)) cmse_abort(void); +#if defined(__cplusplus) +} +#endif + +#endif /* (__ARM_FEATURE_CMSE & 0x1) */ + +#endif /* __ARM_CMSE_H */ diff --git a/clang/lib/Headers/avx512bwintrin.h b/clang/lib/Headers/avx512bwintrin.h index cb2e07619cb7..376558407683 100644 --- a/clang/lib/Headers/avx512bwintrin.h +++ b/clang/lib/Headers/avx512bwintrin.h @@ -1731,13 +1731,13 @@ _mm512_loadu_epi16 (void const *__P) struct __loadu_epi16 { __m512i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi16*)__P)->__v; + return ((const struct __loadu_epi16*)__P)->__v; } static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_mask_loadu_epi16 (__m512i __W, __mmask32 __U, void const *__P) { - return (__m512i) __builtin_ia32_loaddquhi512_mask ((__v32hi *) __P, + return (__m512i) __builtin_ia32_loaddquhi512_mask ((const __v32hi *) __P, (__v32hi) __W, (__mmask32) __U); } @@ -1745,7 +1745,7 @@ _mm512_mask_loadu_epi16 (__m512i __W, __mmask32 __U, void const *__P) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_maskz_loadu_epi16 (__mmask32 __U, void const *__P) { - return (__m512i) __builtin_ia32_loaddquhi512_mask ((__v32hi *) __P, + return (__m512i) __builtin_ia32_loaddquhi512_mask ((const __v32hi *) __P, (__v32hi) _mm512_setzero_si512 (), (__mmask32) __U); @@ -1757,13 +1757,13 @@ _mm512_loadu_epi8 (void const *__P) struct __loadu_epi8 { __m512i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi8*)__P)->__v; + return ((const struct __loadu_epi8*)__P)->__v; } static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_mask_loadu_epi8 (__m512i __W, __mmask64 __U, void const *__P) { - return (__m512i) __builtin_ia32_loaddquqi512_mask ((__v64qi *) __P, + return (__m512i) __builtin_ia32_loaddquqi512_mask ((const __v64qi *) __P, (__v64qi) __W, (__mmask64) __U); } @@ -1771,7 +1771,7 @@ _mm512_mask_loadu_epi8 (__m512i __W, __mmask64 __U, void const *__P) static __inline__ __m512i __DEFAULT_FN_ATTRS512 _mm512_maskz_loadu_epi8 (__mmask64 __U, void const *__P) { - return (__m512i) __builtin_ia32_loaddquqi512_mask ((__v64qi *) __P, + return (__m512i) __builtin_ia32_loaddquqi512_mask ((const __v64qi *) __P, (__v64qi) _mm512_setzero_si512 (), (__mmask64) __U); diff --git a/clang/lib/Headers/avx512fintrin.h b/clang/lib/Headers/avx512fintrin.h index 698e477fe5f3..7465da379bdd 100644 --- a/clang/lib/Headers/avx512fintrin.h +++ b/clang/lib/Headers/avx512fintrin.h @@ -4305,7 +4305,7 @@ _mm512_loadu_si512 (void const *__P) struct __loadu_si512 { __m512i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_si512*)__P)->__v; + return ((const struct __loadu_si512*)__P)->__v; } static __inline __m512i __DEFAULT_FN_ATTRS512 @@ -4314,7 +4314,7 @@ _mm512_loadu_epi32 (void const *__P) struct __loadu_epi32 { __m512i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi32*)__P)->__v; + return ((const struct __loadu_epi32*)__P)->__v; } static __inline __m512i __DEFAULT_FN_ATTRS512 @@ -4341,7 +4341,7 @@ _mm512_loadu_epi64 (void const *__P) struct __loadu_epi64 { __m512i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi64*)__P)->__v; + return ((const struct __loadu_epi64*)__P)->__v; } static __inline __m512i __DEFAULT_FN_ATTRS512 @@ -4401,7 +4401,7 @@ _mm512_loadu_pd(void const *__p) struct __loadu_pd { __m512d_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_pd*)__p)->__v; + return ((const struct __loadu_pd*)__p)->__v; } static __inline __m512 __DEFAULT_FN_ATTRS512 @@ -4410,13 +4410,13 @@ _mm512_loadu_ps(void const *__p) struct __loadu_ps { __m512_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_ps*)__p)->__v; + return ((const struct __loadu_ps*)__p)->__v; } static __inline __m512 __DEFAULT_FN_ATTRS512 _mm512_load_ps(void const *__p) { - return *(__m512*)__p; + return *(const __m512*)__p; } static __inline __m512 __DEFAULT_FN_ATTRS512 @@ -4439,7 +4439,7 @@ _mm512_maskz_load_ps(__mmask16 __U, void const *__P) static __inline __m512d __DEFAULT_FN_ATTRS512 _mm512_load_pd(void const *__p) { - return *(__m512d*)__p; + return *(const __m512d*)__p; } static __inline __m512d __DEFAULT_FN_ATTRS512 @@ -4462,19 +4462,19 @@ _mm512_maskz_load_pd(__mmask8 __U, void const *__P) static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_load_si512 (void const *__P) { - return *(__m512i *) __P; + return *(const __m512i *) __P; } static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_load_epi32 (void const *__P) { - return *(__m512i *) __P; + return *(const __m512i *) __P; } static __inline __m512i __DEFAULT_FN_ATTRS512 _mm512_load_epi64 (void const *__P) { - return *(__m512i *) __P; + return *(const __m512i *) __P; } /* SIMD store ops */ @@ -8724,13 +8724,13 @@ _mm_mask_load_ss (__m128 __W, __mmask8 __U, const float* __A) (__v4sf)_mm_setzero_ps(), 0, 4, 4, 4); - return (__m128) __builtin_ia32_loadss128_mask ((__v4sf *) __A, src, __U & 1); + return (__m128) __builtin_ia32_loadss128_mask ((const __v4sf *) __A, src, __U & 1); } static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_load_ss (__mmask8 __U, const float* __A) { - return (__m128)__builtin_ia32_loadss128_mask ((__v4sf *) __A, + return (__m128)__builtin_ia32_loadss128_mask ((const __v4sf *) __A, (__v4sf) _mm_setzero_ps(), __U & 1); } @@ -8742,13 +8742,13 @@ _mm_mask_load_sd (__m128d __W, __mmask8 __U, const double* __A) (__v2df)_mm_setzero_pd(), 0, 2); - return (__m128d) __builtin_ia32_loadsd128_mask ((__v2df *) __A, src, __U & 1); + return (__m128d) __builtin_ia32_loadsd128_mask ((const __v2df *) __A, src, __U & 1); } static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_maskz_load_sd (__mmask8 __U, const double* __A) { - return (__m128d) __builtin_ia32_loadsd128_mask ((__v2df *) __A, + return (__m128d) __builtin_ia32_loadsd128_mask ((const __v2df *) __A, (__v2df) _mm_setzero_pd(), __U & 1); } diff --git a/clang/lib/Headers/avx512vlbwintrin.h b/clang/lib/Headers/avx512vlbwintrin.h index ead09466bc2c..cd9f2400daa0 100644 --- a/clang/lib/Headers/avx512vlbwintrin.h +++ b/clang/lib/Headers/avx512vlbwintrin.h @@ -2289,13 +2289,13 @@ _mm_loadu_epi16 (void const *__P) struct __loadu_epi16 { __m128i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi16*)__P)->__v; + return ((const struct __loadu_epi16*)__P)->__v; } static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_mask_loadu_epi16 (__m128i __W, __mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_loaddquhi128_mask ((__v8hi *) __P, + return (__m128i) __builtin_ia32_loaddquhi128_mask ((const __v8hi *) __P, (__v8hi) __W, (__mmask8) __U); } @@ -2303,7 +2303,7 @@ _mm_mask_loadu_epi16 (__m128i __W, __mmask8 __U, void const *__P) static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_maskz_loadu_epi16 (__mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_loaddquhi128_mask ((__v8hi *) __P, + return (__m128i) __builtin_ia32_loaddquhi128_mask ((const __v8hi *) __P, (__v8hi) _mm_setzero_si128 (), (__mmask8) __U); @@ -2315,13 +2315,13 @@ _mm256_loadu_epi16 (void const *__P) struct __loadu_epi16 { __m256i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi16*)__P)->__v; + return ((const struct __loadu_epi16*)__P)->__v; } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_mask_loadu_epi16 (__m256i __W, __mmask16 __U, void const *__P) { - return (__m256i) __builtin_ia32_loaddquhi256_mask ((__v16hi *) __P, + return (__m256i) __builtin_ia32_loaddquhi256_mask ((const __v16hi *) __P, (__v16hi) __W, (__mmask16) __U); } @@ -2329,7 +2329,7 @@ _mm256_mask_loadu_epi16 (__m256i __W, __mmask16 __U, void const *__P) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskz_loadu_epi16 (__mmask16 __U, void const *__P) { - return (__m256i) __builtin_ia32_loaddquhi256_mask ((__v16hi *) __P, + return (__m256i) __builtin_ia32_loaddquhi256_mask ((const __v16hi *) __P, (__v16hi) _mm256_setzero_si256 (), (__mmask16) __U); @@ -2341,13 +2341,13 @@ _mm_loadu_epi8 (void const *__P) struct __loadu_epi8 { __m128i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi8*)__P)->__v; + return ((const struct __loadu_epi8*)__P)->__v; } static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_mask_loadu_epi8 (__m128i __W, __mmask16 __U, void const *__P) { - return (__m128i) __builtin_ia32_loaddquqi128_mask ((__v16qi *) __P, + return (__m128i) __builtin_ia32_loaddquqi128_mask ((const __v16qi *) __P, (__v16qi) __W, (__mmask16) __U); } @@ -2355,7 +2355,7 @@ _mm_mask_loadu_epi8 (__m128i __W, __mmask16 __U, void const *__P) static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_maskz_loadu_epi8 (__mmask16 __U, void const *__P) { - return (__m128i) __builtin_ia32_loaddquqi128_mask ((__v16qi *) __P, + return (__m128i) __builtin_ia32_loaddquqi128_mask ((const __v16qi *) __P, (__v16qi) _mm_setzero_si128 (), (__mmask16) __U); @@ -2367,13 +2367,13 @@ _mm256_loadu_epi8 (void const *__P) struct __loadu_epi8 { __m256i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi8*)__P)->__v; + return ((const struct __loadu_epi8*)__P)->__v; } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_mask_loadu_epi8 (__m256i __W, __mmask32 __U, void const *__P) { - return (__m256i) __builtin_ia32_loaddquqi256_mask ((__v32qi *) __P, + return (__m256i) __builtin_ia32_loaddquqi256_mask ((const __v32qi *) __P, (__v32qi) __W, (__mmask32) __U); } @@ -2381,7 +2381,7 @@ _mm256_mask_loadu_epi8 (__m256i __W, __mmask32 __U, void const *__P) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskz_loadu_epi8 (__mmask32 __U, void const *__P) { - return (__m256i) __builtin_ia32_loaddquqi256_mask ((__v32qi *) __P, + return (__m256i) __builtin_ia32_loaddquqi256_mask ((const __v32qi *) __P, (__v32qi) _mm256_setzero_si256 (), (__mmask32) __U); diff --git a/clang/lib/Headers/avx512vlintrin.h b/clang/lib/Headers/avx512vlintrin.h index 9494fc8a6e59..9d1d791bb248 100644 --- a/clang/lib/Headers/avx512vlintrin.h +++ b/clang/lib/Headers/avx512vlintrin.h @@ -2505,7 +2505,7 @@ _mm256_maskz_expand_epi64 (__mmask8 __U, __m256i __A) { static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_expandloadu_pd (__m128d __W, __mmask8 __U, void const *__P) { - return (__m128d) __builtin_ia32_expandloaddf128_mask ((__v2df *) __P, + return (__m128d) __builtin_ia32_expandloaddf128_mask ((const __v2df *) __P, (__v2df) __W, (__mmask8) __U); @@ -2513,7 +2513,7 @@ _mm_mask_expandloadu_pd (__m128d __W, __mmask8 __U, void const *__P) { static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_maskz_expandloadu_pd (__mmask8 __U, void const *__P) { - return (__m128d) __builtin_ia32_expandloaddf128_mask ((__v2df *) __P, + return (__m128d) __builtin_ia32_expandloaddf128_mask ((const __v2df *) __P, (__v2df) _mm_setzero_pd (), (__mmask8) @@ -2522,7 +2522,7 @@ _mm_maskz_expandloadu_pd (__mmask8 __U, void const *__P) { static __inline__ __m256d __DEFAULT_FN_ATTRS256 _mm256_mask_expandloadu_pd (__m256d __W, __mmask8 __U, void const *__P) { - return (__m256d) __builtin_ia32_expandloaddf256_mask ((__v4df *) __P, + return (__m256d) __builtin_ia32_expandloaddf256_mask ((const __v4df *) __P, (__v4df) __W, (__mmask8) __U); @@ -2530,7 +2530,7 @@ _mm256_mask_expandloadu_pd (__m256d __W, __mmask8 __U, void const *__P) { static __inline__ __m256d __DEFAULT_FN_ATTRS256 _mm256_maskz_expandloadu_pd (__mmask8 __U, void const *__P) { - return (__m256d) __builtin_ia32_expandloaddf256_mask ((__v4df *) __P, + return (__m256d) __builtin_ia32_expandloaddf256_mask ((const __v4df *) __P, (__v4df) _mm256_setzero_pd (), (__mmask8) @@ -2539,7 +2539,7 @@ _mm256_maskz_expandloadu_pd (__mmask8 __U, void const *__P) { static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_mask_expandloadu_epi64 (__m128i __W, __mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_expandloaddi128_mask ((__v2di *) __P, + return (__m128i) __builtin_ia32_expandloaddi128_mask ((const __v2di *) __P, (__v2di) __W, (__mmask8) __U); @@ -2547,7 +2547,7 @@ _mm_mask_expandloadu_epi64 (__m128i __W, __mmask8 __U, void const *__P) { static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_maskz_expandloadu_epi64 (__mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_expandloaddi128_mask ((__v2di *) __P, + return (__m128i) __builtin_ia32_expandloaddi128_mask ((const __v2di *) __P, (__v2di) _mm_setzero_si128 (), (__mmask8) @@ -2557,7 +2557,7 @@ _mm_maskz_expandloadu_epi64 (__mmask8 __U, void const *__P) { static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_mask_expandloadu_epi64 (__m256i __W, __mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_expandloaddi256_mask ((__v4di *) __P, + return (__m256i) __builtin_ia32_expandloaddi256_mask ((const __v4di *) __P, (__v4di) __W, (__mmask8) __U); @@ -2565,7 +2565,7 @@ _mm256_mask_expandloadu_epi64 (__m256i __W, __mmask8 __U, static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskz_expandloadu_epi64 (__mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_expandloaddi256_mask ((__v4di *) __P, + return (__m256i) __builtin_ia32_expandloaddi256_mask ((const __v4di *) __P, (__v4di) _mm256_setzero_si256 (), (__mmask8) @@ -2574,14 +2574,14 @@ _mm256_maskz_expandloadu_epi64 (__mmask8 __U, void const *__P) { static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_expandloadu_ps (__m128 __W, __mmask8 __U, void const *__P) { - return (__m128) __builtin_ia32_expandloadsf128_mask ((__v4sf *) __P, + return (__m128) __builtin_ia32_expandloadsf128_mask ((const __v4sf *) __P, (__v4sf) __W, (__mmask8) __U); } static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_expandloadu_ps (__mmask8 __U, void const *__P) { - return (__m128) __builtin_ia32_expandloadsf128_mask ((__v4sf *) __P, + return (__m128) __builtin_ia32_expandloadsf128_mask ((const __v4sf *) __P, (__v4sf) _mm_setzero_ps (), (__mmask8) @@ -2590,14 +2590,14 @@ _mm_maskz_expandloadu_ps (__mmask8 __U, void const *__P) { static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_mask_expandloadu_ps (__m256 __W, __mmask8 __U, void const *__P) { - return (__m256) __builtin_ia32_expandloadsf256_mask ((__v8sf *) __P, + return (__m256) __builtin_ia32_expandloadsf256_mask ((const __v8sf *) __P, (__v8sf) __W, (__mmask8) __U); } static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_maskz_expandloadu_ps (__mmask8 __U, void const *__P) { - return (__m256) __builtin_ia32_expandloadsf256_mask ((__v8sf *) __P, + return (__m256) __builtin_ia32_expandloadsf256_mask ((const __v8sf *) __P, (__v8sf) _mm256_setzero_ps (), (__mmask8) @@ -2606,7 +2606,7 @@ _mm256_maskz_expandloadu_ps (__mmask8 __U, void const *__P) { static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_mask_expandloadu_epi32 (__m128i __W, __mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_expandloadsi128_mask ((__v4si *) __P, + return (__m128i) __builtin_ia32_expandloadsi128_mask ((const __v4si *) __P, (__v4si) __W, (__mmask8) __U); @@ -2614,7 +2614,7 @@ _mm_mask_expandloadu_epi32 (__m128i __W, __mmask8 __U, void const *__P) { static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_maskz_expandloadu_epi32 (__mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_expandloadsi128_mask ((__v4si *) __P, + return (__m128i) __builtin_ia32_expandloadsi128_mask ((const __v4si *) __P, (__v4si) _mm_setzero_si128 (), (__mmask8) __U); @@ -2623,7 +2623,7 @@ _mm_maskz_expandloadu_epi32 (__mmask8 __U, void const *__P) { static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_mask_expandloadu_epi32 (__m256i __W, __mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_expandloadsi256_mask ((__v8si *) __P, + return (__m256i) __builtin_ia32_expandloadsi256_mask ((const __v8si *) __P, (__v8si) __W, (__mmask8) __U); @@ -2631,7 +2631,7 @@ _mm256_mask_expandloadu_epi32 (__m256i __W, __mmask8 __U, static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskz_expandloadu_epi32 (__mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_expandloadsi256_mask ((__v8si *) __P, + return (__m256i) __builtin_ia32_expandloadsi256_mask ((const __v8si *) __P, (__v8si) _mm256_setzero_si256 (), (__mmask8) @@ -5073,13 +5073,13 @@ _mm256_maskz_mov_epi32 (__mmask8 __U, __m256i __A) static __inline __m128i __DEFAULT_FN_ATTRS128 _mm_load_epi32 (void const *__P) { - return *(__m128i *) __P; + return *(const __m128i *) __P; } static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_mask_load_epi32 (__m128i __W, __mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_movdqa32load128_mask ((__v4si *) __P, + return (__m128i) __builtin_ia32_movdqa32load128_mask ((const __v4si *) __P, (__v4si) __W, (__mmask8) __U); @@ -5088,7 +5088,7 @@ _mm_mask_load_epi32 (__m128i __W, __mmask8 __U, void const *__P) static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_maskz_load_epi32 (__mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_movdqa32load128_mask ((__v4si *) __P, + return (__m128i) __builtin_ia32_movdqa32load128_mask ((const __v4si *) __P, (__v4si) _mm_setzero_si128 (), (__mmask8) @@ -5098,13 +5098,13 @@ _mm_maskz_load_epi32 (__mmask8 __U, void const *__P) static __inline __m256i __DEFAULT_FN_ATTRS256 _mm256_load_epi32 (void const *__P) { - return *(__m256i *) __P; + return *(const __m256i *) __P; } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_mask_load_epi32 (__m256i __W, __mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_movdqa32load256_mask ((__v8si *) __P, + return (__m256i) __builtin_ia32_movdqa32load256_mask ((const __v8si *) __P, (__v8si) __W, (__mmask8) __U); @@ -5113,7 +5113,7 @@ _mm256_mask_load_epi32 (__m256i __W, __mmask8 __U, void const *__P) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskz_load_epi32 (__mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_movdqa32load256_mask ((__v8si *) __P, + return (__m256i) __builtin_ia32_movdqa32load256_mask ((const __v8si *) __P, (__v8si) _mm256_setzero_si256 (), (__mmask8) @@ -5183,13 +5183,13 @@ _mm256_maskz_mov_epi64 (__mmask8 __U, __m256i __A) static __inline __m128i __DEFAULT_FN_ATTRS128 _mm_load_epi64 (void const *__P) { - return *(__m128i *) __P; + return *(const __m128i *) __P; } static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_mask_load_epi64 (__m128i __W, __mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_movdqa64load128_mask ((__v2di *) __P, + return (__m128i) __builtin_ia32_movdqa64load128_mask ((const __v2di *) __P, (__v2di) __W, (__mmask8) __U); @@ -5198,7 +5198,7 @@ _mm_mask_load_epi64 (__m128i __W, __mmask8 __U, void const *__P) static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_maskz_load_epi64 (__mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_movdqa64load128_mask ((__v2di *) __P, + return (__m128i) __builtin_ia32_movdqa64load128_mask ((const __v2di *) __P, (__v2di) _mm_setzero_si128 (), (__mmask8) @@ -5208,13 +5208,13 @@ _mm_maskz_load_epi64 (__mmask8 __U, void const *__P) static __inline __m256i __DEFAULT_FN_ATTRS256 _mm256_load_epi64 (void const *__P) { - return *(__m256i *) __P; + return *(const __m256i *) __P; } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_mask_load_epi64 (__m256i __W, __mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_movdqa64load256_mask ((__v4di *) __P, + return (__m256i) __builtin_ia32_movdqa64load256_mask ((const __v4di *) __P, (__v4di) __W, (__mmask8) __U); @@ -5223,7 +5223,7 @@ _mm256_mask_load_epi64 (__m256i __W, __mmask8 __U, void const *__P) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskz_load_epi64 (__mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_movdqa64load256_mask ((__v4di *) __P, + return (__m256i) __builtin_ia32_movdqa64load256_mask ((const __v4di *) __P, (__v4di) _mm256_setzero_si256 (), (__mmask8) @@ -5430,7 +5430,7 @@ _mm256_maskz_set1_epi64 (__mmask8 __M, long long __A) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_load_pd (__m128d __W, __mmask8 __U, void const *__P) { - return (__m128d) __builtin_ia32_loadapd128_mask ((__v2df *) __P, + return (__m128d) __builtin_ia32_loadapd128_mask ((const __v2df *) __P, (__v2df) __W, (__mmask8) __U); } @@ -5438,7 +5438,7 @@ _mm_mask_load_pd (__m128d __W, __mmask8 __U, void const *__P) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_maskz_load_pd (__mmask8 __U, void const *__P) { - return (__m128d) __builtin_ia32_loadapd128_mask ((__v2df *) __P, + return (__m128d) __builtin_ia32_loadapd128_mask ((const __v2df *) __P, (__v2df) _mm_setzero_pd (), (__mmask8) __U); @@ -5447,7 +5447,7 @@ _mm_maskz_load_pd (__mmask8 __U, void const *__P) static __inline__ __m256d __DEFAULT_FN_ATTRS256 _mm256_mask_load_pd (__m256d __W, __mmask8 __U, void const *__P) { - return (__m256d) __builtin_ia32_loadapd256_mask ((__v4df *) __P, + return (__m256d) __builtin_ia32_loadapd256_mask ((const __v4df *) __P, (__v4df) __W, (__mmask8) __U); } @@ -5455,7 +5455,7 @@ _mm256_mask_load_pd (__m256d __W, __mmask8 __U, void const *__P) static __inline__ __m256d __DEFAULT_FN_ATTRS256 _mm256_maskz_load_pd (__mmask8 __U, void const *__P) { - return (__m256d) __builtin_ia32_loadapd256_mask ((__v4df *) __P, + return (__m256d) __builtin_ia32_loadapd256_mask ((const __v4df *) __P, (__v4df) _mm256_setzero_pd (), (__mmask8) __U); @@ -5464,7 +5464,7 @@ _mm256_maskz_load_pd (__mmask8 __U, void const *__P) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_load_ps (__m128 __W, __mmask8 __U, void const *__P) { - return (__m128) __builtin_ia32_loadaps128_mask ((__v4sf *) __P, + return (__m128) __builtin_ia32_loadaps128_mask ((const __v4sf *) __P, (__v4sf) __W, (__mmask8) __U); } @@ -5472,7 +5472,7 @@ _mm_mask_load_ps (__m128 __W, __mmask8 __U, void const *__P) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_load_ps (__mmask8 __U, void const *__P) { - return (__m128) __builtin_ia32_loadaps128_mask ((__v4sf *) __P, + return (__m128) __builtin_ia32_loadaps128_mask ((const __v4sf *) __P, (__v4sf) _mm_setzero_ps (), (__mmask8) __U); @@ -5481,7 +5481,7 @@ _mm_maskz_load_ps (__mmask8 __U, void const *__P) static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_mask_load_ps (__m256 __W, __mmask8 __U, void const *__P) { - return (__m256) __builtin_ia32_loadaps256_mask ((__v8sf *) __P, + return (__m256) __builtin_ia32_loadaps256_mask ((const __v8sf *) __P, (__v8sf) __W, (__mmask8) __U); } @@ -5489,7 +5489,7 @@ _mm256_mask_load_ps (__m256 __W, __mmask8 __U, void const *__P) static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_maskz_load_ps (__mmask8 __U, void const *__P) { - return (__m256) __builtin_ia32_loadaps256_mask ((__v8sf *) __P, + return (__m256) __builtin_ia32_loadaps256_mask ((const __v8sf *) __P, (__v8sf) _mm256_setzero_ps (), (__mmask8) __U); @@ -5501,13 +5501,13 @@ _mm_loadu_epi64 (void const *__P) struct __loadu_epi64 { __m128i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi64*)__P)->__v; + return ((const struct __loadu_epi64*)__P)->__v; } static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_mask_loadu_epi64 (__m128i __W, __mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_loaddqudi128_mask ((__v2di *) __P, + return (__m128i) __builtin_ia32_loaddqudi128_mask ((const __v2di *) __P, (__v2di) __W, (__mmask8) __U); } @@ -5515,7 +5515,7 @@ _mm_mask_loadu_epi64 (__m128i __W, __mmask8 __U, void const *__P) static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_maskz_loadu_epi64 (__mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_loaddqudi128_mask ((__v2di *) __P, + return (__m128i) __builtin_ia32_loaddqudi128_mask ((const __v2di *) __P, (__v2di) _mm_setzero_si128 (), (__mmask8) __U); @@ -5527,13 +5527,13 @@ _mm256_loadu_epi64 (void const *__P) struct __loadu_epi64 { __m256i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi64*)__P)->__v; + return ((const struct __loadu_epi64*)__P)->__v; } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_mask_loadu_epi64 (__m256i __W, __mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_loaddqudi256_mask ((__v4di *) __P, + return (__m256i) __builtin_ia32_loaddqudi256_mask ((const __v4di *) __P, (__v4di) __W, (__mmask8) __U); } @@ -5541,7 +5541,7 @@ _mm256_mask_loadu_epi64 (__m256i __W, __mmask8 __U, void const *__P) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskz_loadu_epi64 (__mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_loaddqudi256_mask ((__v4di *) __P, + return (__m256i) __builtin_ia32_loaddqudi256_mask ((const __v4di *) __P, (__v4di) _mm256_setzero_si256 (), (__mmask8) __U); @@ -5553,13 +5553,13 @@ _mm_loadu_epi32 (void const *__P) struct __loadu_epi32 { __m128i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi32*)__P)->__v; + return ((const struct __loadu_epi32*)__P)->__v; } static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_mask_loadu_epi32 (__m128i __W, __mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_loaddqusi128_mask ((__v4si *) __P, + return (__m128i) __builtin_ia32_loaddqusi128_mask ((const __v4si *) __P, (__v4si) __W, (__mmask8) __U); } @@ -5567,7 +5567,7 @@ _mm_mask_loadu_epi32 (__m128i __W, __mmask8 __U, void const *__P) static __inline__ __m128i __DEFAULT_FN_ATTRS128 _mm_maskz_loadu_epi32 (__mmask8 __U, void const *__P) { - return (__m128i) __builtin_ia32_loaddqusi128_mask ((__v4si *) __P, + return (__m128i) __builtin_ia32_loaddqusi128_mask ((const __v4si *) __P, (__v4si) _mm_setzero_si128 (), (__mmask8) __U); @@ -5579,13 +5579,13 @@ _mm256_loadu_epi32 (void const *__P) struct __loadu_epi32 { __m256i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_epi32*)__P)->__v; + return ((const struct __loadu_epi32*)__P)->__v; } static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_mask_loadu_epi32 (__m256i __W, __mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_loaddqusi256_mask ((__v8si *) __P, + return (__m256i) __builtin_ia32_loaddqusi256_mask ((const __v8si *) __P, (__v8si) __W, (__mmask8) __U); } @@ -5593,7 +5593,7 @@ _mm256_mask_loadu_epi32 (__m256i __W, __mmask8 __U, void const *__P) static __inline__ __m256i __DEFAULT_FN_ATTRS256 _mm256_maskz_loadu_epi32 (__mmask8 __U, void const *__P) { - return (__m256i) __builtin_ia32_loaddqusi256_mask ((__v8si *) __P, + return (__m256i) __builtin_ia32_loaddqusi256_mask ((const __v8si *) __P, (__v8si) _mm256_setzero_si256 (), (__mmask8) __U); @@ -5602,7 +5602,7 @@ _mm256_maskz_loadu_epi32 (__mmask8 __U, void const *__P) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_mask_loadu_pd (__m128d __W, __mmask8 __U, void const *__P) { - return (__m128d) __builtin_ia32_loadupd128_mask ((__v2df *) __P, + return (__m128d) __builtin_ia32_loadupd128_mask ((const __v2df *) __P, (__v2df) __W, (__mmask8) __U); } @@ -5610,7 +5610,7 @@ _mm_mask_loadu_pd (__m128d __W, __mmask8 __U, void const *__P) static __inline__ __m128d __DEFAULT_FN_ATTRS128 _mm_maskz_loadu_pd (__mmask8 __U, void const *__P) { - return (__m128d) __builtin_ia32_loadupd128_mask ((__v2df *) __P, + return (__m128d) __builtin_ia32_loadupd128_mask ((const __v2df *) __P, (__v2df) _mm_setzero_pd (), (__mmask8) __U); @@ -5619,7 +5619,7 @@ _mm_maskz_loadu_pd (__mmask8 __U, void const *__P) static __inline__ __m256d __DEFAULT_FN_ATTRS256 _mm256_mask_loadu_pd (__m256d __W, __mmask8 __U, void const *__P) { - return (__m256d) __builtin_ia32_loadupd256_mask ((__v4df *) __P, + return (__m256d) __builtin_ia32_loadupd256_mask ((const __v4df *) __P, (__v4df) __W, (__mmask8) __U); } @@ -5627,7 +5627,7 @@ _mm256_mask_loadu_pd (__m256d __W, __mmask8 __U, void const *__P) static __inline__ __m256d __DEFAULT_FN_ATTRS256 _mm256_maskz_loadu_pd (__mmask8 __U, void const *__P) { - return (__m256d) __builtin_ia32_loadupd256_mask ((__v4df *) __P, + return (__m256d) __builtin_ia32_loadupd256_mask ((const __v4df *) __P, (__v4df) _mm256_setzero_pd (), (__mmask8) __U); @@ -5636,7 +5636,7 @@ _mm256_maskz_loadu_pd (__mmask8 __U, void const *__P) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_mask_loadu_ps (__m128 __W, __mmask8 __U, void const *__P) { - return (__m128) __builtin_ia32_loadups128_mask ((__v4sf *) __P, + return (__m128) __builtin_ia32_loadups128_mask ((const __v4sf *) __P, (__v4sf) __W, (__mmask8) __U); } @@ -5644,7 +5644,7 @@ _mm_mask_loadu_ps (__m128 __W, __mmask8 __U, void const *__P) static __inline__ __m128 __DEFAULT_FN_ATTRS128 _mm_maskz_loadu_ps (__mmask8 __U, void const *__P) { - return (__m128) __builtin_ia32_loadups128_mask ((__v4sf *) __P, + return (__m128) __builtin_ia32_loadups128_mask ((const __v4sf *) __P, (__v4sf) _mm_setzero_ps (), (__mmask8) __U); @@ -5653,7 +5653,7 @@ _mm_maskz_loadu_ps (__mmask8 __U, void const *__P) static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_mask_loadu_ps (__m256 __W, __mmask8 __U, void const *__P) { - return (__m256) __builtin_ia32_loadups256_mask ((__v8sf *) __P, + return (__m256) __builtin_ia32_loadups256_mask ((const __v8sf *) __P, (__v8sf) __W, (__mmask8) __U); } @@ -5661,7 +5661,7 @@ _mm256_mask_loadu_ps (__m256 __W, __mmask8 __U, void const *__P) static __inline__ __m256 __DEFAULT_FN_ATTRS256 _mm256_maskz_loadu_ps (__mmask8 __U, void const *__P) { - return (__m256) __builtin_ia32_loadups256_mask ((__v8sf *) __P, + return (__m256) __builtin_ia32_loadups256_mask ((const __v8sf *) __P, (__v8sf) _mm256_setzero_ps (), (__mmask8) __U); diff --git a/clang/lib/Headers/avxintrin.h b/clang/lib/Headers/avxintrin.h index a01240b9d157..84421bf1b9d5 100644 --- a/clang/lib/Headers/avxintrin.h +++ b/clang/lib/Headers/avxintrin.h @@ -3069,7 +3069,7 @@ _mm256_broadcast_ps(__m128 const *__a) static __inline __m256d __DEFAULT_FN_ATTRS _mm256_load_pd(double const *__p) { - return *(__m256d *)__p; + return *(const __m256d *)__p; } /// Loads 8 single-precision floating point values from a 32-byte aligned @@ -3085,7 +3085,7 @@ _mm256_load_pd(double const *__p) static __inline __m256 __DEFAULT_FN_ATTRS _mm256_load_ps(float const *__p) { - return *(__m256 *)__p; + return *(const __m256 *)__p; } /// Loads 4 double-precision floating point values from an unaligned @@ -3105,7 +3105,7 @@ _mm256_loadu_pd(double const *__p) struct __loadu_pd { __m256d_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_pd*)__p)->__v; + return ((const struct __loadu_pd*)__p)->__v; } /// Loads 8 single-precision floating point values from an unaligned @@ -3125,7 +3125,7 @@ _mm256_loadu_ps(float const *__p) struct __loadu_ps { __m256_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_ps*)__p)->__v; + return ((const struct __loadu_ps*)__p)->__v; } /// Loads 256 bits of integer data from a 32-byte aligned memory @@ -3161,7 +3161,7 @@ _mm256_loadu_si256(__m256i_u const *__p) struct __loadu_si256 { __m256i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_si256*)__p)->__v; + return ((const struct __loadu_si256*)__p)->__v; } /// Loads 256 bits of integer data from an unaligned memory location diff --git a/clang/lib/Headers/emmintrin.h b/clang/lib/Headers/emmintrin.h index c8fefdfc792a..993c688ce818 100644 --- a/clang/lib/Headers/emmintrin.h +++ b/clang/lib/Headers/emmintrin.h @@ -1578,7 +1578,7 @@ _mm_cvtsd_f64(__m128d __a) static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_load_pd(double const *__dp) { - return *(__m128d*)__dp; + return *(const __m128d*)__dp; } /// Loads a double-precision floating-point value from a specified memory @@ -1599,7 +1599,7 @@ _mm_load1_pd(double const *__dp) struct __mm_load1_pd_struct { double __u; } __attribute__((__packed__, __may_alias__)); - double __u = ((struct __mm_load1_pd_struct*)__dp)->__u; + double __u = ((const struct __mm_load1_pd_struct*)__dp)->__u; return __extension__ (__m128d){ __u, __u }; } @@ -1622,7 +1622,7 @@ _mm_load1_pd(double const *__dp) static __inline__ __m128d __DEFAULT_FN_ATTRS _mm_loadr_pd(double const *__dp) { - __m128d __u = *(__m128d*)__dp; + __m128d __u = *(const __m128d*)__dp; return __builtin_shufflevector((__v2df)__u, (__v2df)__u, 1, 0); } @@ -1643,7 +1643,7 @@ _mm_loadu_pd(double const *__dp) struct __loadu_pd { __m128d_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_pd*)__dp)->__v; + return ((const struct __loadu_pd*)__dp)->__v; } /// Loads a 64-bit integer value to the low element of a 128-bit integer @@ -1663,7 +1663,7 @@ _mm_loadu_si64(void const *__a) struct __loadu_si64 { long long __v; } __attribute__((__packed__, __may_alias__)); - long long __u = ((struct __loadu_si64*)__a)->__v; + long long __u = ((const struct __loadu_si64*)__a)->__v; return __extension__ (__m128i)(__v2di){__u, 0LL}; } @@ -1684,7 +1684,7 @@ _mm_loadu_si32(void const *__a) struct __loadu_si32 { int __v; } __attribute__((__packed__, __may_alias__)); - int __u = ((struct __loadu_si32*)__a)->__v; + int __u = ((const struct __loadu_si32*)__a)->__v; return __extension__ (__m128i)(__v4si){__u, 0, 0, 0}; } @@ -1705,7 +1705,7 @@ _mm_loadu_si16(void const *__a) struct __loadu_si16 { short __v; } __attribute__((__packed__, __may_alias__)); - short __u = ((struct __loadu_si16*)__a)->__v; + short __u = ((const struct __loadu_si16*)__a)->__v; return __extension__ (__m128i)(__v8hi){__u, 0, 0, 0, 0, 0, 0, 0}; } @@ -1726,7 +1726,7 @@ _mm_load_sd(double const *__dp) struct __mm_load_sd_struct { double __u; } __attribute__((__packed__, __may_alias__)); - double __u = ((struct __mm_load_sd_struct*)__dp)->__u; + double __u = ((const struct __mm_load_sd_struct*)__dp)->__u; return __extension__ (__m128d){ __u, 0 }; } @@ -1753,7 +1753,7 @@ _mm_loadh_pd(__m128d __a, double const *__dp) struct __mm_loadh_pd_struct { double __u; } __attribute__((__packed__, __may_alias__)); - double __u = ((struct __mm_loadh_pd_struct*)__dp)->__u; + double __u = ((const struct __mm_loadh_pd_struct*)__dp)->__u; return __extension__ (__m128d){ __a[0], __u }; } @@ -1780,7 +1780,7 @@ _mm_loadl_pd(__m128d __a, double const *__dp) struct __mm_loadl_pd_struct { double __u; } __attribute__((__packed__, __may_alias__)); - double __u = ((struct __mm_loadl_pd_struct*)__dp)->__u; + double __u = ((const struct __mm_loadl_pd_struct*)__dp)->__u; return __extension__ (__m128d){ __u, __a[1] }; } @@ -2288,7 +2288,7 @@ _mm_adds_epu16(__m128i __a, __m128i __b) return (__m128i)__builtin_ia32_paddusw128((__v8hi)__a, (__v8hi)__b); } -/// Computes the rounded avarages of corresponding elements of two +/// Computes the rounded averages of corresponding elements of two /// 128-bit unsigned [16 x i8] vectors, saving each result in the /// corresponding element of a 128-bit result vector of [16 x i8]. /// @@ -2308,7 +2308,7 @@ _mm_avg_epu8(__m128i __a, __m128i __b) return (__m128i)__builtin_ia32_pavgb128((__v16qi)__a, (__v16qi)__b); } -/// Computes the rounded avarages of corresponding elements of two +/// Computes the rounded averages of corresponding elements of two /// 128-bit unsigned [8 x i16] vectors, saving each result in the /// corresponding element of a 128-bit result vector of [8 x i16]. /// @@ -3550,7 +3550,7 @@ _mm_loadu_si128(__m128i_u const *__p) struct __loadu_si128 { __m128i_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_si128*)__p)->__v; + return ((const struct __loadu_si128*)__p)->__v; } /// Returns a vector of [2 x i64] where the lower element is taken from @@ -3571,7 +3571,7 @@ _mm_loadl_epi64(__m128i_u const *__p) struct __mm_loadl_epi64_struct { long long __u; } __attribute__((__packed__, __may_alias__)); - return __extension__ (__m128i) { ((struct __mm_loadl_epi64_struct*)__p)->__u, 0}; + return __extension__ (__m128i) { ((const struct __mm_loadl_epi64_struct*)__p)->__u, 0}; } /// Generates a 128-bit vector of [4 x i32] with unspecified content. diff --git a/clang/lib/Headers/immintrin.h b/clang/lib/Headers/immintrin.h index ae900ee85b76..edf8c42ec491 100644 --- a/clang/lib/Headers/immintrin.h +++ b/clang/lib/Headers/immintrin.h @@ -301,7 +301,7 @@ _loadbe_i16(void const * __P) { struct __loadu_i16 { short __v; } __attribute__((__packed__, __may_alias__)); - return __builtin_bswap16(((struct __loadu_i16*)__P)->__v); + return __builtin_bswap16(((const struct __loadu_i16*)__P)->__v); } static __inline__ void __attribute__((__always_inline__, __nodebug__, __target__("movbe"))) @@ -317,7 +317,7 @@ _loadbe_i32(void const * __P) { struct __loadu_i32 { int __v; } __attribute__((__packed__, __may_alias__)); - return __builtin_bswap32(((struct __loadu_i32*)__P)->__v); + return __builtin_bswap32(((const struct __loadu_i32*)__P)->__v); } static __inline__ void __attribute__((__always_inline__, __nodebug__, __target__("movbe"))) @@ -334,7 +334,7 @@ _loadbe_i64(void const * __P) { struct __loadu_i64 { long long __v; } __attribute__((__packed__, __may_alias__)); - return __builtin_bswap64(((struct __loadu_i64*)__P)->__v); + return __builtin_bswap64(((const struct __loadu_i64*)__P)->__v); } static __inline__ void __attribute__((__always_inline__, __nodebug__, __target__("movbe"))) diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h index 9786ba147fca..f85f7a2beb49 100644 --- a/clang/lib/Headers/intrin.h +++ b/clang/lib/Headers/intrin.h @@ -36,6 +36,12 @@ /* Define the default attributes for the functions in this file. */ #define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__)) +#if __x86_64__ +#define __LPTRINT_TYPE__ __int64 +#else +#define __LPTRINT_TYPE__ long +#endif + #ifdef __cplusplus extern "C" { #endif @@ -94,8 +100,7 @@ void __outword(unsigned short, unsigned short); void __outwordstring(unsigned short, unsigned short *, unsigned long); unsigned long __readcr0(void); unsigned long __readcr2(void); -static __inline__ -unsigned long __readcr3(void); +unsigned __LPTRINT_TYPE__ __readcr3(void); unsigned long __readcr4(void); unsigned long __readcr8(void); unsigned int __readdr(unsigned int); @@ -132,7 +137,7 @@ void __vmx_vmptrst(unsigned __int64 *); void __wbinvd(void); void __writecr0(unsigned int); static __inline__ -void __writecr3(unsigned int); +void __writecr3(unsigned __INTPTR_TYPE__); void __writecr4(unsigned int); void __writecr8(unsigned int); void __writedr(unsigned int, unsigned int); @@ -164,7 +169,6 @@ long _InterlockedExchangeAdd_HLEAcquire(long volatile *, long); long _InterlockedExchangeAdd_HLERelease(long volatile *, long); __int64 _InterlockedExchangeAdd64_HLEAcquire(__int64 volatile *, __int64); __int64 _InterlockedExchangeAdd64_HLERelease(__int64 volatile *, __int64); -void __cdecl _invpcid(unsigned int, void *); static __inline__ void __attribute__((__deprecated__("use other intrinsics or C++11 atomics instead"))) _ReadBarrier(void); @@ -565,24 +569,26 @@ __readmsr(unsigned long __register) { __asm__ ("rdmsr" : "=d"(__edx), "=a"(__eax) : "c"(__register)); return (((unsigned __int64)__edx) << 32) | (unsigned __int64)__eax; } +#endif -static __inline__ unsigned long __DEFAULT_FN_ATTRS +static __inline__ unsigned __LPTRINT_TYPE__ __DEFAULT_FN_ATTRS __readcr3(void) { - unsigned long __cr3_val; - __asm__ __volatile__ ("mov %%cr3, %0" : "=q"(__cr3_val) : : "memory"); + unsigned __LPTRINT_TYPE__ __cr3_val; + __asm__ __volatile__ ("mov %%cr3, %0" : "=r"(__cr3_val) : : "memory"); return __cr3_val; } static __inline__ void __DEFAULT_FN_ATTRS -__writecr3(unsigned int __cr3_val) { - __asm__ ("mov %0, %%cr3" : : "q"(__cr3_val) : "memory"); +__writecr3(unsigned __INTPTR_TYPE__ __cr3_val) { + __asm__ ("mov %0, %%cr3" : : "r"(__cr3_val) : "memory"); } -#endif #ifdef __cplusplus } #endif +#undef __LPTRINT_TYPE__ + #undef __DEFAULT_FN_ATTRS #endif /* __INTRIN_H */ diff --git a/clang/lib/Headers/mwaitxintrin.h b/clang/lib/Headers/mwaitxintrin.h index bca395b0e0d1..ed485380af79 100644 --- a/clang/lib/Headers/mwaitxintrin.h +++ b/clang/lib/Headers/mwaitxintrin.h @@ -17,9 +17,9 @@ /* Define the default attributes for the functions in this file. */ #define __DEFAULT_FN_ATTRS __attribute__((__always_inline__, __nodebug__, __target__("mwaitx"))) static __inline__ void __DEFAULT_FN_ATTRS -_mm_monitorx(void const * __p, unsigned __extensions, unsigned __hints) +_mm_monitorx(void * __p, unsigned __extensions, unsigned __hints) { - __builtin_ia32_monitorx((void *)__p, __extensions, __hints); + __builtin_ia32_monitorx(__p, __extensions, __hints); } static __inline__ void __DEFAULT_FN_ATTRS diff --git a/clang/lib/Headers/pmmintrin.h b/clang/lib/Headers/pmmintrin.h index c376f298cc30..a83b2eb6d8e2 100644 --- a/clang/lib/Headers/pmmintrin.h +++ b/clang/lib/Headers/pmmintrin.h @@ -263,7 +263,7 @@ _mm_movedup_pd(__m128d __a) static __inline__ void __DEFAULT_FN_ATTRS _mm_monitor(void const *__p, unsigned __extensions, unsigned __hints) { - __builtin_ia32_monitor((void *)__p, __extensions, __hints); + __builtin_ia32_monitor(__p, __extensions, __hints); } /// Used with the MONITOR instruction to wait while the processor is in diff --git a/clang/lib/Headers/xmmintrin.h b/clang/lib/Headers/xmmintrin.h index 75ff37655bda..0e61eab44aeb 100644 --- a/clang/lib/Headers/xmmintrin.h +++ b/clang/lib/Headers/xmmintrin.h @@ -1627,7 +1627,7 @@ _mm_loadh_pi(__m128 __a, const __m64 *__p) struct __mm_loadh_pi_struct { __mm_loadh_pi_v2f32 __u; } __attribute__((__packed__, __may_alias__)); - __mm_loadh_pi_v2f32 __b = ((struct __mm_loadh_pi_struct*)__p)->__u; + __mm_loadh_pi_v2f32 __b = ((const struct __mm_loadh_pi_struct*)__p)->__u; __m128 __bb = __builtin_shufflevector(__b, __b, 0, 1, 0, 1); return __builtin_shufflevector(__a, __bb, 0, 1, 4, 5); } @@ -1654,7 +1654,7 @@ _mm_loadl_pi(__m128 __a, const __m64 *__p) struct __mm_loadl_pi_struct { __mm_loadl_pi_v2f32 __u; } __attribute__((__packed__, __may_alias__)); - __mm_loadl_pi_v2f32 __b = ((struct __mm_loadl_pi_struct*)__p)->__u; + __mm_loadl_pi_v2f32 __b = ((const struct __mm_loadl_pi_struct*)__p)->__u; __m128 __bb = __builtin_shufflevector(__b, __b, 0, 1, 0, 1); return __builtin_shufflevector(__a, __bb, 4, 5, 2, 3); } @@ -1680,7 +1680,7 @@ _mm_load_ss(const float *__p) struct __mm_load_ss_struct { float __u; } __attribute__((__packed__, __may_alias__)); - float __u = ((struct __mm_load_ss_struct*)__p)->__u; + float __u = ((const struct __mm_load_ss_struct*)__p)->__u; return __extension__ (__m128){ __u, 0, 0, 0 }; } @@ -1702,7 +1702,7 @@ _mm_load1_ps(const float *__p) struct __mm_load1_ps_struct { float __u; } __attribute__((__packed__, __may_alias__)); - float __u = ((struct __mm_load1_ps_struct*)__p)->__u; + float __u = ((const struct __mm_load1_ps_struct*)__p)->__u; return __extension__ (__m128){ __u, __u, __u, __u }; } @@ -1722,7 +1722,7 @@ _mm_load1_ps(const float *__p) static __inline__ __m128 __DEFAULT_FN_ATTRS _mm_load_ps(const float *__p) { - return *(__m128*)__p; + return *(const __m128*)__p; } /// Loads a 128-bit floating-point vector of [4 x float] from an @@ -1742,7 +1742,7 @@ _mm_loadu_ps(const float *__p) struct __loadu_ps { __m128_u __v; } __attribute__((__packed__, __may_alias__)); - return ((struct __loadu_ps*)__p)->__v; + return ((const struct __loadu_ps*)__p)->__v; } /// Loads four packed float values, in reverse order, from an aligned @@ -2100,7 +2100,7 @@ _mm_storer_ps(float *__p, __m128 __a) /// be generated. \n /// _MM_HINT_T2: Move data using the T2 hint. The PREFETCHT2 instruction will /// be generated. -#define _mm_prefetch(a, sel) (__builtin_prefetch((void *)(a), \ +#define _mm_prefetch(a, sel) (__builtin_prefetch((const void *)(a), \ ((sel) >> 2) & 1, (sel) & 0x3)) #endif diff --git a/clang/lib/Index/CommentToXML.cpp b/clang/lib/Index/CommentToXML.cpp index 55923d679fea..ce6f9e2b13bd 100644 --- a/clang/lib/Index/CommentToXML.cpp +++ b/clang/lib/Index/CommentToXML.cpp @@ -297,6 +297,10 @@ void CommentASTToHTMLConverter::visitInlineCommandComment( appendToResultWithHTMLEscaping(Arg0); Result << "</em>"; return; + case InlineCommandComment::RenderAnchor: + assert(C->getNumArgs() == 1); + Result << "<span id=\"" << Arg0 << "\"></span>"; + return; } } @@ -641,6 +645,10 @@ void CommentASTToXMLConverter::visitInlineCommandComment( appendToResultWithXMLEscaping(Arg0); Result << "</emphasized>"; return; + case InlineCommandComment::RenderAnchor: + assert(C->getNumArgs() == 1); + Result << "<anchor id=\"" << Arg0 << "\"></anchor>"; + return; } } diff --git a/clang/lib/Index/IndexDecl.cpp b/clang/lib/Index/IndexDecl.cpp index 5bbbb0d32bf4..c59b1372e399 100644 --- a/clang/lib/Index/IndexDecl.cpp +++ b/clang/lib/Index/IndexDecl.cpp @@ -7,8 +7,9 @@ //===----------------------------------------------------------------------===// #include "IndexingContext.h" -#include "clang/Index/IndexDataConsumer.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclVisitor.h" +#include "clang/Index/IndexDataConsumer.h" using namespace clang; using namespace index; @@ -42,15 +43,6 @@ public: return true; } - /// Returns true if the given method has been defined explicitly by the - /// user. - static bool hasUserDefined(const ObjCMethodDecl *D, - const ObjCImplDecl *Container) { - const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(), - D->isInstanceMethod()); - return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition(); - } - void handleTemplateArgumentLoc(const TemplateArgumentLoc &TALoc, const NamedDecl *Parent, const DeclContext *DC) { @@ -78,6 +70,17 @@ public: } } + /// Returns true if the given method has been defined explicitly by the + /// user. + static bool hasUserDefined(const ObjCMethodDecl *D, + const ObjCImplDecl *Container) { + const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(), + D->isInstanceMethod()); + return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition() && + !MD->isSynthesizedAccessorStub(); + } + + void handleDeclarator(const DeclaratorDecl *D, const NamedDecl *Parent = nullptr, bool isIBType = false) { @@ -534,13 +537,11 @@ public: SymbolRoleSet AccessorMethodRoles = SymbolRoleSet(SymbolRole::Dynamic) | SymbolRoleSet(SymbolRole::Implicit); if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { - if (MD->isPropertyAccessor() && - !hasUserDefined(MD, Container)) + if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { - if (MD->isPropertyAccessor() && - !hasUserDefined(MD, Container)) + if (MD->isPropertyAccessor() && !hasUserDefined(MD, Container)) IndexCtx.handleDecl(MD, Loc, AccessorMethodRoles, {}, Container); } if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { diff --git a/clang/lib/Index/IndexSymbol.cpp b/clang/lib/Index/IndexSymbol.cpp index 5165567ff75e..ae9134bf1182 100644 --- a/clang/lib/Index/IndexSymbol.cpp +++ b/clang/lib/Index/IndexSymbol.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Index/IndexSymbol.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" diff --git a/clang/lib/Index/IndexingAction.cpp b/clang/lib/Index/IndexingAction.cpp index 6d6133e89d86..4f402135672c 100644 --- a/clang/lib/Index/IndexingAction.cpp +++ b/clang/lib/Index/IndexingAction.cpp @@ -151,7 +151,7 @@ static void indexPreprocessorMacros(const Preprocessor &PP, IndexDataConsumer &DataConsumer) { for (const auto &M : PP.macros()) if (MacroDirective *MD = M.second.getLatest()) - DataConsumer.handleMacroOccurence( + DataConsumer.handleMacroOccurrence( M.first, MD->getMacroInfo(), static_cast<unsigned>(index::SymbolRole::Definition), MD->getLocation()); diff --git a/clang/lib/Index/IndexingContext.cpp b/clang/lib/Index/IndexingContext.cpp index e29856007149..a7c37e8528d1 100644 --- a/clang/lib/Index/IndexingContext.cpp +++ b/clang/lib/Index/IndexingContext.cpp @@ -7,12 +7,13 @@ //===----------------------------------------------------------------------===// #include "IndexingContext.h" -#include "clang/Basic/SourceLocation.h" -#include "clang/Index/IndexDataConsumer.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/Index/IndexDataConsumer.h" using namespace clang; using namespace index; @@ -98,9 +99,8 @@ static void reportModuleReferences(const Module *Mod, return; reportModuleReferences(Mod->Parent, IdLocs.drop_back(), ImportD, DataConsumer); - DataConsumer.handleModuleOccurence(ImportD, Mod, - (SymbolRoleSet)SymbolRole::Reference, - IdLocs.back()); + DataConsumer.handleModuleOccurrence( + ImportD, Mod, (SymbolRoleSet)SymbolRole::Reference, IdLocs.back()); } bool IndexingContext::importedModule(const ImportDecl *ImportD) { @@ -144,7 +144,7 @@ bool IndexingContext::importedModule(const ImportDecl *ImportD) { if (ImportD->isImplicit()) Roles |= (unsigned)SymbolRole::Implicit; - return DataConsumer.handleModuleOccurence(ImportD, Mod, Roles, Loc); + return DataConsumer.handleModuleOccurrence(ImportD, Mod, Roles, Loc); } bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) { @@ -442,26 +442,26 @@ bool IndexingContext::handleDeclOccurrence(const Decl *D, SourceLocation Loc, } IndexDataConsumer::ASTNodeInfo Node{OrigE, OrigD, Parent, ContainerDC}; - return DataConsumer.handleDeclOccurence(D, Roles, FinalRelations, Loc, Node); + return DataConsumer.handleDeclOccurrence(D, Roles, FinalRelations, Loc, Node); } void IndexingContext::handleMacroDefined(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MI) { SymbolRoleSet Roles = (unsigned)SymbolRole::Definition; - DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc); + DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); } void IndexingContext::handleMacroUndefined(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MI) { SymbolRoleSet Roles = (unsigned)SymbolRole::Undefinition; - DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc); + DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); } void IndexingContext::handleMacroReference(const IdentifierInfo &Name, SourceLocation Loc, const MacroInfo &MI) { SymbolRoleSet Roles = (unsigned)SymbolRole::Reference; - DataConsumer.handleMacroOccurence(&Name, &MI, Roles, Loc); + DataConsumer.handleMacroOccurrence(&Name, &MI, Roles, Loc); } diff --git a/clang/lib/Index/USRGeneration.cpp b/clang/lib/Index/USRGeneration.cpp index f4316fe7d067..394daf94c4b2 100644 --- a/clang/lib/Index/USRGeneration.cpp +++ b/clang/lib/Index/USRGeneration.cpp @@ -8,6 +8,7 @@ #include "clang/Index/USRGeneration.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/Lex/PreprocessingRecord.h" diff --git a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp index f063ed711c44..029bfe1cd600 100644 --- a/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp +++ b/clang/lib/Lex/DependencyDirectivesSourceMinimizer.cpp @@ -763,12 +763,13 @@ bool Minimizer::lexEndif(const char *&First, const char *const End) { if (top() == pp_else) popToken(); - // Strip out "#elif" if they're empty. - while (top() == pp_elif) - popToken(); - - // If "#if" is empty, strip it and skip the "#endif". - if (top() == pp_if || top() == pp_ifdef || top() == pp_ifndef) { + // If "#ifdef" is empty, strip it and skip the "#endif". + // + // FIXME: Once/if Clang starts disallowing __has_include in macro expansions, + // we can skip empty `#if` and `#elif` blocks as well after scanning for a + // literal __has_include in the condition. Even without that rule we could + // drop the tokens if we scan for identifiers in the condition and find none. + if (top() == pp_ifdef || top() == pp_ifndef) { popToken(); skipLine(First, End); return false; diff --git a/clang/lib/Lex/Lexer.cpp b/clang/lib/Lex/Lexer.cpp index 17f5ab1e035d..648bda270578 100644 --- a/clang/lib/Lex/Lexer.cpp +++ b/clang/lib/Lex/Lexer.cpp @@ -1431,6 +1431,8 @@ void Lexer::SetByteOffset(unsigned Offset, bool StartOfLine) { static bool isAllowedIDChar(uint32_t C, const LangOptions &LangOpts) { if (LangOpts.AsmPreprocessor) { return false; + } else if (LangOpts.DollarIdents && '$' == C) { + return true; } else if (LangOpts.CPlusPlus11 || LangOpts.C11) { static const llvm::sys::UnicodeCharSet C11AllowedIDChars( C11AllowedIDCharRanges); @@ -2656,6 +2658,7 @@ void Lexer::ReadToEndOfLine(SmallVectorImpl<char> *Result) { assert(ParsingPreprocessorDirective && ParsingFilename == false && "Must be in a preprocessing directive!"); Token Tmp; + Tmp.startToken(); // CurPtr - Cache BufferPtr in an automatic variable. const char *CurPtr = BufferPtr; diff --git a/clang/lib/Lex/LiteralSupport.cpp b/clang/lib/Lex/LiteralSupport.cpp index 2108408377fb..9a852141c6ee 100644 --- a/clang/lib/Lex/LiteralSupport.cpp +++ b/clang/lib/Lex/LiteralSupport.cpp @@ -1051,7 +1051,11 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) { Str = Buffer; } - return Result.convertFromString(Str, APFloat::rmNearestTiesToEven); + auto StatusOrErr = + Result.convertFromString(Str, APFloat::rmNearestTiesToEven); + assert(StatusOrErr && "Invalid floating point representation"); + return !errorToBool(StatusOrErr.takeError()) ? *StatusOrErr + : APFloat::opInvalidOp; } static inline bool IsExponentPart(char c) { diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index db59629997ee..fe20a3507036 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -229,7 +229,7 @@ const FileEntry *ModuleMap::findHeader( llvm::sys::path::append(FullPathName, RelativePathName); auto *NormalHdrFile = GetFile(FullPathName); - if (M && !NormalHdrFile && Directory->getName().endswith(".framework")) { + if (!NormalHdrFile && Directory->getName().endswith(".framework")) { // The lack of 'framework' keyword in a module declaration it's a simple // mistake we can diagnose when the header exists within the proper // framework style path. diff --git a/clang/lib/Lex/PPDirectives.cpp b/clang/lib/Lex/PPDirectives.cpp index 3b7eaee3c914..e433b2cf1b95 100644 --- a/clang/lib/Lex/PPDirectives.cpp +++ b/clang/lib/Lex/PPDirectives.cpp @@ -2727,7 +2727,9 @@ void Preprocessor::HandleDefineDirective( /*Syntactic=*/LangOpts.MicrosoftExt)) Diag(MI->getDefinitionLoc(), diag::warn_pp_macro_def_mismatch_with_pch) << MacroNameTok.getIdentifierInfo(); - return; + // Issue the diagnostic but allow the change if msvc extensions are enabled + if (!LangOpts.MicrosoftExt) + return; } // Finally, if this identifier already had a macro defined for it, verify that diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index dfbcaedcacff..cf8bb2fbab99 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Attributes.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" @@ -28,6 +29,7 @@ #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PreprocessorLexer.h" +#include "clang/Lex/PreprocessorOptions.h" #include "clang/Lex/Token.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -35,9 +37,9 @@ #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Casting.h" @@ -369,7 +371,11 @@ void Preprocessor::RegisterBuiltinMacros() { Ident__has_extension = RegisterBuiltinMacro(*this, "__has_extension"); Ident__has_builtin = RegisterBuiltinMacro(*this, "__has_builtin"); Ident__has_attribute = RegisterBuiltinMacro(*this, "__has_attribute"); - Ident__has_c_attribute = RegisterBuiltinMacro(*this, "__has_c_attribute"); + if (!LangOpts.CPlusPlus) + Ident__has_c_attribute = RegisterBuiltinMacro(*this, "__has_c_attribute"); + else + Ident__has_c_attribute = nullptr; + Ident__has_declspec = RegisterBuiltinMacro(*this, "__has_declspec_attribute"); Ident__has_include = RegisterBuiltinMacro(*this, "__has_include"); Ident__has_include_next = RegisterBuiltinMacro(*this, "__has_include_next"); @@ -820,18 +826,26 @@ MacroArgs *Preprocessor::ReadMacroCallArgumentList(Token &MacroName, } } else if (Tok.is(tok::l_paren)) { ++NumParens; - } else if (Tok.is(tok::comma) && NumParens == 0 && - !(Tok.getFlags() & Token::IgnoredComma)) { + } else if (Tok.is(tok::comma)) { // In Microsoft-compatibility mode, single commas from nested macro // expansions should not be considered as argument separators. We test - // for this with the IgnoredComma token flag above. - - // Comma ends this argument if there are more fixed arguments expected. - // However, if this is a variadic macro, and this is part of the - // variadic part, then the comma is just an argument token. - if (!isVariadic) break; - if (NumFixedArgsLeft > 1) - break; + // for this with the IgnoredComma token flag. + if (Tok.getFlags() & Token::IgnoredComma) { + // However, in MSVC's preprocessor, subsequent expansions do treat + // these commas as argument separators. This leads to a common + // workaround used in macros that need to work in both MSVC and + // compliant preprocessors. Therefore, the IgnoredComma flag can only + // apply once to any given token. + Tok.clearFlag(Token::IgnoredComma); + } else if (NumParens == 0) { + // Comma ends this argument if there are more fixed arguments + // expected. However, if this is a variadic macro, and this is part of + // the variadic part, then the comma is just an argument token. + if (!isVariadic) + break; + if (NumFixedArgsLeft > 1) + break; + } } else if (Tok.is(tok::comment) && !KeepMacroComments) { // If this is a comment token in the argument list and we're just in // -C mode (not -CC mode), discard the comment. @@ -1437,6 +1451,17 @@ static bool isTargetEnvironment(const TargetInfo &TI, return TI.getTriple().getEnvironment() == Env.getEnvironment(); } +static void remapMacroPath( + SmallString<256> &Path, + const std::map<std::string, std::string, std::greater<std::string>> + &MacroPrefixMap) { + for (const auto &Entry : MacroPrefixMap) + if (Path.startswith(Entry.first)) { + Path = (Twine(Entry.second) + Path.substr(Entry.first.size())).str(); + break; + } +} + /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { @@ -1503,7 +1528,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { } // Escape this filename. Turn '\' -> '\\' '"' -> '\"' - SmallString<128> FN; + SmallString<256> FN; if (PLoc.isValid()) { // __FILE_NAME__ is a Clang-specific extension that expands to the // the last part of __FILE__. @@ -1519,6 +1544,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { FN += PLoc.getFilename(); } Lexer::Stringify(FN); + remapMacroPath(FN, PPOpts->MacroPrefixMap); OS << '"' << FN << '"'; } Tok.setKind(tok::string_literal); diff --git a/clang/lib/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 79953804b5d3..e4636265a72b 100644 --- a/clang/lib/Lex/Pragma.cpp +++ b/clang/lib/Lex/Pragma.cpp @@ -848,8 +848,8 @@ void Preprocessor::HandlePragmaModuleBuild(Token &Tok) { CurLexer->getBuffer().begin() <= End && End <= CurLexer->getBuffer().end() && "module source range not contained within same file buffer"); - TheModuleLoader.loadModuleFromSource(Loc, ModuleName->getName(), - StringRef(Start, End - Start)); + TheModuleLoader.createModuleFromSource(Loc, ModuleName->getName(), + StringRef(Start, End - Start)); } void Preprocessor::HandlePragmaHdrstop(Token &Tok) { diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 82007732a9b1..0e9be3923630 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -25,6 +25,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/Preprocessor.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/FileSystemStatCache.h" #include "clang/Basic/IdentifierTable.h" @@ -53,9 +54,9 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Support/Capacity.h" @@ -112,6 +113,8 @@ Preprocessor::Preprocessor(std::shared_ptr<PreprocessorOptions> PPOpts, // We haven't read anything from the external source. ReadMacrosFromExternalSource = false; + BuiltinInfo = std::make_unique<Builtin::Context>(); + // "Poison" __VA_ARGS__, __VA_OPT__ which can only appear in the expansion of // a macro. They get unpoisoned where it is allowed. (Ident__VA_ARGS__ = getIdentifierInfo("__VA_ARGS__"))->setIsPoisoned(); @@ -202,7 +205,7 @@ void Preprocessor::Initialize(const TargetInfo &Target, this->AuxTarget = AuxTarget; // Initialize information about built-ins. - BuiltinInfo.InitializeTarget(Target, AuxTarget); + BuiltinInfo->InitializeTarget(Target, AuxTarget); HeaderInfo.setTarget(Target); // Populate the identifier table with info about keywords for the current language. diff --git a/clang/lib/Parse/ParseAST.cpp b/clang/lib/Parse/ParseAST.cpp index 3efd893e499c..01510e8caf3b 100644 --- a/clang/lib/Parse/ParseAST.cpp +++ b/clang/lib/Parse/ParseAST.cpp @@ -151,7 +151,7 @@ void clang::ParseAST(Sema &S, bool PrintStats, bool SkipFunctionBodies) { bool HaveLexer = S.getPreprocessor().getCurrentLexer(); if (HaveLexer) { - llvm::TimeTraceScope TimeScope("Frontend", StringRef("")); + llvm::TimeTraceScope TimeScope("Frontend"); P.Initialize(); Parser::DeclGroupPtrTy ADecl; for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF; diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index aa314da8e5b4..f8b5fec43800 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -223,6 +223,7 @@ Parser::LateParsedDeclaration::~LateParsedDeclaration() {} void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {} void Parser::LateParsedDeclaration::ParseLexedMemberInitializers() {} void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {} +void Parser::LateParsedDeclaration::ParseLexedPragmas() {} Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C) : Self(P), Class(C) {} @@ -243,6 +244,10 @@ void Parser::LateParsedClass::ParseLexedMethodDefs() { Self->ParseLexedMethodDefs(*Class); } +void Parser::LateParsedClass::ParseLexedPragmas() { + Self->ParseLexedPragmas(*Class); +} + void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() { Self->ParseLexedMethodDeclaration(*this); } @@ -255,6 +260,10 @@ void Parser::LateParsedMemberInitializer::ParseLexedMemberInitializers() { Self->ParseLexedMemberInitializer(*this); } +void Parser::LateParsedPragma::ParseLexedPragmas() { + Self->ParseLexedPragma(*this); +} + /// ParseLexedMethodDeclarations - We finished parsing the member /// specification of a top (non-nested) C++ class. Now go over the /// stack of method declarations with some parts for which parsing was @@ -651,6 +660,43 @@ void Parser::ParseLexedMemberInitializer(LateParsedMemberInitializer &MI) { ConsumeAnyToken(); } +void Parser::ParseLexedPragmas(ParsingClass &Class) { + bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; + ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, + HasTemplateScope); + TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); + if (HasTemplateScope) { + Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate); + ++CurTemplateDepthTracker; + } + bool HasClassScope = !Class.TopLevelClass; + ParseScope ClassScope(this, Scope::ClassScope | Scope::DeclScope, + HasClassScope); + + for (LateParsedDeclaration *LPD : Class.LateParsedDeclarations) + LPD->ParseLexedPragmas(); +} + +void Parser::ParseLexedPragma(LateParsedPragma &LP) { + PP.EnterToken(Tok, /*IsReinject=*/true); + PP.EnterTokenStream(LP.toks(), /*DisableMacroExpansion=*/true, + /*IsReinject=*/true); + + // Consume the previously pushed token. + ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true); + assert(Tok.isAnnotation() && "Expected annotation token."); + switch (Tok.getKind()) { + case tok::annot_pragma_openmp: { + AccessSpecifier AS = LP.getAccessSpecifier(); + ParsedAttributesWithRange Attrs(AttrFactory); + (void)ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs); + break; + } + default: + llvm_unreachable("Unexpected token."); + } +} + /// ConsumeAndStoreUntil - Consume and store the token at the passed token /// container until the token 'T' is reached (which gets /// consumed/stored too, if ConsumeFinalToken). diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index b248d7582d84..69a3ed9cbad7 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -2014,6 +2014,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, return nullptr; } + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); + // Save late-parsed attributes for now; they need to be parsed in the // appropriate function scope after the function Decl has been constructed. // These will be parsed in ParseFunctionDefinition or ParseLexedAttrList. @@ -2165,6 +2168,12 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, ParseDeclarator(D); if (!D.isInvalidType()) { + // C++2a [dcl.decl]p1 + // init-declarator: + // declarator initializer[opt] + // declarator requires-clause + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); Decl *ThisDecl = ParseDeclarationAfterDeclarator(D); D.complete(ThisDecl); if (ThisDecl) @@ -2197,7 +2206,7 @@ bool Parser::ParseAsmAttributesAfterDeclarator(Declarator &D) { // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; - ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi, StopBeforeMatch); return true; @@ -2349,7 +2358,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) << 0 /* default */; else - Diag(ConsumeToken(), diag::err_default_special_members); + Diag(ConsumeToken(), diag::err_default_special_members) + << getLangOpts().CPlusPlus2a; } else { InitializerScopeRAII InitScope(*this, D, ThisDecl); @@ -3948,9 +3958,14 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, PrevSpec = Tok.getIdentifierInfo()->getNameStart(); isInvalid = true; break; - }; + } LLVM_FALLTHROUGH; case tok::kw_private: + // It's fine (but redundant) to check this for __generic on the + // fallthrough path; we only form the __generic token in OpenCL mode. + if (!getLangOpts().OpenCL) + goto DoneWithDeclSpec; + LLVM_FALLTHROUGH; case tok::kw___private: case tok::kw___global: case tok::kw___local: @@ -5106,6 +5121,13 @@ bool Parser::isDeclarationSpecifier(bool DisambiguatingWithExpression) { return !DisambiguatingWithExpression || !isStartOfObjCClassMessageMissingOpenBracket(); + // placeholder-type-specifier + case tok::annot_template_id: { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + return TemplateId->Kind == TNK_Concept_template && + (NextToken().is(tok::kw_auto) || NextToken().is(tok::kw_decltype)); + } + case tok::kw___declspec: case tok::kw___cdecl: case tok::kw___stdcall: @@ -6026,6 +6048,22 @@ void Parser::ParseDirectDeclarator(Declarator &D) { PrototypeScope.Exit(); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); + } else if (Tok.is(tok::kw_requires) && D.hasGroupingParens()) { + // This declarator is declaring a function, but the requires clause is + // in the wrong place: + // void (f() requires true); + // instead of + // void f() requires true; + // or + // void (f()) requires true; + Diag(Tok, diag::err_requires_clause_inside_parens); + ConsumeToken(); + ExprResult TrailingRequiresClause = Actions.CorrectDelayedTyposInExpr( + ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true)); + if (TrailingRequiresClause.isUsable() && D.isFunctionDeclarator() && + !D.hasTrailingRequiresClause()) + // We're already ill-formed if we got here but we'll accept it anyway. + D.setTrailingRequiresClause(TrailingRequiresClause.get()); } else { break; } @@ -6206,6 +6244,47 @@ void Parser::ParseParenDeclarator(Declarator &D) { PrototypeScope.Exit(); } +void Parser::InitCXXThisScopeForDeclaratorIfRelevant( + const Declarator &D, const DeclSpec &DS, + llvm::Optional<Sema::CXXThisScopeRAII> &ThisScope) { + // C++11 [expr.prim.general]p3: + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq + // and the end of the function-definition, member-declarator, or + // declarator. + // FIXME: currently, "static" case isn't handled correctly. + bool IsCXX11MemberFunction = getLangOpts().CPlusPlus11 && + D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && + (D.getContext() == DeclaratorContext::MemberContext + ? !D.getDeclSpec().isFriendSpecified() + : D.getContext() == DeclaratorContext::FileContext && + D.getCXXScopeSpec().isValid() && + Actions.CurContext->isRecord()); + if (!IsCXX11MemberFunction) + return; + + Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers()); + if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14) + Q.addConst(); + // FIXME: Collect C++ address spaces. + // If there are multiple different address spaces, the source is invalid. + // Carry on using the first addr space for the qualifiers of 'this'. + // The diagnostic will be given later while creating the function + // prototype for the method. + if (getLangOpts().OpenCLCPlusPlus) { + for (ParsedAttr &attr : DS.getAttributes()) { + LangAS ASIdx = attr.asOpenCLLangAS(); + if (ASIdx != LangAS::Default) { + Q.addAddressSpace(ASIdx); + break; + } + } + } + ThisScope.emplace(Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q, + IsCXX11MemberFunction); +} + /// ParseFunctionDeclarator - We are after the identifier and have parsed the /// declarator D up to a paren, which indicates that we are parsing function /// arguments. @@ -6219,7 +6298,8 @@ void Parser::ParseParenDeclarator(Declarator &D) { /// /// For C++, after the parameter-list, it also parses the cv-qualifier-seq[opt], /// (C++11) ref-qualifier[opt], exception-specification[opt], -/// (C++11) attribute-specifier-seq[opt], and (C++11) trailing-return-type[opt]. +/// (C++11) attribute-specifier-seq[opt], (C++11) trailing-return-type[opt] and +/// (C++2a) the trailing requires-clause. /// /// [C++11] exception-specification: /// dynamic-exception-specification @@ -6314,43 +6394,8 @@ void Parser::ParseFunctionDeclarator(Declarator &D, if (ParseRefQualifier(RefQualifierIsLValueRef, RefQualifierLoc)) EndLoc = RefQualifierLoc; - // C++11 [expr.prim.general]p3: - // If a declaration declares a member function or member function - // template of a class X, the expression this is a prvalue of type - // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq - // and the end of the function-definition, member-declarator, or - // declarator. - // FIXME: currently, "static" case isn't handled correctly. - bool IsCXX11MemberFunction = - getLangOpts().CPlusPlus11 && - D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_typedef && - (D.getContext() == DeclaratorContext::MemberContext - ? !D.getDeclSpec().isFriendSpecified() - : D.getContext() == DeclaratorContext::FileContext && - D.getCXXScopeSpec().isValid() && - Actions.CurContext->isRecord()); - - Qualifiers Q = Qualifiers::fromCVRUMask(DS.getTypeQualifiers()); - if (D.getDeclSpec().hasConstexprSpecifier() && !getLangOpts().CPlusPlus14) - Q.addConst(); - // FIXME: Collect C++ address spaces. - // If there are multiple different address spaces, the source is invalid. - // Carry on using the first addr space for the qualifiers of 'this'. - // The diagnostic will be given later while creating the function - // prototype for the method. - if (getLangOpts().OpenCLCPlusPlus) { - for (ParsedAttr &attr : DS.getAttributes()) { - LangAS ASIdx = attr.asOpenCLLangAS(); - if (ASIdx != LangAS::Default) { - Q.addAddressSpace(ASIdx); - break; - } - } - } - - Sema::CXXThisScopeRAII ThisScope( - Actions, dyn_cast<CXXRecordDecl>(Actions.CurContext), Q, - IsCXX11MemberFunction); + llvm::Optional<Sema::CXXThisScopeRAII> ThisScope; + InitCXXThisScopeForDeclaratorIfRelevant(D, DS, ThisScope); // Parse exception-specification[opt]. bool Delayed = D.isFirstDeclarationOfMember() && @@ -6565,6 +6610,19 @@ void Parser::ParseParameterDeclarationClause( ParsedAttributes &FirstArgAttrs, SmallVectorImpl<DeclaratorChunk::ParamInfo> &ParamInfo, SourceLocation &EllipsisLoc) { + + // Avoid exceeding the maximum function scope depth. + // See https://bugs.llvm.org/show_bug.cgi?id=19607 + // Note Sema::ActOnParamDeclarator calls ParmVarDecl::setScopeInfo with + // getFunctionPrototypeDepth() - 1. + if (getCurScope()->getFunctionPrototypeDepth() - 1 > + ParmVarDecl::getMaxFunctionScopeDepth()) { + Diag(Tok.getLocation(), diag::err_function_scope_depth_exceeded) + << ParmVarDecl::getMaxFunctionScopeDepth(); + cutOffParsing(); + return; + } + do { // FIXME: Issue a diagnostic if we parsed an attribute-specifier-seq // before deciding this was a parameter-declaration-clause. @@ -6605,6 +6663,17 @@ void Parser::ParseParameterDeclarationClause( // Parse GNU attributes, if present. MaybeParseGNUAttributes(ParmDeclarator); + if (Tok.is(tok::kw_requires)) { + // User tried to define a requires clause in a parameter declaration, + // which is surely not a function declaration. + // void f(int (*g)(int, int) requires true); + Diag(Tok, + diag::err_requires_clause_on_declarator_not_declaring_a_function); + ConsumeToken(); + Actions.CorrectDelayedTyposInExpr( + ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true)); + } + // Remember this parsed parameter in ParamInfo. IdentifierInfo *ParmII = ParmDeclarator.getIdentifier(); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index b98ce3e66292..081d4d8b1209 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -600,7 +600,10 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context, if (ParseOptionalCXXScopeSpecifier(D.SS, nullptr, /*EnteringContext=*/false, /*MayBePseudoDtor=*/nullptr, /*IsTypename=*/false, - /*LastII=*/&LastII)) + /*LastII=*/&LastII, + /*OnlyNamespace=*/false, + /*InUsingDeclaration=*/true)) + return true; if (D.SS.isInvalid()) return true; @@ -2298,6 +2301,7 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( LateParsedAttrList &LateParsedAttrs) { // member-declarator: // declarator pure-specifier[opt] + // declarator requires-clause // declarator brace-or-equal-initializer[opt] // identifier[opt] ':' constant-expression if (Tok.isNot(tok::colon)) @@ -2311,6 +2315,8 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( BitfieldSize = ParseConstantExpression(); if (BitfieldSize.isInvalid()) SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); + } else if (Tok.is(tok::kw_requires)) { + ParseTrailingRequiresClause(DeclaratorInfo); } else { ParseOptionalCXX11VirtSpecifierSeq( VS, getCurrentClass().IsInterface, @@ -2322,7 +2328,7 @@ bool Parser::ParseCXXMemberDeclaratorBeforeInitializer( // If a simple-asm-expr is present, parse it. if (Tok.is(tok::kw_asm)) { SourceLocation Loc; - ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc)); if (AsmLabel.isInvalid()) SkipUntil(tok::comma, StopAtSemi | StopBeforeMatch); @@ -2433,6 +2439,7 @@ void Parser::MaybeParseAndDiagnoseDeclSpecAfterCXX11VirtSpecifierSeq( /// /// member-declarator: /// declarator virt-specifier-seq[opt] pure-specifier[opt] +/// [C++2a] declarator requires-clause /// declarator constant-initializer[opt] /// [C++11] declarator brace-or-equal-initializer[opt] /// identifier[opt] ':' constant-expression @@ -2666,6 +2673,7 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SmallVector<Decl *, 8> DeclsInGroup; ExprResult BitfieldSize; + ExprResult TrailingRequiresClause; bool ExpectSemi = true; // Parse the first declarator. @@ -2978,7 +2986,8 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, Diag(Tok, diag::err_default_delete_in_multiple_declaration) << 0 /* default */; else - Diag(ConsumeToken(), diag::err_default_special_members); + Diag(ConsumeToken(), diag::err_default_special_members) + << getLangOpts().CPlusPlus2a; return ExprError(); } } @@ -3132,8 +3141,8 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( } case tok::annot_pragma_openmp: - return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, AccessAttrs, TagType, - TagDecl); + return ParseOpenMPDeclarativeDirectiveWithExtDecl( + AS, AccessAttrs, /*Delayed=*/true, TagType, TagDecl); default: if (tok::isPragmaAnnotation(Tok.getKind())) { @@ -3351,6 +3360,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // declarations and the lexed inline method definitions, along with any // delayed attributes. SourceLocation SavedPrevTokLocation = PrevTokLocation; + ParseLexedPragmas(getCurrentClass()); ParseLexedAttributes(getCurrentClass()); ParseLexedMethodDeclarations(getCurrentClass()); @@ -3363,7 +3373,7 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, // We've finished parsing everything, including default argument // initializers. - Actions.ActOnFinishCXXNonNestedClass(TagDecl); + Actions.ActOnFinishCXXNonNestedClass(); } if (TagDecl) @@ -3788,6 +3798,62 @@ TypeResult Parser::ParseTrailingReturnType(SourceRange &Range, : DeclaratorContext::TrailingReturnContext); } +/// Parse a requires-clause as part of a function declaration. +void Parser::ParseTrailingRequiresClause(Declarator &D) { + assert(Tok.is(tok::kw_requires) && "expected requires"); + + SourceLocation RequiresKWLoc = ConsumeToken(); + + ExprResult TrailingRequiresClause; + ParseScope ParamScope(this, + Scope::DeclScope | + Scope::FunctionDeclarationScope | + Scope::FunctionPrototypeScope); + + Actions.ActOnStartTrailingRequiresClause(getCurScope(), D); + + llvm::Optional<Sema::CXXThisScopeRAII> ThisScope; + InitCXXThisScopeForDeclaratorIfRelevant(D, D.getDeclSpec(), ThisScope); + + TrailingRequiresClause = + ParseConstraintLogicalOrExpression(/*IsTrailingRequiresClause=*/true); + + TrailingRequiresClause = + Actions.ActOnFinishTrailingRequiresClause(TrailingRequiresClause); + + if (!D.isDeclarationOfFunction()) { + Diag(RequiresKWLoc, + diag::err_requires_clause_on_declarator_not_declaring_a_function); + return; + } + + if (TrailingRequiresClause.isInvalid()) + SkipUntil({tok::l_brace, tok::arrow, tok::kw_try, tok::comma, tok::colon}, + StopAtSemi | StopBeforeMatch); + else + D.setTrailingRequiresClause(TrailingRequiresClause.get()); + + // Did the user swap the trailing return type and requires clause? + if (D.isFunctionDeclarator() && Tok.is(tok::arrow) && + D.getDeclSpec().getTypeSpecType() == TST_auto) { + SourceLocation ArrowLoc = Tok.getLocation(); + SourceRange Range; + TypeResult TrailingReturnType = + ParseTrailingReturnType(Range, /*MayBeFollowedByDirectInit=*/false); + + if (!TrailingReturnType.isInvalid()) { + Diag(ArrowLoc, + diag::err_requires_clause_must_appear_after_trailing_return) + << Range; + auto &FunctionChunk = D.getFunctionTypeInfo(); + FunctionChunk.HasTrailingReturnType = TrailingReturnType.isUsable(); + FunctionChunk.TrailingReturnType = TrailingReturnType.get(); + } else + SkipUntil({tok::equal, tok::l_brace, tok::arrow, tok::kw_try, tok::comma}, + StopAtSemi | StopBeforeMatch); + } +} + /// We have just started parsing the definition of a new class, /// so push that class onto our stack of classes that is currently /// being parsed. diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index b74a95a3cd4b..1442df046bb9 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -22,6 +22,7 @@ #include "clang/Parse/Parser.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ExprCXX.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/DeclSpec.h" @@ -145,7 +146,7 @@ Parser::ParseExpressionWithLeadingExtension(SourceLocation ExtLoc) { // Silence extension warnings in the sub-expression ExtensionRAIIObject O(Diags); - LHS = ParseCastExpression(false); + LHS = ParseCastExpression(AnyCastExpr); } if (!LHS.isInvalid()) @@ -169,7 +170,7 @@ ExprResult Parser::ParseAssignmentExpression(TypeCastState isTypeCast) { if (Tok.is(tok::kw_co_yield)) return ParseCoyieldExpression(); - ExprResult LHS = ParseCastExpression(/*isUnaryExpression=*/false, + ExprResult LHS = ParseCastExpression(AnyCastExpr, /*isAddressOfOperand=*/false, isTypeCast); return ParseRHSOfBinaryExpression(LHS, prec::Assignment); @@ -202,7 +203,7 @@ Parser::ParseConstantExpressionInExprEvalContext(TypeCastState isTypeCast) { Sema::ExpressionEvaluationContext::ConstantEvaluated && "Call this function only if your ExpressionEvaluationContext is " "already ConstantEvaluated"); - ExprResult LHS(ParseCastExpression(false, false, isTypeCast)); + ExprResult LHS(ParseCastExpression(AnyCastExpr, false, isTypeCast)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); return Actions.ActOnConstantExpression(Res); } @@ -220,7 +221,7 @@ ExprResult Parser::ParseConstantExpression(TypeCastState isTypeCast) { ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); - ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); + ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); return Actions.ActOnCaseExpr(CaseLoc, Res); } @@ -234,13 +235,141 @@ ExprResult Parser::ParseCaseExpression(SourceLocation CaseLoc) { ExprResult Parser::ParseConstraintExpression() { EnterExpressionEvaluationContext ConstantEvaluated( Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); - ExprResult LHS(ParseCastExpression(/*isUnaryExpression=*/false)); + ExprResult LHS(ParseCastExpression(AnyCastExpr)); ExprResult Res(ParseRHSOfBinaryExpression(LHS, prec::LogicalOr)); - if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) + if (Res.isUsable() && !Actions.CheckConstraintExpression(Res.get())) { + Actions.CorrectDelayedTyposInExpr(Res); return ExprError(); + } return Res; } +/// \brief Parse a constraint-logical-and-expression. +/// +/// \verbatim +/// C++2a[temp.constr.decl]p1 +/// constraint-logical-and-expression: +/// primary-expression +/// constraint-logical-and-expression '&&' primary-expression +/// +/// \endverbatim +ExprResult +Parser::ParseConstraintLogicalAndExpression(bool IsTrailingRequiresClause) { + EnterExpressionEvaluationContext ConstantEvaluated( + Actions, Sema::ExpressionEvaluationContext::ConstantEvaluated); + bool NotPrimaryExpression = false; + auto ParsePrimary = [&] () { + ExprResult E = ParseCastExpression(PrimaryExprOnly, + /*isAddressOfOperand=*/false, + /*isTypeCast=*/NotTypeCast, + /*isVectorLiteral=*/false, + &NotPrimaryExpression); + if (E.isInvalid()) + return ExprError(); + auto RecoverFromNonPrimary = [&] (ExprResult E, bool Note) { + E = ParsePostfixExpressionSuffix(E); + // Use InclusiveOr, the precedence just after '&&' to not parse the + // next arguments to the logical and. + E = ParseRHSOfBinaryExpression(E, prec::InclusiveOr); + if (!E.isInvalid()) + Diag(E.get()->getExprLoc(), + Note + ? diag::note_unparenthesized_non_primary_expr_in_requires_clause + : diag::err_unparenthesized_non_primary_expr_in_requires_clause) + << FixItHint::CreateInsertion(E.get()->getBeginLoc(), "(") + << FixItHint::CreateInsertion( + PP.getLocForEndOfToken(E.get()->getEndLoc()), ")") + << E.get()->getSourceRange(); + return E; + }; + + if (NotPrimaryExpression || + // Check if the following tokens must be a part of a non-primary + // expression + getBinOpPrecedence(Tok.getKind(), GreaterThanIsOperator, + /*CPlusPlus11=*/true) > prec::LogicalAnd || + // Postfix operators other than '(' (which will be checked for in + // CheckConstraintExpression). + Tok.isOneOf(tok::period, tok::plusplus, tok::minusminus) || + (Tok.is(tok::l_square) && !NextToken().is(tok::l_square))) { + E = RecoverFromNonPrimary(E, /*Note=*/false); + if (E.isInvalid()) + return ExprError(); + NotPrimaryExpression = false; + } + bool PossibleNonPrimary; + bool IsConstraintExpr = + Actions.CheckConstraintExpression(E.get(), Tok, &PossibleNonPrimary, + IsTrailingRequiresClause); + if (!IsConstraintExpr || PossibleNonPrimary) { + // Atomic constraint might be an unparenthesized non-primary expression + // (such as a binary operator), in which case we might get here (e.g. in + // 'requires 0 + 1 && true' we would now be at '+', and parse and ignore + // the rest of the addition expression). Try to parse the rest of it here. + if (PossibleNonPrimary) + E = RecoverFromNonPrimary(E, /*Note=*/!IsConstraintExpr); + Actions.CorrectDelayedTyposInExpr(E); + return ExprError(); + } + return E; + }; + ExprResult LHS = ParsePrimary(); + if (LHS.isInvalid()) + return ExprError(); + while (Tok.is(tok::ampamp)) { + SourceLocation LogicalAndLoc = ConsumeToken(); + ExprResult RHS = ParsePrimary(); + if (RHS.isInvalid()) { + Actions.CorrectDelayedTyposInExpr(LHS); + return ExprError(); + } + ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalAndLoc, + tok::ampamp, LHS.get(), RHS.get()); + if (!Op.isUsable()) { + Actions.CorrectDelayedTyposInExpr(RHS); + Actions.CorrectDelayedTyposInExpr(LHS); + return ExprError(); + } + LHS = Op; + } + return LHS; +} + +/// \brief Parse a constraint-logical-or-expression. +/// +/// \verbatim +/// C++2a[temp.constr.decl]p1 +/// constraint-logical-or-expression: +/// constraint-logical-and-expression +/// constraint-logical-or-expression '||' +/// constraint-logical-and-expression +/// +/// \endverbatim +ExprResult +Parser::ParseConstraintLogicalOrExpression(bool IsTrailingRequiresClause) { + ExprResult LHS(ParseConstraintLogicalAndExpression(IsTrailingRequiresClause)); + if (!LHS.isUsable()) + return ExprError(); + while (Tok.is(tok::pipepipe)) { + SourceLocation LogicalOrLoc = ConsumeToken(); + ExprResult RHS = + ParseConstraintLogicalAndExpression(IsTrailingRequiresClause); + if (!RHS.isUsable()) { + Actions.CorrectDelayedTyposInExpr(LHS); + return ExprError(); + } + ExprResult Op = Actions.ActOnBinOp(getCurScope(), LogicalOrLoc, + tok::pipepipe, LHS.get(), RHS.get()); + if (!Op.isUsable()) { + Actions.CorrectDelayedTyposInExpr(RHS); + Actions.CorrectDelayedTyposInExpr(LHS); + return ExprError(); + } + LHS = Op; + } + return LHS; +} + bool Parser::isNotExpressionStart() { tok::TokenKind K = Tok.getKind(); if (K == tok::l_brace || K == tok::r_brace || @@ -414,7 +543,7 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } else if (getLangOpts().CPlusPlus && NextTokPrec <= prec::Conditional) RHS = ParseAssignmentExpression(); else - RHS = ParseCastExpression(false); + RHS = ParseCastExpression(AnyCastExpr); if (RHS.isInvalid()) { // FIXME: Errors generated by the delayed typo correction should be @@ -519,22 +648,24 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, prec::Level MinPrec) { } } -/// Parse a cast-expression, or, if \p isUnaryExpression is true, -/// parse a unary-expression. +/// Parse a cast-expression, unary-expression or primary-expression, based +/// on \p ExprType. /// /// \p isAddressOfOperand exists because an id-expression that is the /// operand of address-of gets special treatment due to member pointers. /// -ExprResult Parser::ParseCastExpression(bool isUnaryExpression, +ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, TypeCastState isTypeCast, - bool isVectorLiteral) { + bool isVectorLiteral, + bool *NotPrimaryExpression) { bool NotCastExpr; - ExprResult Res = ParseCastExpression(isUnaryExpression, + ExprResult Res = ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, - isVectorLiteral); + isVectorLiteral, + NotPrimaryExpression); if (NotCastExpr) Diag(Tok, diag::err_expected_expression); return Res; @@ -759,11 +890,12 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback { /// '__is_rvalue_expr' /// \endverbatim /// -ExprResult Parser::ParseCastExpression(bool isUnaryExpression, +ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, bool &NotCastExpr, TypeCastState isTypeCast, - bool isVectorLiteral) { + bool isVectorLiteral, + bool *NotPrimaryExpression) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); auto SavedType = PreferredType; @@ -782,11 +914,21 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // ParsePostfixExpressionSuffix. switch (SavedKind) { case tok::l_paren: { - // If this expression is limited to being a unary-expression, the parent can + // If this expression is limited to being a unary-expression, the paren can // not start a cast expression. - ParenParseOption ParenExprType = - (isUnaryExpression && !getLangOpts().CPlusPlus) ? CompoundLiteral - : CastExpr; + ParenParseOption ParenExprType; + switch (ParseKind) { + case CastParseKind::UnaryExprOnly: + if (!getLangOpts().CPlusPlus) + ParenExprType = CompoundLiteral; + LLVM_FALLTHROUGH; + case CastParseKind::AnyCastExpr: + ParenExprType = ParenParseOption::CastExpr; + break; + case CastParseKind::PrimaryExprOnly: + ParenExprType = FoldExpr; + break; + } ParsedType CastTy; SourceLocation RParenLoc; Res = ParseParenExpression(ParenExprType, false/*stopIfCastExr*/, @@ -861,8 +1003,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (TryAnnotateTypeOrScopeToken()) return ExprError(); assert(Tok.isNot(tok::kw_decltype) && Tok.isNot(tok::kw___super)); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand); - + return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, + isVectorLiteral, NotPrimaryExpression); + case tok::identifier: { // primary-expression: identifier // unqualified-id: identifier // constant: enumeration-constant @@ -949,8 +1092,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, = RevertibleTypeTraits.find(II); if (Known != RevertibleTypeTraits.end()) { Tok.setKind(Known->second); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); + return ParseCastExpression(ParseKind, isAddressOfOperand, + NotCastExpr, isTypeCast, + isVectorLiteral, NotPrimaryExpression); } } @@ -961,7 +1105,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::identifier)) - return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + return ParseCastExpression(ParseKind, isAddressOfOperand, + NotCastExpr, isTypeCast, + isVectorLiteral, + NotPrimaryExpression); } } @@ -1076,8 +1223,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, Tok.is(tok::r_paren) ? nullptr : &Replacement); if (!Res.isInvalid() && Res.isUnset()) { UnconsumeToken(Replacement); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); + return ParseCastExpression(ParseKind, isAddressOfOperand, + NotCastExpr, isTypeCast, + /*isVectorLiteral=*/false, + NotPrimaryExpression); } if (!Res.isInvalid() && Tok.is(tok::less)) checkPotentialAngleBracket(Res); @@ -1122,12 +1271,16 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___builtin_FILE: case tok::kw___builtin_FUNCTION: case tok::kw___builtin_LINE: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseBuiltinPrimaryExpression(); case tok::kw___null: return Actions.ActOnGNUNullExpr(ConsumeToken()); case tok::plusplus: // unary-expression: '++' unary-expression [C99] case tok::minusminus: { // unary-expression: '--' unary-expression [C99] + if (NotPrimaryExpression) + *NotPrimaryExpression = true; // C++ [expr.unary] has: // unary-expression: // ++ cast-expression @@ -1140,7 +1293,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // One special case is implicitly handled here: if the preceding tokens are // an ambiguous cast expression, such as "(T())++", then we recurse to // determine whether the '++' is prefix or postfix. - Res = ParseCastExpression(!getLangOpts().CPlusPlus, + Res = ParseCastExpression(getLangOpts().CPlusPlus ? + UnaryExprOnly : AnyCastExpr, /*isAddressOfOperand*/false, NotCastExpr, NotTypeCast); if (NotCastExpr) { @@ -1156,10 +1310,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return Res; } case tok::amp: { // unary-expression: '&' cast-expression + if (NotPrimaryExpression) + *NotPrimaryExpression = true; // Special treatment because of member pointers SourceLocation SavedLoc = ConsumeToken(); PreferredType.enterUnary(Actions, Tok.getLocation(), tok::amp, SavedLoc); - Res = ParseCastExpression(false, true); + Res = ParseCastExpression(AnyCastExpr, true); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return Res; @@ -1172,17 +1328,21 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::exclaim: // unary-expression: '!' cast-expression case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] case tok::kw___imag: { // unary-expression: '__imag' cast-expression [GNU] + if (NotPrimaryExpression) + *NotPrimaryExpression = true; SourceLocation SavedLoc = ConsumeToken(); PreferredType.enterUnary(Actions, Tok.getLocation(), SavedKind, SavedLoc); - Res = ParseCastExpression(false); + Res = ParseCastExpression(AnyCastExpr); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return Res; } case tok::kw_co_await: { // unary-expression: 'co_await' cast-expression + if (NotPrimaryExpression) + *NotPrimaryExpression = true; SourceLocation CoawaitLoc = ConsumeToken(); - Res = ParseCastExpression(false); + Res = ParseCastExpression(AnyCastExpr); if (!Res.isInvalid()) Res = Actions.ActOnCoawaitExpr(getCurScope(), CoawaitLoc, Res.get()); return Res; @@ -1190,9 +1350,11 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] // __extension__ silences extension warnings in the subexpression. + if (NotPrimaryExpression) + *NotPrimaryExpression = true; ExtensionRAIIObject O(Diags); // Use RAII to do this. SourceLocation SavedLoc = ConsumeToken(); - Res = ParseCastExpression(false); + Res = ParseCastExpression(AnyCastExpr); if (!Res.isInvalid()) Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get()); return Res; @@ -1209,8 +1371,12 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression // unary-expression: '__builtin_omp_required_simd_align' '(' type-name ')' case tok::kw___builtin_omp_required_simd_align: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseUnaryExprOrTypeTraitExpression(); case tok::ampamp: { // unary-expression: '&&' identifier + if (NotPrimaryExpression) + *NotPrimaryExpression = true; SourceLocation AmpAmpLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) return ExprError(Diag(Tok, diag::err_expected) << tok::identifier); @@ -1229,15 +1395,23 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw_dynamic_cast: case tok::kw_reinterpret_cast: case tok::kw_static_cast: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Res = ParseCXXCasts(); break; case tok::kw___builtin_bit_cast: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Res = ParseBuiltinBitCast(); break; case tok::kw_typeid: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Res = ParseCXXTypeid(); break; case tok::kw___uuidof: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Res = ParseCXXUuidof(); break; case tok::kw_this: @@ -1302,6 +1476,10 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, return ExprError(); } + // Everything henceforth is a postfix-expression. + if (NotPrimaryExpression) + *NotPrimaryExpression = true; + if (SavedKind == tok::kw_typename) { // postfix-expression: typename-specifier '(' expression-list[opt] ')' // typename-specifier braced-init-list @@ -1338,8 +1516,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::annot_cxxscope)) - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); + return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, + isTypeCast, isVectorLiteral, + NotPrimaryExpression); Token Next = NextToken(); if (Next.is(tok::annot_template_id)) { @@ -1352,8 +1531,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, ParseOptionalCXXScopeSpecifier(SS, nullptr, /*EnteringContext=*/false); AnnotateTemplateIdTokenAsType(); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); + return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, + isTypeCast, isVectorLiteral, + NotPrimaryExpression); } } @@ -1369,8 +1549,9 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // translate it into a type and continue parsing as a cast // expression. AnnotateTemplateIdTokenAsType(); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); + return ParseCastExpression(ParseKind, isAddressOfOperand, + NotCastExpr, isTypeCast, isVectorLiteral, + NotPrimaryExpression); } // Fall through to treat the template-id as an id-expression. @@ -1387,15 +1568,22 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, if (TryAnnotateTypeOrScopeToken()) return ExprError(); if (!Tok.is(tok::coloncolon)) - return ParseCastExpression(isUnaryExpression, isAddressOfOperand); + return ParseCastExpression(ParseKind, isAddressOfOperand, isTypeCast, + isVectorLiteral, NotPrimaryExpression); // ::new -> [C++] new-expression // ::delete -> [C++] delete-expression SourceLocation CCLoc = ConsumeToken(); - if (Tok.is(tok::kw_new)) + if (Tok.is(tok::kw_new)) { + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseCXXNewExpression(true, CCLoc); - if (Tok.is(tok::kw_delete)) + } + if (Tok.is(tok::kw_delete)) { + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseCXXDeleteExpression(true, CCLoc); + } // This is not a type name or scope specifier, it is an invalid expression. Diag(CCLoc, diag::err_expected_expression); @@ -1403,12 +1591,18 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, } case tok::kw_new: // [C++] new-expression + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseCXXNewExpression(false, Tok.getLocation()); case tok::kw_delete: // [C++] delete-expression + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseCXXDeleteExpression(false, Tok.getLocation()); case tok::kw_noexcept: { // [C++0x] 'noexcept' '(' expression ')' + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Diag(Tok, diag::warn_cxx98_compat_noexcept_expr); SourceLocation KeyLoc = ConsumeToken(); BalancedDelimiterTracker T(*this, tok::l_paren); @@ -1437,13 +1631,19 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___array_rank: case tok::kw___array_extent: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseArrayTypeTrait(); case tok::kw___is_lvalue_expr: case tok::kw___is_rvalue_expr: + if (NotPrimaryExpression) + *NotPrimaryExpression = true; return ParseExpressionTrait(); case tok::at: { + if (NotPrimaryExpression) + *NotPrimaryExpression = true; SourceLocation AtLoc = ConsumeToken(); return ParseObjCAtExpression(AtLoc); } @@ -1465,8 +1665,13 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // expression, or we have something that doesn't appear to be a lambda. // If we're in the last case, we fall back to ParseObjCMessageExpression. Res = TryParseLambdaExpression(); - if (!Res.isInvalid() && !Res.get()) + if (!Res.isInvalid() && !Res.get()) { + // We assume Objective-C++ message expressions are not + // primary-expressions. + if (NotPrimaryExpression) + *NotPrimaryExpression = true; Res = ParseObjCMessageExpression(); + } break; } Res = ParseLambdaExpression(); @@ -1486,6 +1691,11 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // are compiling for OpenCL, we need to return an error as this implies // that the address of the function is being taken, which is illegal in CL. + if (ParseKind == PrimaryExprOnly) + // This is strictly a primary-expression - no postfix-expr pieces should be + // parsed. + return Res; + // These can be followed by postfix-expr pieces. PreferredType = SavedType; Res = ParsePostfixExpressionSuffix(Res); @@ -1929,7 +2139,7 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok, return ExprError(); } - Operand = ParseCastExpression(true/*isUnaryExpression*/); + Operand = ParseCastExpression(UnaryExprOnly); } else { // If it starts with a '(', we know that it is either a parenthesized // type-name, or it is a unary-expression that starts with a compound @@ -2474,8 +2684,8 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, RParenLoc = T.getCloseLocation(); PreferredType.enterTypeCast(Tok.getLocation(), Ty.get().get()); - ExprResult SubExpr = ParseCastExpression(/*isUnaryExpression=*/false); - + ExprResult SubExpr = ParseCastExpression(AnyCastExpr); + if (Ty.isInvalid() || SubExpr.isInvalid()) return ExprError(); @@ -2555,7 +2765,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, // Parse the cast-expression that follows it next. // isVectorLiteral = true will make sure we don't parse any // Postfix expression yet - Result = ParseCastExpression(/*isUnaryExpression=*/false, + Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr, /*isAddressOfOperand=*/false, /*isTypeCast=*/IsTypeCast, /*isVectorLiteral=*/true); @@ -2607,7 +2817,7 @@ Parser::ParseParenExpression(ParenParseOption &ExprType, bool stopIfCastExpr, PreferredType.enterTypeCast(Tok.getLocation(), CastTy.get()); // Parse the cast-expression that follows it next. // TODO: For cast expression with CastTy. - Result = ParseCastExpression(/*isUnaryExpression=*/false, + Result = ParseCastExpression(/*isUnaryExpression=*/AnyCastExpr, /*isAddressOfOperand=*/false, /*isTypeCast=*/IsTypeCast); if (!Result.isInvalid()) { diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index a064e4b17587..e685d5ea8a9c 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -142,6 +142,7 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, /// /// \param OnlyNamespace If true, only considers namespaces in lookup. /// +/// /// \returns true if there was an error parsing a scope specifier bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, ParsedType ObjectType, @@ -149,7 +150,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, bool *MayBePseudoDestructor, bool IsTypename, IdentifierInfo **LastII, - bool OnlyNamespace) { + bool OnlyNamespace, + bool InUsingDeclaration) { assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -240,7 +242,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // Code completion for a nested-name-specifier, where the code // completion token follows the '::'. Actions.CodeCompleteQualifiedId(getCurScope(), SS, EnteringContext, - ObjectType.get(), + InUsingDeclaration, ObjectType.get(), SavedType.get(SS.getBeginLoc())); // Include code completion token into the range of the scope otherwise // when we try to annotate the scope tokens the dangling code completion @@ -479,6 +481,7 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // nested-name-specifier: // type-name '<' if (Next.is(tok::less)) { + TemplateTy Template; UnqualifiedId TemplateName; TemplateName.setIdentifier(&II, Tok.getLocation()); @@ -503,7 +506,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // template-id to be translated into a type annotation, // because some clients (e.g., the parsing of class template // specializations) still want to see the original template-id - // token. + // token, and it might not be a type at all (e.g. a concept name in a + // type-constraint). ConsumeToken(); if (AnnotateTemplateIdToken(Template, TNK, SS, SourceLocation(), TemplateName, false)) @@ -1355,6 +1359,13 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( // Parse attribute-specifier[opt]. MaybeParseCXX11Attributes(Attr, &DeclEndLoc); + // Parse OpenCL addr space attribute. + if (Tok.isOneOf(tok::kw___private, tok::kw___global, tok::kw___local, + tok::kw___constant, tok::kw___generic)) { + ParseOpenCLQualifiers(DS.getAttributes()); + ConsumeToken(); + } + SourceLocation FunLocalRangeEnd = DeclEndLoc; // Parse trailing-return-type[opt]. @@ -1367,10 +1378,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DeclEndLoc = Range.getEnd(); } - PrototypeScope.Exit(); - - WarnIfHasCUDATargetAttr(); - SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction( /*HasProto=*/true, @@ -1383,21 +1390,38 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( NoexceptExpr.isUsable() ? NoexceptExpr.get() : nullptr, /*ExceptionSpecTokens*/ nullptr, /*DeclsInPrototype=*/None, LParenLoc, FunLocalRangeEnd, D, - TrailingReturnType), + TrailingReturnType, &DS), std::move(Attr), DeclEndLoc); + + // Parse requires-clause[opt]. + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); + + PrototypeScope.Exit(); + + WarnIfHasCUDATargetAttr(); } else if (Tok.isOneOf(tok::kw_mutable, tok::arrow, tok::kw___attribute, - tok::kw_constexpr, tok::kw_consteval) || + tok::kw_constexpr, tok::kw_consteval, + tok::kw___private, tok::kw___global, tok::kw___local, + tok::kw___constant, tok::kw___generic, + tok::kw_requires) || (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) { // It's common to forget that one needs '()' before 'mutable', an attribute - // specifier, or the result type. Deal with this. + // specifier, the result type, or the requires clause. Deal with this. unsigned TokKind = 0; switch (Tok.getKind()) { case tok::kw_mutable: TokKind = 0; break; case tok::arrow: TokKind = 1; break; case tok::kw___attribute: + case tok::kw___private: + case tok::kw___global: + case tok::kw___local: + case tok::kw___constant: + case tok::kw___generic: case tok::l_square: TokKind = 2; break; case tok::kw_constexpr: TokKind = 3; break; case tok::kw_consteval: TokKind = 4; break; + case tok::kw_requires: TokKind = 5; break; default: llvm_unreachable("Unknown token kind"); } @@ -1429,8 +1453,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DeclEndLoc = Range.getEnd(); } - WarnIfHasCUDATargetAttr(); - SourceLocation NoLoc; D.AddTypeInfo(DeclaratorChunk::getFunction( /*HasProto=*/true, @@ -1451,6 +1473,12 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( /*DeclsInPrototype=*/None, DeclLoc, DeclEndLoc, D, TrailingReturnType), std::move(Attr), DeclEndLoc); + + // Parse the requires-clause, if present. + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(D); + + WarnIfHasCUDATargetAttr(); } // FIXME: Rename BlockScope -> ClosureScope if we decide to continue using @@ -1851,9 +1879,11 @@ Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { CommaLocsTy CommaLocs; auto RunSignatureHelp = [&]() { - QualType PreferredType = Actions.ProduceConstructorSignatureHelp( - getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), - DS.getEndLoc(), Exprs, T.getOpenLocation()); + QualType PreferredType; + if (TypeRep) + PreferredType = Actions.ProduceConstructorSignatureHelp( + getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), + DS.getEndLoc(), Exprs, T.getOpenLocation()); CalledSignatureHelp = true; return PreferredType; }; @@ -2004,7 +2034,7 @@ Sema::ConditionResult Parser::ParseCXXCondition(StmtResult *InitStmt, // simple-asm-expr[opt] if (Tok.is(tok::kw_asm)) { SourceLocation Loc; - ExprResult AsmLabel(ParseSimpleAsm(&Loc)); + ExprResult AsmLabel(ParseSimpleAsm(/*ForAsmLabel*/ true, &Loc)); if (AsmLabel.isInvalid()) { SkipUntil(tok::semi, StopAtSemi); return Sema::ConditionError(); @@ -3027,6 +3057,7 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) { auto RunSignatureHelp = [&]() { ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); + assert(TypeRep && "invalid types should be handled before"); QualType PreferredType = Actions.ProduceConstructorSignatureHelp( getCurScope(), TypeRep.get()->getCanonicalTypeInternal(), DeclaratorInfo.getEndLoc(), ConstructorArgs, ConstructorLParen); @@ -3224,7 +3255,7 @@ Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) { return ExprError(); } - ExprResult Operand(ParseCastExpression(false)); + ExprResult Operand(ParseCastExpression(AnyCastExpr)); if (Operand.isInvalid()) return Operand; @@ -3455,7 +3486,7 @@ Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType, // If it is not a cast-expression, NotCastExpr will be true and no token // will be consumed. ColonProt.restore(); - Result = ParseCastExpression(false/*isUnaryExpression*/, + Result = ParseCastExpression(AnyCastExpr, false/*isAddressofOperand*/, NotCastExpr, // type-id has priority. diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 42d6221a7333..efcef6d3b123 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -822,6 +822,7 @@ static void diagnoseRedundantPropertyNullability(Parser &P, /// property-attribute: /// getter '=' identifier /// setter '=' identifier ':' +/// direct /// readonly /// readwrite /// assign @@ -954,6 +955,8 @@ void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_null_resettable); } else if (II->isStr("class")) { DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_class); + } else if (II->isStr("direct")) { + DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_direct); } else { Diag(AttrName, diag::err_objc_expected_property_attr) << II; SkipUntil(tok::r_paren, StopAtSemi); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 91fe10e667db..1095919baa7d 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -12,6 +12,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/StmtOpenMP.h" +#include "clang/Basic/OpenMPKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -20,6 +21,7 @@ #include "llvm/ADT/UniqueVector.h" using namespace clang; +using namespace llvm::omp; //===----------------------------------------------------------------------===// // OpenMP declarative directives. @@ -27,7 +29,7 @@ using namespace clang; namespace { enum OpenMPDirectiveKindEx { - OMPD_cancellation = OMPD_unknown + 1, + OMPD_cancellation = unsigned(OMPD_unknown) + 1, OMPD_data, OMPD_declare, OMPD_end, @@ -44,7 +46,20 @@ enum OpenMPDirectiveKindEx { OMPD_target_teams_distribute_parallel, OMPD_mapper, OMPD_variant, - OMPD_parallel_master, +}; + +// Helper to unify the enum class OpenMPDirectiveKind with its extension +// the OpenMPDirectiveKindEx enum which allows to use them together as if they +// are unsigned values. +struct OpenMPDirectiveKindExWrapper { + OpenMPDirectiveKindExWrapper(unsigned Value) : Value(Value) {} + OpenMPDirectiveKindExWrapper(OpenMPDirectiveKind DK) : Value(unsigned(DK)) {} + bool operator==(OpenMPDirectiveKind V) const { return Value == unsigned(V); } + bool operator!=(OpenMPDirectiveKind V) const { return Value != unsigned(V); } + bool operator<(OpenMPDirectiveKind V) const { return Value < unsigned(V); } + operator unsigned() const { return Value; } + operator OpenMPDirectiveKind() const { return OpenMPDirectiveKind(Value); } + unsigned Value; }; class DeclDirectiveListParserHelper final { @@ -68,11 +83,11 @@ public: // Map token string to extended OMP token kind that are // OpenMPDirectiveKind + OpenMPDirectiveKindEx. static unsigned getOpenMPDirectiveKindEx(StringRef S) { - auto DKind = getOpenMPDirectiveKind(S); + OpenMPDirectiveKindExWrapper DKind = getOpenMPDirectiveKind(S); if (DKind != OMPD_unknown) return DKind; - return llvm::StringSwitch<unsigned>(S) + return llvm::StringSwitch<OpenMPDirectiveKindExWrapper>(S) .Case("cancellation", OMPD_cancellation) .Case("data", OMPD_data) .Case("declare", OMPD_declare) @@ -87,11 +102,11 @@ static unsigned getOpenMPDirectiveKindEx(StringRef S) { .Default(OMPD_unknown); } -static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) { +static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) { // Array of foldings: F[i][0] F[i][1] ===> F[i][2]. // E.g.: OMPD_for OMPD_simd ===> OMPD_for_simd // TODO: add other combined directives in topological order. - static const unsigned F[][3] = { + static const OpenMPDirectiveKindExWrapper F[][3] = { {OMPD_cancellation, OMPD_point, OMPD_cancellation_point}, {OMPD_declare, OMPD_reduction, OMPD_declare_reduction}, {OMPD_declare, OMPD_mapper, OMPD_declare_mapper}, @@ -140,10 +155,12 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) { {OMPD_master, OMPD_taskloop, OMPD_master_taskloop}, {OMPD_master_taskloop, OMPD_simd, OMPD_master_taskloop_simd}, {OMPD_parallel, OMPD_master, OMPD_parallel_master}, - {OMPD_parallel_master, OMPD_taskloop, OMPD_parallel_master_taskloop}}; + {OMPD_parallel_master, OMPD_taskloop, OMPD_parallel_master_taskloop}, + {OMPD_parallel_master_taskloop, OMPD_simd, + OMPD_parallel_master_taskloop_simd}}; enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 }; Token Tok = P.getCurToken(); - unsigned DKind = + OpenMPDirectiveKindExWrapper DKind = Tok.isAnnotation() ? static_cast<unsigned>(OMPD_unknown) : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok)); @@ -155,7 +172,7 @@ static OpenMPDirectiveKind parseOpenMPDirectiveKind(Parser &P) { continue; Tok = P.getPreprocessor().LookAhead(0); - unsigned SDKind = + OpenMPDirectiveKindExWrapper SDKind = Tok.isAnnotation() ? static_cast<unsigned>(OMPD_unknown) : getOpenMPDirectiveKindEx(P.getPreprocessor().getSpelling(Tok)); @@ -237,8 +254,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); - if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPDirectiveName(OMPD_declare_reduction))) { + if (T.expectAndConsume( + diag::err_expected_lparen_after, + getOpenMPDirectiveName(OMPD_declare_reduction).data())) { SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); return DeclGroupPtrTy(); } @@ -325,9 +343,8 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { Scope::OpenMPDirectiveScope); // Parse <combiner> expression. Actions.ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D); - ExprResult CombinerResult = - Actions.ActOnFinishFullExpr(ParseAssignmentExpression().get(), - D->getLocation(), /*DiscardedValue*/ false); + ExprResult CombinerResult = Actions.ActOnFinishFullExpr( + ParseExpression().get(), D->getLocation(), /*DiscardedValue*/ false); Actions.ActOnOpenMPDeclareReductionCombinerEnd(D, CombinerResult.get()); if (CombinerResult.isInvalid() && Tok.isNot(tok::r_paren) && @@ -366,14 +383,8 @@ Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { // Check if initializer is omp_priv <init_expr> or something else. if (Tok.is(tok::identifier) && Tok.getIdentifierInfo()->isStr("omp_priv")) { - if (Actions.getLangOpts().CPlusPlus) { - InitializerResult = Actions.ActOnFinishFullExpr( - ParseAssignmentExpression().get(), D->getLocation(), - /*DiscardedValue*/ false); - } else { - ConsumeToken(); - ParseOpenMPReductionInitializerForDecl(OmpPrivParm); - } + ConsumeToken(); + ParseOpenMPReductionInitializerForDecl(OmpPrivParm); } else { InitializerResult = Actions.ActOnFinishFullExpr( ParseAssignmentExpression().get(), D->getLocation(), @@ -417,7 +428,8 @@ void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) { return; } - ExprResult Init(ParseInitializer()); + PreferredType.enterVariableInit(Tok.getLocation(), OmpPrivParm); + ExprResult Init = ParseInitializer(); if (Init.isInvalid()) { SkipUntil(tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); @@ -495,7 +507,7 @@ Parser::ParseOpenMPDeclareMapperDirective(AccessSpecifier AS) { // Parse '(' BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPDirectiveName(OMPD_declare_mapper))) { + getOpenMPDirectiveName(OMPD_declare_mapper).data())) { SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); return DeclGroupPtrTy(); } @@ -722,10 +734,12 @@ static bool parseDeclareSimdClauses( CKind == OMPC_linear) { Parser::OpenMPVarListDataTy Data; SmallVectorImpl<Expr *> *Vars = &Uniforms; - if (CKind == OMPC_aligned) + if (CKind == OMPC_aligned) { Vars = &Aligneds; - else if (CKind == OMPC_linear) + } else if (CKind == OMPC_linear) { + Data.ExtraModifier = OMPC_LINEAR_val; Vars = &Linears; + } P.ConsumeToken(); if (P.ParseOpenMPVarList(OMPD_declare_simd, @@ -734,11 +748,15 @@ static bool parseDeclareSimdClauses( if (CKind == OMPC_aligned) { Alignments.append(Aligneds.size() - Alignments.size(), Data.TailExpr); } else if (CKind == OMPC_linear) { - if (P.getActions().CheckOpenMPLinearModifier(Data.LinKind, - Data.DepLinMapLoc)) - Data.LinKind = OMPC_LINEAR_val; + assert(0 <= Data.ExtraModifier && + Data.ExtraModifier <= OMPC_LINEAR_unknown && + "Unexpected linear modifier."); + if (P.getActions().CheckOpenMPLinearModifier( + static_cast<OpenMPLinearClauseKind>(Data.ExtraModifier), + Data.DepLinMapLastLoc)) + Data.ExtraModifier = OMPC_LINEAR_val; LinModifiers.append(Linears.size() - LinModifiers.size(), - Data.LinKind); + Data.ExtraModifier); Steps.append(Linears.size() - Steps.size(), Data.TailExpr); } } else @@ -795,16 +813,11 @@ Parser::ParseOMPDeclareSimdClauses(Parser::DeclGroupPtrTy Ptr, /// Parse optional 'score' '(' <expr> ')' ':'. static ExprResult parseContextScore(Parser &P) { ExprResult ScoreExpr; - SmallString<16> Buffer; + Sema::OMPCtxStringType Buffer; StringRef SelectorName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer); - OMPDeclareVariantAttr::ScoreType ScoreKind = - OMPDeclareVariantAttr::ScoreUnknown; - (void)OMPDeclareVariantAttr::ConvertStrToScoreType(SelectorName, ScoreKind); - if (ScoreKind == OMPDeclareVariantAttr::ScoreUnknown) + if (!SelectorName.equals("score")) return ScoreExpr; - assert(ScoreKind == OMPDeclareVariantAttr::ScoreSpecified && - "Expected \"score\" clause."); (void)P.ConsumeToken(); SourceLocation RLoc; ScoreExpr = P.ParseOpenMPParensExpr(SelectorName, RLoc); @@ -820,11 +833,10 @@ static ExprResult parseContextScore(Parser &P) { /// Parse context selector for 'implementation' selector set: /// 'vendor' '(' [ 'score' '(' <score _expr> ')' ':' ] <vendor> { ',' <vendor> } /// ')' -static void parseImplementationSelector( - Parser &P, SourceLocation Loc, llvm::StringMap<SourceLocation> &UsedCtx, - llvm::function_ref<void(SourceRange, - const Sema::OpenMPDeclareVariantCtsSelectorData &)> - Callback) { +static void +parseImplementationSelector(Parser &P, SourceLocation Loc, + llvm::StringMap<SourceLocation> &UsedCtx, + SmallVectorImpl<Sema::OMPCtxSelectorData> &Data) { const Token &Tok = P.getCurToken(); // Parse inner context selector set name, if any. if (!Tok.is(tok::identifier)) { @@ -836,7 +848,7 @@ static void parseImplementationSelector( ; return; } - SmallString<16> Buffer; + Sema::OMPCtxStringType Buffer; StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer); auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation()); if (!Res.second) { @@ -847,19 +859,16 @@ static void parseImplementationSelector( P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here) << CtxSelectorName; } - OMPDeclareVariantAttr::CtxSelectorType CSKind = - OMPDeclareVariantAttr::CtxUnknown; - (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorType(CtxSelectorName, - CSKind); + OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName); (void)P.ConsumeToken(); switch (CSKind) { - case OMPDeclareVariantAttr::CtxVendor: { + case OMP_CTX_vendor: { // Parse '('. BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end); (void)T.expectAndConsume(diag::err_expected_lparen_after, CtxSelectorName.data()); - const ExprResult Score = parseContextScore(P); - llvm::UniqueVector<llvm::SmallString<16>> Vendors; + ExprResult Score = parseContextScore(P); + llvm::UniqueVector<Sema::OMPCtxStringType> Vendors; do { // Parse <vendor>. StringRef VendorName; @@ -882,18 +891,12 @@ static void parseImplementationSelector( } while (Tok.is(tok::identifier)); // Parse ')'. (void)T.consumeClose(); - if (!Vendors.empty()) { - SmallVector<StringRef, 4> ImplVendors(Vendors.size()); - llvm::copy(Vendors, ImplVendors.begin()); - Sema::OpenMPDeclareVariantCtsSelectorData Data( - OMPDeclareVariantAttr::CtxSetImplementation, CSKind, - llvm::makeMutableArrayRef(ImplVendors.begin(), ImplVendors.size()), - Score); - Callback(SourceRange(Loc, Tok.getLocation()), Data); - } + if (!Vendors.empty()) + Data.emplace_back(OMP_CTX_SET_implementation, CSKind, Score, Vendors); break; } - case OMPDeclareVariantAttr::CtxUnknown: + case OMP_CTX_kind: + case OMP_CTX_unknown: P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) << "implementation"; // Skip until either '}', ')', or end of directive. @@ -904,15 +907,97 @@ static void parseImplementationSelector( } } +/// Parse context selector for 'device' selector set: +/// 'kind' '(' <kind> { ',' <kind> } ')' +static void +parseDeviceSelector(Parser &P, SourceLocation Loc, + llvm::StringMap<SourceLocation> &UsedCtx, + SmallVectorImpl<Sema::OMPCtxSelectorData> &Data) { + const Token &Tok = P.getCurToken(); + // Parse inner context selector set name, if any. + if (!Tok.is(tok::identifier)) { + P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) + << "device"; + // Skip until either '}', ')', or end of directive. + while (!P.SkipUntil(tok::r_brace, tok::r_paren, + tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) + ; + return; + } + Sema::OMPCtxStringType Buffer; + StringRef CtxSelectorName = P.getPreprocessor().getSpelling(Tok, Buffer); + auto Res = UsedCtx.try_emplace(CtxSelectorName, Tok.getLocation()); + if (!Res.second) { + // OpenMP 5.0, 2.3.2 Context Selectors, Restrictions. + // Each trait-selector-name can only be specified once. + P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_ctx_mutiple_use) + << CtxSelectorName << "device"; + P.Diag(Res.first->getValue(), diag::note_omp_declare_variant_ctx_used_here) + << CtxSelectorName; + } + OpenMPContextSelectorKind CSKind = getOpenMPContextSelector(CtxSelectorName); + (void)P.ConsumeToken(); + switch (CSKind) { + case OMP_CTX_kind: { + // Parse '('. + BalancedDelimiterTracker T(P, tok::l_paren, tok::annot_pragma_openmp_end); + (void)T.expectAndConsume(diag::err_expected_lparen_after, + CtxSelectorName.data()); + llvm::UniqueVector<Sema::OMPCtxStringType> Kinds; + do { + // Parse <kind>. + StringRef KindName; + if (Tok.is(tok::identifier)) { + Buffer.clear(); + KindName = P.getPreprocessor().getSpelling(P.getCurToken(), Buffer); + SourceLocation SLoc = P.getCurToken().getLocation(); + (void)P.ConsumeToken(); + if (llvm::StringSwitch<bool>(KindName) + .Case("host", false) + .Case("nohost", false) + .Case("cpu", false) + .Case("gpu", false) + .Case("fpga", false) + .Default(true)) { + P.Diag(SLoc, diag::err_omp_wrong_device_kind_trait) << KindName; + } else { + Kinds.insert(KindName); + } + } else { + P.Diag(Tok.getLocation(), diag::err_omp_declare_variant_item_expected) + << "'host', 'nohost', 'cpu', 'gpu', or 'fpga'" + << "kind" + << "device"; + } + if (!P.TryConsumeToken(tok::comma) && Tok.isNot(tok::r_paren)) { + P.Diag(Tok, diag::err_expected_punc) + << (KindName.empty() ? "kind of device" : KindName); + } + } while (Tok.is(tok::identifier)); + // Parse ')'. + (void)T.consumeClose(); + if (!Kinds.empty()) + Data.emplace_back(OMP_CTX_SET_device, CSKind, ExprResult(), Kinds); + break; + } + case OMP_CTX_vendor: + case OMP_CTX_unknown: + P.Diag(Tok.getLocation(), diag::warn_omp_declare_variant_cs_name_expected) + << "device"; + // Skip until either '}', ')', or end of directive. + while (!P.SkipUntil(tok::r_brace, tok::r_paren, + tok::annot_pragma_openmp_end, Parser::StopBeforeMatch)) + ; + return; + } +} + /// Parses clauses for 'declare variant' directive. /// clause: /// <selector_set_name> '=' '{' <context_selectors> '}' /// [ ',' <selector_set_name> '=' '{' <context_selectors> '}' ] bool Parser::parseOpenMPContextSelectors( - SourceLocation Loc, - llvm::function_ref<void(SourceRange, - const Sema::OpenMPDeclareVariantCtsSelectorData &)> - Callback) { + SourceLocation Loc, SmallVectorImpl<Sema::OMPCtxSelectorData> &Data) { llvm::StringMap<SourceLocation> UsedCtxSets; do { // Parse inner context selector set name. @@ -921,7 +1006,7 @@ bool Parser::parseOpenMPContextSelectors( << getOpenMPClauseName(OMPC_match); return true; } - SmallString<16> Buffer; + Sema::OMPCtxStringType Buffer; StringRef CtxSelectorSetName = PP.getSpelling(Tok, Buffer); auto Res = UsedCtxSets.try_emplace(CtxSelectorSetName, Tok.getLocation()); if (!Res.second) { @@ -949,17 +1034,18 @@ bool Parser::parseOpenMPContextSelectors( tok::annot_pragma_openmp_end); if (TBr.expectAndConsume(diag::err_expected_lbrace_after, "=")) return true; - OMPDeclareVariantAttr::CtxSelectorSetType CSSKind = - OMPDeclareVariantAttr::CtxSetUnknown; - (void)OMPDeclareVariantAttr::ConvertStrToCtxSelectorSetType( - CtxSelectorSetName, CSSKind); + OpenMPContextSelectorSetKind CSSKind = + getOpenMPContextSelectorSet(CtxSelectorSetName); llvm::StringMap<SourceLocation> UsedCtx; do { switch (CSSKind) { - case OMPDeclareVariantAttr::CtxSetImplementation: - parseImplementationSelector(*this, Loc, UsedCtx, Callback); + case OMP_CTX_SET_implementation: + parseImplementationSelector(*this, Loc, UsedCtx, Data); break; - case OMPDeclareVariantAttr::CtxSetUnknown: + case OMP_CTX_SET_device: + parseDeviceSelector(*this, Loc, UsedCtx, Data); + break; + case OMP_CTX_SET_unknown: // Skip until either '}', ')', or end of directive. while (!SkipUntil(tok::r_brace, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch)) @@ -998,9 +1084,16 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, SourceLocation RLoc; // Parse with IsAddressOfOperand set to true to parse methods as DeclRefExprs // instead of MemberExprs. - ExprResult AssociatedFunction = - ParseOpenMPParensExpr(getOpenMPDirectiveName(OMPD_declare_variant), RLoc, - /*IsAddressOfOperand=*/true); + ExprResult AssociatedFunction; + { + // Do not mark function as is used to prevent its emission if this is the + // only place where it is used. + EnterExpressionEvaluationContext Unevaluated( + Actions, Sema::ExpressionEvaluationContext::Unevaluated); + AssociatedFunction = ParseOpenMPParensExpr( + getOpenMPDirectiveName(OMPD_declare_variant), RLoc, + /*IsAddressOfOperand=*/true); + } if (!AssociatedFunction.isUsable()) { if (!Tok.is(tok::annot_pragma_openmp_end)) while (!SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch)) @@ -1039,15 +1132,8 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, } // Parse inner context selectors. - if (!parseOpenMPContextSelectors( - Loc, [this, &DeclVarData]( - SourceRange SR, - const Sema::OpenMPDeclareVariantCtsSelectorData &Data) { - if (DeclVarData.hasValue()) - Actions.ActOnOpenMPDeclareVariantDirective( - DeclVarData.getValue().first, DeclVarData.getValue().second, - SR, Data); - })) { + SmallVector<Sema::OMPCtxSelectorData, 4> Data; + if (!parseOpenMPContextSelectors(Loc, Data)) { // Parse ')'. (void)T.consumeClose(); // Need to check for extra tokens. @@ -1060,6 +1146,10 @@ void Parser::ParseOMPDeclareVariantClauses(Parser::DeclGroupPtrTy Ptr, // Skip last tokens. while (Tok.isNot(tok::annot_pragma_openmp_end)) ConsumeAnyToken(); + if (DeclVarData.hasValue()) + Actions.ActOnOpenMPDeclareVariantDirective( + DeclVarData.getValue().first, DeclVarData.getValue().second, + SourceRange(Loc, Tok.getLocation()), Data); // Skip the last annot_pragma_openmp_end. (void)ConsumeAnnotationToken(); } @@ -1245,13 +1335,45 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind, /// annot_pragma_openmp_end /// Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( - AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, + AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, bool Delayed, DeclSpec::TST TagType, Decl *Tag) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); - SourceLocation Loc = ConsumeAnnotationToken(); - OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this); + SourceLocation Loc; + OpenMPDirectiveKind DKind; + if (Delayed) { + TentativeParsingAction TPA(*this); + Loc = ConsumeAnnotationToken(); + DKind = parseOpenMPDirectiveKind(*this); + if (DKind == OMPD_declare_reduction || DKind == OMPD_declare_mapper) { + // Need to delay parsing until completion of the parent class. + TPA.Revert(); + CachedTokens Toks; + unsigned Cnt = 1; + Toks.push_back(Tok); + while (Cnt && Tok.isNot(tok::eof)) { + (void)ConsumeAnyToken(); + if (Tok.is(tok::annot_pragma_openmp)) + ++Cnt; + else if (Tok.is(tok::annot_pragma_openmp_end)) + --Cnt; + Toks.push_back(Tok); + } + // Skip last annot_pragma_openmp_end. + if (Cnt == 0) + (void)ConsumeAnyToken(); + auto *LP = new LateParsedPragma(this, AS); + LP->takeToks(Toks); + getCurrentClass().LateParsedDeclarations.push_back(LP); + return nullptr; + } + TPA.Commit(); + } else { + Loc = ConsumeAnnotationToken(); + DKind = parseOpenMPDirectiveKind(*this); + } switch (DKind) { case OMPD_threadprivate: { @@ -1403,7 +1525,8 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( DeclGroupPtrTy Ptr; if (Tok.is(tok::annot_pragma_openmp)) { - Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, TagType, Tag); + Ptr = ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, Attrs, Delayed, + TagType, Tag); } else if (Tok.isNot(tok::r_brace) && !isEofOrEom()) { // Here we expect to see some function declaration. if (AS == AS_none) { @@ -1496,6 +1619,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_parallel_sections: + case OMPD_parallel_master: case OMPD_atomic: case OMPD_target: case OMPD_teams: @@ -1511,6 +1635,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_distribute: case OMPD_end_declare_target: case OMPD_target_update: @@ -1562,24 +1687,26 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( /// executable-directive: /// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' | /// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] | -/// 'parallel for' | 'parallel sections' | 'task' | 'taskyield' | -/// 'barrier' | 'taskwait' | 'flush' | 'ordered' | 'atomic' | -/// 'for simd' | 'parallel for simd' | 'target' | 'target data' | -/// 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' | 'master -/// taskloop' | 'master taskloop simd' | 'parallel master taskloop' | -/// 'distribute' | 'target enter data' | 'target exit data' | 'target -/// parallel' | 'target parallel for' | 'target update' | 'distribute -/// parallel for' | 'distribute paralle for simd' | 'distribute simd' | -/// 'target parallel for simd' | 'target simd' | 'teams distribute' | -/// 'teams distribute simd' | 'teams distribute parallel for simd' | -/// 'teams distribute parallel for' | 'target teams' | 'target teams -/// distribute' | 'target teams distribute parallel for' | 'target teams -/// distribute parallel for simd' | 'target teams distribute simd' -/// {clause} annot_pragma_openmp_end +/// 'parallel for' | 'parallel sections' | 'parallel master' | 'task' | +/// 'taskyield' | 'barrier' | 'taskwait' | 'flush' | 'ordered' | +/// 'atomic' | 'for simd' | 'parallel for simd' | 'target' | 'target +/// data' | 'taskgroup' | 'teams' | 'taskloop' | 'taskloop simd' | +/// 'master taskloop' | 'master taskloop simd' | 'parallel master +/// taskloop' | 'parallel master taskloop simd' | 'distribute' | 'target +/// enter data' | 'target exit data' | 'target parallel' | 'target +/// parallel for' | 'target update' | 'distribute parallel for' | +/// 'distribute paralle for simd' | 'distribute simd' | 'target parallel +/// for simd' | 'target simd' | 'teams distribute' | 'teams distribute +/// simd' | 'teams distribute parallel for simd' | 'teams distribute +/// parallel for' | 'target teams' | 'target teams distribute' | 'target +/// teams distribute parallel for' | 'target teams distribute parallel +/// for simd' | 'target teams distribute simd' {clause} +/// annot_pragma_openmp_end /// StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); SmallVector<OMPClause *, 5> Clauses; SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1> @@ -1739,6 +1866,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_parallel_sections: + case OMPD_parallel_master: case OMPD_task: case OMPD_ordered: case OMPD_atomic: @@ -1753,6 +1881,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_distribute: case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: @@ -1890,7 +2019,7 @@ bool Parser::ParseOpenMPSimpleVarList( // Parse '('. BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); if (T.expectAndConsume(diag::err_expected_lparen_after, - getOpenMPDirectiveName(Kind))) + getOpenMPDirectiveName(Kind).data())) return true; bool IsCorrect = true; bool NoIdentIsFound = true; @@ -1963,7 +2092,8 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, bool ErrorFound = false; bool WrongDirective = false; // Check if clause is allowed for the given directive. - if (CKind != OMPC_unknown && !isAllowedClauseForDirective(DKind, CKind)) { + if (CKind != OMPC_unknown && + !isAllowedClauseForDirective(DKind, CKind, getLangOpts().OpenMP)) { Diag(Tok, diag::err_omp_unexpected_clause) << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind); ErrorFound = true; @@ -2042,15 +2172,15 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_defaultmap: // OpenMP [2.7.1, Restrictions, p. 3] // Only one schedule clause can appear on a loop directive. - // OpenMP [2.10.4, Restrictions, p. 106] + // OpenMP 4.5 [2.10.4, Restrictions, p. 106] // At most one defaultmap clause can appear on the directive. - if (!FirstClause) { + if ((getLangOpts().OpenMP < 50 || CKind != OMPC_defaultmap) && + !FirstClause) { Diag(Tok, diag::err_omp_more_one_clause) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0; ErrorFound = true; } LLVM_FALLTHROUGH; - case OMPC_if: Clause = ParseOpenMPSingleExprWithArgClause(CKind, WrongDirective); break; @@ -2102,6 +2232,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, case OMPC_use_device_ptr: case OMPC_is_device_ptr: case OMPC_allocate: + case OMPC_nontemporal: Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective); break; case OMPC_device_type: @@ -2133,8 +2264,8 @@ ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName, return ExprError(); SourceLocation ELoc = Tok.getLocation(); - ExprResult LHS(ParseCastExpression( - /*isUnaryExpression=*/false, IsAddressOfOperand, NotTypeCast)); + ExprResult LHS(ParseCastExpression(AnyCastExpr, IsAddressOfOperand, + NotTypeCast)); ExprResult Val(ParseRHSOfBinaryExpression(LHS, prec::Conditional)); Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false); @@ -2334,8 +2465,13 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind, DelimLoc = ConsumeAnyToken(); } else if (Kind == OMPC_defaultmap) { // Get a defaultmap modifier - Arg.push_back(getOpenMPSimpleClauseType( - Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok))); + unsigned Modifier = getOpenMPSimpleClauseType( + Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok)); + // Set defaultmap modifier to unknown if it is either scalar, aggregate, or + // pointer + if (Modifier < OMPC_DEFAULTMAP_MODIFIER_unknown) + Modifier = OMPC_DEFAULTMAP_MODIFIER_unknown; + Arg.push_back(Modifier); KLoc.push_back(Tok.getLocation()); if (Tok.isNot(tok::r_paren) && Tok.isNot(tok::comma) && Tok.isNot(tok::annot_pragma_openmp_end)) @@ -2356,15 +2492,16 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind, assert(Kind == OMPC_if); KLoc.push_back(Tok.getLocation()); TentativeParsingAction TPA(*this); - Arg.push_back(parseOpenMPDirectiveKind(*this)); - if (Arg.back() != OMPD_unknown) { + auto DK = parseOpenMPDirectiveKind(*this); + Arg.push_back(DK); + if (DK != OMPD_unknown) { ConsumeToken(); if (Tok.is(tok::colon) && getLangOpts().OpenMP > 40) { TPA.Commit(); DelimLoc = ConsumeToken(); } else { TPA.Revert(); - Arg.back() = OMPD_unknown; + Arg.back() = unsigned(OMPD_unknown); } } else { TPA.Revert(); @@ -2376,7 +2513,7 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPClauseKind Kind, Kind == OMPC_if; if (NeedAnExpression) { SourceLocation ELoc = Tok.getLocation(); - ExprResult LHS(ParseCastExpression(false, false, NotTypeCast)); + ExprResult LHS(ParseCastExpression(AnyCastExpr, false, NotTypeCast)); Val = ParseRHSOfBinaryExpression(LHS, prec::Conditional); Val = Actions.ActOnFinishFullExpr(Val.get(), ELoc, /*DiscardedValue*/ false); @@ -2541,8 +2678,8 @@ static void parseMapType(Parser &P, Parser::OpenMPVarListDataTy &Data) { P.Diag(Tok, diag::err_omp_map_type_missing); return; } - Data.MapType = isMapType(P); - if (Data.MapType == OMPC_MAP_unknown) + Data.ExtraModifier = isMapType(P); + if (Data.ExtraModifier == OMPC_MAP_unknown) P.Diag(Tok, diag::err_omp_unknown_map_type); P.ConsumeToken(); } @@ -2587,20 +2724,18 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.ReductionOrMapperId = Actions.GetNameFromUnqualifiedId(UnqualifiedReductionId); } else if (Kind == OMPC_depend) { - // Handle dependency type for depend clause. + // Handle dependency type for depend clause. ColonProtectionRAIIObject ColonRAII(*this); - Data.DepKind = - static_cast<OpenMPDependClauseKind>(getOpenMPSimpleClauseType( - Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : "")); - Data.DepLinMapLoc = Tok.getLocation(); - - if (Data.DepKind == OMPC_DEPEND_unknown) { + Data.ExtraModifier = getOpenMPSimpleClauseType( + Kind, Tok.is(tok::identifier) ? PP.getSpelling(Tok) : ""); + Data.DepLinMapLastLoc = Tok.getLocation(); + if (Data.ExtraModifier == OMPC_DEPEND_unknown) { SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, StopBeforeMatch); } else { ConsumeToken(); // Special processing for depend(source) clause. - if (DKind == OMPD_ordered && Data.DepKind == OMPC_DEPEND_source) { + if (DKind == OMPD_ordered && Data.ExtraModifier == OMPC_DEPEND_source) { // Parse ')'. T.consumeClose(); return false; @@ -2615,13 +2750,32 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, } } else if (Kind == OMPC_linear) { // Try to parse modifier if any. + Data.ExtraModifier = OMPC_LINEAR_val; if (Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::l_paren)) { - Data.LinKind = static_cast<OpenMPLinearClauseKind>( - getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok))); - Data.DepLinMapLoc = ConsumeToken(); + Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + Data.DepLinMapLastLoc = ConsumeToken(); LinearT.consumeOpen(); NeedRParenForLinear = true; } + } else if (Kind == OMPC_lastprivate) { + // Try to parse modifier if any. + Data.ExtraModifier = OMPC_LASTPRIVATE_unknown; + // Conditional modifier allowed only in OpenMP 5.0 and not supported in + // distribute and taskloop based directives. + if ((getLangOpts().OpenMP >= 50 && !isOpenMPDistributeDirective(DKind) && + !isOpenMPTaskLoopDirective(DKind)) && + Tok.is(tok::identifier) && PP.LookAhead(0).is(tok::colon)) { + Data.ExtraModifier = getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok)); + Data.DepLinMapLastLoc = Tok.getLocation(); + if (Data.ExtraModifier == OMPC_LASTPRIVATE_unknown) { + SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } else { + ConsumeToken(); + } + assert(Tok.is(tok::colon) && "Expected colon."); + Data.ColonLoc = ConsumeToken(); + } } else if (Kind == OMPC_map) { // Handle map type for map clause. ColonProtectionRAIIObject ColonRAII(*this); @@ -2629,7 +2783,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, // The first identifier may be a list item, a map-type or a // map-type-modifier. The map-type can also be delete which has the same // spelling of the C++ delete keyword. - Data.DepLinMapLoc = Tok.getLocation(); + Data.ExtraModifier = OMPC_MAP_unknown; + Data.DepLinMapLastLoc = Tok.getLocation(); // Check for presence of a colon in the map clause. TentativeParsingAction TPA(*this); @@ -2649,8 +2804,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, else SkipUntil(tok::colon, tok::annot_pragma_openmp_end, StopBeforeMatch); } - if (Data.MapType == OMPC_MAP_unknown) { - Data.MapType = OMPC_MAP_tofrom; + if (Data.ExtraModifier == OMPC_MAP_unknown) { + Data.ExtraModifier = OMPC_MAP_tofrom; Data.IsMapTypeImplicit = true; } @@ -2716,8 +2871,8 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, (Kind != OMPC_reduction && Kind != OMPC_task_reduction && Kind != OMPC_in_reduction && Kind != OMPC_depend && Kind != OMPC_map) || (Kind == OMPC_reduction && !InvalidReductionId) || - (Kind == OMPC_map && Data.MapType != OMPC_MAP_unknown) || - (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown); + (Kind == OMPC_map && Data.ExtraModifier != OMPC_MAP_unknown) || + (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown); const bool MayHaveTail = (Kind == OMPC_linear || Kind == OMPC_aligned); while (IsComma || (Tok.isNot(tok::r_paren) && Tok.isNot(tok::colon) && Tok.isNot(tok::annot_pragma_openmp_end))) { @@ -2767,7 +2922,7 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind DKind, Data.RLoc = Tok.getLocation(); if (!T.consumeClose()) Data.RLoc = T.getCloseLocation(); - return (Kind == OMPC_depend && Data.DepKind != OMPC_DEPEND_unknown && + return (Kind == OMPC_depend && Data.ExtraModifier != OMPC_DEPEND_unknown && Vars.empty()) || (Kind != OMPC_depend && Kind != OMPC_map && Vars.empty()) || (MustHaveTail && !Data.TailExpr) || InvalidReductionId || @@ -2837,8 +2992,8 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind, OMPVarListLocTy Locs(Loc, LOpen, Data.RLoc); return Actions.ActOnOpenMPVarListClause( Kind, Vars, Data.TailExpr, Locs, Data.ColonLoc, - Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId, Data.DepKind, - Data.LinKind, Data.MapTypeModifiers, Data.MapTypeModifiersLoc, - Data.MapType, Data.IsMapTypeImplicit, Data.DepLinMapLoc); + Data.ReductionOrMapperIdScopeSpec, Data.ReductionOrMapperId, + Data.ExtraModifier, Data.MapTypeModifiers, Data.MapTypeModifiersLoc, + Data.IsMapTypeImplicit, Data.DepLinMapLastLoc); } diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index cdbf697cf7f1..df411e1928d6 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -734,7 +734,7 @@ void Parser::HandlePragmaMSVtorDisp() { uintptr_t Value = reinterpret_cast<uintptr_t>(Tok.getAnnotationValue()); Sema::PragmaMsStackAction Action = static_cast<Sema::PragmaMsStackAction>((Value >> 16) & 0xFFFF); - MSVtorDispAttr::Mode Mode = MSVtorDispAttr::Mode(Value & 0xFFFF); + MSVtorDispMode Mode = MSVtorDispMode(Value & 0xFFFF); SourceLocation PragmaLoc = ConsumeAnnotationToken(); Actions.ActOnPragmaMSVtorDisp(Action, PragmaLoc, Mode); } diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index 727ab75adae8..0339328ca513 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -1191,6 +1191,99 @@ bool Parser::ParseParenExprOrCondition(StmtResult *InitStmt, return false; } +namespace { + +enum MisleadingStatementKind { MSK_if, MSK_else, MSK_for, MSK_while }; + +struct MisleadingIndentationChecker { + Parser &P; + SourceLocation StmtLoc; + SourceLocation PrevLoc; + unsigned NumDirectives; + MisleadingStatementKind Kind; + bool ShouldSkip; + MisleadingIndentationChecker(Parser &P, MisleadingStatementKind K, + SourceLocation SL) + : P(P), StmtLoc(SL), PrevLoc(P.getCurToken().getLocation()), + NumDirectives(P.getPreprocessor().getNumDirectives()), Kind(K), + ShouldSkip(P.getCurToken().is(tok::l_brace)) { + if (!P.MisleadingIndentationElseLoc.isInvalid()) { + StmtLoc = P.MisleadingIndentationElseLoc; + P.MisleadingIndentationElseLoc = SourceLocation(); + } + if (Kind == MSK_else && !ShouldSkip) + P.MisleadingIndentationElseLoc = SL; + } + + /// Compute the column number will aligning tabs on TabStop (-ftabstop), this + /// gives the visual indentation of the SourceLocation. + static unsigned getVisualIndentation(SourceManager &SM, SourceLocation Loc) { + unsigned TabStop = SM.getDiagnostics().getDiagnosticOptions().TabStop; + + unsigned ColNo = SM.getSpellingColumnNumber(Loc); + if (ColNo == 0 || TabStop == 1) + return ColNo; + + std::pair<FileID, unsigned> FIDAndOffset = SM.getDecomposedLoc(Loc); + + bool Invalid; + StringRef BufData = SM.getBufferData(FIDAndOffset.first, &Invalid); + if (Invalid) + return 0; + + const char *EndPos = BufData.data() + FIDAndOffset.second; + // FileOffset are 0-based and Column numbers are 1-based + assert(FIDAndOffset.second + 1 >= ColNo && + "Column number smaller than file offset?"); + + unsigned VisualColumn = 0; // Stored as 0-based column, here. + // Loop from beginning of line up to Loc's file position, counting columns, + // expanding tabs. + for (const char *CurPos = EndPos - (ColNo - 1); CurPos != EndPos; + ++CurPos) { + if (*CurPos == '\t') + // Advance visual column to next tabstop. + VisualColumn += (TabStop - VisualColumn % TabStop); + else + VisualColumn++; + } + return VisualColumn + 1; + } + + void Check() { + Token Tok = P.getCurToken(); + if (P.getActions().getDiagnostics().isIgnored( + diag::warn_misleading_indentation, Tok.getLocation()) || + ShouldSkip || NumDirectives != P.getPreprocessor().getNumDirectives() || + Tok.isOneOf(tok::semi, tok::r_brace) || Tok.isAnnotation() || + Tok.getLocation().isMacroID() || PrevLoc.isMacroID() || + StmtLoc.isMacroID() || + (Kind == MSK_else && P.MisleadingIndentationElseLoc.isInvalid())) { + P.MisleadingIndentationElseLoc = SourceLocation(); + return; + } + if (Kind == MSK_else) + P.MisleadingIndentationElseLoc = SourceLocation(); + + SourceManager &SM = P.getPreprocessor().getSourceManager(); + unsigned PrevColNum = getVisualIndentation(SM, PrevLoc); + unsigned CurColNum = getVisualIndentation(SM, Tok.getLocation()); + unsigned StmtColNum = getVisualIndentation(SM, StmtLoc); + + if (PrevColNum != 0 && CurColNum != 0 && StmtColNum != 0 && + ((PrevColNum > StmtColNum && PrevColNum == CurColNum) || + !Tok.isAtStartOfLine()) && + SM.getPresumedLineNumber(StmtLoc) != + SM.getPresumedLineNumber(Tok.getLocation()) && + (Tok.isNot(tok::identifier) || + P.getPreprocessor().LookAhead(0).isNot(tok::colon))) { + P.Diag(Tok.getLocation(), diag::warn_misleading_indentation) << Kind; + P.Diag(StmtLoc, diag::note_previous_statement); + } + } +}; + +} /// ParseIfStatement /// if-statement: [C99 6.8.4.1] @@ -1265,6 +1358,8 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { // ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); + MisleadingIndentationChecker MIChecker(*this, MSK_if, IfLoc); + // Read the 'then' stmt. SourceLocation ThenStmtLoc = Tok.getLocation(); @@ -1278,6 +1373,9 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { ThenStmt = ParseStatement(&InnerStatementTrailingElseLoc); } + if (Tok.isNot(tok::kw_else)) + MIChecker.Check(); + // Pop the 'if' scope if needed. InnerScope.Exit(); @@ -1305,12 +1403,17 @@ StmtResult Parser::ParseIfStatement(SourceLocation *TrailingElseLoc) { ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); + MisleadingIndentationChecker MIChecker(*this, MSK_else, ElseLoc); + EnterExpressionEvaluationContext PotentiallyDiscarded( Actions, Sema::ExpressionEvaluationContext::DiscardedStatement, nullptr, Sema::ExpressionEvaluationContextRecord::EK_Other, /*ShouldEnter=*/ConstexprCondition && *ConstexprCondition); ElseStmt = ParseStatement(); + if (ElseStmt.isUsable()) + MIChecker.Check(); + // Pop the 'else' scope if needed. InnerScope.Exit(); } else if (Tok.is(tok::code_completion)) { @@ -1484,9 +1587,13 @@ StmtResult Parser::ParseWhileStatement(SourceLocation *TrailingElseLoc) { // ParseScope InnerScope(this, Scope::DeclScope, C99orCXX, Tok.is(tok::l_brace)); + MisleadingIndentationChecker MIChecker(*this, MSK_while, WhileLoc); + // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); + if (Body.isUsable()) + MIChecker.Check(); // Pop the body scope if needed. InnerScope.Exit(); WhileScope.Exit(); @@ -1918,9 +2025,14 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc) { if (C99orCXXorObjC) getCurScope()->decrementMSManglingNumber(); + MisleadingIndentationChecker MIChecker(*this, MSK_for, ForLoc); + // Read the body statement. StmtResult Body(ParseStatement(TrailingElseLoc)); + if (Body.isUsable()) + MIChecker.Check(); + // Pop the body scope if needed. InnerScope.Exit(); diff --git a/clang/lib/Parse/ParseStmtAsm.cpp b/clang/lib/Parse/ParseStmtAsm.cpp index 1153c2510b05..ea2c871d6a82 100644 --- a/clang/lib/Parse/ParseStmtAsm.cpp +++ b/clang/lib/Parse/ParseStmtAsm.cpp @@ -547,12 +547,9 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { // We need an actual supported target. const llvm::Triple &TheTriple = Actions.Context.getTargetInfo().getTriple(); - llvm::Triple::ArchType ArchTy = TheTriple.getArch(); const std::string &TT = TheTriple.getTriple(); const llvm::Target *TheTarget = nullptr; - bool UnsupportedArch = - (ArchTy != llvm::Triple::x86 && ArchTy != llvm::Triple::x86_64); - if (UnsupportedArch) { + if (!TheTriple.isX86()) { Diag(AsmLoc, diag::err_msasm_unsupported_arch) << TheTriple.getArchName(); } else { std::string Error; @@ -563,16 +560,19 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { assert(!LBraceLocs.empty() && "Should have at least one location here"); + SmallString<512> AsmString; + auto EmptyStmt = [&] { + return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, AsmString, + /*NumOutputs*/ 0, /*NumInputs*/ 0, + ConstraintRefs, ClobberRefs, Exprs, EndLoc); + }; // If we don't support assembly, or the assembly is empty, we don't // need to instantiate the AsmParser, etc. if (!TheTarget || AsmToks.empty()) { - return Actions.ActOnMSAsmStmt(AsmLoc, LBraceLocs[0], AsmToks, StringRef(), - /*NumOutputs*/ 0, /*NumInputs*/ 0, - ConstraintRefs, ClobberRefs, Exprs, EndLoc); + return EmptyStmt(); } // Expand the tokens into a string buffer. - SmallString<512> AsmString; SmallVector<unsigned, 8> TokOffsets; if (buildMSAsmString(PP, AsmLoc, AsmToks, TokOffsets, AsmString)) return StmtError(); @@ -582,12 +582,26 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { llvm::join(TO.Features.begin(), TO.Features.end(), ","); std::unique_ptr<llvm::MCRegisterInfo> MRI(TheTarget->createMCRegInfo(TT)); - std::unique_ptr<llvm::MCAsmInfo> MAI(TheTarget->createMCAsmInfo(*MRI, TT)); + if (!MRI) { + Diag(AsmLoc, diag::err_msasm_unable_to_create_target) + << "target MC unavailable"; + return EmptyStmt(); + } + // FIXME: init MCOptions from sanitizer flags here. + llvm::MCTargetOptions MCOptions; + std::unique_ptr<llvm::MCAsmInfo> MAI( + TheTarget->createMCAsmInfo(*MRI, TT, MCOptions)); // Get the instruction descriptor. std::unique_ptr<llvm::MCInstrInfo> MII(TheTarget->createMCInstrInfo()); std::unique_ptr<llvm::MCObjectFileInfo> MOFI(new llvm::MCObjectFileInfo()); std::unique_ptr<llvm::MCSubtargetInfo> STI( TheTarget->createMCSubtargetInfo(TT, TO.CPU, FeaturesStr)); + // Target MCTargetDesc may not be linked in clang-based tools. + if (!MAI || !MII | !MOFI || !STI) { + Diag(AsmLoc, diag::err_msasm_unable_to_create_target) + << "target MC unavailable"; + return EmptyStmt(); + } llvm::SourceMgr TempSrcMgr; llvm::MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &TempSrcMgr); @@ -602,10 +616,14 @@ StmtResult Parser::ParseMicrosoftAsmStatement(SourceLocation AsmLoc) { std::unique_ptr<llvm::MCAsmParser> Parser( createMCAsmParser(TempSrcMgr, Ctx, *Str.get(), *MAI)); - // FIXME: init MCOptions from sanitizer flags here. - llvm::MCTargetOptions MCOptions; std::unique_ptr<llvm::MCTargetAsmParser> TargetParser( TheTarget->createMCAsmParser(*STI, *Parser, *MII, MCOptions)); + // Target AsmParser may not be linked in clang-based tools. + if (!TargetParser) { + Diag(AsmLoc, diag::err_msasm_unable_to_create_target) + << "target ASM parser unavailable"; + return EmptyStmt(); + } std::unique_ptr<llvm::MCInstPrinter> IP( TheTarget->createMCInstPrinter(llvm::Triple(TT), 1, *MAI, *MII, *MRI)); @@ -725,7 +743,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { BalancedDelimiterTracker T(*this, tok::l_paren); T.consumeOpen(); - ExprResult AsmString(ParseAsmStringLiteral()); + ExprResult AsmString(ParseAsmStringLiteral(/*ForAsmLabel*/ false)); // Check if GNU-style InlineAsm is disabled. // Error on anything other than empty string. @@ -805,7 +823,7 @@ StmtResult Parser::ParseAsmStatement(bool &msAsm) { // Parse the asm-string list for clobbers if present. if (!AteExtraColon && isTokenStringLiteral()) { while (1) { - ExprResult Clobber(ParseAsmStringLiteral()); + ExprResult Clobber(ParseAsmStringLiteral(/*ForAsmLabel*/ false)); if (Clobber.isInvalid()) break; @@ -902,7 +920,7 @@ bool Parser::ParseAsmOperandsOpt(SmallVectorImpl<IdentifierInfo *> &Names, } else Names.push_back(nullptr); - ExprResult Constraint(ParseAsmStringLiteral()); + ExprResult Constraint(ParseAsmStringLiteral(/*ForAsmLabel*/ false)); if (Constraint.isInvalid()) { SkipUntil(tok::r_paren, StopAtSemi); return true; diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 928bc5aa25b3..1b9301b6591d 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -12,6 +12,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" +#include "clang/AST/ExprCXX.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" @@ -130,7 +131,9 @@ Decl *Parser::ParseTemplateDeclarationOrSpecialization( if (TryConsumeToken(tok::kw_requires)) { OptionalRequiresClauseConstraintER = - Actions.CorrectDelayedTyposInExpr(ParseConstraintExpression()); + Actions.CorrectDelayedTyposInExpr( + ParseConstraintLogicalOrExpression( + /*IsTrailingRequiresClause=*/false)); if (!OptionalRequiresClauseConstraintER.isUsable()) { // Skip until the semi-colon or a '}'. SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); @@ -254,8 +257,12 @@ Decl *Parser::ParseSingleDeclarationAfterTemplate( }); LateParsedAttrList LateParsedAttrs(true); - if (DeclaratorInfo.isFunctionDeclarator()) + if (DeclaratorInfo.isFunctionDeclarator()) { + if (Tok.is(tok::kw_requires)) + ParseTrailingRequiresClause(DeclaratorInfo); + MaybeParseGNUAttributes(DeclaratorInfo, &LateParsedAttrs); + } if (DeclaratorInfo.isFunctionDeclarator() && isStartOfFunctionDefinition(DeclaratorInfo)) { @@ -492,7 +499,10 @@ Parser::ParseTemplateParameterList(const unsigned Depth, /// Determine whether the parser is at the start of a template /// type parameter. -bool Parser::isStartOfTemplateTypeParameter() { +/// \param ScopeError will receive true if there was an error parsing a +/// scope specifier at the current location. +bool Parser::isStartOfTemplateTypeParameter(bool &ScopeError) { + ScopeError = false; if (Tok.is(tok::kw_class)) { // "class" may be the start of an elaborated-type-specifier or a // type-parameter. Per C++ [temp.param]p3, we prefer the type-parameter. @@ -525,6 +535,40 @@ bool Parser::isStartOfTemplateTypeParameter() { } } + bool WasScopeAnnotation = Tok.is(tok::annot_cxxscope); + CXXScopeSpec SS; + ScopeError = + ParseOptionalCXXScopeSpecifier(SS, ParsedType(), + /*EnteringContext=*/false, + /*MayBePseudoDestructor=*/nullptr, + // If this is not a type-constraint, then + // this scope-spec is part of the typename + // of a non-type template parameter + /*IsTypename=*/true, /*LastII=*/nullptr, + // We won't find concepts in + // non-namespaces anyway, so might as well + // parse this correctly for possible type + // names. + /*OnlyNamespace=*/false); + if (ScopeError) + return false; + if (TryAnnotateTypeConstraint(SS)) + return false; + bool IsTypeConstraint = isTypeConstraintAnnotation(); + if (!IsTypeConstraint && SS.isNotEmpty()) { + // This isn't a type-constraint but we've already parsed this scope + // specifier - annotate it. + AnnotateScopeToken(SS, /*isNewAnnotation=*/!WasScopeAnnotation); + return false; + } + + if (IsTypeConstraint && + // Next token might be 'auto' or 'decltype', indicating that this + // type-constraint is in fact part of a placeholder-type-specifier of a + // non-type template parameter. + !NextToken().isOneOf(tok::kw_auto, tok::kw_decltype)) + return true; + // 'typedef' is a reasonably-common typo/thinko for 'typename', and is // ill-formed otherwise. if (Tok.isNot(tok::kw_typename) && Tok.isNot(tok::kw_typedef)) @@ -568,24 +612,37 @@ bool Parser::isStartOfTemplateTypeParameter() { /// type-parameter /// parameter-declaration /// -/// type-parameter: (see below) -/// 'class' ...[opt] identifier[opt] -/// 'class' identifier[opt] '=' type-id -/// 'typename' ...[opt] identifier[opt] -/// 'typename' identifier[opt] '=' type-id -/// 'template' '<' template-parameter-list '>' -/// 'class' ...[opt] identifier[opt] -/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] -/// = id-expression +/// type-parameter: (See below) +/// type-parameter-key ...[opt] identifier[opt] +/// type-parameter-key identifier[opt] = type-id +/// (C++2a) type-constraint ...[opt] identifier[opt] +/// (C++2a) type-constraint identifier[opt] = type-id +/// 'template' '<' template-parameter-list '>' type-parameter-key +/// ...[opt] identifier[opt] +/// 'template' '<' template-parameter-list '>' type-parameter-key +/// identifier[opt] '=' id-expression +/// +/// type-parameter-key: +/// class +/// typename +/// NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { - if (isStartOfTemplateTypeParameter()) { - // Is there just a typo in the input code? ('typedef' instead of 'typename') + // We could be facing a type-constraint, which (could) start a type parameter. + // Annotate it now (we might end up not using it if we determine this + // type-constraint is in fact part of a placeholder-type-specifier of a + // non-type template parameter. + + bool ScopeError; + if (isStartOfTemplateTypeParameter(ScopeError)) { + // Is there just a typo in the input code? ('typedef' instead of + // 'typename') if (Tok.is(tok::kw_typedef)) { Diag(Tok.getLocation(), diag::err_expected_template_parameter); Diag(Tok.getLocation(), diag::note_meant_to_use_typename) << FixItHint::CreateReplacement(CharSourceRange::getCharRange( - Tok.getLocation(), Tok.getEndLoc()), + Tok.getLocation(), + Tok.getEndLoc()), "typename"); Tok.setKind(tok::kw_typename); @@ -593,7 +650,26 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { return ParseTypeParameter(Depth, Position); } - + if (ScopeError) { + // We return an invalid parameter as opposed to null to avoid having bogus + // diagnostics about an empty template parameter list. + // FIXME: Fix ParseTemplateParameterList to better handle nullptr results + // from here. + // Return a NTTP as if there was an error in a scope specifier, the user + // probably meant to write the type of a NTTP. + DeclSpec DS(getAttrFactory()); + DS.SetTypeSpecError(); + Declarator D(DS, DeclaratorContext::TemplateParamContext); + D.SetIdentifier(nullptr, Tok.getLocation()); + D.setInvalidType(true); + NamedDecl *ErrorParam = Actions.ActOnNonTypeTemplateParameter( + getCurScope(), D, Depth, Position, /*EqualLoc=*/SourceLocation(), + /*DefaultArg=*/nullptr); + ErrorParam->setInvalidDecl(true); + SkipUntil(tok::comma, tok::greater, tok::greatergreater, + StopAtSemi | StopBeforeMatch); + return ErrorParam; + } if (Tok.is(tok::kw_template)) return ParseTemplateTemplateParameter(Depth, Position); @@ -603,6 +679,56 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { return ParseNonTypeTemplateParameter(Depth, Position); } +/// Check whether the current token is a template-id annotation denoting a +/// type-constraint. +bool Parser::isTypeConstraintAnnotation() { + if (Tok.isNot(tok::annot_template_id)) + return false; + const auto *ExistingAnnot = + static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + return ExistingAnnot->Kind == TNK_Concept_template; +} + +/// Try parsing a type-constraint construct at the current location, after the +/// optional scope specifier. +/// +/// type-constraint: +/// nested-name-specifier[opt] concept-name +/// nested-name-specifier[opt] concept-name +/// '<' template-argument-list[opt] '>'[opt] +/// +/// \returns true if an error occurred, and false otherwise. +bool Parser::TryAnnotateTypeConstraint(CXXScopeSpec &SS) { + if (!getLangOpts().ConceptsTS || Tok.isNot(tok::identifier)) + return false; + + UnqualifiedId PossibleConceptName; + PossibleConceptName.setIdentifier(Tok.getIdentifierInfo(), + Tok.getLocation()); + + TemplateTy PossibleConcept; + bool MemberOfUnknownSpecialization = false; + auto TNK = Actions.isTemplateName(getCurScope(), SS, + /*hasTemplateKeyword=*/false, + PossibleConceptName, + /*ObjectType=*/ParsedType(), + /*EnteringContext=*/false, + PossibleConcept, + MemberOfUnknownSpecialization); + assert(!MemberOfUnknownSpecialization + && "Member when we only allowed namespace scope qualifiers??"); + if (!PossibleConcept || TNK != TNK_Concept_template) + return false; + + // At this point we're sure we're dealing with a constrained parameter. It + // may or may not have a template parameter list following the concept name. + return AnnotateTemplateIdToken(PossibleConcept, TNK, SS, + /*TemplateKWLoc=*/SourceLocation(), + PossibleConceptName, + /*AllowTypeAnnotation=*/false, + /*TypeConstraint=*/true); +} + /// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]). /// Other kinds of template parameters are parsed in /// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter. @@ -613,12 +739,25 @@ NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) { /// 'typename' ...[opt][C++0x] identifier[opt] /// 'typename' identifier[opt] '=' type-id NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { - assert(Tok.isOneOf(tok::kw_class, tok::kw_typename) && - "A type-parameter starts with 'class' or 'typename'"); + assert(Tok.isOneOf(tok::kw_class, tok::kw_typename, tok::annot_template_id) && + "A type-parameter starts with 'class', 'typename' or a " + "type-constraint"); - // Consume the 'class' or 'typename' keyword. - bool TypenameKeyword = Tok.is(tok::kw_typename); - SourceLocation KeyLoc = ConsumeToken(); + TemplateIdAnnotation *TypeConstraint = nullptr; + bool TypenameKeyword = false; + SourceLocation KeyLoc; + if (Tok.is(tok::annot_template_id)) { + // Consume the 'type-constraint'. + TypeConstraint = + static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue()); + assert(TypeConstraint->Kind == TNK_Concept_template && + "stray non-concept template-id annotation"); + KeyLoc = ConsumeAnnotationToken(); + } else { + // Consume the 'class' or 'typename' keyword. + TypenameKeyword = Tok.is(tok::kw_typename); + KeyLoc = ConsumeToken(); + } // Grab the ellipsis (if given). SourceLocation EllipsisLoc; @@ -658,9 +797,19 @@ NamedDecl *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { DefaultArg = ParseTypeName(/*Range=*/nullptr, DeclaratorContext::TemplateTypeArgContext).get(); - return Actions.ActOnTypeParameter(getCurScope(), TypenameKeyword, EllipsisLoc, - KeyLoc, ParamName, NameLoc, Depth, Position, - EqualLoc, DefaultArg); + NamedDecl *NewDecl = Actions.ActOnTypeParameter(getCurScope(), + TypenameKeyword, EllipsisLoc, + KeyLoc, ParamName, NameLoc, + Depth, Position, EqualLoc, + DefaultArg, + TypeConstraint != nullptr); + + if (TypeConstraint) + Actions.ActOnTypeConstraint(TypeConstraint, + cast<TemplateTypeParmDecl>(NewDecl), + EllipsisLoc); + + return NewDecl; } /// ParseTemplateTemplateParameter - Handle the parsing of template @@ -823,7 +972,7 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { // Create the parameter. return Actions.ActOnNonTypeTemplateParameter(getCurScope(), ParamDecl, - Depth, Position, EqualLoc, + Depth, Position, EqualLoc, DefaultArg.get()); } @@ -1099,6 +1248,10 @@ Parser::ParseTemplateIdAfterTemplateName(bool ConsumeLastToken, /// simple-template-id is always replaced with a template-id /// annotation token. /// +/// \param TypeConstraint if true, then this is actually a type-constraint, +/// meaning that the template argument list can be omitted (and the template in +/// question must be a concept). +/// /// If an unrecoverable parse error occurs and no annotation token can be /// formed, this function returns true. /// @@ -1106,10 +1259,15 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, UnqualifiedId &TemplateName, - bool AllowTypeAnnotation) { + bool AllowTypeAnnotation, + bool TypeConstraint) { assert(getLangOpts().CPlusPlus && "Can only annotate template-ids in C++"); - assert(Template && Tok.is(tok::less) && + assert(Template && (Tok.is(tok::less) || TypeConstraint) && "Parser isn't at the beginning of a template-id"); + assert(!(TypeConstraint && AllowTypeAnnotation) && "type-constraint can't be " + "a type annotation"); + assert((!TypeConstraint || TNK == TNK_Concept_template) && "type-constraint " + "must accompany a concept name"); // Consume the template-name. SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin(); @@ -1117,17 +1275,19 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // Parse the enclosed template argument list. SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; - bool Invalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, - TemplateArgs, - RAngleLoc); + if (!TypeConstraint || Tok.is(tok::less)) { + bool Invalid = ParseTemplateIdAfterTemplateName(false, LAngleLoc, + TemplateArgs, + RAngleLoc); - if (Invalid) { - // If we failed to parse the template ID but skipped ahead to a >, we're not - // going to be able to form a token annotation. Eat the '>' if present. - TryConsumeToken(tok::greater); - // FIXME: Annotate the token stream so we don't produce the same errors - // again if we're doing this annotation as part of a tentative parse. - return true; + if (Invalid) { + // If we failed to parse the template ID but skipped ahead to a >, we're not + // going to be able to form a token annotation. Eat the '>' if present. + TryConsumeToken(tok::greater); + // FIXME: Annotate the token stream so we don't produce the same errors + // again if we're doing this annotation as part of a tentative parse. + return true; + } } ASTTemplateArgsPtr TemplateArgsPtr(TemplateArgs); @@ -1365,8 +1525,9 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { // Parse a non-type template argument. SourceLocation Loc = Tok.getLocation(); ExprResult ExprArg = ParseConstantExpressionInExprEvalContext(MaybeTypeCast); - if (ExprArg.isInvalid() || !ExprArg.get()) + if (ExprArg.isInvalid() || !ExprArg.get()) { return ParsedTemplateArgument(); + } return ParsedTemplateArgument(ParsedTemplateArgument::NonType, ExprArg.get(), Loc); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index e2e16ca63d1e..4d69fb4693fb 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1031,6 +1031,10 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract, // direct-declarator '[' constant-expression[opt] ']' // direct-abstract-declarator[opt] '[' constant-expression[opt] ']' TPR = TryParseBracketDeclarator(); + } else if (Tok.is(tok::kw_requires)) { + // declarator requires-clause + // A requires clause indicates a function declaration. + TPR = TPResult::True; } else { break; } @@ -2014,7 +2018,6 @@ Parser::TryParseParameterDeclarationClause(bool *InvalidAsDeclaration, /// 'throw' '(' type-id-list[opt] ')' /// Parser::TPResult Parser::TryParseFunctionDeclarator() { - // The '(' is already parsed. TPResult TPR = TryParseParameterDeclarationClause(); @@ -2066,9 +2069,21 @@ Parser::TPResult Parser::TryParseFunctionDeclarator() { /// Parser::TPResult Parser::TryParseBracketDeclarator() { ConsumeBracket(); - if (!SkipUntil(tok::r_square, StopAtSemi)) + + // A constant-expression cannot begin with a '{', but the + // expr-or-braced-init-list of a postfix-expression can. + if (Tok.is(tok::l_brace)) + return TPResult::False; + + if (!SkipUntil(tok::r_square, tok::comma, StopAtSemi | StopBeforeMatch)) return TPResult::Error; + // If we hit a comma before the ']', this is not a constant-expression, + // but might still be the expr-or-braced-init-list of a postfix-expression. + if (Tok.isNot(tok::r_square)) + return TPResult::False; + + ConsumeBracket(); return TPResult::Ambiguous; } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 2645f27e656f..4249de361b89 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -278,6 +278,10 @@ bool Parser::SkipUntil(ArrayRef<tok::TokenKind> Toks, SkipUntilFlags Flags) { case tok::annot_pragma_openmp: case tok::annot_pragma_openmp_end: // Stop before an OpenMP pragma boundary. + if (OpenMPDirectiveParsing) + return false; + ConsumeAnnotationToken(); + break; case tok::annot_module_begin: case tok::annot_module_end: case tok::annot_module_include: @@ -799,7 +803,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc; - ExprResult Result(ParseSimpleAsm(&EndLoc)); + ExprResult Result(ParseSimpleAsm(/*ForAsmLabel*/ false, &EndLoc)); // Check if GNU-style InlineAsm is disabled. // Empty asm string is allowed because it will not introduce @@ -1463,11 +1467,14 @@ void Parser::ParseKNRParamDeclarations(Declarator &D) { /// ParseAsmStringLiteral - This is just a normal string-literal, but is not /// allowed to be a wide string, and is not subject to character translation. +/// Unlike GCC, we also diagnose an empty string literal when parsing for an +/// asm label as opposed to an asm statement, because such a construct does not +/// behave well. /// /// [GNU] asm-string-literal: /// string-literal /// -ExprResult Parser::ParseAsmStringLiteral() { +ExprResult Parser::ParseAsmStringLiteral(bool ForAsmLabel) { if (!isTokenStringLiteral()) { Diag(Tok, diag::err_expected_string_literal) << /*Source='in...'*/0 << "'asm'"; @@ -1483,6 +1490,11 @@ ExprResult Parser::ParseAsmStringLiteral() { << SL->getSourceRange(); return ExprError(); } + if (ForAsmLabel && SL->getString().empty()) { + Diag(Tok, diag::err_asm_operand_wide_string_literal) + << 2 /* an empty */ << SL->getSourceRange(); + return ExprError(); + } } return AsmString; } @@ -1492,7 +1504,7 @@ ExprResult Parser::ParseAsmStringLiteral() { /// [GNU] simple-asm-expr: /// 'asm' '(' asm-string-literal ')' /// -ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { +ExprResult Parser::ParseSimpleAsm(bool ForAsmLabel, SourceLocation *EndLoc) { assert(Tok.is(tok::kw_asm) && "Not an asm!"); SourceLocation Loc = ConsumeToken(); @@ -1512,7 +1524,7 @@ ExprResult Parser::ParseSimpleAsm(SourceLocation *EndLoc) { return ExprError(); } - ExprResult Result(ParseAsmStringLiteral()); + ExprResult Result(ParseAsmStringLiteral(ForAsmLabel)); if (!Result.isInvalid()) { // Close the paren and get the location of the end bracket diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 2c70c0599ecf..04611dadde66 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -1174,7 +1174,7 @@ namespace { // We analyze lambda bodies separately. Skip them here. bool TraverseLambdaExpr(LambdaExpr *LE) { // Traverse the captures, but not the body. - for (const auto &C : zip(LE->captures(), LE->capture_inits())) + for (const auto C : zip(LE->captures(), LE->capture_inits())) TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C)); return true; } diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index c8743df90e34..960e62d4a2db 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -546,8 +546,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, SmallVector<const Expr *, 4> CommaLHS; SmallVector<SubobjectAdjustment, 4> Adjustments; const Expr *ExtendedObject = - MTE->GetTemporaryExpr()->skipRValueSubobjectAdjustments( - CommaLHS, Adjustments); + MTE->getSubExpr()->skipRValueSubobjectAdjustments(CommaLHS, + Adjustments); if (ExtendedObject->getType().isDestructedType()) { Scopes.push_back(GotoScope(ParentScope, 0, diag::note_exits_temporary_dtor, diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index b0aa67454a7b..2b0cd6b8c4fc 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -15,6 +15,8 @@ using namespace clang; +char MultiplexExternalSemaSource::ID; + ///Constructs a new multiplexing external sema source and appends the /// given element to it. /// diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td index 298614059467..9d6bb411eff8 100644 --- a/clang/lib/Sema/OpenCLBuiltins.td +++ b/clang/lib/Sema/OpenCLBuiltins.td @@ -40,6 +40,30 @@ def ConstantAS : AddressSpace<"clang::LangAS::opencl_constant">; def LocalAS : AddressSpace<"clang::LangAS::opencl_local">; def GenericAS : AddressSpace<"clang::LangAS::opencl_generic">; +// OpenCL language extension. +class AbstractExtension<string _Ext> { + // One or more OpenCL extensions, space separated. Each extension must be + // a valid extension name for the opencl extension pragma. + string ExtName = _Ext; +} + +// Extension associated to a builtin function. +class FunctionExtension<string _Ext> : AbstractExtension<_Ext>; + +// FunctionExtension definitions. +def FuncExtNone : FunctionExtension<"">; +def FuncExtKhrSubgroups : FunctionExtension<"cl_khr_subgroups">; +def FuncExtKhrGlobalInt32BaseAtomics : FunctionExtension<"cl_khr_global_int32_base_atomics">; +def FuncExtKhrGlobalInt32ExtendedAtomics : FunctionExtension<"cl_khr_global_int32_extended_atomics">; +def FuncExtKhrLocalInt32BaseAtomics : FunctionExtension<"cl_khr_local_int32_base_atomics">; +def FuncExtKhrLocalInt32ExtendedAtomics : FunctionExtension<"cl_khr_local_int32_extended_atomics">; +def FuncExtKhrInt64BaseAtomics : FunctionExtension<"cl_khr_int64_base_atomics">; +def FuncExtKhrInt64ExtendedAtomics : FunctionExtension<"cl_khr_int64_extended_atomics">; +def FuncExtKhrMipmapImage : FunctionExtension<"cl_khr_mipmap_image">; +def FuncExtKhrGlMsaaSharing : FunctionExtension<"cl_khr_gl_msaa_sharing">; + +// Multiple extensions +def FuncExtKhrMipmapAndWrite3d : FunctionExtension<"cl_khr_mipmap_image cl_khr_3d_image_writes">; // Qualified Type. These map to ASTContext::QualType. class QualType<string _Name, bit _IsAbstract=0> { @@ -180,18 +204,32 @@ class GenericType<string _Ty, TypeList _TypeList, IntList _VectorList> : let VecWidth = 0; } +// Builtin function attributes. +def Attr { + list<bit> None = [0, 0, 0]; + list<bit> Pure = [1, 0, 0]; + list<bit> Const = [0, 1, 0]; + list<bit> Convergent = [0, 0, 1]; +} + //===----------------------------------------------------------------------===// // OpenCL C class for builtin functions //===----------------------------------------------------------------------===// -class Builtin<string _Name, list<Type> _Signature> { +class Builtin<string _Name, list<Type> _Signature, list<bit> _Attributes = Attr.None> { // Name of the builtin function string Name = _Name; // List of types used by the function. The first one is the return type and // the following are the arguments. The list must have at least one element // (the return type). list<Type> Signature = _Signature; - // OpenCL Extension to which the function belongs (cl_khr_subgroups, ...) - string Extension = ""; + // Function attribute __attribute__((pure)) + bit IsPure = _Attributes[0]; + // Function attribute __attribute__((const)) + bit IsConst = _Attributes[1]; + // Function attribute __attribute__((convergent)) + bit IsConv = _Attributes[2]; + // OpenCL extensions to which the function belongs. + FunctionExtension Extension = FuncExtNone; // Version of OpenCL from which the function is available (e.g.: CL10). // MinVersion is inclusive. Version MinVersion = CL10; @@ -260,10 +298,25 @@ def Event : Type<"Event", QualType<"OCLEventTy">>; def VecAndScalar: IntList<"VecAndScalar", [1, 2, 3, 4, 8, 16]>; def VecNoScalar : IntList<"VecNoScalar", [2, 3, 4, 8, 16]>; def Vec1 : IntList<"Vec1", [1]>; +def Vec2 : IntList<"Vec2", [2]>; +def Vec4 : IntList<"Vec4", [4]>; +def Vec8 : IntList<"Vec8", [8]>; +def Vec16 : IntList<"Vec16", [16]>; +def Vec1234 : IntList<"Vec1234", [1, 2, 3, 4]>; // Type lists. -def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>; +def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>; +def TLAllUnsigned : TypeList<"TLAllUnsigned", [UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong, UInt, ULong, UShort]>; def TLFloat : TypeList<"TLFloat", [Float, Double, Half]>; +def TLSignedInts : TypeList<"TLSignedInts", [Char, Short, Int, Long]>; +def TLUnsignedInts : TypeList<"TLUnsignedInts", [UChar, UShort, UInt, ULong]>; + +def TLIntLongFloats : TypeList<"TLIntLongFloats", [Int, UInt, Long, ULong, Float, Double, Half]>; + +// All unsigned integer types twice, to facilitate unsigned return types for e.g. +// uchar abs(char) and +// uchar abs(uchar). +def TLAllUIntsTwice : TypeList<"TLAllUIntsTwice", [UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong]>; def TLAllInts : TypeList<"TLAllInts", [Char, UChar, Short, UShort, Int, UInt, Long, ULong]>; @@ -276,8 +329,16 @@ def AGenTypeNNoScalar : GenericType<"AGenTypeNNoScalar", TLAll, VecNoScalar def AIGenType1 : GenericType<"AIGenType1", TLAllInts, Vec1>; def AIGenTypeN : GenericType<"AIGenTypeN", TLAllInts, VecAndScalar>; def AIGenTypeNNoScalar : GenericType<"AIGenTypeNNoScalar", TLAllInts, VecNoScalar>; +// All integer to unsigned +def AI2UGenTypeN : GenericType<"AI2UGenTypeN", TLAllUIntsTwice, VecAndScalar>; +// Signed integer +def SGenTypeN : GenericType<"SGenTypeN", TLSignedInts, VecAndScalar>; +// Unsigned integer +def UGenTypeN : GenericType<"UGenTypeN", TLUnsignedInts, VecAndScalar>; // Float def FGenTypeN : GenericType<"FGenTypeN", TLFloat, VecAndScalar>; +// (u)int, (u)long, and all floats +def IntLongFloatGenType1 : GenericType<"IntLongFloatGenType1", TLIntLongFloats, Vec1>; // GenType definitions for every single base type (e.g. fp32 only). // Names are like: GenTypeFloatVecAndScalar. @@ -292,6 +353,14 @@ foreach Type = [Char, UChar, Short, UShort, } } +// GenType definitions for vec1234. +foreach Type = [Float, Double, Half] in { + def "GenType" # Type # Vec1234 : + GenericType<"GenType" # Type # Vec1234, + TypeList<"GL" # Type.Name, [Type]>, + Vec1234>; +} + //===----------------------------------------------------------------------===// // Definitions of OpenCL builtin functions @@ -307,11 +376,12 @@ foreach RType = [Float, Double, Half, Char, UChar, Short, UShort, Int, UInt, Long, ULong] in { foreach sat = ["", "_sat"] in { foreach rnd = ["", "_rte", "_rtn", "_rtp", "_rtz"] in { - def : Builtin<"convert_" # RType.Name # sat # rnd, [RType, IType]>; + def : Builtin<"convert_" # RType.Name # sat # rnd, [RType, IType], + Attr.Const>; foreach v = [2, 3, 4, 8, 16] in { def : Builtin<"convert_" # RType.Name # v # sat # rnd, - [VectorType<RType, v>, - VectorType<IType, v>]>; + [VectorType<RType, v>, VectorType<IType, v>], + Attr.Const>; } } } @@ -321,11 +391,11 @@ foreach RType = [Float, Double, Half, Char, UChar, Short, //-------------------------------------------------------------------- // OpenCL v1.1 s6.11.1, v1.2 s6.12.1, v2.0 s6.13.1 - Work-item Functions // --- Table 7 --- -def : Builtin<"get_work_dim", [UInt]>; +def : Builtin<"get_work_dim", [UInt], Attr.Const>; foreach name = ["get_global_size", "get_global_id", "get_local_size", "get_local_id", "get_num_groups", "get_group_id", "get_global_offset"] in { - def : Builtin<name, [Size, UInt]>; + def : Builtin<name, [Size, UInt], Attr.Const>; } let MinVersion = CL20 in { @@ -335,9 +405,303 @@ let MinVersion = CL20 in { } } + +//-------------------------------------------------------------------- +// OpenCL v1.1 s6.11.2, v1.2 s6.12.2, v2.0 s6.13.2 - Math functions +// OpenCL Extension v2.0 s5.1.2 and s6.1.2 - Math Functions +// --- Table 8 --- +// --- 1 argument --- +foreach name = ["acos", "acosh", "acospi", + "asin", "asinh", "asinpi", + "atan", "atanh", "atanpi", + "cbrt", "ceil", + "cos", "cosh", "cospi", + "erfc", "erf", + "exp", "exp2", "exp10", "expm1", + "fabs", "floor", + "log", "log2", "log10", "log1p", "logb", + "rint", "round", "rsqrt", + "sin", "sinh", "sinpi", + "sqrt", + "tan", "tanh", "tanpi", + "tgamma", "trunc", + "lgamma"] in { + def : Builtin<name, [FGenTypeN, FGenTypeN], Attr.Const>; +} +foreach name = ["nan"] in { + def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeULongVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>; +} + +// --- 2 arguments --- +foreach name = ["atan2", "atan2pi", "copysign", "fdim", "fmod", "hypot", + "maxmag", "minmag", "nextafter", "pow", "powr", + "remainder"] in { + def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>; +} +foreach name = ["fmax", "fmin"] in { + def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>; + def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double], Attr.Const>; + def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half], Attr.Const>; +} +foreach name = ["ilogb"] in { + def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeDoubleVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeHalfVecAndScalar], Attr.Const>; +} +foreach name = ["ldexp"] in { + def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Int], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Int], Attr.Const>; + def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Int], Attr.Const>; +} +foreach name = ["pown", "rootn"] in { + def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>; +} + +// --- 3 arguments --- +foreach name = ["fma", "mad"] in { + def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>; +} + +// --- Version dependent --- +let MaxVersion = CL20 in { + foreach AS = [GlobalAS, LocalAS, PrivateAS] in { + foreach name = ["fract", "modf", "sincos"] in { + def : Builtin<name, [FGenTypeN, FGenTypeN, PointerType<FGenTypeN, AS>]>; + } + foreach name = ["frexp", "lgamma_r"] in { + foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in { + def : Builtin<name, [Type, Type, PointerType<GenTypeIntVecAndScalar, AS>]>; + } + } + foreach name = ["remquo"] in { + foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in { + def : Builtin<name, [Type, Type, Type, PointerType<GenTypeIntVecAndScalar, AS>]>; + } + } + } +} +let MinVersion = CL20 in { + foreach name = ["fract", "modf", "sincos"] in { + def : Builtin<name, [FGenTypeN, FGenTypeN, PointerType<FGenTypeN, GenericAS>]>; + } + foreach name = ["frexp", "lgamma_r"] in { + foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in { + def : Builtin<name, [Type, Type, PointerType<GenTypeIntVecAndScalar, GenericAS>]>; + } } + foreach name = ["remquo"] in { + foreach Type = [GenTypeFloatVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeHalfVecAndScalar] in { + def : Builtin<name, [Type, Type, Type, PointerType<GenTypeIntVecAndScalar, GenericAS>]>; + } + } +} + +// --- Table 9 --- +foreach name = ["half_cos", + "half_exp", "half_exp2", "half_exp10", + "half_log", "half_log2", "half_log10", + "half_recip", "half_rsqrt", + "half_sin", "half_sqrt", "half_tan", + "native_cos", + "native_exp", "native_exp2", "native_exp10", + "native_log", "native_log2", "native_log10", + "native_recip", "native_rsqrt", + "native_sin", "native_sqrt", "native_tan"] in { + def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>; +} +foreach name = ["half_divide", "half_powr", + "native_divide", "native_powr"] in { + def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>; +} + +//-------------------------------------------------------------------- +// OpenCL v1.1 s6.11.3, v1.2 s6.12.3, v2.0 s6.13.3 - Integer Functions +// --- Table 10 --- +// --- 1 argument --- +foreach name = ["abs"] in { + def : Builtin<name, [AI2UGenTypeN, AIGenTypeN], Attr.Const>; +} +foreach name = ["clz", "popcount"] in { + def : Builtin<name, [AIGenTypeN, AIGenTypeN], Attr.Const>; +} +let MinVersion = CL20 in { + foreach name = ["ctz"] in { + def : Builtin<name, [AIGenTypeN, AIGenTypeN]>; + } +} + +// --- 2 arguments --- +foreach name = ["abs_diff"] in { + def : Builtin<name, [AI2UGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>; +} +foreach name = ["add_sat", "hadd", "rhadd", "mul_hi", "rotate", "sub_sat"] in { + def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>; +} +foreach name = ["max", "min"] in { + def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>; + def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1], Attr.Const>; +} +foreach name = ["upsample"] in { + def : Builtin<name, [GenTypeShortVecAndScalar, GenTypeCharVecAndScalar, GenTypeUCharVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeUShortVecAndScalar, GenTypeUCharVecAndScalar, GenTypeUCharVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeShortVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeUIntVecAndScalar, GenTypeUShortVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeLongVecAndScalar, GenTypeIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeULongVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>; +} + +// --- 3 arguments --- +foreach name = ["clamp"] in { + def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>; + def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1, AIGenType1], Attr.Const>; +} +foreach name = ["mad_hi", "mad_sat"] in { + def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN, AIGenTypeN], Attr.Const>; +} + +// --- Table 11 --- +foreach name = ["mad24"] in { + def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeIntVecAndScalar, GenTypeIntVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>; +} +foreach name = ["mul24"] in { + def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeIntVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>; +} + +//-------------------------------------------------------------------- +// OpenCL v1.1 s6.11.4, v1.2 s6.12.4, v2.0 s6.13.4 - Common Functions +// OpenCL Extension v2.0 s5.1.3 and s6.1.3 - Common Functions +// --- Table 12 --- +// --- 1 argument --- +foreach name = ["degrees", "radians", "sign"] in { + def : Builtin<name, [FGenTypeN, FGenTypeN], Attr.Const>; +} + +// --- 2 arguments --- +foreach name = ["max", "min"] in { + def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>; + def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double], Attr.Const>; + def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half], Attr.Const>; +} +foreach name = ["step"] in { + def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>; + def : Builtin<name, [GenTypeFloatVecNoScalar, Float, GenTypeFloatVecNoScalar], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVecNoScalar, Double, GenTypeDoubleVecNoScalar], Attr.Const>; + def : Builtin<name, [GenTypeHalfVecNoScalar, Half, GenTypeHalfVecNoScalar], Attr.Const>; +} + +// --- 3 arguments --- +foreach name = ["clamp", "mix"] in { + def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>; + def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float, Float], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double, Double], Attr.Const>; + def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half, Half], Attr.Const>; +} +foreach name = ["smoothstep"] in { + def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN, FGenTypeN], Attr.Const>; + def : Builtin<name, [GenTypeFloatVecNoScalar, Float, Float, GenTypeFloatVecNoScalar], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVecNoScalar, Double, Double, GenTypeDoubleVecNoScalar], Attr.Const>; + def : Builtin<name, [GenTypeHalfVecNoScalar, Half, Half, GenTypeHalfVecNoScalar], Attr.Const>; +} + + +//-------------------------------------------------------------------- +// OpenCL v1.1 s6.11.5, v1.2 s6.12.5, v2.0 s6.13.5 - Geometric Functions +// OpenCL Extension v2.0 s5.1.4 and s6.1.4 - Geometric Functions +// --- Table 13 --- +// --- 1 argument --- +foreach name = ["length"] in { + def : Builtin<name, [Float, GenTypeFloatVec1234], Attr.Const>; + def : Builtin<name, [Double, GenTypeDoubleVec1234], Attr.Const>; + def : Builtin<name, [Half, GenTypeHalfVec1234], Attr.Const>; +} +foreach name = ["normalize"] in { + def : Builtin<name, [GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVec1234, GenTypeDoubleVec1234], Attr.Const>; + def : Builtin<name, [GenTypeHalfVec1234, GenTypeHalfVec1234], Attr.Const>; +} +foreach name = ["fast_length"] in { + def : Builtin<name, [Float, GenTypeFloatVec1234], Attr.Const>; +} +foreach name = ["fast_normalize"] in { + def : Builtin<name, [GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>; +} + +// --- 2 arguments --- +foreach name = ["cross"] in { + foreach VSize = [3, 4] in { + def : Builtin<name, [VectorType<Float, VSize>, VectorType<Float, VSize>, VectorType<Float, VSize>], Attr.Const>; + def : Builtin<name, [VectorType<Double, VSize>, VectorType<Double, VSize>, VectorType<Double, VSize>], Attr.Const>; + def : Builtin<name, [VectorType<Half, VSize>, VectorType<Half, VSize>, VectorType<Half, VSize>], Attr.Const>; + } +} +foreach name = ["dot", "distance"] in { + def : Builtin<name, [Float, GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>; + def : Builtin<name, [Double, GenTypeDoubleVec1234, GenTypeDoubleVec1234], Attr.Const>; + def : Builtin<name, [Half, GenTypeHalfVec1234, GenTypeHalfVec1234], Attr.Const>; +} +foreach name = ["fast_distance"] in { + def : Builtin<name, [Float, GenTypeFloatVec1234, GenTypeFloatVec1234], Attr.Const>; +} + + +//-------------------------------------------------------------------- +// OpenCL v1.1 s6.11.6, v1.2 s6.12.6, v2.0 s6.13.6 - Relational Functions +// OpenCL Extension v2.0 s5.1.5 and s6.1.5 - Relational Functions +// --- Table 14 --- +// --- 1 argument --- +foreach name = ["isfinite", "isinf", "isnan", "isnormal", "signbit"] in { + def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>; + def : Builtin<name, [Int, Double], Attr.Const>; + def : Builtin<name, [GenTypeLongVecNoScalar, GenTypeDoubleVecNoScalar], Attr.Const>; + def : Builtin<name, [Int, Half], Attr.Const>; + def : Builtin<name, [GenTypeShortVecNoScalar, GenTypeHalfVecNoScalar], Attr.Const>; +} +foreach name = ["any", "all"] in { + def : Builtin<name, [Int, AIGenTypeN], Attr.Const>; +} + +// --- 2 arguments --- +foreach name = ["isequal", "isnotequal", "isgreater", "isgreaterequal", + "isless", "islessequal", "islessgreater", "isordered", + "isunordered"] in { + def : Builtin<name, [GenTypeIntVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar], Attr.Const>; + def : Builtin<name, [Int, Double, Double], Attr.Const>; + def : Builtin<name, [GenTypeLongVecNoScalar, GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar], Attr.Const>; + def : Builtin<name, [Int, Half, Half], Attr.Const>; + def : Builtin<name, [GenTypeShortVecNoScalar, GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar], Attr.Const>; +} + +// --- 3 arguments --- +foreach name = ["bitselect"] in { + def : Builtin<name, [AGenTypeN, AGenTypeN, AGenTypeN, AGenTypeN], Attr.Const>; +} +foreach name = ["select"] in { + def : Builtin<name, [SGenTypeN, SGenTypeN, SGenTypeN, SGenTypeN], Attr.Const>; + def : Builtin<name, [SGenTypeN, SGenTypeN, SGenTypeN, UGenTypeN], Attr.Const>; + def : Builtin<name, [UGenTypeN, UGenTypeN, UGenTypeN, UGenTypeN], Attr.Const>; + def : Builtin<name, [UGenTypeN, UGenTypeN, UGenTypeN, SGenTypeN], Attr.Const>; + def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeIntVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeFloatVecAndScalar, GenTypeUIntVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeLongVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeDoubleVecAndScalar, GenTypeULongVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeShortVecAndScalar], Attr.Const>; + def : Builtin<name, [GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeHalfVecAndScalar, GenTypeUShortVecAndScalar], Attr.Const>; +} + + //-------------------------------------------------------------------- // OpenCL v1.1 s6.11.7, v1.2 s6.12.7, v2.0 s6.13.7 - Vector Data Load and Store Functions -// OpenCL Extension v1.1 s9.3.6 and s9.6.6, v1.2 s9.5.6, v2.0 s9.4.6, v2.0 s5.1.6 and 6.1.6 - Vector Data Load and Store Functions +// OpenCL Extension v1.1 s9.3.6 and s9.6.6, v1.2 s9.5.6, v2.0 s5.1.6 and s6.1.6 - Vector Data Load and Store Functions // --- Table 15 --- // Variants for OpenCL versions below 2.0, using pointers to the global, local // and private address spaces. @@ -448,6 +812,55 @@ foreach VSize = [2, 3, 4, 8, 16] in { } } } +let MaxVersion = CL20 in { + foreach AS = [GlobalAS, LocalAS, PrivateAS] in { + def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>; + foreach VSize = [2, 3, 4, 8, 16] in { + foreach name = ["vload_half" # VSize] in { + def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>; + } + } + foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { + def : Builtin<"vstore_half" # rnd, [Void, Float, Size, PointerType<Half, AS>]>; + def : Builtin<"vstore_half" # rnd, [Void, Double, Size, PointerType<Half, AS>]>; + foreach VSize = [2, 3, 4, 8, 16] in { + foreach name = ["vstore_half" # VSize # rnd] in { + def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>; + def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, AS>]>; + } + } + } + } +} +let MinVersion = CL20 in { + foreach AS = [GenericAS] in { + def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>; + foreach VSize = [2, 3, 4, 8, 16] in { + foreach name = ["vload_half" # VSize] in { + def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>; + } + } + foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { + def : Builtin<"vstore_half" # rnd, [Void, Float, Size, PointerType<Half, AS>]>; + def : Builtin<"vstore_half" # rnd, [Void, Double, Size, PointerType<Half, AS>]>; + foreach VSize = [2, 3, 4, 8, 16] in { + foreach name = ["vstore_half" # VSize # rnd] in { + def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>; + def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, AS>]>; + } + } + } + } +} + +foreach AS = [ConstantAS] in { + def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>; + foreach VSize = [2, 3, 4, 8, 16] in { + foreach name = ["vload_half" # VSize] in { + def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>; + } + } +} //-------------------------------------------------------------------- // OpenCL v1.1 s6.11.10, v1.2 s6.12.10, v2.0 s6.13.10: Async Copies from Global to Local Memory, Local to Global Memory, and Prefetch @@ -473,42 +886,116 @@ foreach name = ["prefetch"] in { // Functions that use memory_order and cl_mem_fence_flags enums are not // declared here as the TableGen backend does not handle enums. -// OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers. +// OpenCL v1.0 s9.5, s9.6, s9.7 - Atomic Functions for 32-bit integers // --- Table 9.1 --- -foreach Type = [Int, UInt] in { - foreach name = ["atom_add", "atom_sub", "atom_xchg"] in { - def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type]>; +let Extension = FuncExtKhrGlobalInt32BaseAtomics in { + foreach Type = [Int, UInt] in { + foreach name = ["atom_add", "atom_sub", "atom_xchg"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type]>; + } + foreach name = ["atom_inc", "atom_dec"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>]>; + } + foreach name = ["atom_cmpxchg"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type, Type]>; + } + } +} +// --- Table 9.3 --- +let Extension = FuncExtKhrLocalInt32BaseAtomics in { + foreach Type = [Int, UInt] in { + foreach name = ["atom_add", "atom_sub", "atom_xchg"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>, Type]>; + } + foreach name = ["atom_inc", "atom_dec"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>]>; + } + foreach name = ["atom_cmpxchg"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>, Type, Type]>; + } + } +} +// --- Table 9.5 --- +let Extension = FuncExtKhrInt64BaseAtomics in { + foreach AS = [GlobalAS, LocalAS] in { + foreach Type = [Long, ULong] in { + foreach name = ["atom_add", "atom_sub", "atom_xchg"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type]>; + } + foreach name = ["atom_inc", "atom_dec"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>]>; + } + foreach name = ["atom_cmpxchg"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type, Type]>; + } + } } - foreach name = ["atom_inc", "atom_dec"] in { - def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>]>; +} +// --- Table 9.2 --- +let Extension = FuncExtKhrGlobalInt32ExtendedAtomics in { + foreach Type = [Int, UInt] in { + foreach name = ["atom_min", "atom_max", "atom_and", + "atom_or", "atom_xor"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type]>; + } } - foreach name = ["atom_cmpxchg"] in { - def : Builtin<name, [Type, PointerType<VolatileType<Type>, GlobalAS>, Type, Type]>; +} +// --- Table 9.4 --- +let Extension = FuncExtKhrLocalInt32ExtendedAtomics in { + foreach Type = [Int, UInt] in { + foreach name = ["atom_min", "atom_max", "atom_and", + "atom_or", "atom_xor"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, LocalAS>, Type]>; + } } } - -// OpenCL v1.2 s6.12.2: Math Functions -foreach name = ["acos", "acosh", "acospi", - "asin", "asinh", "asinpi", - "atan", "atanh", "atanpi"] in { - def : Builtin<name, [FGenTypeN, FGenTypeN]>; +// --- Table 9.6 --- +let Extension = FuncExtKhrInt64ExtendedAtomics in { + foreach AS = [GlobalAS, LocalAS] in { + foreach Type = [Long, ULong] in { + foreach name = ["atom_min", "atom_max", "atom_and", + "atom_or", "atom_xor"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type]>; + } + } + } } - -foreach name = ["atan2", "atan2pi"] in { - def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>; +// OpenCL v1.1 s6.11.1, v1.2 s6.12.11 - Atomic Functions +foreach AS = [GlobalAS, LocalAS] in { + foreach Type = [Int, UInt] in { + foreach name = ["atomic_add", "atomic_sub", "atomic_xchg", + "atomic_min", "atomic_max", "atomic_and", + "atomic_or", "atomic_xor"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type]>; + } + foreach name = ["atomic_inc", "atomic_dec"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>]>; + } + foreach name = ["atomic_cmpxchg"] in { + def : Builtin<name, [Type, PointerType<VolatileType<Type>, AS>, Type, Type]>; + } + } } -foreach name = ["fmax", "fmin"] in { - def : Builtin<name, [FGenTypeN, FGenTypeN, FGenTypeN]>; - def : Builtin<name, [GenTypeFloatVecNoScalar, GenTypeFloatVecNoScalar, Float]>; - def : Builtin<name, [GenTypeDoubleVecNoScalar, GenTypeDoubleVecNoScalar, Double]>; - def : Builtin<name, [GenTypeHalfVecNoScalar, GenTypeHalfVecNoScalar, Half]>; +//-------------------------------------------------------------------- +// OpenCL v1.1 s6.11.12, v1.2 s6.12.12, v2.0 s6.13.12 - Miscellaneous Vector Functions +// --- Table 19 --- +foreach VSize1 = [Vec2, Vec4, Vec8, Vec16] in { + foreach VSize2 = [Vec2, Vec4, Vec8, Vec16] in { + def : Builtin<"shuffle", [GenericType<"TLAll" # VSize1.Name, TLAll, VSize1>, + GenericType<"TLAll" # VSize2.Name, TLAll, VSize2>, + GenericType<"TLAllUnsigned" # VSize1.Name, TLAllUnsigned, VSize1>], + Attr.Const>; + } } - -// OpenCL v1.1 s6.11.3, v1.2 s6.12.3, v2.0 s6.13.3 - Integer Functions -foreach name = ["max", "min"] in { - def : Builtin<name, [AIGenTypeN, AIGenTypeN, AIGenTypeN]>; - def : Builtin<name, [AIGenTypeNNoScalar, AIGenTypeNNoScalar, AIGenType1]>; +foreach VSize1 = [Vec2, Vec4, Vec8, Vec16] in { + foreach VSize2 = [Vec2, Vec4, Vec8, Vec16] in { + def : Builtin<"shuffle2", [GenericType<"TLAll" # VSize1.Name, TLAll, VSize1>, + GenericType<"TLAll" # VSize2.Name, TLAll, VSize2>, + GenericType<"TLAll" # VSize2.Name, TLAll, VSize2>, + GenericType<"TLAllUnsigned" # VSize1.Name, TLAllUnsigned, VSize1>], + Attr.Const>; + } } //-------------------------------------------------------------------- @@ -517,49 +1004,49 @@ foreach name = ["max", "min"] in { // --- Table 22: Image Read Functions with Samplers --- foreach imgTy = [Image1d] in { foreach coordTy = [Int, Float] in { - def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>; - def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>; - def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, coordTy]>; + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, coordTy], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, coordTy], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, coordTy], Attr.Pure>; } } foreach imgTy = [Image2d, Image1dArray] in { foreach coordTy = [Int, Float] in { - def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>; - def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>; - def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>]>; + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>; } } foreach imgTy = [Image3d, Image2dArray] in { foreach coordTy = [Int, Float] in { - def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>; - def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>; - def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>]>; + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>; } } foreach coordTy = [Int, Float] in { - def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, "RO">, Sampler, VectorType<coordTy, 2>]>; - def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, "RO">, Sampler, VectorType<coordTy, 4>]>; + def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, "RO">, Sampler, VectorType<coordTy, 2>], Attr.Pure>; + def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, "RO">, Sampler, VectorType<coordTy, 4>], Attr.Pure>; } // --- Table 23: Sampler-less Read Functions --- foreach aQual = ["RO", "RW"] in { foreach imgTy = [Image2d, Image1dArray] in { - def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>; - def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>; - def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>; + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>; } foreach imgTy = [Image3d, Image2dArray] in { - def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>; - def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>; - def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>; + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>; } foreach imgTy = [Image1d, Image1dBuffer] in { - def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, Int]>; - def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, Int]>; - def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Int]>; + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>; } - def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>]>; - def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>]>; + def : Builtin<"read_imagef", [Float, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>], Attr.Pure>; + def : Builtin<"read_imagef", [Float, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>], Attr.Pure>; } // --- Table 24: Image Write Functions --- @@ -624,13 +1111,13 @@ foreach aQual = ["RO"] in { foreach name = ["read_imageh"] in { foreach coordTy = [Int, Float] in { foreach imgTy = [Image2d, Image1dArray] in { - def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 2>]>; + def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 2>], Attr.Pure>; } foreach imgTy = [Image3d, Image2dArray] in { - def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 4>]>; + def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<coordTy, 4>], Attr.Pure>; } foreach imgTy = [Image1d] in { - def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, coordTy]>; + def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Sampler, coordTy], Attr.Pure>; } } } @@ -640,13 +1127,13 @@ foreach aQual = ["RO"] in { foreach aQual = ["RO", "RW"] in { foreach name = ["read_imageh"] in { foreach imgTy = [Image2d, Image1dArray] in { - def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>]>; + def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>], Attr.Pure>; } foreach imgTy = [Image3d, Image2dArray] in { - def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>]>; + def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>], Attr.Pure>; } foreach imgTy = [Image1d, Image1dBuffer] in { - def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Int]>; + def : Builtin<name, [VectorType<Half, 4>, ImageType<imgTy, aQual>, Int], Attr.Pure>; } } } @@ -664,11 +1151,201 @@ foreach aQual = ["WO", "RW"] in { } +//-------------------------------------------------------------------- +// OpenCL v2.0 s6.13.15 - Work-group Functions +// --- Table 26 --- +let MinVersion = CL20 in { + foreach name = ["work_group_all", "work_group_any"] in { + def : Builtin<name, [Int, Int], Attr.Convergent>; + } + foreach name = ["work_group_broadcast"] in { + def : Builtin<name, [IntLongFloatGenType1, IntLongFloatGenType1, Size], Attr.Convergent>; + def : Builtin<name, [IntLongFloatGenType1, IntLongFloatGenType1, Size, Size], Attr.Convergent>; + def : Builtin<name, [IntLongFloatGenType1, IntLongFloatGenType1, Size, Size, Size], Attr.Convergent>; + } + foreach op = ["add", "min", "max"] in { + foreach name = ["work_group_reduce_", "work_group_scan_exclusive_", + "work_group_scan_inclusive_"] in { + def : Builtin<name # op, [IntLongFloatGenType1, IntLongFloatGenType1], Attr.Convergent>; + } + } +} + + // OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions let MinVersion = CL20 in { - let Extension = "cl_khr_subgroups" in { + let Extension = FuncExtKhrSubgroups in { def get_sub_group_size : Builtin<"get_sub_group_size", [UInt]>; def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [UInt]>; def get_num_sub_groups : Builtin<"get_num_sub_groups", [UInt]>; } } + +//-------------------------------------------------------------------- +// End of the builtin functions defined in the OpenCL C specification. +// Builtin functions defined in the OpenCL C Extension are below. +//-------------------------------------------------------------------- + + +// OpenCL Extension v2.0 s9.18 - Mipmaps +let Extension = FuncExtKhrMipmapImage in { + // Added to section 6.13.14.2. + foreach aQual = ["RO"] in { + foreach imgTy = [Image2d] in { + foreach name = ["read_imagef"] in { + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>; + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>; + } + foreach name = ["read_imagei"] in { + def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>; + def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>; + } + foreach name = ["read_imageui"] in { + def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>; + def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>; + } + } + foreach imgTy = [Image2dDepth] in { + foreach name = ["read_imagef"] in { + def : Builtin<name, [Float, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>; + def : Builtin<name, [Float, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>; + } + } + foreach imgTy = [Image1d] in { + foreach name = ["read_imagef"] in { + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float], Attr.Pure>; + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float, Float], Attr.Pure>; + } + foreach name = ["read_imagei"] in { + def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float], Attr.Pure>; + def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float, Float], Attr.Pure>; + } + foreach name = ["read_imageui"] in { + def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float], Attr.Pure>; + def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, Float, Float, Float], Attr.Pure>; + } + } + foreach imgTy = [Image3d] in { + foreach name = ["read_imagef"] in { + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 4>, VectorType<Float, 4>], Attr.Pure>; + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>; + } + foreach name = ["read_imagei"] in { + def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 4>, VectorType<Float, 4>], Attr.Pure>; + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>; + } + foreach name = ["read_imageui"] in { + def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 4>, VectorType<Float, 4>], Attr.Pure>; + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>; + } + } + foreach imgTy = [Image1dArray] in { + foreach name = ["read_imagef"] in { + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>; + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float, Float], Attr.Pure>; + } + foreach name = ["read_imagei"] in { + def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>; + def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float, Float], Attr.Pure>; + } + foreach name = ["read_imageui"] in { + def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float], Attr.Pure>; + def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 2>, Float, Float], Attr.Pure>; + } + } + foreach imgTy = [Image2dArray] in { + foreach name = ["read_imagef"] in { + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>; + def : Builtin<name, [VectorType<Float, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>; + } + foreach name = ["read_imagei"] in { + def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>; + def : Builtin<name, [VectorType<Int, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>; + } + foreach name = ["read_imageui"] in { + def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>; + def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>; + } + } + foreach imgTy = [Image2dArrayDepth] in { + foreach name = ["read_imagef"] in { + def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, Float], Attr.Pure>; + def : Builtin<name, [VectorType<UInt, 4>, ImageType<imgTy, aQual>, Sampler, VectorType<Float, 4>, VectorType<Float, 2>, VectorType<Float, 2>], Attr.Pure>; + } + } + } + // Added to section 6.13.14.4. + foreach aQual = ["WO"] in { + foreach imgTy = [Image2d] in { + def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Float, 4>]>; + def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Int, 4>]>; + def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<UInt, 4>]>; + } + def : Builtin<"write_imagef", [Void, ImageType<Image2dDepth, aQual>, VectorType<Int, 2>, Int, Float]>; + foreach imgTy = [Image1d] in { + def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, Int, Int, VectorType<Float, 4>]>; + def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, Int, Int, VectorType<Int, 4>]>; + def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, Int, Int, VectorType<UInt, 4>]>; + } + foreach imgTy = [Image1dArray] in { + def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Float, 4>]>; + def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<Int, 4>]>; + def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int, VectorType<UInt, 4>]>; + } + foreach imgTy = [Image2dArray] in { + def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Float, 4>]>; + def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Int, 4>]>; + def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<UInt, 4>]>; + } + def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, Int, Float]>; + let Extension = FuncExtKhrMipmapAndWrite3d in { + foreach imgTy = [Image3d] in { + def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Float, 4>]>; + def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Int, 4>]>; + def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<UInt, 4>]>; + } + } + } + // Added to section 6.13.14.5 + foreach aQual = ["RO", "WO", "RW"] in { + foreach imgTy = [Image1d, Image2d, Image3d, Image1dArray, Image2dArray, Image2dDepth, Image2dArrayDepth] in { + def : Builtin<"get_image_num_mip_levels", [Int, ImageType<imgTy, aQual>]>; + } + } +} + + +//-------------------------------------------------------------------- +// OpenCL Extension v2.0 s18.3 - Creating OpenCL Memory Objects from OpenGL MSAA Textures +let Extension = FuncExtKhrGlMsaaSharing in { + // --- Table 6.13.14.3 --- + foreach aQual = ["RO", "RW"] in { + foreach imgTy = [Image2dMsaa] in { + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; + } + foreach imgTy = [Image2dArrayMsaa] in { + def : Builtin<"read_imagef", [VectorType<Float, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; + def : Builtin<"read_imagei", [VectorType<Int, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; + def : Builtin<"read_imageui", [VectorType<UInt, 4>, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; + } + foreach name = ["read_imagef"] in { + def : Builtin<name, [Float, ImageType<Image2dMsaaDepth, aQual>, VectorType<Int, 2>, Int], Attr.Pure>; + def : Builtin<name, [Float, ImageType<Image2dArrayMsaaDepth, aQual>, VectorType<Int, 4>, Int], Attr.Pure>; + } + } + + // --- Table 6.13.14.5 --- + foreach aQual = ["RO", "WO", "RW"] in { + foreach imgTy = [Image2dMsaa, Image2dArrayMsaa, Image2dMsaaDepth, Image2dArrayMsaaDepth] in { + foreach name = ["get_image_width", "get_image_height", + "get_image_channel_data_type", "get_image_channel_order", + "get_image_num_samples"] in { + def : Builtin<name, [Int, ImageType<imgTy, aQual>], Attr.Const>; + } + def : Builtin<"get_image_dim", [VectorType<Int, 2>, ImageType<imgTy, aQual>], Attr.Const>; + } + def : Builtin<"get_image_array_size", [Size, ImageType<Image2dArrayMsaaDepth, aQual>], Attr.Const>; + } +} diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index bedea2167950..2cd158a8b43c 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -137,7 +137,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, OriginalLexicalContext(nullptr), MSStructPragmaOn(false), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), - VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), PackStack(0), + VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0), DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr), CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr), @@ -189,6 +189,9 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, SemaPPCallbackHandler->set(*this); } +// Anchor Sema's type info to this TU. +void Sema::anchor() {} + void Sema::addImplicitTypedef(StringRef Name, QualType T) { DeclarationName DN = &Context.Idents.get(Name); if (IdResolver.begin(DN) == IdResolver.end()) @@ -921,8 +924,7 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { } { - llvm::TimeTraceScope TimeScope("PerformPendingInstantiations", - StringRef("")); + llvm::TimeTraceScope TimeScope("PerformPendingInstantiations"); PerformPendingInstantiations(); } @@ -1134,6 +1136,13 @@ void Sema::ActOnEndOfTranslationUnit() { Consumer.CompleteTentativeDefinition(VD); } + for (auto D : ExternalDeclarations) { + if (!D || D->isInvalidDecl() || D->getPreviousDecl() || !D->isUsed()) + continue; + + Consumer.CompleteExternalDeclaration(D); + } + // If there were errors, disable 'unused' warnings since they will mostly be // noise. Don't warn for a use from a module: either we should warn on all // file-scope declarations in modules or not at all, but whether the @@ -1287,6 +1296,12 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() { return nullptr; } +LangAS Sema::getDefaultCXXMethodAddrSpace() const { + if (getLangOpts().OpenCL) + return LangAS::opencl_generic; + return LangAS::Default; +} + void Sema::EmitCurrentDiagnostic(unsigned DiagID) { // FIXME: It doesn't make sense to me that DiagID is an incoming argument here // and yet we also use the current diag ID on the DiagnosticsEngine. This has @@ -1902,6 +1917,7 @@ void Sema::ActOnComment(SourceRange Comment) { // Pin this vtable to this file. ExternalSemaSource::~ExternalSemaSource() {} +char ExternalSemaSource::ID; void ExternalSemaSource::ReadMethodPool(Selector Sel) { } void ExternalSemaSource::updateOutOfDateSelector(Selector Sel) { } diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index 9dbb93322b7d..bd15b81cbed0 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -1560,21 +1560,24 @@ Sema::AccessResult Sema::CheckUnresolvedMemberAccess(UnresolvedMemberExpr *E, return CheckAccess(*this, E->getMemberLoc(), Entity); } -/// Is the given special member function accessible for the purposes of -/// deciding whether to define a special member function as deleted? -bool Sema::isSpecialMemberAccessibleForDeletion(CXXMethodDecl *decl, - AccessSpecifier access, - QualType objectType) { +/// Is the given member accessible for the purposes of deciding whether to +/// define a special member function as deleted? +bool Sema::isMemberAccessibleForDeletion(CXXRecordDecl *NamingClass, + DeclAccessPair Found, + QualType ObjectType, + SourceLocation Loc, + const PartialDiagnostic &Diag) { // Fast path. - if (access == AS_public || !getLangOpts().AccessControl) return true; + if (Found.getAccess() == AS_public || !getLangOpts().AccessControl) + return true; - AccessTarget entity(Context, AccessTarget::Member, decl->getParent(), - DeclAccessPair::make(decl, access), objectType); + AccessTarget Entity(Context, AccessTarget::Member, NamingClass, Found, + ObjectType); // Suppress diagnostics. - entity.setDiag(PDiag()); + Entity.setDiag(Diag); - switch (CheckAccess(*this, SourceLocation(), entity)) { + switch (CheckAccess(*this, Loc, Entity)) { case AR_accessible: return true; case AR_inaccessible: return false; case AR_dependent: llvm_unreachable("dependent for =delete computation"); diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 70186c966f8f..cd2a65276b09 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -80,9 +80,9 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) { // FIXME: We should merge AddAlignmentAttributesForRecord with // AddMsStructLayoutForRecord into AddPragmaAttributesForRecord, which takes // all active pragmas and applies them as attributes to class definitions. - if (VtorDispStack.CurrentValue != getLangOpts().VtorDispMode) - RD->addAttr( - MSVtorDispAttr::CreateImplicit(Context, VtorDispStack.CurrentValue)); + if (VtorDispStack.CurrentValue != getLangOpts().getVtorDispMode()) + RD->addAttr(MSVtorDispAttr::CreateImplicit( + Context, unsigned(VtorDispStack.CurrentValue))); } template <typename Attribute> @@ -416,7 +416,7 @@ void Sema::ActOnPragmaMSPointersToMembers( void Sema::ActOnPragmaMSVtorDisp(PragmaMsStackAction Action, SourceLocation PragmaLoc, - MSVtorDispAttr::Mode Mode) { + MSVtorDispMode Mode) { if (Action & PSK_Pop && VtorDispStack.Stack.empty()) Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp" << "stack empty"; diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index d0ddfd040c9c..0c61057e1072 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -492,6 +492,8 @@ void Sema::checkAllowedCUDAInitializer(VarDecl *VD) { const Expr *Init = VD->getInit(); if (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() || VD->hasAttr<CUDASharedAttr>()) { + if (LangOpts.GPUAllowDeviceInit) + return; assert(!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>()); bool AllowedInit = false; if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 0ebb5c68f7c2..a905ebc67305 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -423,7 +423,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, case OR_Ambiguous: msg = diag::err_ovl_ambiguous_conversion_in_cast; - howManyCandidates = OCD_ViableCandidates; + howManyCandidates = OCD_AmbiguousCandidates; break; case OR_Deleted: @@ -740,7 +740,7 @@ void CastOperation::CheckDynamicCast() { assert(DestPointer && "Reference to void is not possible"); } else if (DestRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), DestPointee, - diag::err_bad_dynamic_cast_incomplete, + diag::err_bad_cast_incomplete, DestRange)) { SrcExpr = ExprError(); return; @@ -763,7 +763,7 @@ void CastOperation::CheckDynamicCast() { SrcPointee = SrcPointer->getPointeeType(); } else { Self.Diag(OpRange.getBegin(), diag::err_bad_dynamic_cast_not_ptr) - << OrigSrcType << SrcExpr.get()->getSourceRange(); + << OrigSrcType << this->DestType << SrcExpr.get()->getSourceRange(); SrcExpr = ExprError(); return; } @@ -785,7 +785,7 @@ void CastOperation::CheckDynamicCast() { const RecordType *SrcRecord = SrcPointee->getAs<RecordType>(); if (SrcRecord) { if (Self.RequireCompleteType(OpRange.getBegin(), SrcPointee, - diag::err_bad_dynamic_cast_incomplete, + diag::err_bad_cast_incomplete, SrcExpr.get())) { SrcExpr = ExprError(); return; @@ -1182,6 +1182,11 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // The same goes for reverse floating point promotion/conversion and // floating-integral conversions. Again, only floating->enum is relevant. if (DestType->isEnumeralType()) { + if (Self.RequireCompleteType(OpRange.getBegin(), DestType, + diag::err_bad_cast_incomplete)) { + SrcExpr = ExprError(); + return TC_Failed; + } if (SrcType->isIntegralOrEnumerationType()) { Kind = CK_IntegralCast; return TC_Success; @@ -1301,10 +1306,6 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, // Because we try the reference downcast before this function, from now on // this is the only cast possibility, so we issue an error if we fail now. // FIXME: Should allow casting away constness if CStyle. - bool DerivedToBase; - bool ObjCConversion; - bool ObjCLifetimeConversion; - bool FunctionConversion; QualType FromType = SrcExpr->getType(); QualType ToType = R->getPointeeType(); if (CStyle) { @@ -1312,9 +1313,9 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, ToType = ToType.getUnqualifiedType(); } + Sema::ReferenceConversions RefConv; Sema::ReferenceCompareResult RefResult = Self.CompareReferenceRelationship( - SrcExpr->getBeginLoc(), ToType, FromType, DerivedToBase, ObjCConversion, - ObjCLifetimeConversion, FunctionConversion); + SrcExpr->getBeginLoc(), ToType, FromType, &RefConv); if (RefResult != Sema::Ref_Compatible) { if (CStyle || RefResult == Sema::Ref_Incompatible) return TC_NotApplicable; @@ -1326,7 +1327,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, return TC_Failed; } - if (DerivedToBase) { + if (RefConv & Sema::ReferenceConversions::DerivedToBase) { Kind = CK_DerivedToBase; CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, /*DetectVirtual=*/true); @@ -1651,7 +1652,7 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, CastKind &Kind, bool ListInitialization) { if (DestType->isRecordType()) { if (Self.RequireCompleteType(OpRange.getBegin(), DestType, - diag::err_bad_dynamic_cast_incomplete) || + diag::err_bad_cast_incomplete) || Self.RequireNonAbstractType(OpRange.getBegin(), DestType, diag::err_allocation_of_abstract_type)) { msg = 0; @@ -2007,7 +2008,7 @@ static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType, // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization // preserves Result. Result = E; - if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate( + if (!Self.resolveAndFixAddressOfSingleOverloadCandidate( Result, /*DoFunctionPointerConversion=*/true)) return false; return Result.isUsable(); diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index dca81d1d275f..74742023d1b3 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -201,6 +201,87 @@ static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) { return false; } +/// Check that the value argument for __builtin_is_aligned(value, alignment) and +/// __builtin_aligned_{up,down}(value, alignment) is an integer or a pointer +/// type (but not a function pointer) and that the alignment is a power-of-two. +static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { + if (checkArgCount(S, TheCall, 2)) + return true; + + clang::Expr *Source = TheCall->getArg(0); + bool IsBooleanAlignBuiltin = ID == Builtin::BI__builtin_is_aligned; + + auto IsValidIntegerType = [](QualType Ty) { + return Ty->isIntegerType() && !Ty->isEnumeralType() && !Ty->isBooleanType(); + }; + QualType SrcTy = Source->getType(); + // We should also be able to use it with arrays (but not functions!). + if (SrcTy->canDecayToPointerType() && SrcTy->isArrayType()) { + SrcTy = S.Context.getDecayedType(SrcTy); + } + if ((!SrcTy->isPointerType() && !IsValidIntegerType(SrcTy)) || + SrcTy->isFunctionPointerType()) { + // FIXME: this is not quite the right error message since we don't allow + // floating point types, or member pointers. + S.Diag(Source->getExprLoc(), diag::err_typecheck_expect_scalar_operand) + << SrcTy; + return true; + } + + clang::Expr *AlignOp = TheCall->getArg(1); + if (!IsValidIntegerType(AlignOp->getType())) { + S.Diag(AlignOp->getExprLoc(), diag::err_typecheck_expect_int) + << AlignOp->getType(); + return true; + } + Expr::EvalResult AlignResult; + unsigned MaxAlignmentBits = S.Context.getIntWidth(SrcTy) - 1; + // We can't check validity of alignment if it is type dependent. + if (!AlignOp->isInstantiationDependent() && + AlignOp->EvaluateAsInt(AlignResult, S.Context, + Expr::SE_AllowSideEffects)) { + llvm::APSInt AlignValue = AlignResult.Val.getInt(); + llvm::APSInt MaxValue( + llvm::APInt::getOneBitSet(MaxAlignmentBits + 1, MaxAlignmentBits)); + if (AlignValue < 1) { + S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_small) << 1; + return true; + } + if (llvm::APSInt::compareValues(AlignValue, MaxValue) > 0) { + S.Diag(AlignOp->getExprLoc(), diag::err_alignment_too_big) + << MaxValue.toString(10); + return true; + } + if (!AlignValue.isPowerOf2()) { + S.Diag(AlignOp->getExprLoc(), diag::err_alignment_not_power_of_two); + return true; + } + if (AlignValue == 1) { + S.Diag(AlignOp->getExprLoc(), diag::warn_alignment_builtin_useless) + << IsBooleanAlignBuiltin; + } + } + + ExprResult SrcArg = S.PerformCopyInitialization( + InitializedEntity::InitializeParameter(S.Context, SrcTy, false), + SourceLocation(), Source); + if (SrcArg.isInvalid()) + return true; + TheCall->setArg(0, SrcArg.get()); + ExprResult AlignArg = + S.PerformCopyInitialization(InitializedEntity::InitializeParameter( + S.Context, AlignOp->getType(), false), + SourceLocation(), AlignOp); + if (AlignArg.isInvalid()) + return true; + TheCall->setArg(1, AlignArg.get()); + // For align_up/align_down, the return type is the same as the (potentially + // decayed) argument type including qualifiers. For is_aligned(), the result + // is always bool. + TheCall->setType(IsBooleanAlignBuiltin ? S.Context.BoolTy : SrcTy); + return false; +} + static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 3)) return true; @@ -340,7 +421,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, case Builtin::BI__builtin___strncat_chk: case Builtin::BI__builtin___strncpy_chk: case Builtin::BI__builtin___stpncpy_chk: - case Builtin::BI__builtin___memccpy_chk: { + case Builtin::BI__builtin___memccpy_chk: + case Builtin::BI__builtin___mempcpy_chk: { DiagID = diag::warn_builtin_chk_overflow; IsChkVariant = true; SizeIndex = TheCall->getNumArgs() - 2; @@ -379,7 +461,9 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, case Builtin::BImemmove: case Builtin::BI__builtin_memmove: case Builtin::BImemset: - case Builtin::BI__builtin_memset: { + case Builtin::BI__builtin_memset: + case Builtin::BImempcpy: + case Builtin::BI__builtin_mempcpy: { DiagID = diag::warn_fortify_source_overflow; SizeIndex = TheCall->getNumArgs() - 1; ObjectIndex = 0; @@ -1354,6 +1438,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinAddressof(*this, TheCall)) return ExprError(); break; + case Builtin::BI__builtin_is_aligned: + case Builtin::BI__builtin_align_up: + case Builtin::BI__builtin_align_down: + if (SemaBuiltinAlignment(*this, TheCall, BuiltinID)) + return ExprError(); + break; case Builtin::BI__builtin_add_overflow: case Builtin::BI__builtin_sub_overflow: case Builtin::BI__builtin_mul_overflow: @@ -1536,6 +1626,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: case llvm::Triple::aarch64_be: if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) return ExprError(); @@ -1685,6 +1776,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch(); bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 || + Arch == llvm::Triple::aarch64_32 || Arch == llvm::Triple::aarch64_be; bool IsInt64Long = Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong; @@ -1717,6 +1809,14 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +bool Sema::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { + switch (BuiltinID) { + default: + return false; + #include "clang/Basic/arm_mve_builtin_sema.inc" + } +} + bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, unsigned MaxWidth) { assert((BuiltinID == ARM::BI__builtin_arm_ldrex || @@ -1857,6 +1957,8 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) return true; + if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall)) + return true; // For intrinsics which take an immediate value as part of the instruction, // range check them here. @@ -3039,8 +3141,37 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CheckHexagonBuiltinArgument(BuiltinID, TheCall); } +bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { + return CheckMipsBuiltinCpu(BuiltinID, TheCall) || + CheckMipsBuiltinArgument(BuiltinID, TheCall); +} + +bool Sema::CheckMipsBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) { + const TargetInfo &TI = Context.getTargetInfo(); + + if (Mips::BI__builtin_mips_addu_qb <= BuiltinID && + BuiltinID <= Mips::BI__builtin_mips_lwx) { + if (!TI.hasFeature("dsp")) + return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_dsp); + } + + if (Mips::BI__builtin_mips_absq_s_qb <= BuiltinID && + BuiltinID <= Mips::BI__builtin_mips_subuh_r_qb) { + if (!TI.hasFeature("dspr2")) + return Diag(TheCall->getBeginLoc(), + diag::err_mips_builtin_requires_dspr2); + } -// CheckMipsBuiltinFunctionCall - Checks the constant value passed to the + if (Mips::BI__builtin_msa_add_a_b <= BuiltinID && + BuiltinID <= Mips::BI__builtin_msa_xori_b) { + if (!TI.hasFeature("msa")) + return Diag(TheCall->getBeginLoc(), diag::err_mips_builtin_requires_msa); + } + + return false; +} + +// CheckMipsBuiltinArgument - Checks the constant value passed to the // intrinsic is correct. The switch statement is ordered by DSP, MSA. The // ordering for DSP is unspecified. MSA is ordered by the data format used // by the underlying instruction i.e., df/m, df/n and then by size. @@ -3049,7 +3180,7 @@ bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, // definitions from include/clang/Basic/BuiltinsMips.def. // FIXME: GCC is strict on signedness for some of these intrinsics, we should // be too. -bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { +bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { unsigned i = 0, l = 0, u = 0, m = 0; switch (BuiltinID) { default: return false; @@ -4560,20 +4691,19 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, && sizeof(NumVals)/sizeof(NumVals[0]) == NumForm, "need to update code for modified forms"); static_assert(AtomicExpr::AO__c11_atomic_init == 0 && - AtomicExpr::AO__c11_atomic_fetch_xor + 1 == + AtomicExpr::AO__c11_atomic_fetch_min + 1 == AtomicExpr::AO__atomic_load, "need to update code for modified C11 atomics"); bool IsOpenCL = Op >= AtomicExpr::AO__opencl_atomic_init && Op <= AtomicExpr::AO__opencl_atomic_fetch_max; bool IsC11 = (Op >= AtomicExpr::AO__c11_atomic_init && - Op <= AtomicExpr::AO__c11_atomic_fetch_xor) || + Op <= AtomicExpr::AO__c11_atomic_fetch_min) || IsOpenCL; bool IsN = Op == AtomicExpr::AO__atomic_load_n || Op == AtomicExpr::AO__atomic_store_n || Op == AtomicExpr::AO__atomic_exchange_n || Op == AtomicExpr::AO__atomic_compare_exchange_n; bool IsAddSub = false; - bool IsMinMax = false; switch (Op) { case AtomicExpr::AO__c11_atomic_init: @@ -4602,8 +4732,6 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, case AtomicExpr::AO__c11_atomic_fetch_sub: case AtomicExpr::AO__opencl_atomic_fetch_add: case AtomicExpr::AO__opencl_atomic_fetch_sub: - case AtomicExpr::AO__opencl_atomic_fetch_min: - case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__atomic_fetch_add: case AtomicExpr::AO__atomic_fetch_sub: case AtomicExpr::AO__atomic_add_fetch: @@ -4624,12 +4752,14 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, case AtomicExpr::AO__atomic_or_fetch: case AtomicExpr::AO__atomic_xor_fetch: case AtomicExpr::AO__atomic_nand_fetch: - Form = Arithmetic; - break; - + case AtomicExpr::AO__c11_atomic_fetch_min: + case AtomicExpr::AO__c11_atomic_fetch_max: + case AtomicExpr::AO__opencl_atomic_fetch_min: + case AtomicExpr::AO__opencl_atomic_fetch_max: + case AtomicExpr::AO__atomic_min_fetch: + case AtomicExpr::AO__atomic_max_fetch: case AtomicExpr::AO__atomic_fetch_min: case AtomicExpr::AO__atomic_fetch_max: - IsMinMax = true; Form = Arithmetic; break; @@ -4721,16 +4851,8 @@ ExprResult Sema::BuildAtomicExpr(SourceRange CallRange, SourceRange ExprRange, << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } - if (IsMinMax) { - const BuiltinType *BT = ValType->getAs<BuiltinType>(); - if (!BT || (BT->getKind() != BuiltinType::Int && - BT->getKind() != BuiltinType::UInt)) { - Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_int32_or_ptr); - return ExprError(); - } - } - if (!IsAddSub && !IsMinMax && !ValType->isIntegerType()) { - Diag(ExprRange.getBegin(), diag::err_atomic_op_bitwise_needs_atomic_int) + if (!IsAddSub && !ValType->isIntegerType()) { + Diag(ExprRange.getBegin(), diag::err_atomic_op_needs_atomic_int) << IsC11 << Ptr->getType() << Ptr->getSourceRange(); return ExprError(); } @@ -5506,7 +5628,8 @@ ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) { static bool checkVAStartABI(Sema &S, unsigned BuiltinID, Expr *Fn) { const llvm::Triple &TT = S.Context.getTargetInfo().getTriple(); bool IsX64 = TT.getArch() == llvm::Triple::x86_64; - bool IsAArch64 = TT.getArch() == llvm::Triple::aarch64; + bool IsAArch64 = (TT.getArch() == llvm::Triple::aarch64 || + TT.getArch() == llvm::Triple::aarch64_32); bool IsWindows = TT.isOSWindows(); bool IsMSVAStart = BuiltinID == Builtin::BI__builtin_ms_va_start; if (IsX64 || IsAArch64) { @@ -5723,7 +5846,8 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall) { // Do standard promotions between the two arguments, returning their common // type. - QualType Res = UsualArithmeticConversions(OrigArg0, OrigArg1, false); + QualType Res = UsualArithmeticConversions( + OrigArg0, OrigArg1, TheCall->getExprLoc(), ACK_Comparison); if (OrigArg0.isInvalid() || OrigArg1.isInvalid()) return true; @@ -5763,36 +5887,41 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { << SourceRange(TheCall->getArg(NumArgs)->getBeginLoc(), (*(TheCall->arg_end() - 1))->getEndLoc()); + // __builtin_fpclassify is the only case where NumArgs != 1, so we can count + // on all preceding parameters just being int. Try all of those. + for (unsigned i = 0; i < NumArgs - 1; ++i) { + Expr *Arg = TheCall->getArg(i); + + if (Arg->isTypeDependent()) + return false; + + ExprResult Res = PerformImplicitConversion(Arg, Context.IntTy, AA_Passing); + + if (Res.isInvalid()) + return true; + TheCall->setArg(i, Res.get()); + } + Expr *OrigArg = TheCall->getArg(NumArgs-1); if (OrigArg->isTypeDependent()) return false; + // Usual Unary Conversions will convert half to float, which we want for + // machines that use fp16 conversion intrinsics. Else, we wnat to leave the + // type how it is, but do normal L->Rvalue conversions. + if (Context.getTargetInfo().useFP16ConversionIntrinsics()) + OrigArg = UsualUnaryConversions(OrigArg).get(); + else + OrigArg = DefaultFunctionArrayLvalueConversion(OrigArg).get(); + TheCall->setArg(NumArgs - 1, OrigArg); + // This operation requires a non-_Complex floating-point number. if (!OrigArg->getType()->isRealFloatingType()) return Diag(OrigArg->getBeginLoc(), diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); - // If this is an implicit conversion from float -> float, double, or - // long double, remove it. - if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) { - // Only remove standard FloatCasts, leaving other casts inplace - if (Cast->getCastKind() == CK_FloatingCast) { - Expr *CastArg = Cast->getSubExpr(); - if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { - assert( - (Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || - Cast->getType()->isSpecificBuiltinType(BuiltinType::Float) || - Cast->getType()->isSpecificBuiltinType(BuiltinType::LongDouble)) && - "promotion from float to either float, double, or long double is " - "the only expected cast here"); - Cast->setSubExpr(nullptr); - TheCall->setArg(NumArgs-1, CastArg); - } - } - } - return false; } @@ -6235,6 +6364,101 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, return false; } +/// SemaBuiltinConstantArgPower2 - Check if argument ArgNum of TheCall is a +/// constant expression representing a power of 2. +bool Sema::SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum) { + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + // Bit-twiddling to test for a power of 2: for x > 0, x & (x-1) is zero if + // and only if x is a power of 2. + if (Result.isStrictlyPositive() && (Result & (Result - 1)) == 0) + return false; + + return Diag(TheCall->getBeginLoc(), diag::err_argument_not_power_of_2) + << Arg->getSourceRange(); +} + +static bool IsShiftedByte(llvm::APSInt Value) { + if (Value.isNegative()) + return false; + + // Check if it's a shifted byte, by shifting it down + while (true) { + // If the value fits in the bottom byte, the check passes. + if (Value < 0x100) + return true; + + // Otherwise, if the value has _any_ bits in the bottom byte, the check + // fails. + if ((Value & 0xFF) != 0) + return false; + + // If the bottom 8 bits are all 0, but something above that is nonzero, + // then shifting the value right by 8 bits won't affect whether it's a + // shifted byte or not. So do that, and go round again. + Value >>= 8; + } +} + +/// SemaBuiltinConstantArgShiftedByte - Check if argument ArgNum of TheCall is +/// a constant expression representing an arbitrary byte value shifted left by +/// a multiple of 8 bits. +bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum) { + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + if (IsShiftedByte(Result)) + return false; + + return Diag(TheCall->getBeginLoc(), diag::err_argument_not_shifted_byte) + << Arg->getSourceRange(); +} + +/// SemaBuiltinConstantArgShiftedByteOr0xFF - Check if argument ArgNum of +/// TheCall is a constant expression representing either a shifted byte value, +/// or a value of the form 0x??FF (i.e. a member of the arithmetic progression +/// 0x00FF, 0x01FF, ..., 0xFFFF). This strange range check is needed for some +/// Arm MVE intrinsics. +bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, + int ArgNum) { + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + // Check to see if it's in either of the required forms. + if (IsShiftedByte(Result) || + (Result > 0 && Result < 0x10000 && (Result & 0xFF) == 0xFF)) + return false; + + return Diag(TheCall->getBeginLoc(), + diag::err_argument_not_shifted_byte_or_xxff) + << Arg->getSourceRange(); +} + /// SemaBuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == AArch64::BI__builtin_arm_irg) { @@ -9162,7 +9386,7 @@ void Sema::CheckMaxUnsignedZero(const CallExpr *Call, auto IsLiteralZeroArg = [](const Expr* E) -> bool { const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E); if (!MTE) return false; - const auto *Num = dyn_cast<IntegerLiteral>(MTE->GetTemporaryExpr()); + const auto *Num = dyn_cast<IntegerLiteral>(MTE->getSubExpr()); if (!Num) return false; if (Num->getValue() != 0) return false; return true; @@ -11371,32 +11595,6 @@ static const IntegerLiteral *getIntegerLiteral(Expr *E) { return IL; } -static void CheckConditionalWithEnumTypes(Sema &S, SourceLocation Loc, - Expr *LHS, Expr *RHS) { - QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType(); - QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType(); - - const auto *LHSEnumType = LHSStrippedType->getAs<EnumType>(); - if (!LHSEnumType) - return; - const auto *RHSEnumType = RHSStrippedType->getAs<EnumType>(); - if (!RHSEnumType) - return; - - // Ignore anonymous enums. - if (!LHSEnumType->getDecl()->hasNameForLinkage()) - return; - if (!RHSEnumType->getDecl()->hasNameForLinkage()) - return; - - if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) - return; - - S.Diag(Loc, diag::warn_conditional_mixed_enum_types) - << LHSStrippedType << RHSStrippedType << LHS->getSourceRange() - << RHS->getSourceRange(); -} - static void DiagnoseIntInBoolContext(Sema &S, Expr *E) { E = E->IgnoreParenImpCasts(); SourceLocation ExprLoc = E->getExprLoc(); @@ -11737,7 +11935,7 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; if (isObjCSignedCharBool(S, T) && !Source->isCharType() && - !E->isKnownToHaveBooleanValue()) { + !E->isKnownToHaveBooleanValue(/*Semantic=*/false)) { return adornObjCBoolConversionDiagWithTernaryFixit( S, E, S.Diag(CC, diag::warn_impcast_int_to_objc_signed_char_bool) @@ -11888,8 +12086,6 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, bool Suspicious = false; CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious); CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious); - CheckConditionalWithEnumTypes(S, E->getBeginLoc(), E->getTrueExpr(), - E->getFalseExpr()); if (T->isBooleanType()) DiagnoseIntInBoolContext(S, E); @@ -12360,8 +12556,8 @@ namespace { /// Visitor for expressions which looks for unsequenced operations on the /// same object. -class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { - using Base = EvaluatedExprVisitor<SequenceChecker>; +class SequenceChecker : public ConstEvaluatedExprVisitor<SequenceChecker> { + using Base = ConstEvaluatedExprVisitor<SequenceChecker>; /// A tree of sequenced regions within an expression. Two regions are /// unsequenced if one is an ancestor or a descendent of the other. When we @@ -12431,7 +12627,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { }; /// An object for which we can track unsequenced uses. - using Object = NamedDecl *; + using Object = const NamedDecl *; /// Different flavors of object usage which we track. We only track the /// least-sequenced usage of each kind. @@ -12450,17 +12646,19 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { UK_Count = UK_ModAsSideEffect + 1 }; + /// Bundle together a sequencing region and the expression corresponding + /// to a specific usage. One Usage is stored for each usage kind in UsageInfo. struct Usage { - Expr *Use; + const Expr *UsageExpr; SequenceTree::Seq Seq; - Usage() : Use(nullptr), Seq() {} + Usage() : UsageExpr(nullptr), Seq() {} }; struct UsageInfo { Usage Uses[UK_Count]; - /// Have we issued a diagnostic for this variable already? + /// Have we issued a diagnostic for this object already? bool Diagnosed; UsageInfo() : Uses(), Diagnosed(false) {} @@ -12484,7 +12682,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { /// Expressions to check later. We defer checking these to reduce /// stack usage. - SmallVectorImpl<Expr *> &WorkList; + SmallVectorImpl<const Expr *> &WorkList; /// RAII object wrapping the visitation of a sequenced subexpression of an /// expression. At the end of this process, the side-effects of the evaluation @@ -12498,10 +12696,13 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { } ~SequencedSubexpression() { - for (auto &M : llvm::reverse(ModAsSideEffect)) { - UsageInfo &U = Self.UsageMap[M.first]; - auto &SideEffectUsage = U.Uses[UK_ModAsSideEffect]; - Self.addUsage(U, M.first, SideEffectUsage.Use, UK_ModAsValue); + for (const std::pair<Object, Usage> &M : llvm::reverse(ModAsSideEffect)) { + // Add a new usage with usage kind UK_ModAsValue, and then restore + // the previous usage with UK_ModAsSideEffect (thus clearing it if + // the previous one was empty). + UsageInfo &UI = Self.UsageMap[M.first]; + auto &SideEffectUsage = UI.Uses[UK_ModAsSideEffect]; + Self.addUsage(M.first, UI, SideEffectUsage.UsageExpr, UK_ModAsValue); SideEffectUsage = M.second; } Self.ModAsSideEffect = OldModAsSideEffect; @@ -12545,49 +12746,60 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { /// Find the object which is produced by the specified expression, /// if any. - Object getObject(Expr *E, bool Mod) const { + Object getObject(const Expr *E, bool Mod) const { E = E->IgnoreParenCasts(); - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { if (Mod && (UO->getOpcode() == UO_PreInc || UO->getOpcode() == UO_PreDec)) return getObject(UO->getSubExpr(), Mod); - } else if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + } else if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { if (BO->getOpcode() == BO_Comma) return getObject(BO->getRHS(), Mod); if (Mod && BO->isAssignmentOp()) return getObject(BO->getLHS(), Mod); - } else if (MemberExpr *ME = dyn_cast<MemberExpr>(E)) { + } else if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { // FIXME: Check for more interesting cases, like "x.n = ++x.n". if (isa<CXXThisExpr>(ME->getBase()->IgnoreParenCasts())) return ME->getMemberDecl(); - } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) + } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) // FIXME: If this is a reference, map through to its value. return DRE->getDecl(); return nullptr; } - /// Note that an object was modified or used by an expression. - void addUsage(UsageInfo &UI, Object O, Expr *Ref, UsageKind UK) { + /// Note that an object \p O was modified or used by an expression + /// \p UsageExpr with usage kind \p UK. \p UI is the \p UsageInfo for + /// the object \p O as obtained via the \p UsageMap. + void addUsage(Object O, UsageInfo &UI, const Expr *UsageExpr, UsageKind UK) { + // Get the old usage for the given object and usage kind. Usage &U = UI.Uses[UK]; - if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) { + if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) { + // If we have a modification as side effect and are in a sequenced + // subexpression, save the old Usage so that we can restore it later + // in SequencedSubexpression::~SequencedSubexpression. if (UK == UK_ModAsSideEffect && ModAsSideEffect) ModAsSideEffect->push_back(std::make_pair(O, U)); - U.Use = Ref; + // Then record the new usage with the current sequencing region. + U.UsageExpr = UsageExpr; U.Seq = Region; } } - /// Check whether a modification or use conflicts with a prior usage. - void checkUsage(Object O, UsageInfo &UI, Expr *Ref, UsageKind OtherKind, - bool IsModMod) { + /// Check whether a modification or use of an object \p O in an expression + /// \p UsageExpr conflicts with a prior usage of kind \p OtherKind. \p UI is + /// the \p UsageInfo for the object \p O as obtained via the \p UsageMap. + /// \p IsModMod is true when we are checking for a mod-mod unsequenced + /// usage and false we are checking for a mod-use unsequenced usage. + void checkUsage(Object O, UsageInfo &UI, const Expr *UsageExpr, + UsageKind OtherKind, bool IsModMod) { if (UI.Diagnosed) return; const Usage &U = UI.Uses[OtherKind]; - if (!U.Use || !Tree.isUnsequenced(Region, U.Seq)) + if (!U.UsageExpr || !Tree.isUnsequenced(Region, U.Seq)) return; - Expr *Mod = U.Use; - Expr *ModOrUse = Ref; + const Expr *Mod = U.UsageExpr; + const Expr *ModOrUse = UsageExpr; if (OtherKind == UK_Use) std::swap(Mod, ModOrUse); @@ -12599,47 +12811,79 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { UI.Diagnosed = true; } - void notePreUse(Object O, Expr *Use) { - UsageInfo &U = UsageMap[O]; + // A note on note{Pre, Post}{Use, Mod}: + // + // (It helps to follow the algorithm with an expression such as + // "((++k)++, k) = k" or "k = (k++, k++)". Both contain unsequenced + // operations before C++17 and both are well-defined in C++17). + // + // When visiting a node which uses/modify an object we first call notePreUse + // or notePreMod before visiting its sub-expression(s). At this point the + // children of the current node have not yet been visited and so the eventual + // uses/modifications resulting from the children of the current node have not + // been recorded yet. + // + // We then visit the children of the current node. After that notePostUse or + // notePostMod is called. These will 1) detect an unsequenced modification + // as side effect (as in "k++ + k") and 2) add a new usage with the + // appropriate usage kind. + // + // We also have to be careful that some operation sequences modification as + // side effect as well (for example: || or ,). To account for this we wrap + // the visitation of such a sub-expression (for example: the LHS of || or ,) + // with SequencedSubexpression. SequencedSubexpression is an RAII object + // which record usages which are modifications as side effect, and then + // downgrade them (or more accurately restore the previous usage which was a + // modification as side effect) when exiting the scope of the sequenced + // subexpression. + + void notePreUse(Object O, const Expr *UseExpr) { + UsageInfo &UI = UsageMap[O]; // Uses conflict with other modifications. - checkUsage(O, U, Use, UK_ModAsValue, false); + checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/false); } - void notePostUse(Object O, Expr *Use) { - UsageInfo &U = UsageMap[O]; - checkUsage(O, U, Use, UK_ModAsSideEffect, false); - addUsage(U, O, Use, UK_Use); + void notePostUse(Object O, const Expr *UseExpr) { + UsageInfo &UI = UsageMap[O]; + checkUsage(O, UI, UseExpr, /*OtherKind=*/UK_ModAsSideEffect, + /*IsModMod=*/false); + addUsage(O, UI, UseExpr, /*UsageKind=*/UK_Use); } - void notePreMod(Object O, Expr *Mod) { - UsageInfo &U = UsageMap[O]; + void notePreMod(Object O, const Expr *ModExpr) { + UsageInfo &UI = UsageMap[O]; // Modifications conflict with other modifications and with uses. - checkUsage(O, U, Mod, UK_ModAsValue, true); - checkUsage(O, U, Mod, UK_Use, false); + checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsValue, /*IsModMod=*/true); + checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_Use, /*IsModMod=*/false); } - void notePostMod(Object O, Expr *Use, UsageKind UK) { - UsageInfo &U = UsageMap[O]; - checkUsage(O, U, Use, UK_ModAsSideEffect, true); - addUsage(U, O, Use, UK); + void notePostMod(Object O, const Expr *ModExpr, UsageKind UK) { + UsageInfo &UI = UsageMap[O]; + checkUsage(O, UI, ModExpr, /*OtherKind=*/UK_ModAsSideEffect, + /*IsModMod=*/true); + addUsage(O, UI, ModExpr, /*UsageKind=*/UK); } public: - SequenceChecker(Sema &S, Expr *E, SmallVectorImpl<Expr *> &WorkList) + SequenceChecker(Sema &S, const Expr *E, + SmallVectorImpl<const Expr *> &WorkList) : Base(S.Context), SemaRef(S), Region(Tree.root()), WorkList(WorkList) { Visit(E); + // Silence a -Wunused-private-field since WorkList is now unused. + // TODO: Evaluate if it can be used, and if not remove it. + (void)this->WorkList; } - void VisitStmt(Stmt *S) { + void VisitStmt(const Stmt *S) { // Skip all statements which aren't expressions for now. } - void VisitExpr(Expr *E) { + void VisitExpr(const Expr *E) { // By default, just recurse to evaluated subexpressions. Base::VisitStmt(E); } - void VisitCastExpr(CastExpr *E) { + void VisitCastExpr(const CastExpr *E) { Object O = Object(); if (E->getCastKind() == CK_LValueToRValue) O = getObject(E->getSubExpr(), false); @@ -12651,7 +12895,8 @@ public: notePostUse(O, E); } - void VisitSequencedExpressions(Expr *SequencedBefore, Expr *SequencedAfter) { + void VisitSequencedExpressions(const Expr *SequencedBefore, + const Expr *SequencedAfter) { SequenceTree::Seq BeforeRegion = Tree.allocate(Region); SequenceTree::Seq AfterRegion = Tree.allocate(Region); SequenceTree::Seq OldRegion = Region; @@ -12671,17 +12916,46 @@ public: Tree.merge(AfterRegion); } - void VisitArraySubscriptExpr(ArraySubscriptExpr *ASE) { + void VisitArraySubscriptExpr(const ArraySubscriptExpr *ASE) { // C++17 [expr.sub]p1: // The expression E1[E2] is identical (by definition) to *((E1)+(E2)). The // expression E1 is sequenced before the expression E2. if (SemaRef.getLangOpts().CPlusPlus17) VisitSequencedExpressions(ASE->getLHS(), ASE->getRHS()); - else - Base::VisitStmt(ASE); + else { + Visit(ASE->getLHS()); + Visit(ASE->getRHS()); + } + } + + void VisitBinPtrMemD(const BinaryOperator *BO) { VisitBinPtrMem(BO); } + void VisitBinPtrMemI(const BinaryOperator *BO) { VisitBinPtrMem(BO); } + void VisitBinPtrMem(const BinaryOperator *BO) { + // C++17 [expr.mptr.oper]p4: + // Abbreviating pm-expression.*cast-expression as E1.*E2, [...] + // the expression E1 is sequenced before the expression E2. + if (SemaRef.getLangOpts().CPlusPlus17) + VisitSequencedExpressions(BO->getLHS(), BO->getRHS()); + else { + Visit(BO->getLHS()); + Visit(BO->getRHS()); + } } - void VisitBinComma(BinaryOperator *BO) { + void VisitBinShl(const BinaryOperator *BO) { VisitBinShlShr(BO); } + void VisitBinShr(const BinaryOperator *BO) { VisitBinShlShr(BO); } + void VisitBinShlShr(const BinaryOperator *BO) { + // C++17 [expr.shift]p4: + // The expression E1 is sequenced before the expression E2. + if (SemaRef.getLangOpts().CPlusPlus17) + VisitSequencedExpressions(BO->getLHS(), BO->getRHS()); + else { + Visit(BO->getLHS()); + Visit(BO->getRHS()); + } + } + + void VisitBinComma(const BinaryOperator *BO) { // C++11 [expr.comma]p1: // Every value computation and side effect associated with the left // expression is sequenced before every value computation and side @@ -12689,47 +12963,77 @@ public: VisitSequencedExpressions(BO->getLHS(), BO->getRHS()); } - void VisitBinAssign(BinaryOperator *BO) { - // The modification is sequenced after the value computation of the LHS - // and RHS, so check it before inspecting the operands and update the + void VisitBinAssign(const BinaryOperator *BO) { + SequenceTree::Seq RHSRegion; + SequenceTree::Seq LHSRegion; + if (SemaRef.getLangOpts().CPlusPlus17) { + RHSRegion = Tree.allocate(Region); + LHSRegion = Tree.allocate(Region); + } else { + RHSRegion = Region; + LHSRegion = Region; + } + SequenceTree::Seq OldRegion = Region; + + // C++11 [expr.ass]p1: + // [...] the assignment is sequenced after the value computation + // of the right and left operands, [...] + // + // so check it before inspecting the operands and update the // map afterwards. - Object O = getObject(BO->getLHS(), true); - if (!O) - return VisitExpr(BO); + Object O = getObject(BO->getLHS(), /*Mod=*/true); + if (O) + notePreMod(O, BO); - notePreMod(O, BO); + if (SemaRef.getLangOpts().CPlusPlus17) { + // C++17 [expr.ass]p1: + // [...] The right operand is sequenced before the left operand. [...] + { + SequencedSubexpression SeqBefore(*this); + Region = RHSRegion; + Visit(BO->getRHS()); + } - // C++11 [expr.ass]p7: - // E1 op= E2 is equivalent to E1 = E1 op E2, except that E1 is evaluated - // only once. - // - // Therefore, for a compound assignment operator, O is considered used - // everywhere except within the evaluation of E1 itself. - if (isa<CompoundAssignOperator>(BO)) - notePreUse(O, BO); + Region = LHSRegion; + Visit(BO->getLHS()); - Visit(BO->getLHS()); + if (O && isa<CompoundAssignOperator>(BO)) + notePostUse(O, BO); - if (isa<CompoundAssignOperator>(BO)) - notePostUse(O, BO); + } else { + // C++11 does not specify any sequencing between the LHS and RHS. + Region = LHSRegion; + Visit(BO->getLHS()); + + if (O && isa<CompoundAssignOperator>(BO)) + notePostUse(O, BO); - Visit(BO->getRHS()); + Region = RHSRegion; + Visit(BO->getRHS()); + } // C++11 [expr.ass]p1: - // the assignment is sequenced [...] before the value computation of the - // assignment expression. + // the assignment is sequenced [...] before the value computation of the + // assignment expression. // C11 6.5.16/3 has no such rule. - notePostMod(O, BO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue - : UK_ModAsSideEffect); + Region = OldRegion; + if (O) + notePostMod(O, BO, + SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue + : UK_ModAsSideEffect); + if (SemaRef.getLangOpts().CPlusPlus17) { + Tree.merge(RHSRegion); + Tree.merge(LHSRegion); + } } - void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) { + void VisitCompoundAssignOperator(const CompoundAssignOperator *CAO) { VisitBinAssign(CAO); } - void VisitUnaryPreInc(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } - void VisitUnaryPreDec(UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } - void VisitUnaryPreIncDec(UnaryOperator *UO) { + void VisitUnaryPreInc(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } + void VisitUnaryPreDec(const UnaryOperator *UO) { VisitUnaryPreIncDec(UO); } + void VisitUnaryPreIncDec(const UnaryOperator *UO) { Object O = getObject(UO->getSubExpr(), true); if (!O) return VisitExpr(UO); @@ -12738,13 +13042,14 @@ public: Visit(UO->getSubExpr()); // C++11 [expr.pre.incr]p1: // the expression ++x is equivalent to x+=1 - notePostMod(O, UO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue - : UK_ModAsSideEffect); + notePostMod(O, UO, + SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue + : UK_ModAsSideEffect); } - void VisitUnaryPostInc(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } - void VisitUnaryPostDec(UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } - void VisitUnaryPostIncDec(UnaryOperator *UO) { + void VisitUnaryPostInc(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } + void VisitUnaryPostDec(const UnaryOperator *UO) { VisitUnaryPostIncDec(UO); } + void VisitUnaryPostIncDec(const UnaryOperator *UO) { Object O = getObject(UO->getSubExpr(), true); if (!O) return VisitExpr(UO); @@ -12754,67 +13059,129 @@ public: notePostMod(O, UO, UK_ModAsSideEffect); } - /// Don't visit the RHS of '&&' or '||' if it might not be evaluated. - void VisitBinLOr(BinaryOperator *BO) { - // The side-effects of the LHS of an '&&' are sequenced before the - // value computation of the RHS, and hence before the value computation - // of the '&&' itself, unless the LHS evaluates to zero. We treat them - // as if they were unconditionally sequenced. + void VisitBinLOr(const BinaryOperator *BO) { + // C++11 [expr.log.or]p2: + // If the second expression is evaluated, every value computation and + // side effect associated with the first expression is sequenced before + // every value computation and side effect associated with the + // second expression. + SequenceTree::Seq LHSRegion = Tree.allocate(Region); + SequenceTree::Seq RHSRegion = Tree.allocate(Region); + SequenceTree::Seq OldRegion = Region; + EvaluationTracker Eval(*this); { SequencedSubexpression Sequenced(*this); + Region = LHSRegion; Visit(BO->getLHS()); } - bool Result; - if (Eval.evaluate(BO->getLHS(), Result)) { - if (!Result) - Visit(BO->getRHS()); - } else { - // Check for unsequenced operations in the RHS, treating it as an - // entirely separate evaluation. - // - // FIXME: If there are operations in the RHS which are unsequenced - // with respect to operations outside the RHS, and those operations - // are unconditionally evaluated, diagnose them. - WorkList.push_back(BO->getRHS()); + // C++11 [expr.log.or]p1: + // [...] the second operand is not evaluated if the first operand + // evaluates to true. + bool EvalResult = false; + bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult); + bool ShouldVisitRHS = !EvalOK || (EvalOK && !EvalResult); + if (ShouldVisitRHS) { + Region = RHSRegion; + Visit(BO->getRHS()); } + + Region = OldRegion; + Tree.merge(LHSRegion); + Tree.merge(RHSRegion); } - void VisitBinLAnd(BinaryOperator *BO) { + + void VisitBinLAnd(const BinaryOperator *BO) { + // C++11 [expr.log.and]p2: + // If the second expression is evaluated, every value computation and + // side effect associated with the first expression is sequenced before + // every value computation and side effect associated with the + // second expression. + SequenceTree::Seq LHSRegion = Tree.allocate(Region); + SequenceTree::Seq RHSRegion = Tree.allocate(Region); + SequenceTree::Seq OldRegion = Region; + EvaluationTracker Eval(*this); { SequencedSubexpression Sequenced(*this); + Region = LHSRegion; Visit(BO->getLHS()); } - bool Result; - if (Eval.evaluate(BO->getLHS(), Result)) { - if (Result) - Visit(BO->getRHS()); - } else { - WorkList.push_back(BO->getRHS()); + // C++11 [expr.log.and]p1: + // [...] the second operand is not evaluated if the first operand is false. + bool EvalResult = false; + bool EvalOK = Eval.evaluate(BO->getLHS(), EvalResult); + bool ShouldVisitRHS = !EvalOK || (EvalOK && EvalResult); + if (ShouldVisitRHS) { + Region = RHSRegion; + Visit(BO->getRHS()); } + + Region = OldRegion; + Tree.merge(LHSRegion); + Tree.merge(RHSRegion); } - // Only visit the condition, unless we can be sure which subexpression will - // be chosen. - void VisitAbstractConditionalOperator(AbstractConditionalOperator *CO) { + void VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO) { + // C++11 [expr.cond]p1: + // [...] Every value computation and side effect associated with the first + // expression is sequenced before every value computation and side effect + // associated with the second or third expression. + SequenceTree::Seq ConditionRegion = Tree.allocate(Region); + + // No sequencing is specified between the true and false expression. + // However since exactly one of both is going to be evaluated we can + // consider them to be sequenced. This is needed to avoid warning on + // something like "x ? y+= 1 : y += 2;" in the case where we will visit + // both the true and false expressions because we can't evaluate x. + // This will still allow us to detect an expression like (pre C++17) + // "(x ? y += 1 : y += 2) = y". + // + // We don't wrap the visitation of the true and false expression with + // SequencedSubexpression because we don't want to downgrade modifications + // as side effect in the true and false expressions after the visition + // is done. (for example in the expression "(x ? y++ : y++) + y" we should + // not warn between the two "y++", but we should warn between the "y++" + // and the "y". + SequenceTree::Seq TrueRegion = Tree.allocate(Region); + SequenceTree::Seq FalseRegion = Tree.allocate(Region); + SequenceTree::Seq OldRegion = Region; + EvaluationTracker Eval(*this); { SequencedSubexpression Sequenced(*this); + Region = ConditionRegion; Visit(CO->getCond()); } - bool Result; - if (Eval.evaluate(CO->getCond(), Result)) - Visit(Result ? CO->getTrueExpr() : CO->getFalseExpr()); - else { - WorkList.push_back(CO->getTrueExpr()); - WorkList.push_back(CO->getFalseExpr()); + // C++11 [expr.cond]p1: + // [...] The first expression is contextually converted to bool (Clause 4). + // It is evaluated and if it is true, the result of the conditional + // expression is the value of the second expression, otherwise that of the + // third expression. Only one of the second and third expressions is + // evaluated. [...] + bool EvalResult = false; + bool EvalOK = Eval.evaluate(CO->getCond(), EvalResult); + bool ShouldVisitTrueExpr = !EvalOK || (EvalOK && EvalResult); + bool ShouldVisitFalseExpr = !EvalOK || (EvalOK && !EvalResult); + if (ShouldVisitTrueExpr) { + Region = TrueRegion; + Visit(CO->getTrueExpr()); + } + if (ShouldVisitFalseExpr) { + Region = FalseRegion; + Visit(CO->getFalseExpr()); } + + Region = OldRegion; + Tree.merge(ConditionRegion); + Tree.merge(TrueRegion); + Tree.merge(FalseRegion); } - void VisitCallExpr(CallExpr *CE) { + void VisitCallExpr(const CallExpr *CE) { // C++11 [intro.execution]p15: // When calling a function [...], every value computation and side effect // associated with any argument expression, or with the postfix expression @@ -12822,12 +13189,13 @@ public: // expression or statement in the body of the function [and thus before // the value computation of its result]. SequencedSubexpression Sequenced(*this); - Base::VisitCallExpr(CE); + SemaRef.runWithSufficientStackSpace(CE->getExprLoc(), + [&] { Base::VisitCallExpr(CE); }); // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions. } - void VisitCXXConstructExpr(CXXConstructExpr *CCE) { + void VisitCXXConstructExpr(const CXXConstructExpr *CCE) { // This is a call, so all subexpressions are sequenced before the result. SequencedSubexpression Sequenced(*this); @@ -12837,8 +13205,8 @@ public: // In C++11, list initializations are sequenced. SmallVector<SequenceTree::Seq, 32> Elts; SequenceTree::Seq Parent = Region; - for (CXXConstructExpr::arg_iterator I = CCE->arg_begin(), - E = CCE->arg_end(); + for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(), + E = CCE->arg_end(); I != E; ++I) { Region = Tree.allocate(Parent); Elts.push_back(Region); @@ -12851,7 +13219,7 @@ public: Tree.merge(Elts[I]); } - void VisitInitListExpr(InitListExpr *ILE) { + void VisitInitListExpr(const InitListExpr *ILE) { if (!SemaRef.getLangOpts().CPlusPlus11) return VisitExpr(ILE); @@ -12859,8 +13227,9 @@ public: SmallVector<SequenceTree::Seq, 32> Elts; SequenceTree::Seq Parent = Region; for (unsigned I = 0; I < ILE->getNumInits(); ++I) { - Expr *E = ILE->getInit(I); - if (!E) continue; + const Expr *E = ILE->getInit(I); + if (!E) + continue; Region = Tree.allocate(Parent); Elts.push_back(Region); Visit(E); @@ -12875,11 +13244,11 @@ public: } // namespace -void Sema::CheckUnsequencedOperations(Expr *E) { - SmallVector<Expr *, 8> WorkList; +void Sema::CheckUnsequencedOperations(const Expr *E) { + SmallVector<const Expr *, 8> WorkList; WorkList.push_back(E); while (!WorkList.empty()) { - Expr *Item = WorkList.pop_back_val(); + const Expr *Item = WorkList.pop_back_val(); SequenceChecker(*this, Item, WorkList); } } @@ -14577,6 +14946,8 @@ void Sema::RefersToMemberWithReducedAlignment( bool AnyIsPacked = false; do { QualType BaseType = ME->getBase()->getType(); + if (BaseType->isDependentType()) + return; if (ME->isArrow()) BaseType = BaseType->getPointeeType(); RecordDecl *RD = BaseType->castAs<RecordType>()->getDecl(); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index f24c3b234ff2..7260977c634d 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -692,18 +692,6 @@ getRequiredQualification(ASTContext &Context, const DeclContext *CurContext, return Result; } -/// Determine whether \p Id is a name reserved for the implementation (C99 -/// 7.1.3, C++ [lib.global.names]). -static bool isReservedName(const IdentifierInfo *Id, - bool doubleUnderscoreOnly = false) { - if (Id->getLength() < 2) - return false; - const char *Name = Id->getNameStart(); - return Name[0] == '_' && - (Name[1] == '_' || - (Name[1] >= 'A' && Name[1] <= 'Z' && !doubleUnderscoreOnly)); -} - // Some declarations have reserved names that we don't want to ever show. // Filter out names reserved for the implementation if they come from a // system header. @@ -713,13 +701,13 @@ static bool shouldIgnoreDueToReservedName(const NamedDecl *ND, Sema &SemaRef) { return false; // Ignore reserved names for compiler provided decls. - if (isReservedName(Id) && ND->getLocation().isInvalid()) + if (Id->isReservedName() && ND->getLocation().isInvalid()) return true; // For system headers ignore only double-underscore names. // This allows for system headers providing private symbols with a single // underscore. - if (isReservedName(Id, /*doubleUnderscoreOnly=*/true) && + if (Id->isReservedName(/*doubleUnderscoreOnly=*/true) && SemaRef.SourceMgr.isInSystemHeader( SemaRef.SourceMgr.getSpellingLoc(ND->getLocation()))) return true; @@ -1321,7 +1309,7 @@ void ResultBuilder::AddResult(Result R, DeclContext *CurContext, /// Motivating case is const_iterator begin() const vs iterator begin(). auto &OverloadSet = OverloadMap[std::make_pair( CurContext, Method->getDeclName().getAsOpaqueInteger())]; - for (const DeclIndexPair& Entry : OverloadSet) { + for (const DeclIndexPair Entry : OverloadSet) { Result &Incumbent = Results[Entry.second]; switch (compareOverloads(*Method, *cast<CXXMethodDecl>(Incumbent.Declaration), @@ -2324,6 +2312,13 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); } + // For pointers, suggest 'return nullptr' in C++. + if (SemaRef.getLangOpts().CPlusPlus11 && + (ReturnType->isPointerType() || ReturnType->isMemberPointerType())) { + Builder.AddTypedTextChunk("return nullptr"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(Result(Builder.TakeString())); + } } // goto identifier ; @@ -2991,7 +2986,11 @@ static void AddTemplateParameterChunks( if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*P)) { if (TTP->wasDeclaredWithTypename()) PlaceholderStr = "typename"; - else + else if (const auto *TC = TTP->getTypeConstraint()) { + llvm::raw_string_ostream OS(PlaceholderStr); + TC->print(OS, Policy); + OS.flush(); + } else PlaceholderStr = "class"; if (TTP->getIdentifier()) { @@ -3327,6 +3326,18 @@ CodeCompletionResult::createCodeCompletionStringForOverride( return Result.TakeString(); } +// FIXME: Right now this works well with lambdas. Add support for other functor +// types like std::function. +static const NamedDecl *extractFunctorCallOperator(const NamedDecl *ND) { + const auto *VD = dyn_cast<VarDecl>(ND); + if (!VD) + return nullptr; + const auto *RecordDecl = VD->getType()->getAsCXXRecordDecl(); + if (!RecordDecl || !RecordDecl->isLambda()) + return nullptr; + return RecordDecl->getLambdaCallOperator(); +} + CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( Preprocessor &PP, ASTContext &Ctx, CodeCompletionBuilder &Result, bool IncludeBriefComments, const CodeCompletionContext &CCContext, @@ -3351,9 +3362,8 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( for (const auto *I : ND->specific_attrs<AnnotateAttr>()) Result.AddAnnotation(Result.getAllocator().CopyString(I->getAnnotation())); - AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result); - - if (const auto *Function = dyn_cast<FunctionDecl>(ND)) { + auto AddFunctionTypeAndResult = [&](const FunctionDecl *Function) { + AddResultTypeChunk(Ctx, Policy, Function, CCContext.getBaseType(), Result); AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, Ctx, Policy); AddTypedNameChunk(Ctx, Policy, ND, Result); @@ -3361,9 +3371,21 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( AddFunctionParameterChunks(PP, Policy, Function, Result); Result.AddChunk(CodeCompletionString::CK_RightParen); AddFunctionTypeQualsToCompletionString(Result, Function); + }; + + if (const auto *Function = dyn_cast<FunctionDecl>(ND)) { + AddFunctionTypeAndResult(Function); + return Result.TakeString(); + } + + if (const auto *CallOperator = + dyn_cast_or_null<FunctionDecl>(extractFunctorCallOperator(ND))) { + AddFunctionTypeAndResult(CallOperator); return Result.TakeString(); } + AddResultTypeChunk(Ctx, Policy, ND, CCContext.getBaseType(), Result); + if (const FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(ND)) { AddQualifierToCompletionString(Result, Qualifier, QualifierIsInformative, @@ -3429,6 +3451,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( Result.AddChunk(CodeCompletionString::CK_RightAngle); return Result.TakeString(); } + if (const auto *Method = dyn_cast<ObjCMethodDecl>(ND)) { Selector Sel = Method->getSelector(); if (Sel.isUnarySelector()) { @@ -3653,6 +3676,10 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( unsigned CurrentArg, Sema &S, CodeCompletionAllocator &Allocator, CodeCompletionTUInfo &CCTUInfo, bool IncludeBriefComments) const { PrintingPolicy Policy = getCompletionPrintingPolicy(S); + // Show signatures of constructors as they are declared: + // vector(int n) rather than vector<string>(int n) + // This is less noisy without being less clear, and avoids tricky cases. + Policy.SuppressTemplateArgsInCXXConstructors = true; // FIXME: Set priority, availability appropriately. CodeCompletionBuilder Result(Allocator, CCTUInfo, 1, @@ -4783,7 +4810,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, } // Add properties from the protocols in a qualified interface. - for (auto *I : BaseType->getAs<ObjCObjectPointerType>()->quals()) + for (auto *I : BaseType->castAs<ObjCObjectPointerType>()->quals()) AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true, CurContext, AddedProperties, Results, IsBaseExprStatement, /*IsClassProperty*/ false, @@ -4796,7 +4823,7 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, BaseType->getAs<ObjCObjectPointerType>()) Class = ObjCPtr->getInterfaceDecl(); else - Class = BaseType->getAs<ObjCObjectType>()->getInterface(); + Class = BaseType->castAs<ObjCObjectType>()->getInterface(); // Add all ivars from this class and its superclasses. if (Class) { @@ -5330,18 +5357,21 @@ void Sema::CodeCompleteAfterIf(Scope *S) { } void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, - bool EnteringContext, QualType BaseType, + bool EnteringContext, + bool IsUsingDeclaration, QualType BaseType, QualType PreferredType) { if (SS.isEmpty() || !CodeCompleter) return; + CodeCompletionContext CC(CodeCompletionContext::CCC_Symbol, PreferredType); + CC.setIsUsingDeclaration(IsUsingDeclaration); + CC.setCXXScopeSpecifier(SS); + // We want to keep the scope specifier even if it's invalid (e.g. the scope // "a::b::" is not corresponding to any context/namespace in the AST), since // it can be useful for global code completion which have information about // contexts/symbols that are not in the AST. if (SS.isInvalid()) { - CodeCompletionContext CC(CodeCompletionContext::CCC_Symbol, PreferredType); - CC.setCXXScopeSpecifier(SS); // As SS is invalid, we try to collect accessible contexts from the current // scope with a dummy lookup so that the completion consumer can try to // guess what the specified scope is. @@ -5371,10 +5401,8 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx)) return; - ResultBuilder Results( - *this, CodeCompleter->getAllocator(), - CodeCompleter->getCodeCompletionTUInfo(), - CodeCompletionContext(CodeCompletionContext::CCC_Symbol, PreferredType)); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), CC); if (!PreferredType.isNull()) Results.setPreferredType(PreferredType); Results.EnterNewScope(); @@ -5403,23 +5431,21 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, CodeCompleter->loadExternal()); } - auto CC = Results.getCompletionContext(); - CC.setCXXScopeSpecifier(SS); - - HandleCodeCompleteResults(this, CodeCompleter, CC, Results.data(), - Results.size()); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); } void Sema::CodeCompleteUsing(Scope *S) { if (!CodeCompleter) return; + // This can be both a using alias or using declaration, in the former we + // expect a new name and a symbol in the latter case. + CodeCompletionContext Context(CodeCompletionContext::CCC_SymbolOrNewName); + Context.setIsUsingDeclaration(true); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), - CodeCompleter->getCodeCompletionTUInfo(), - // This can be both a using alias or using - // declaration, in the former we expect a new name and a - // symbol in the latter case. - CodeCompletionContext::CCC_SymbolOrNewName, + CodeCompleter->getCodeCompletionTUInfo(), Context, &ResultBuilder::IsNestedNameSpecifier); Results.EnterNewScope(); @@ -7721,8 +7747,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && (ReturnType.isNull() || (ReturnType->isObjCObjectPointerType() && - ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() && - ReturnType->getAs<ObjCObjectPointerType>() + ReturnType->castAs<ObjCObjectPointerType>()->getInterfaceDecl() && + ReturnType->castAs<ObjCObjectPointerType>() ->getInterfaceDecl() ->getName() == "NSArray"))) { std::string SelectorName = (Twine(Property->getName()) + "AtIndexes").str(); @@ -8108,8 +8134,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (!IsInstanceMethod && (ReturnType.isNull() || (ReturnType->isObjCObjectPointerType() && - ReturnType->getAs<ObjCObjectPointerType>()->getInterfaceDecl() && - ReturnType->getAs<ObjCObjectPointerType>() + ReturnType->castAs<ObjCObjectPointerType>()->getInterfaceDecl() && + ReturnType->castAs<ObjCObjectPointerType>() ->getInterfaceDecl() ->getName() == "NSSet"))) { std::string SelectorName = diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 848ccf543445..018ac2d7dc9d 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -11,15 +11,24 @@ // //===----------------------------------------------------------------------===// +#include "clang/Sema/SemaConcept.h" #include "clang/Sema/Sema.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/Template.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/OperatorPrecedence.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/PointerUnion.h" using namespace clang; using namespace sema; -bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) { +bool +Sema::CheckConstraintExpression(Expr *ConstraintExpression, Token NextToken, + bool *PossibleNonPrimary, + bool IsTrailingRequiresClause) { // C++2a [temp.constr.atomic]p1 // ..E shall be a constant expression of type bool. @@ -27,99 +36,793 @@ bool Sema::CheckConstraintExpression(Expr *ConstraintExpression) { if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) { if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr) - return CheckConstraintExpression(BinOp->getLHS()) && - CheckConstraintExpression(BinOp->getRHS()); + return CheckConstraintExpression(BinOp->getLHS(), NextToken, + PossibleNonPrimary) && + CheckConstraintExpression(BinOp->getRHS(), NextToken, + PossibleNonPrimary); } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression)) - return CheckConstraintExpression(C->getSubExpr()); + return CheckConstraintExpression(C->getSubExpr(), NextToken, + PossibleNonPrimary); + + QualType Type = ConstraintExpression->getType(); + + auto CheckForNonPrimary = [&] { + if (PossibleNonPrimary) + *PossibleNonPrimary = + // We have the following case: + // template<typename> requires func(0) struct S { }; + // The user probably isn't aware of the parentheses required around + // the function call, and we're only going to parse 'func' as the + // primary-expression, and complain that it is of non-bool type. + (NextToken.is(tok::l_paren) && + (IsTrailingRequiresClause || + (Type->isDependentType() && + IsDependentFunctionNameExpr(ConstraintExpression)) || + Type->isFunctionType() || + Type->isSpecificBuiltinType(BuiltinType::Overload))) || + // We have the following case: + // template<typename T> requires size_<T> == 0 struct S { }; + // The user probably isn't aware of the parentheses required around + // the binary operator, and we're only going to parse 'func' as the + // first operand, and complain that it is of non-bool type. + getBinOpPrecedence(NextToken.getKind(), + /*GreaterThanIsOperator=*/true, + getLangOpts().CPlusPlus11) > prec::LogicalAnd; + }; // An atomic constraint! - if (ConstraintExpression->isTypeDependent()) + if (ConstraintExpression->isTypeDependent()) { + CheckForNonPrimary(); return true; + } - QualType Type = ConstraintExpression->getType(); if (!Context.hasSameUnqualifiedType(Type, Context.BoolTy)) { Diag(ConstraintExpression->getExprLoc(), diag::err_non_bool_atomic_constraint) << Type << ConstraintExpression->getSourceRange(); + CheckForNonPrimary(); return false; } + + if (PossibleNonPrimary) + *PossibleNonPrimary = false; return true; } -bool -Sema::CalculateConstraintSatisfaction(ConceptDecl *NamedConcept, - MultiLevelTemplateArgumentList &MLTAL, - Expr *ConstraintExpr, - bool &IsSatisfied) { +template <typename AtomicEvaluator> +static bool +calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, + ConstraintSatisfaction &Satisfaction, + AtomicEvaluator &&Evaluator) { ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts(); if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) { - if (BO->getOpcode() == BO_LAnd) { - if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(), - IsSatisfied)) + if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) { + if (calculateConstraintSatisfaction(S, BO->getLHS(), Satisfaction, + Evaluator)) return true; - if (!IsSatisfied) + + bool IsLHSSatisfied = Satisfaction.IsSatisfied; + + if (BO->getOpcode() == BO_LOr && IsLHSSatisfied) + // [temp.constr.op] p3 + // A disjunction is a constraint taking two operands. To determine if + // a disjunction is satisfied, the satisfaction of the first operand + // is checked. If that is satisfied, the disjunction is satisfied. + // Otherwise, the disjunction is satisfied if and only if the second + // operand is satisfied. return false; - return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(), - IsSatisfied); - } else if (BO->getOpcode() == BO_LOr) { - if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getLHS(), - IsSatisfied)) - return true; - if (IsSatisfied) + + if (BO->getOpcode() == BO_LAnd && !IsLHSSatisfied) + // [temp.constr.op] p2 + // A conjunction is a constraint taking two operands. To determine if + // a conjunction is satisfied, the satisfaction of the first operand + // is checked. If that is not satisfied, the conjunction is not + // satisfied. Otherwise, the conjunction is satisfied if and only if + // the second operand is satisfied. return false; - return CalculateConstraintSatisfaction(NamedConcept, MLTAL, BO->getRHS(), - IsSatisfied); + + return calculateConstraintSatisfaction(S, BO->getRHS(), Satisfaction, + std::forward<AtomicEvaluator>(Evaluator)); } } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) - return CalculateConstraintSatisfaction(NamedConcept, MLTAL, C->getSubExpr(), - IsSatisfied); + return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction, + std::forward<AtomicEvaluator>(Evaluator)); - EnterExpressionEvaluationContext ConstantEvaluated( - *this, Sema::ExpressionEvaluationContext::ConstantEvaluated); + // An atomic constraint expression + ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr); - // Atomic constraint - substitute arguments and check satisfaction. - ExprResult E; - { - TemplateDeductionInfo Info(ConstraintExpr->getBeginLoc()); - InstantiatingTemplate Inst(*this, ConstraintExpr->getBeginLoc(), - InstantiatingTemplate::ConstraintSubstitution{}, - NamedConcept, Info, - ConstraintExpr->getSourceRange()); - if (Inst.isInvalid()) - return true; - // We do not want error diagnostics escaping here. - Sema::SFINAETrap Trap(*this); + if (SubstitutedAtomicExpr.isInvalid()) + return true; + + if (!SubstitutedAtomicExpr.isUsable()) + // Evaluator has decided satisfaction without yielding an expression. + return false; - E = SubstExpr(ConstraintExpr, MLTAL); - if (E.isInvalid() || Trap.hasErrorOccurred()) { + EnterExpressionEvaluationContext ConstantEvaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + SmallVector<PartialDiagnosticAt, 2> EvaluationDiags; + Expr::EvalResult EvalResult; + EvalResult.Diag = &EvaluationDiags; + if (!SubstitutedAtomicExpr.get()->EvaluateAsRValue(EvalResult, S.Context)) { // C++2a [temp.constr.atomic]p1 - // ...If substitution results in an invalid type or expression, the - // constraint is not satisfied. - IsSatisfied = false; + // ...E shall be a constant expression of type bool. + S.Diag(SubstitutedAtomicExpr.get()->getBeginLoc(), + diag::err_non_constant_constraint_expression) + << SubstitutedAtomicExpr.get()->getSourceRange(); + for (const PartialDiagnosticAt &PDiag : EvaluationDiags) + S.Diag(PDiag.first, PDiag.second); + return true; + } + + Satisfaction.IsSatisfied = EvalResult.Val.getInt().getBoolValue(); + if (!Satisfaction.IsSatisfied) + Satisfaction.Details.emplace_back(ConstraintExpr, + SubstitutedAtomicExpr.get()); + + return false; +} + +template <typename TemplateDeclT> +static bool calculateConstraintSatisfaction( + Sema &S, TemplateDeclT *Template, ArrayRef<TemplateArgument> TemplateArgs, + SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL, + const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { + return calculateConstraintSatisfaction( + S, ConstraintExpr, Satisfaction, [&](const Expr *AtomicExpr) { + EnterExpressionEvaluationContext ConstantEvaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + // Atomic constraint - substitute arguments and check satisfaction. + ExprResult SubstitutedExpression; + { + TemplateDeductionInfo Info(TemplateNameLoc); + Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(), + Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template, + Info, AtomicExpr->getSourceRange()); + if (Inst.isInvalid()) + return ExprError(); + // We do not want error diagnostics escaping here. + Sema::SFINAETrap Trap(S); + SubstitutedExpression = S.SubstExpr(const_cast<Expr *>(AtomicExpr), + MLTAL); + if (SubstitutedExpression.isInvalid() || Trap.hasErrorOccurred()) { + // C++2a [temp.constr.atomic]p1 + // ...If substitution results in an invalid type or expression, the + // constraint is not satisfied. + if (!Trap.hasErrorOccurred()) + // A non-SFINAE error has occured as a result of this + // substitution. + return ExprError(); + + PartialDiagnosticAt SubstDiag{SourceLocation(), + PartialDiagnostic::NullDiagnostic()}; + Info.takeSFINAEDiagnostic(SubstDiag); + // FIXME: Concepts: This is an unfortunate consequence of there + // being no serialization code for PartialDiagnostics and the fact + // that serializing them would likely take a lot more storage than + // just storing them as strings. We would still like, in the + // future, to serialize the proper PartialDiagnostic as serializing + // it as a string defeats the purpose of the diagnostic mechanism. + SmallString<128> DiagString; + DiagString = ": "; + SubstDiag.second.EmitToString(S.getDiagnostics(), DiagString); + unsigned MessageSize = DiagString.size(); + char *Mem = new (S.Context) char[MessageSize]; + memcpy(Mem, DiagString.c_str(), MessageSize); + Satisfaction.Details.emplace_back( + AtomicExpr, + new (S.Context) ConstraintSatisfaction::SubstitutionDiagnostic{ + SubstDiag.first, StringRef(Mem, MessageSize)}); + Satisfaction.IsSatisfied = false; + return ExprEmpty(); + } + } + + if (!S.CheckConstraintExpression(SubstitutedExpression.get())) + return ExprError(); + + return SubstitutedExpression; + }); +} + +template<typename TemplateDeclT> +static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, + ArrayRef<const Expr *> ConstraintExprs, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange TemplateIDRange, + ConstraintSatisfaction &Satisfaction) { + if (ConstraintExprs.empty()) { + Satisfaction.IsSatisfied = true; + return false; + } + + for (auto& Arg : TemplateArgs) + if (Arg.isInstantiationDependent()) { + // No need to check satisfaction for dependent constraint expressions. + Satisfaction.IsSatisfied = true; return false; } + + Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), + Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs, + TemplateIDRange); + if (Inst.isInvalid()) + return true; + + MultiLevelTemplateArgumentList MLTAL; + MLTAL.addOuterTemplateArguments(TemplateArgs); + + for (const Expr *ConstraintExpr : ConstraintExprs) { + if (calculateConstraintSatisfaction(S, Template, TemplateArgs, + TemplateIDRange.getBegin(), MLTAL, + ConstraintExpr, Satisfaction)) + return true; + if (!Satisfaction.IsSatisfied) + // [temp.constr.op] p2 + // [...] To determine if a conjunction is satisfied, the satisfaction + // of the first operand is checked. If that is not satisfied, the + // conjunction is not satisfied. [...] + return false; } + return false; +} + +bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template, + ArrayRef<const Expr *> ConstraintExprs, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange TemplateIDRange, + ConstraintSatisfaction &Satisfaction) { + return ::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, + TemplateArgs, TemplateIDRange, + Satisfaction); +} - if (!CheckConstraintExpression(E.get())) +bool +Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part, + ArrayRef<const Expr *> ConstraintExprs, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange TemplateIDRange, + ConstraintSatisfaction &Satisfaction) { + return ::CheckConstraintSatisfaction(*this, Part, ConstraintExprs, + TemplateArgs, TemplateIDRange, + Satisfaction); +} + +bool +Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial, + ArrayRef<const Expr *> ConstraintExprs, + ArrayRef<TemplateArgument> TemplateArgs, + SourceRange TemplateIDRange, + ConstraintSatisfaction &Satisfaction) { + return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExprs, + TemplateArgs, TemplateIDRange, + Satisfaction); +} + +bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, + ConstraintSatisfaction &Satisfaction) { + return calculateConstraintSatisfaction( + *this, ConstraintExpr, Satisfaction, + [](const Expr *AtomicExpr) -> ExprResult { + return ExprResult(const_cast<Expr *>(AtomicExpr)); + }); +} + +bool Sema::EnsureTemplateArgumentListConstraints( + TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs, + SourceRange TemplateIDRange) { + ConstraintSatisfaction Satisfaction; + llvm::SmallVector<const Expr *, 3> AssociatedConstraints; + TD->getAssociatedConstraints(AssociatedConstraints); + if (CheckConstraintSatisfaction(TD, AssociatedConstraints, TemplateArgs, + TemplateIDRange, Satisfaction)) return true; - SmallVector<PartialDiagnosticAt, 2> EvaluationDiags; - Expr::EvalResult EvalResult; - EvalResult.Diag = &EvaluationDiags; - if (!E.get()->EvaluateAsRValue(EvalResult, Context)) { - // C++2a [temp.constr.atomic]p1 - // ...E shall be a constant expression of type bool. - Diag(E.get()->getBeginLoc(), - diag::err_non_constant_constraint_expression) - << E.get()->getSourceRange(); - for (const PartialDiagnosticAt &PDiag : EvaluationDiags) - Diag(PDiag.first, PDiag.second); + if (!Satisfaction.IsSatisfied) { + SmallString<128> TemplateArgString; + TemplateArgString = " "; + TemplateArgString += getTemplateArgumentBindingsText( + TD->getTemplateParameters(), TemplateArgs.data(), TemplateArgs.size()); + + Diag(TemplateIDRange.getBegin(), + diag::err_template_arg_list_constraints_not_satisfied) + << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << TD + << TemplateArgString << TemplateIDRange; + DiagnoseUnsatisfiedConstraint(Satisfaction); + return true; + } + return false; +} + +static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S, + Expr *SubstExpr, + bool First = true) { + SubstExpr = SubstExpr->IgnoreParenImpCasts(); + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(SubstExpr)) { + switch (BO->getOpcode()) { + // These two cases will in practice only be reached when using fold + // expressions with || and &&, since otherwise the || and && will have been + // broken down into atomic constraints during satisfaction checking. + case BO_LOr: + // Or evaluated to false - meaning both RHS and LHS evaluated to false. + diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First); + diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), + /*First=*/false); + return; + case BO_LAnd: + bool LHSSatisfied; + BO->getLHS()->EvaluateAsBooleanCondition(LHSSatisfied, S.Context); + if (LHSSatisfied) { + // LHS is true, so RHS must be false. + diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), First); + return; + } + // LHS is false + diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getLHS(), First); + + // RHS might also be false + bool RHSSatisfied; + BO->getRHS()->EvaluateAsBooleanCondition(RHSSatisfied, S.Context); + if (!RHSSatisfied) + diagnoseWellFormedUnsatisfiedConstraintExpr(S, BO->getRHS(), + /*First=*/false); + return; + case BO_GE: + case BO_LE: + case BO_GT: + case BO_LT: + case BO_EQ: + case BO_NE: + if (BO->getLHS()->getType()->isIntegerType() && + BO->getRHS()->getType()->isIntegerType()) { + Expr::EvalResult SimplifiedLHS; + Expr::EvalResult SimplifiedRHS; + BO->getLHS()->EvaluateAsInt(SimplifiedLHS, S.Context); + BO->getRHS()->EvaluateAsInt(SimplifiedRHS, S.Context); + if (!SimplifiedLHS.Diag && ! SimplifiedRHS.Diag) { + S.Diag(SubstExpr->getBeginLoc(), + diag::note_atomic_constraint_evaluated_to_false_elaborated) + << (int)First << SubstExpr + << SimplifiedLHS.Val.getInt().toString(10) + << BinaryOperator::getOpcodeStr(BO->getOpcode()) + << SimplifiedRHS.Val.getInt().toString(10); + return; + } + } + break; + + default: + break; + } + } else if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(SubstExpr)) { + if (CSE->getTemplateArgsAsWritten()->NumTemplateArgs == 1) { + S.Diag( + CSE->getSourceRange().getBegin(), + diag:: + note_single_arg_concept_specialization_constraint_evaluated_to_false) + << (int)First + << CSE->getTemplateArgsAsWritten()->arguments()[0].getArgument() + << CSE->getNamedConcept(); + } else { + S.Diag(SubstExpr->getSourceRange().getBegin(), + diag::note_concept_specialization_constraint_evaluated_to_false) + << (int)First << CSE; + } + S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction()); + return; + } + + S.Diag(SubstExpr->getSourceRange().getBegin(), + diag::note_atomic_constraint_evaluated_to_false) + << (int)First << SubstExpr; +} + +template<typename SubstitutionDiagnostic> +static void diagnoseUnsatisfiedConstraintExpr( + Sema &S, const Expr *E, + const llvm::PointerUnion<Expr *, SubstitutionDiagnostic *> &Record, + bool First = true) { + if (auto *Diag = Record.template dyn_cast<SubstitutionDiagnostic *>()){ + S.Diag(Diag->first, diag::note_substituted_constraint_expr_is_ill_formed) + << Diag->second; + return; + } + + diagnoseWellFormedUnsatisfiedConstraintExpr(S, + Record.template get<Expr *>(), First); +} + +void Sema::DiagnoseUnsatisfiedConstraint( + const ConstraintSatisfaction& Satisfaction) { + assert(!Satisfaction.IsSatisfied && + "Attempted to diagnose a satisfied constraint"); + bool First = true; + for (auto &Pair : Satisfaction.Details) { + diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First); + First = false; + } +} + +void Sema::DiagnoseUnsatisfiedConstraint( + const ASTConstraintSatisfaction &Satisfaction) { + assert(!Satisfaction.IsSatisfied && + "Attempted to diagnose a satisfied constraint"); + bool First = true; + for (auto &Pair : Satisfaction) { + diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First); + First = false; + } +} + +const NormalizedConstraint * +Sema::getNormalizedAssociatedConstraints( + NamedDecl *ConstrainedDecl, ArrayRef<const Expr *> AssociatedConstraints) { + auto CacheEntry = NormalizationCache.find(ConstrainedDecl); + if (CacheEntry == NormalizationCache.end()) { + auto Normalized = + NormalizedConstraint::fromConstraintExprs(*this, ConstrainedDecl, + AssociatedConstraints); + CacheEntry = + NormalizationCache + .try_emplace(ConstrainedDecl, + Normalized + ? new (Context) NormalizedConstraint( + std::move(*Normalized)) + : nullptr) + .first; + } + return CacheEntry->second; +} + +static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, + ConceptDecl *Concept, ArrayRef<TemplateArgument> TemplateArgs, + const ASTTemplateArgumentListInfo *ArgsAsWritten) { + if (!N.isAtomic()) { + if (substituteParameterMappings(S, N.getLHS(), Concept, TemplateArgs, + ArgsAsWritten)) + return true; + return substituteParameterMappings(S, N.getRHS(), Concept, TemplateArgs, + ArgsAsWritten); + } + TemplateParameterList *TemplateParams = Concept->getTemplateParameters(); + + AtomicConstraint &Atomic = *N.getAtomicConstraint(); + TemplateArgumentListInfo SubstArgs; + MultiLevelTemplateArgumentList MLTAL; + MLTAL.addOuterTemplateArguments(TemplateArgs); + if (!Atomic.ParameterMapping) { + llvm::SmallBitVector OccurringIndices(TemplateParams->size()); + S.MarkUsedTemplateParameters(Atomic.ConstraintExpr, /*OnlyDeduced=*/false, + /*Depth=*/0, OccurringIndices); + Atomic.ParameterMapping.emplace( + MutableArrayRef<TemplateArgumentLoc>( + new (S.Context) TemplateArgumentLoc[OccurringIndices.count()], + OccurringIndices.count())); + for (unsigned I = 0, J = 0, C = TemplateParams->size(); I != C; ++I) + if (OccurringIndices[I]) + new (&(*Atomic.ParameterMapping)[J++]) TemplateArgumentLoc( + S.getIdentityTemplateArgumentLoc(TemplateParams->begin()[I], + // Here we assume we do not support things like + // template<typename A, typename B> + // concept C = ...; + // + // template<typename... Ts> requires C<Ts...> + // struct S { }; + // The above currently yields a diagnostic. + // We still might have default arguments for concept parameters. + ArgsAsWritten->NumTemplateArgs > I ? + ArgsAsWritten->arguments()[I].getLocation() : + SourceLocation())); + } + Sema::InstantiatingTemplate Inst( + S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(), + Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept, + SourceRange(ArgsAsWritten->arguments()[0].getSourceRange().getBegin(), + ArgsAsWritten->arguments().back().getSourceRange().getEnd())); + if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs)) + return true; + std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(), + N.getAtomicConstraint()->ParameterMapping->begin()); + return false; +} + +Optional<NormalizedConstraint> +NormalizedConstraint::fromConstraintExprs(Sema &S, NamedDecl *D, + ArrayRef<const Expr *> E) { + assert(E.size() != 0); + auto First = fromConstraintExpr(S, D, E[0]); + if (E.size() == 1) + return First; + auto Second = fromConstraintExpr(S, D, E[1]); + if (!Second) + return None; + llvm::Optional<NormalizedConstraint> Conjunction; + Conjunction.emplace(S.Context, std::move(*First), std::move(*Second), + CCK_Conjunction); + for (unsigned I = 2; I < E.size(); ++I) { + auto Next = fromConstraintExpr(S, D, E[I]); + if (!Next) + return llvm::Optional<NormalizedConstraint>{}; + NormalizedConstraint NewConjunction(S.Context, std::move(*Conjunction), + std::move(*Next), CCK_Conjunction); + *Conjunction = std::move(NewConjunction); + } + return Conjunction; +} + +llvm::Optional<NormalizedConstraint> +NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { + assert(E != nullptr); + + // C++ [temp.constr.normal]p1.1 + // [...] + // - The normal form of an expression (E) is the normal form of E. + // [...] + E = E->IgnoreParenImpCasts(); + if (auto *BO = dyn_cast<const BinaryOperator>(E)) { + if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) { + auto LHS = fromConstraintExpr(S, D, BO->getLHS()); + if (!LHS) + return None; + auto RHS = fromConstraintExpr(S, D, BO->getRHS()); + if (!RHS) + return None; + + return NormalizedConstraint( + S.Context, std::move(*LHS), std::move(*RHS), + BO->getOpcode() == BO_LAnd ? CCK_Conjunction : CCK_Disjunction); + } + } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) { + const NormalizedConstraint *SubNF; + { + Sema::InstantiatingTemplate Inst( + S, CSE->getExprLoc(), + Sema::InstantiatingTemplate::ConstraintNormalization{}, D, + CSE->getSourceRange()); + // C++ [temp.constr.normal]p1.1 + // [...] + // The normal form of an id-expression of the form C<A1, A2, ..., AN>, + // where C names a concept, is the normal form of the + // constraint-expression of C, after substituting A1, A2, ..., AN for C’s + // respective template parameters in the parameter mappings in each atomic + // constraint. If any such substitution results in an invalid type or + // expression, the program is ill-formed; no diagnostic is required. + // [...] + ConceptDecl *CD = CSE->getNamedConcept(); + SubNF = S.getNormalizedAssociatedConstraints(CD, + {CD->getConstraintExpr()}); + if (!SubNF) + return None; + } + + Optional<NormalizedConstraint> New; + New.emplace(S.Context, *SubNF); + + if (substituteParameterMappings( + S, *New, CSE->getNamedConcept(), + CSE->getTemplateArguments(), CSE->getTemplateArgsAsWritten())) + return None; + + return New; + } + return NormalizedConstraint{new (S.Context) AtomicConstraint(S, E)}; +} + +using NormalForm = + llvm::SmallVector<llvm::SmallVector<AtomicConstraint *, 2>, 4>; + +static NormalForm makeCNF(const NormalizedConstraint &Normalized) { + if (Normalized.isAtomic()) + return {{Normalized.getAtomicConstraint()}}; + + NormalForm LCNF = makeCNF(Normalized.getLHS()); + NormalForm RCNF = makeCNF(Normalized.getRHS()); + if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Conjunction) { + LCNF.reserve(LCNF.size() + RCNF.size()); + while (!RCNF.empty()) + LCNF.push_back(RCNF.pop_back_val()); + return LCNF; + } + + // Disjunction + NormalForm Res; + Res.reserve(LCNF.size() * RCNF.size()); + for (auto &LDisjunction : LCNF) + for (auto &RDisjunction : RCNF) { + NormalForm::value_type Combined; + Combined.reserve(LDisjunction.size() + RDisjunction.size()); + std::copy(LDisjunction.begin(), LDisjunction.end(), + std::back_inserter(Combined)); + std::copy(RDisjunction.begin(), RDisjunction.end(), + std::back_inserter(Combined)); + Res.emplace_back(Combined); + } + return Res; +} + +static NormalForm makeDNF(const NormalizedConstraint &Normalized) { + if (Normalized.isAtomic()) + return {{Normalized.getAtomicConstraint()}}; + + NormalForm LDNF = makeDNF(Normalized.getLHS()); + NormalForm RDNF = makeDNF(Normalized.getRHS()); + if (Normalized.getCompoundKind() == NormalizedConstraint::CCK_Disjunction) { + LDNF.reserve(LDNF.size() + RDNF.size()); + while (!RDNF.empty()) + LDNF.push_back(RDNF.pop_back_val()); + return LDNF; + } + + // Conjunction + NormalForm Res; + Res.reserve(LDNF.size() * RDNF.size()); + for (auto &LConjunction : LDNF) { + for (auto &RConjunction : RDNF) { + NormalForm::value_type Combined; + Combined.reserve(LConjunction.size() + RConjunction.size()); + std::copy(LConjunction.begin(), LConjunction.end(), + std::back_inserter(Combined)); + std::copy(RConjunction.begin(), RConjunction.end(), + std::back_inserter(Combined)); + Res.emplace_back(Combined); + } + } + return Res; +} + +template<typename AtomicSubsumptionEvaluator> +static bool subsumes(NormalForm PDNF, NormalForm QCNF, + AtomicSubsumptionEvaluator E) { + // C++ [temp.constr.order] p2 + // Then, P subsumes Q if and only if, for every disjunctive clause Pi in the + // disjunctive normal form of P, Pi subsumes every conjunctive clause Qj in + // the conjuctive normal form of Q, where [...] + for (const auto &Pi : PDNF) { + for (const auto &Qj : QCNF) { + // C++ [temp.constr.order] p2 + // - [...] a disjunctive clause Pi subsumes a conjunctive clause Qj if + // and only if there exists an atomic constraint Pia in Pi for which + // there exists an atomic constraint, Qjb, in Qj such that Pia + // subsumes Qjb. + bool Found = false; + for (const AtomicConstraint *Pia : Pi) { + for (const AtomicConstraint *Qjb : Qj) { + if (E(*Pia, *Qjb)) { + Found = true; + break; + } + } + if (Found) + break; + } + if (!Found) + return false; + } + } + return true; +} + +template<typename AtomicSubsumptionEvaluator> +static bool subsumes(Sema &S, NamedDecl *DP, ArrayRef<const Expr *> P, + NamedDecl *DQ, ArrayRef<const Expr *> Q, bool &Subsumes, + AtomicSubsumptionEvaluator E) { + // C++ [temp.constr.order] p2 + // In order to determine if a constraint P subsumes a constraint Q, P is + // transformed into disjunctive normal form, and Q is transformed into + // conjunctive normal form. [...] + auto *PNormalized = S.getNormalizedAssociatedConstraints(DP, P); + if (!PNormalized) + return true; + const NormalForm PDNF = makeDNF(*PNormalized); + + auto *QNormalized = S.getNormalizedAssociatedConstraints(DQ, Q); + if (!QNormalized) return true; + const NormalForm QCNF = makeCNF(*QNormalized); + + Subsumes = subsumes(PDNF, QCNF, E); + return false; +} + +bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1, + NamedDecl *D2, ArrayRef<const Expr *> AC2, + bool &Result) { + if (AC1.empty()) { + Result = AC2.empty(); + return false; + } + if (AC2.empty()) { + // TD1 has associated constraints and TD2 does not. + Result = true; + return false; } - IsSatisfied = EvalResult.Val.getInt().getBoolValue(); + std::pair<NamedDecl *, NamedDecl *> Key{D1, D2}; + auto CacheEntry = SubsumptionCache.find(Key); + if (CacheEntry != SubsumptionCache.end()) { + Result = CacheEntry->second; + return false; + } + if (subsumes(*this, D1, AC1, D2, AC2, Result, + [this] (const AtomicConstraint &A, const AtomicConstraint &B) { + return A.subsumes(Context, B); + })) + return true; + SubsumptionCache.try_emplace(Key, Result); return false; -}
\ No newline at end of file +} + +bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, + ArrayRef<const Expr *> AC1, NamedDecl *D2, ArrayRef<const Expr *> AC2) { + if (isSFINAEContext()) + // No need to work here because our notes would be discarded. + return false; + + if (AC1.empty() || AC2.empty()) + return false; + + auto NormalExprEvaluator = + [this] (const AtomicConstraint &A, const AtomicConstraint &B) { + return A.subsumes(Context, B); + }; + + const Expr *AmbiguousAtomic1 = nullptr, *AmbiguousAtomic2 = nullptr; + auto IdenticalExprEvaluator = + [&] (const AtomicConstraint &A, const AtomicConstraint &B) { + if (!A.hasMatchingParameterMapping(Context, B)) + return false; + const Expr *EA = A.ConstraintExpr, *EB = B.ConstraintExpr; + if (EA == EB) + return true; + + // Not the same source level expression - are the expressions + // identical? + llvm::FoldingSetNodeID IDA, IDB; + EA->Profile(IDA, Context, /*Cannonical=*/true); + EB->Profile(IDB, Context, /*Cannonical=*/true); + if (IDA != IDB) + return false; + + AmbiguousAtomic1 = EA; + AmbiguousAtomic2 = EB; + return true; + }; + + { + // The subsumption checks might cause diagnostics + SFINAETrap Trap(*this); + auto *Normalized1 = getNormalizedAssociatedConstraints(D1, AC1); + if (!Normalized1) + return false; + const NormalForm DNF1 = makeDNF(*Normalized1); + const NormalForm CNF1 = makeCNF(*Normalized1); + + auto *Normalized2 = getNormalizedAssociatedConstraints(D2, AC2); + if (!Normalized2) + return false; + const NormalForm DNF2 = makeDNF(*Normalized2); + const NormalForm CNF2 = makeCNF(*Normalized2); + + bool Is1AtLeastAs2Normally = subsumes(DNF1, CNF2, NormalExprEvaluator); + bool Is2AtLeastAs1Normally = subsumes(DNF2, CNF1, NormalExprEvaluator); + bool Is1AtLeastAs2 = subsumes(DNF1, CNF2, IdenticalExprEvaluator); + bool Is2AtLeastAs1 = subsumes(DNF2, CNF1, IdenticalExprEvaluator); + if (Is1AtLeastAs2 == Is1AtLeastAs2Normally && + Is2AtLeastAs1 == Is2AtLeastAs1Normally) + // Same result - no ambiguity was caused by identical atomic expressions. + return false; + } + + // A different result! Some ambiguous atomic constraint(s) caused a difference + assert(AmbiguousAtomic1 && AmbiguousAtomic2); + + Diag(AmbiguousAtomic1->getBeginLoc(), diag::note_ambiguous_atomic_constraints) + << AmbiguousAtomic1->getSourceRange(); + Diag(AmbiguousAtomic2->getBeginLoc(), + diag::note_ambiguous_atomic_constraints_similar_expression) + << AmbiguousAtomic2->getSourceRange(); + return true; +} diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index fd2fd35921ce..6dc9e342beb9 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" +#include "clang/Basic/Builtins.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Overload.h" @@ -1227,7 +1228,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { return false; if (RequiresNoThrowAlloc) { - const auto *FT = OperatorNew->getType()->getAs<FunctionProtoType>(); + const auto *FT = OperatorNew->getType()->castAs<FunctionProtoType>(); if (!FT->isNothrow(/*ResultIfDependent*/ false)) { S.Diag(OperatorNew->getLocation(), diag::err_coroutine_promise_new_requires_nothrow) @@ -1280,7 +1281,7 @@ bool CoroutineStmtBuilder::makeNewAndDeleteExpr() { // Check if we need to pass the size. const auto *OpDeleteType = - OpDeleteQualType.getTypePtr()->getAs<FunctionProtoType>(); + OpDeleteQualType.getTypePtr()->castAs<FunctionProtoType>(); if (OpDeleteType->getNumParams() > 1) DeleteArgs.push_back(FrameSize); @@ -1526,8 +1527,8 @@ bool Sema::buildCoroutineParameterMoves(SourceLocation Loc) { auto *FD = cast<FunctionDecl>(CurContext); auto *ScopeInfo = getCurFunction(); - assert(ScopeInfo->CoroutineParameterMoves.empty() && - "Should not build parameter moves twice"); + if (!ScopeInfo->CoroutineParameterMoves.empty()) + return false; for (auto *PD : FD->parameters()) { if (PD->getType()->isDependentType()) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 62ec83967bff..507e4a6cd436 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -867,6 +867,9 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); LookupParsedName(Result, S, &SS, !CurMethod); + if (SS.isInvalid()) + return NameClassification::Error(); + // For unqualified lookup in a class template in MSVC mode, look into // dependent base classes where the primary class template is known. if (Result.empty() && SS.isEmpty() && getLangOpts().MSVCCompat) { @@ -879,7 +882,7 @@ Sema::NameClassification Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, // synthesized instance variables), if we're in an Objective-C method. // FIXME: This lookup really, really needs to be folded in to the normal // unqualified lookup mechanism. - if (!SS.isSet() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) { + if (SS.isEmpty() && CurMethod && !isResultTypeOrTemplate(Result, NextToken)) { DeclResult Ivar = LookupIvarInObjCMethod(Result, S, Name); if (Ivar.isInvalid()) return NameClassification::Error(); @@ -899,7 +902,7 @@ Corrected: case LookupResult::NotFound: // If an unqualified-id is followed by a '(', then we have a function // call. - if (!SS.isSet() && NextToken.is(tok::l_paren)) { + if (SS.isEmpty() && NextToken.is(tok::l_paren)) { // In C++, this is an ADL-only call. // FIXME: Reference? if (getLangOpts().CPlusPlus) @@ -921,7 +924,7 @@ Corrected: return NameClassification::NonType(D); } - if (getLangOpts().CPlusPlus2a && !SS.isSet() && NextToken.is(tok::less)) { + if (getLangOpts().CPlusPlus2a && SS.isEmpty() && NextToken.is(tok::less)) { // In C++20 onwards, this could be an ADL-only call to a function // template, and we're required to assume that this is a template name. // @@ -1063,7 +1066,7 @@ Corrected: hasAnyAcceptableTemplateNames( Result, /*AllowFunctionTemplates=*/true, /*AllowDependent=*/false, - /*AllowNonTemplateFunctions*/ !SS.isSet() && + /*AllowNonTemplateFunctions*/ SS.isEmpty() && getLangOpts().CPlusPlus2a))) { // C++ [temp.names]p3: // After name lookup (3.4) finds that a name is a template-name or that @@ -1092,7 +1095,7 @@ Corrected: IsFunctionTemplate = isa<FunctionTemplateDecl>(TD); IsVarTemplate = isa<VarTemplateDecl>(TD); - if (SS.isSet() && !SS.isInvalid()) + if (SS.isNotEmpty()) Template = Context.getQualifiedTemplateName(SS.getScopeRep(), /*TemplateKeyword=*/false, TD); @@ -1802,6 +1805,13 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { (VD->getInit()->isValueDependent() || !VD->evaluateValue())) return false; } + + // Suppress the warning if we don't know how this is constructed, and + // it could possibly be non-trivial constructor. + if (Init->isTypeDependent()) + for (const CXXConstructorDecl *Ctor : RD->ctors()) + if (!Ctor->isTrivial()) + return false; } } } @@ -2549,7 +2559,7 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, NewAttr = S.mergeCodeSegAttr(D, *CSA, CSA->getName()); else if (const auto *IA = dyn_cast<MSInheritanceAttr>(Attr)) NewAttr = S.mergeMSInheritanceAttr(D, *IA, IA->getBestCase(), - IA->getSemanticSpelling()); + IA->getInheritanceModel()); else if (const auto *AA = dyn_cast<AlwaysInlineAttr>(Attr)) NewAttr = S.mergeAlwaysInlineAttr(D, *AA, &S.Context.Idents.get(AA->getSpelling())); @@ -2675,6 +2685,10 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { // C's _Noreturn is allowed to be added to a function after it is defined. ++I; continue; + } else if (isa<UuidAttr>(NewAttribute)) { + // msvc will allow a subsequent definition to add an uuid to a class + ++I; + continue; } else if (const AlignedAttr *AA = dyn_cast<AlignedAttr>(NewAttribute)) { if (AA->isAlignas()) { // C++11 [dcl.align]p6: @@ -2993,28 +3007,6 @@ struct GNUCompatibleParamWarning { } // end anonymous namespace -/// getSpecialMember - get the special member enum for a method. -Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { - if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(MD)) { - if (Ctor->isDefaultConstructor()) - return Sema::CXXDefaultConstructor; - - if (Ctor->isCopyConstructor()) - return Sema::CXXCopyConstructor; - - if (Ctor->isMoveConstructor()) - return Sema::CXXMoveConstructor; - } else if (isa<CXXDestructorDecl>(MD)) { - return Sema::CXXDestructor; - } else if (MD->isCopyAssignmentOperator()) { - return Sema::CXXCopyAssignment; - } else if (MD->isMoveAssignmentOperator()) { - return Sema::CXXMoveAssignment; - } - - return Sema::CXXInvalid; -} - // Determine whether the previous declaration was a definition, implicit // declaration, or a declaration. template <typename T> @@ -3668,6 +3660,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, return MergeCompatibleFunctionDecls(New, Old, S, MergeTypeWithOld); } + // Check if the function types are compatible when pointer size address + // spaces are ignored. + if (Context.hasSameFunctionTypeIgnoringPtrSizes(OldQType, NewQType)) + return false; + // GNU C permits a K&R definition to follow a prototype declaration // if the declared types of the parameters in the K&R definition // match the types in the prototype declaration, even when the @@ -5032,6 +5029,8 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, /*BitWidth=*/nullptr, /*Mutable=*/false, /*InitStyle=*/ICIS_NoInit); Anon->setAccess(AS); + ProcessDeclAttributes(S, Anon, Dc); + if (getLangOpts().CPlusPlus) FieldCollector->Add(cast<FieldDecl>(Anon)); } else { @@ -5045,6 +5044,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, SC = SC_None; } + assert(DS.getAttributes().empty() && "No attribute expected"); Anon = VarDecl::Create(Context, Owner, DS.getBeginLoc(), Record->getLocation(), /*IdentifierInfo=*/nullptr, Context.getTypeDeclType(Record), TInfo, SC); @@ -6139,6 +6139,41 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) { return false; } +void Sema::deduceOpenCLAddressSpace(ValueDecl *Decl) { + if (Decl->getType().hasAddressSpace()) + return; + if (VarDecl *Var = dyn_cast<VarDecl>(Decl)) { + QualType Type = Var->getType(); + if (Type->isSamplerT() || Type->isVoidType()) + return; + LangAS ImplAS = LangAS::opencl_private; + if ((getLangOpts().OpenCLCPlusPlus || getLangOpts().OpenCLVersion >= 200) && + Var->hasGlobalStorage()) + ImplAS = LangAS::opencl_global; + // If the original type from a decayed type is an array type and that array + // type has no address space yet, deduce it now. + if (auto DT = dyn_cast<DecayedType>(Type)) { + auto OrigTy = DT->getOriginalType(); + if (!OrigTy.hasAddressSpace() && OrigTy->isArrayType()) { + // Add the address space to the original array type and then propagate + // that to the element type through `getAsArrayType`. + OrigTy = Context.getAddrSpaceQualType(OrigTy, ImplAS); + OrigTy = QualType(Context.getAsArrayType(OrigTy), 0); + // Re-generate the decayed type. + Type = Context.getDecayedType(OrigTy); + } + } + Type = Context.getAddrSpaceQualType(Type, ImplAS); + // Apply any qualifiers (including address space) from the array type to + // the element type. This implements C99 6.7.3p8: "If the specification of + // an array type includes any type qualifiers, the element type is so + // qualified, not the array type." + if (Type->isArrayType()) + Type = QualType(Context.getAsArrayType(Type), 0); + Decl->setType(Type); + } +} + static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { // Ensure that an auto decl is deduced otherwise the checks below might cache // the wrong linkage. @@ -6496,6 +6531,105 @@ static bool isDeclExternC(const Decl *D) { llvm_unreachable("Unknown type of decl!"); } +/// Returns true if there hasn't been any invalid type diagnosed. +static bool diagnoseOpenCLTypes(Scope *S, Sema &Se, Declarator &D, + DeclContext *DC, QualType R) { + // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument. + // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function + // argument. + if (R->isImageType() || R->isPipeType()) { + Se.Diag(D.getIdentifierLoc(), + diag::err_opencl_type_can_only_be_used_as_function_parameter) + << R; + D.setInvalidType(); + return false; + } + + // OpenCL v1.2 s6.9.r: + // The event type cannot be used to declare a program scope variable. + // OpenCL v2.0 s6.9.q: + // The clk_event_t and reserve_id_t types cannot be declared in program + // scope. + if (NULL == S->getParent()) { + if (R->isReserveIDT() || R->isClkEventT() || R->isEventT()) { + Se.Diag(D.getIdentifierLoc(), + diag::err_invalid_type_for_program_scope_var) + << R; + D.setInvalidType(); + return false; + } + } + + // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed. + QualType NR = R; + while (NR->isPointerType()) { + if (NR->isFunctionPointerType()) { + Se.Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer); + D.setInvalidType(); + return false; + } + NR = NR->getPointeeType(); + } + + if (!Se.getOpenCLOptions().isEnabled("cl_khr_fp16")) { + // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and + // half array type (unless the cl_khr_fp16 extension is enabled). + if (Se.Context.getBaseElementType(R)->isHalfType()) { + Se.Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R; + D.setInvalidType(); + return false; + } + } + + // OpenCL v1.2 s6.9.r: + // The event type cannot be used with the __local, __constant and __global + // address space qualifiers. + if (R->isEventT()) { + if (R.getAddressSpace() != LangAS::opencl_private) { + Se.Diag(D.getBeginLoc(), diag::err_event_t_addr_space_qual); + D.setInvalidType(); + return false; + } + } + + // C++ for OpenCL does not allow the thread_local storage qualifier. + // OpenCL C does not support thread_local either, and + // also reject all other thread storage class specifiers. + DeclSpec::TSCS TSC = D.getDeclSpec().getThreadStorageClassSpec(); + if (TSC != TSCS_unspecified) { + bool IsCXX = Se.getLangOpts().OpenCLCPlusPlus; + Se.Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), + diag::err_opencl_unknown_type_specifier) + << IsCXX << Se.getLangOpts().getOpenCLVersionTuple().getAsString() + << DeclSpec::getSpecifierName(TSC) << 1; + D.setInvalidType(); + return false; + } + + if (R->isSamplerT()) { + // OpenCL v1.2 s6.9.b p4: + // The sampler type cannot be used with the __local and __global address + // space qualifiers. + if (R.getAddressSpace() == LangAS::opencl_local || + R.getAddressSpace() == LangAS::opencl_global) { + Se.Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace); + D.setInvalidType(); + } + + // OpenCL v1.2 s6.12.14.1: + // A global sampler must be declared with either the constant address + // space qualifier or with the const qualifier. + if (DC->isTranslationUnit() && + !(R.getAddressSpace() == LangAS::opencl_constant || + R.isConstQualified())) { + Se.Diag(D.getIdentifierLoc(), diag::err_opencl_nonconst_global_sampler); + D.setInvalidType(); + } + if (D.isInvalidType()) + return false; + } + return true; +} NamedDecl *Sema::ActOnVariableDeclarator( Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, @@ -6519,95 +6653,6 @@ NamedDecl *Sema::ActOnVariableDeclarator( return nullptr; } - if (getLangOpts().OpenCL) { - // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument. - // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function - // argument. - if (R->isImageType() || R->isPipeType()) { - Diag(D.getIdentifierLoc(), - diag::err_opencl_type_can_only_be_used_as_function_parameter) - << R; - D.setInvalidType(); - return nullptr; - } - - // OpenCL v1.2 s6.9.r: - // The event type cannot be used to declare a program scope variable. - // OpenCL v2.0 s6.9.q: - // The clk_event_t and reserve_id_t types cannot be declared in program scope. - if (NULL == S->getParent()) { - if (R->isReserveIDT() || R->isClkEventT() || R->isEventT()) { - Diag(D.getIdentifierLoc(), - diag::err_invalid_type_for_program_scope_var) << R; - D.setInvalidType(); - return nullptr; - } - } - - // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed. - QualType NR = R; - while (NR->isPointerType()) { - if (NR->isFunctionPointerType()) { - Diag(D.getIdentifierLoc(), diag::err_opencl_function_pointer); - D.setInvalidType(); - break; - } - NR = NR->getPointeeType(); - } - - if (!getOpenCLOptions().isEnabled("cl_khr_fp16")) { - // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and - // half array type (unless the cl_khr_fp16 extension is enabled). - if (Context.getBaseElementType(R)->isHalfType()) { - Diag(D.getIdentifierLoc(), diag::err_opencl_half_declaration) << R; - D.setInvalidType(); - } - } - - if (R->isSamplerT()) { - // OpenCL v1.2 s6.9.b p4: - // The sampler type cannot be used with the __local and __global address - // space qualifiers. - if (R.getAddressSpace() == LangAS::opencl_local || - R.getAddressSpace() == LangAS::opencl_global) { - Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace); - } - - // OpenCL v1.2 s6.12.14.1: - // A global sampler must be declared with either the constant address - // space qualifier or with the const qualifier. - if (DC->isTranslationUnit() && - !(R.getAddressSpace() == LangAS::opencl_constant || - R.isConstQualified())) { - Diag(D.getIdentifierLoc(), diag::err_opencl_nonconst_global_sampler); - D.setInvalidType(); - } - } - - // OpenCL v1.2 s6.9.r: - // The event type cannot be used with the __local, __constant and __global - // address space qualifiers. - if (R->isEventT()) { - if (R.getAddressSpace() != LangAS::opencl_private) { - Diag(D.getBeginLoc(), diag::err_event_t_addr_space_qual); - D.setInvalidType(); - } - } - - // C++ for OpenCL does not allow the thread_local storage qualifier. - // OpenCL C does not support thread_local either, and - // also reject all other thread storage class specifiers. - DeclSpec::TSCS TSC = D.getDeclSpec().getThreadStorageClassSpec(); - if (TSC != TSCS_unspecified) { - bool IsCXX = getLangOpts().OpenCLCPlusPlus; - Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), - diag::err_opencl_unknown_type_specifier) - << IsCXX << getLangOpts().getOpenCLVersionTuple().getAsString() - << DeclSpec::getSpecifierName(TSC) << 1; - D.setInvalidType(); - return nullptr; - } - } DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec()); @@ -6964,6 +7009,13 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } + if (getLangOpts().OpenCL) { + + deduceOpenCLAddressSpace(NewVD); + + diagnoseOpenCLTypes(S, *this, D, DC, NewVD->getType()); + } + // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); @@ -7039,8 +7091,9 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } - NewVD->addAttr(::new (Context) AsmLabelAttr( - Context, SE->getStrTokenLoc(0), Label, /*IsLiteralLabel=*/true)); + NewVD->addAttr(AsmLabelAttr::Create(Context, Label, + /*IsLiteralLabel=*/true, + SE->getStrTokenLoc(0))); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I = ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); @@ -7842,7 +7895,13 @@ struct FindOverriddenMethod { Path.Decls = Path.Decls.slice(1)) { NamedDecl *D = Path.Decls.front(); if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D)) { - if (MD->isVirtual() && !S->IsOverload(Method, MD, false)) + if (MD->isVirtual() && + !S->IsOverload( + Method, MD, /*UseMemberUsingDeclRules=*/false, + /*ConsiderCudaAttrs=*/true, + // C++2a [class.virtual]p2 does not consider requires clauses + // when overriding. + /*ConsiderRequiresClauses=*/false)) return true; } } @@ -8187,7 +8246,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, NewFD = FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC, isInline, HasPrototype, - CSK_unspecified); + CSK_unspecified, + /*TrailingRequiresClause=*/nullptr); if (D.isInvalidType()) NewFD->setInvalidDecl(); @@ -8204,6 +8264,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, ConstexprKind = CSK_unspecified; D.getMutableDeclSpec().ClearConstexprSpec(); } + Expr *TrailingRequiresClause = D.getTrailingRequiresClause(); // Check that the return type is not an abstract class type. // For record types, this is done by the AbstractClassUsageDiagnoser once @@ -8223,7 +8284,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, return CXXConstructorDecl::Create( SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R, TInfo, ExplicitSpecifier, isInline, - /*isImplicitlyDeclared=*/false, ConstexprKind); + /*isImplicitlyDeclared=*/false, ConstexprKind, InheritedConstructor(), + TrailingRequiresClause); } else if (Name.getNameKind() == DeclarationName::CXXDestructorName) { // This is a C++ destructor declaration. @@ -8232,8 +8294,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); CXXDestructorDecl *NewDD = CXXDestructorDecl::Create( SemaRef.Context, Record, D.getBeginLoc(), NameInfo, R, TInfo, - isInline, - /*isImplicitlyDeclared=*/false, ConstexprKind); + isInline, /*isImplicitlyDeclared=*/false, ConstexprKind, + TrailingRequiresClause); // If the destructor needs an implicit exception specification, set it // now. FIXME: It'd be nice to be able to create the right type to start @@ -8253,7 +8315,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), D.getIdentifierLoc(), Name, R, TInfo, SC, isInline, - /*hasPrototype=*/true, ConstexprKind); + /*hasPrototype=*/true, ConstexprKind, + TrailingRequiresClause); } } else if (Name.getNameKind() == DeclarationName::CXXConversionFunctionName) { @@ -8270,9 +8333,14 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, IsVirtualOkay = true; return CXXConversionDecl::Create( SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R, - TInfo, isInline, ExplicitSpecifier, ConstexprKind, SourceLocation()); + TInfo, isInline, ExplicitSpecifier, ConstexprKind, SourceLocation(), + TrailingRequiresClause); } else if (Name.getNameKind() == DeclarationName::CXXDeductionGuideName) { + if (TrailingRequiresClause) + SemaRef.Diag(TrailingRequiresClause->getBeginLoc(), + diag::err_trailing_requires_clause_on_deduction_guide) + << TrailingRequiresClause->getSourceRange(); SemaRef.CheckDeductionGuideDeclarator(D, R, SC); return CXXDeductionGuideDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), @@ -8294,7 +8362,8 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, // This is a C++ method declaration. CXXMethodDecl *Ret = CXXMethodDecl::Create( SemaRef.Context, cast<CXXRecordDecl>(DC), D.getBeginLoc(), NameInfo, R, - TInfo, SC, isInline, ConstexprKind, SourceLocation()); + TInfo, SC, isInline, ConstexprKind, SourceLocation(), + TrailingRequiresClause); IsVirtualOkay = !Ret->isStatic(); return Ret; } else { @@ -8308,7 +8377,7 @@ static FunctionDecl *CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, // - we're in C++ (where every function has a prototype), return FunctionDecl::Create(SemaRef.Context, DC, D.getBeginLoc(), NameInfo, R, TInfo, SC, isInline, true /*HasPrototype*/, - ConstexprKind); + ConstexprKind, TrailingRequiresClause); } } @@ -8332,7 +8401,7 @@ static bool isOpenCLSizeDependentType(ASTContext &C, QualType Ty) { QualType DesugaredTy = Ty; do { ArrayRef<StringRef> Names(SizeTypeNames); - auto Match = llvm::find(Names, DesugaredTy.getAsString()); + auto Match = llvm::find(Names, DesugaredTy.getUnqualifiedType().getAsString()); if (Names.end() != Match) return true; @@ -8943,9 +9012,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (Expr *E = (Expr*) D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast<StringLiteral>(E); - NewFD->addAttr(::new (Context) - AsmLabelAttr(Context, SE->getStrTokenLoc(0), - SE->getString(), /*IsLiteralLabel=*/true)); + NewFD->addAttr(AsmLabelAttr::Create(Context, SE->getString(), + /*IsLiteralLabel=*/true, + SE->getStrTokenLoc(0))); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I = ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier()); @@ -9551,6 +9620,29 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } + // Diagnose no_builtin attribute on function declaration that are not a + // definition. + // FIXME: We should really be doing this in + // SemaDeclAttr.cpp::handleNoBuiltinAttr, unfortunately we only have access to + // the FunctionDecl and at this point of the code + // FunctionDecl::isThisDeclarationADefinition() which always returns `false` + // because Sema::ActOnStartOfFunctionDef has not been called yet. + if (const auto *NBA = NewFD->getAttr<NoBuiltinAttr>()) + switch (D.getFunctionDefinitionKind()) { + case FDK_Defaulted: + case FDK_Deleted: + Diag(NBA->getLocation(), + diag::err_attribute_no_builtin_on_defaulted_deleted_function) + << NBA->getSpelling(); + break; + case FDK_Declaration: + Diag(NBA->getLocation(), diag::err_attribute_no_builtin_on_non_definition) + << NBA->getSpelling(); + break; + case FDK_Definition: + break; + } + return NewFD; } @@ -9687,7 +9779,7 @@ bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) { static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) { const auto *TA = FD->getAttr<TargetAttr>(); assert(TA && "MultiVersion Candidate requires a target attribute"); - TargetAttr::ParsedTargetAttr ParseInfo = TA->parse(); + ParsedTargetAttr ParseInfo = TA->parse(); const TargetInfo &TargetInfo = S.Context.getTargetInfo(); enum ErrType { Feature = 0, Architecture = 1 }; @@ -9764,13 +9856,15 @@ bool Sema::areMultiversionVariantFunctionsCompatible( Linkage = 5, }; - if (OldFD && !OldFD->getType()->getAs<FunctionProtoType>()) { + if (NoProtoDiagID.getDiagID() != 0 && OldFD && + !OldFD->getType()->getAs<FunctionProtoType>()) { Diag(OldFD->getLocation(), NoProtoDiagID); Diag(NoteCausedDiagIDAt.first, NoteCausedDiagIDAt.second); return true; } - if (!NewFD->getType()->getAs<FunctionProtoType>()) + if (NoProtoDiagID.getDiagID() != 0 && + !NewFD->getType()->getAs<FunctionProtoType>()) return Diag(NewFD->getLocation(), NoProtoDiagID); if (!TemplatesSupported && @@ -9938,7 +10032,7 @@ static bool CheckTargetCausesMultiVersioning( bool &Redeclaration, NamedDecl *&OldDecl, bool &MergeTypeWithPrevious, LookupResult &Previous) { const auto *OldTA = OldFD->getAttr<TargetAttr>(); - TargetAttr::ParsedTargetAttr NewParsed = NewTA->parse(); + ParsedTargetAttr NewParsed = NewTA->parse(); // Sort order doesn't matter, it just needs to be consistent. llvm::sort(NewParsed.Features); @@ -9982,8 +10076,7 @@ static bool CheckTargetCausesMultiVersioning( return true; } - TargetAttr::ParsedTargetAttr OldParsed = - OldTA->parse(std::less<std::string>()); + ParsedTargetAttr OldParsed = OldTA->parse(std::less<std::string>()); if (OldParsed == NewParsed) { S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); @@ -10036,7 +10129,7 @@ static bool CheckMultiVersionAdditionalDecl( return true; } - TargetAttr::ParsedTargetAttr NewParsed; + ParsedTargetAttr NewParsed; if (NewTA) { NewParsed = NewTA->parse(); llvm::sort(NewParsed.Features); @@ -10063,8 +10156,7 @@ static bool CheckMultiVersionAdditionalDecl( return false; } - TargetAttr::ParsedTargetAttr CurParsed = - CurTA->parse(std::less<std::string>()); + ParsedTargetAttr CurParsed = CurTA->parse(std::less<std::string>()); if (CurParsed == NewParsed) { S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); S.Diag(CurFD->getLocation(), diag::note_previous_declaration); @@ -10496,6 +10588,11 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } } + if (Method->isVirtual() && NewFD->getTrailingRequiresClause()) + // C++2a [class.virtual]p6 + // A virtual method shall not have a requires-clause. + Diag(NewFD->getTrailingRequiresClause()->getBeginLoc(), + diag::err_constrained_virtual_method); if (Method->isStatic()) checkThisInStaticMemberFunctionType(Method); @@ -11281,6 +11378,9 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, if (getLangOpts().ObjCAutoRefCount && inferObjCARCLifetime(VDecl)) VDecl->setInvalidDecl(); + if (getLangOpts().OpenCL) + deduceOpenCLAddressSpace(VDecl); + // If this is a redeclaration, check that the type we just deduced matches // the previously declared type. if (VarDecl *Old = VDecl->getPreviousDecl()) { @@ -12145,6 +12245,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { Diag(Var->getLocation(), diag::note_private_extern); } + if (Context.getTargetInfo().allowDebugInfoForExternalVar() && + !Var->isInvalidDecl() && !getLangOpts().CPlusPlus) + ExternalDeclarations.push_back(Var); + return; case VarDecl::TentativeDefinition: @@ -13103,6 +13207,10 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (New->hasAttr<BlocksAttr>()) { Diag(New->getLocation(), diag::err_block_on_nonlocal); } + + if (getLangOpts().OpenCL) + deduceOpenCLAddressSpace(New); + return New; } @@ -13315,8 +13423,10 @@ ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, return false; // Don't warn about 'main'. - if (FD->isMain()) - return false; + if (isa<TranslationUnitDecl>(FD->getDeclContext()->getRedeclContext())) + if (IdentifierInfo *II = FD->getIdentifier()) + if (II->isStr("main")) + return false; // Don't warn about inline functions. if (FD->isInlined()) @@ -13826,8 +13936,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, LSI->ReturnType.isNull() ? Context.VoidTy : LSI->ReturnType; // Update the return type to the deduced type. - const FunctionProtoType *Proto = - FD->getType()->getAs<FunctionProtoType>(); + const auto *Proto = FD->getType()->castAs<FunctionProtoType>(); FD->setType(Context.getFunctionType(RetType, Proto->getParamTypes(), Proto->getExtProtoInfo())); } @@ -16031,7 +16140,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } // TR 18037 does not allow fields to be declared with address space - if (T.getQualifiers().hasAddressSpace() || T->isDependentAddressSpaceType() || + if (T.hasAddressSpace() || T->isDependentAddressSpaceType() || T->getBaseElementTypeUnsafe()->isDependentAddressSpaceType()) { Diag(Loc, diag::err_field_with_address_space); Record->setInvalidDecl(); @@ -16754,7 +16863,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, if (const MSInheritanceAttr *IA = Record->getAttr<MSInheritanceAttr>()) checkMSInheritanceAttrOnDefinition(cast<CXXRecordDecl>(Record), IA->getRange(), IA->getBestCase(), - IA->getSemanticSpelling()); + IA->getInheritanceModel()); } // Check if the structure/union declaration is a type that can have zero diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index b2be6245a814..5c51b0f9b8cb 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -23,6 +23,7 @@ #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetBuiltins.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" @@ -1068,6 +1069,56 @@ static void handleDiagnoseIfAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Context, AL, Cond, Msg, DiagType, ArgDependent, cast<NamedDecl>(D))); } +static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + static constexpr const StringRef kWildcard = "*"; + + llvm::SmallVector<StringRef, 16> Names; + bool HasWildcard = false; + + const auto AddBuiltinName = [&Names, &HasWildcard](StringRef Name) { + if (Name == kWildcard) + HasWildcard = true; + Names.push_back(Name); + }; + + // Add previously defined attributes. + if (const auto *NBA = D->getAttr<NoBuiltinAttr>()) + for (StringRef BuiltinName : NBA->builtinNames()) + AddBuiltinName(BuiltinName); + + // Add current attributes. + if (AL.getNumArgs() == 0) + AddBuiltinName(kWildcard); + else + for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) { + StringRef BuiltinName; + SourceLocation LiteralLoc; + if (!S.checkStringLiteralArgumentAttr(AL, I, BuiltinName, &LiteralLoc)) + return; + + if (Builtin::Context::isBuiltinFunc(BuiltinName)) + AddBuiltinName(BuiltinName); + else + S.Diag(LiteralLoc, diag::warn_attribute_no_builtin_invalid_builtin_name) + << BuiltinName << AL.getAttrName()->getName(); + } + + // Repeating the same attribute is fine. + llvm::sort(Names); + Names.erase(std::unique(Names.begin(), Names.end()), Names.end()); + + // Empty no_builtin must be on its own. + if (HasWildcard && Names.size() > 1) + S.Diag(D->getLocation(), + diag::err_attribute_no_builtin_wildcard_or_builtin_name) + << AL.getAttrName()->getName(); + + if (D->hasAttr<NoBuiltinAttr>()) + D->dropAttr<NoBuiltinAttr>(); + D->addAttr(::new (S.Context) + NoBuiltinAttr(S.Context, AL, Names.data(), Names.size())); +} + static void handlePassObjectSizeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (D->hasAttr<PassObjectSizeAttr>()) { S.Diag(D->getBeginLoc(), diag::err_attribute_only_once_per_parameter) << AL; @@ -2549,6 +2600,29 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, D->addAttr(newAttr); } +static void handleObjCDirectAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // objc_direct cannot be set on methods declared in the context of a protocol + if (isa<ObjCProtocolDecl>(D->getDeclContext())) { + S.Diag(AL.getLoc(), diag::err_objc_direct_on_protocol) << false; + return; + } + + if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) { + handleSimpleAttribute<ObjCDirectAttr>(S, D, AL); + } else { + S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL; + } +} + +static void handleObjCDirectMembersAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + if (S.getLangOpts().ObjCRuntime.allowsDirectDispatch()) { + handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL); + } else { + S.Diag(AL.getLoc(), diag::warn_objc_direct_ignored) << AL; + } +} + static void handleObjCMethodFamilyAttr(Sema &S, Decl *D, const ParsedAttr &AL) { const auto *M = cast<ObjCMethodDecl>(D); if (!AL.isArgIdent(0)) { @@ -2839,7 +2913,7 @@ static void handleVecTypeHint(Sema &S, Decl *D, const ParsedAttr &AL) { if (!ParmType->isExtVectorType() && !ParmType->isFloatingType() && (ParmType->isBooleanType() || !ParmType->isIntegralType(S.getASTContext()))) { - S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 3 << AL; + S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) << 2 << AL; return; } @@ -2972,7 +3046,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << Str; - TargetAttr::ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr); + ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr); if (!ParsedAttrs.Architecture.empty() && !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture)) @@ -2990,6 +3064,19 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { << Unsupported << None << CurFeature; } + TargetInfo::BranchProtectionInfo BPI; + StringRef Error; + if (!ParsedAttrs.BranchProtection.empty() && + !Context.getTargetInfo().validateBranchProtection( + ParsedAttrs.BranchProtection, BPI, Error)) { + if (Error.empty()) + return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) + << Unsupported << None << "branch-protection"; + else + return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec) + << Error; + } + return false; } @@ -3798,7 +3885,7 @@ void Sema::CheckAlignasUnderalignment(Decl *D) { bool Sema::checkMSInheritanceAttrOnDefinition( CXXRecordDecl *RD, SourceRange Range, bool BestCase, - MSInheritanceAttr::Spelling SemanticSpelling) { + MSInheritanceModel ExplicitModel) { assert(RD->hasDefinition() && "RD has no definition!"); // We may not have seen base specifiers or any virtual methods yet. We will @@ -3807,14 +3894,14 @@ bool Sema::checkMSInheritanceAttrOnDefinition( return false; // The unspecified model never matches what a definition could need. - if (SemanticSpelling == MSInheritanceAttr::Keyword_unspecified_inheritance) + if (ExplicitModel == MSInheritanceModel::Unspecified) return false; if (BestCase) { - if (RD->calculateInheritanceModel() == SemanticSpelling) + if (RD->calculateInheritanceModel() == ExplicitModel) return false; } else { - if (RD->calculateInheritanceModel() <= SemanticSpelling) + if (RD->calculateInheritanceModel() <= ExplicitModel) return false; } @@ -4367,12 +4454,10 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { ParmType = S.GetTypeFromParser(AL.getTypeArg(), &DerefTypeLoc); unsigned SelectIdx = ~0U; - if (ParmType->isVoidType()) + if (ParmType->isReferenceType()) SelectIdx = 0; - else if (ParmType->isReferenceType()) - SelectIdx = 1; else if (ParmType->isArrayType()) - SelectIdx = 2; + SelectIdx = 1; if (SelectIdx != ~0U) { S.Diag(AL.getLoc(), diag::err_attribute_invalid_argument) @@ -4830,6 +4915,54 @@ static void handleXRayLogArgsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { XRayLogArgsAttr(S.Context, AL, ArgCount.getSourceIndex())); } +static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + uint32_t Count = 0, Offset = 0; + if (!checkUInt32Argument(S, AL, AL.getArgAsExpr(0), Count, 0, true)) + return; + if (AL.getNumArgs() == 2) { + Expr *Arg = AL.getArgAsExpr(1); + if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true)) + return; + if (Offset) { + S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range) + << &AL << 0 << 0 << Arg->getBeginLoc(); + return; + } + } + D->addAttr(::new (S.Context) + PatchableFunctionEntryAttr(S.Context, AL, Count, Offset)); +} + +static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) { + if (AliasName.startswith("__arm_")) + AliasName = AliasName.substr(6); + switch (BuiltinID) { +#include "clang/Basic/arm_mve_builtin_aliases.inc" + default: + return false; + } +} + +static void handleArmMveAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) + << AL << 1 << AANT_ArgumentIdentifier; + return; + } + + IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident; + unsigned BuiltinID = Ident->getBuiltinID(); + + if (!ArmMveAliasValid(BuiltinID, + cast<FunctionDecl>(D)->getIdentifier()->getName())) { + S.Diag(AL.getLoc(), diag::err_attribute_arm_mve_alias); + return; + } + + D->addAttr(::new (S.Context) ArmMveAliasAttr(S.Context, AL, Ident)); +} + //===----------------------------------------------------------------------===// // Checker-specific attribute handlers. //===----------------------------------------------------------------------===// @@ -5278,9 +5411,11 @@ UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, if (const auto *UA = D->getAttr<UuidAttr>()) { if (UA->getGuid().equals_lower(Uuid)) return nullptr; - Diag(UA->getLocation(), diag::err_mismatched_uuid); - Diag(CI.getLoc(), diag::note_previous_uuid); - D->dropAttr<UuidAttr>(); + if (!UA->getGuid().empty()) { + Diag(UA->getLocation(), diag::err_mismatched_uuid); + Diag(CI.getLoc(), diag::note_previous_uuid); + D->dropAttr<UuidAttr>(); + } } return ::new (Context) UuidAttr(Context, CI, Uuid); @@ -5342,8 +5477,7 @@ static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } MSInheritanceAttr *IA = S.mergeMSInheritanceAttr( - D, AL, /*BestCase=*/true, - (MSInheritanceAttr::Spelling)AL.getSemanticSpelling()); + D, AL, /*BestCase=*/true, (MSInheritanceModel)AL.getSemanticSpelling()); if (IA) { D->addAttr(IA); S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D)); @@ -5620,6 +5754,47 @@ static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { handleSimpleAttribute<AVRSignalAttr>(S, D, AL); } +static void handleBPFPreserveAIRecord(Sema &S, RecordDecl *RD) { + // Add preserve_access_index attribute to all fields and inner records. + for (auto D : RD->decls()) { + if (D->hasAttr<BPFPreserveAccessIndexAttr>()) + continue; + + D->addAttr(BPFPreserveAccessIndexAttr::CreateImplicit(S.Context)); + if (auto *Rec = dyn_cast<RecordDecl>(D)) + handleBPFPreserveAIRecord(S, Rec); + } +} + +static void handleBPFPreserveAccessIndexAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { + auto *Rec = cast<RecordDecl>(D); + handleBPFPreserveAIRecord(S, Rec); + Rec->addAttr(::new (S.Context) BPFPreserveAccessIndexAttr(S.Context, AL)); +} + +static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (!isFunctionOrMethod(D)) { + S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) + << "'export_name'" << ExpectedFunction; + return; + } + + auto *FD = cast<FunctionDecl>(D); + if (FD->isThisDeclarationADefinition()) { + S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; + return; + } + + StringRef Str; + SourceLocation ArgLoc; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) + return; + + D->addAttr(::new (S.Context) WebAssemblyExportNameAttr(S.Context, AL, Str)); + D->addAttr(UsedAttr::CreateImplicit(S.Context)); +} + static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) @@ -5977,9 +6152,9 @@ static void handleDLLAttr(Sema &S, Decl *D, const ParsedAttr &A) { MSInheritanceAttr * Sema::mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI, bool BestCase, - MSInheritanceAttr::Spelling SemanticSpelling) { + MSInheritanceModel Model) { if (MSInheritanceAttr *IA = D->getAttr<MSInheritanceAttr>()) { - if (IA->getSemanticSpelling() == SemanticSpelling) + if (IA->getInheritanceModel() == Model) return nullptr; Diag(IA->getLocation(), diag::err_mismatched_ms_inheritance) << 1 /*previous declaration*/; @@ -5990,7 +6165,7 @@ Sema::mergeMSInheritanceAttr(Decl *D, const AttributeCommonInfo &CI, auto *RD = cast<CXXRecordDecl>(D); if (RD->hasDefinition()) { if (checkMSInheritanceAttrOnDefinition(RD, CI.getRange(), BestCase, - SemanticSpelling)) { + Model)) { return nullptr; } } else { @@ -6278,6 +6453,45 @@ static void handleOpenCLAccessAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(::new (S.Context) OpenCLAccessAttr(S.Context, AL)); } +static void handleSYCLKernelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // The 'sycl_kernel' attribute applies only to function templates. + const auto *FD = cast<FunctionDecl>(D); + const FunctionTemplateDecl *FT = FD->getDescribedFunctionTemplate(); + assert(FT && "Function template is expected"); + + // Function template must have at least two template parameters. + const TemplateParameterList *TL = FT->getTemplateParameters(); + if (TL->size() < 2) { + S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_template_params); + return; + } + + // Template parameters must be typenames. + for (unsigned I = 0; I < 2; ++I) { + const NamedDecl *TParam = TL->getParam(I); + if (isa<NonTypeTemplateParmDecl>(TParam)) { + S.Diag(FT->getLocation(), + diag::warn_sycl_kernel_invalid_template_param_type); + return; + } + } + + // Function must have at least one argument. + if (getFunctionOrMethodNumParams(D) != 1) { + S.Diag(FT->getLocation(), diag::warn_sycl_kernel_num_of_function_params); + return; + } + + // Function must return void. + QualType RetTy = getFunctionOrMethodResultType(D); + if (!RetTy->isVoidType()) { + S.Diag(FT->getLocation(), diag::warn_sycl_kernel_return_type); + return; + } + + handleSimpleAttribute<SYCLKernelAttr>(S, D, AL); +} + static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) { if (!cast<VarDecl>(D)->hasGlobalStorage()) { S.Diag(D->getLocation(), diag::err_destroy_attr_on_non_static_var) @@ -6406,6 +6620,50 @@ static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { handleSimpleAttribute<MSAllocatorAttr>(S, D, AL); } +static void handeAcquireHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (AL.isUsedAsTypeAttr()) + return; + // Warn if the parameter is definitely not an output parameter. + if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) { + if (PVD->getType()->isIntegerType()) { + S.Diag(AL.getLoc(), diag::err_attribute_output_parameter) + << AL.getRange(); + return; + } + } + StringRef Argument; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument)) + return; + D->addAttr(AcquireHandleAttr::Create(S.Context, Argument, AL)); +} + +template<typename Attr> +static void handleHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + StringRef Argument; + if (!S.checkStringLiteralArgumentAttr(AL, 0, Argument)) + return; + D->addAttr(Attr::Create(S.Context, Argument, AL)); +} + +static void handleCFGuardAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + // The guard attribute takes a single identifier argument. + + if (!AL.isArgIdent(0)) { + S.Diag(AL.getLoc(), diag::err_attribute_argument_type) + << AL << AANT_ArgumentIdentifier; + return; + } + + CFGuardAttr::GuardArg Arg; + IdentifierInfo *II = AL.getArgAsIdent(0)->Ident; + if (!CFGuardAttr::ConvertStrToGuardArg(II->getName(), Arg)) { + S.Diag(AL.getLoc(), diag::warn_attribute_type_not_supported) << AL << II; + return; + } + + D->addAttr(::new (S.Context) CFGuardAttr(S.Context, AL, Arg)); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -6496,6 +6754,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_AVRSignal: handleAVRSignalAttr(S, D, AL); break; + case ParsedAttr::AT_BPFPreserveAccessIndex: + handleBPFPreserveAccessIndexAttr(S, D, AL); + break; + case ParsedAttr::AT_WebAssemblyExportName: + handleWebAssemblyExportNameAttr(S, D, AL); + break; case ParsedAttr::AT_WebAssemblyImportModule: handleWebAssemblyImportModuleAttr(S, D, AL); break; @@ -6578,6 +6842,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_DiagnoseIf: handleDiagnoseIfAttr(S, D, AL); break; + case ParsedAttr::AT_NoBuiltin: + handleNoBuiltinAttr(S, D, AL); + break; case ParsedAttr::AT_ExtVectorType: handleExtVectorTypeAttr(S, D, AL); break; @@ -6599,6 +6866,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Flatten: handleSimpleAttribute<FlattenAttr>(S, D, AL); break; + case ParsedAttr::AT_SYCLKernel: + handleSYCLKernelAttr(S, D, AL); + break; case ParsedAttr::AT_Format: handleFormatAttr(S, D, AL); break; @@ -6826,6 +7096,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_ObjCRootClass: handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL); break; + case ParsedAttr::AT_ObjCDirect: + handleObjCDirectAttr(S, D, AL); + break; + case ParsedAttr::AT_ObjCDirectMembers: + handleObjCDirectMembersAttr(S, D, AL); + handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL); + break; case ParsedAttr::AT_ObjCNonLazyClass: handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL); break; @@ -7015,6 +7292,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_AbiTag: handleAbiTagAttr(S, D, AL); break; + case ParsedAttr::AT_CFGuard: + handleCFGuardAttr(S, D, AL); + break; // Thread safety attributes: case ParsedAttr::AT_AssertExclusiveLock: @@ -7135,6 +7415,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleXRayLogArgsAttr(S, D, AL); break; + case ParsedAttr::AT_PatchableFunctionEntry: + handlePatchableFunctionEntryAttr(S, D, AL); + break; + // Move semantics attribute. case ParsedAttr::AT_Reinitializes: handleSimpleAttribute<ReinitializesAttr>(S, D, AL); @@ -7160,6 +7444,22 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_MSAllocator: handleMSAllocatorAttr(S, D, AL); break; + + case ParsedAttr::AT_ArmMveAlias: + handleArmMveAliasAttr(S, D, AL); + break; + + case ParsedAttr::AT_AcquireHandle: + handeAcquireHandleAttr(S, D, AL); + break; + + case ParsedAttr::AT_ReleaseHandle: + handleHandleAttr<ReleaseHandleAttr>(S, D, AL); + break; + + case ParsedAttr::AT_UseHandle: + handleHandleAttr<UseHandleAttr>(S, D, AL); + break; } } @@ -7238,7 +7538,8 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } } -// Helper for delayed processing TransparentUnion attribute. +// Helper for delayed processing TransparentUnion or BPFPreserveAccessIndexAttr +// attribute. void Sema::ProcessDeclAttributeDelayed(Decl *D, const ParsedAttributesView &AttrList) { for (const ParsedAttr &AL : AttrList) @@ -7246,6 +7547,11 @@ void Sema::ProcessDeclAttributeDelayed(Decl *D, handleTransparentUnionAttr(*this, D, AL); break; } + + // For BPFPreserveAccessIndexAttr, we want to populate the attributes + // to fields and inner records as well. + if (D && D->hasAttr<BPFPreserveAccessIndexAttr>()) + handleBPFPreserveAIRecord(*this, cast<RecordDecl>(D)); } // Annotation attributes are the only attributes allowed after an access @@ -7308,7 +7614,8 @@ NamedDecl * Sema::DeclClonePragmaWeak(NamedDecl *ND, IdentifierInfo *II, NewFD = FunctionDecl::Create( FD->getASTContext(), FD->getDeclContext(), Loc, Loc, DeclarationName(II), FD->getType(), FD->getTypeSourceInfo(), SC_None, - false /*isInlineSpecified*/, FD->hasPrototype(), CSK_unspecified); + false /*isInlineSpecified*/, FD->hasPrototype(), CSK_unspecified, + FD->getTrailingRequiresClause()); NewD = NewFD; if (FD->getQualifier()) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ff90b9548e29..9916d3be77e1 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -217,8 +217,8 @@ Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, Exceptions.push_back(E); } -void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { - if (!E || ComputedEST == EST_MSAny) +void Sema::ImplicitExceptionSpecification::CalledStmt(Stmt *S) { + if (!S || ComputedEST == EST_MSAny) return; // FIXME: @@ -242,7 +242,7 @@ void Sema::ImplicitExceptionSpecification::CalledExpr(Expr *E) { // implicit definition. For now, we assume that any non-nothrow expression can // throw any exception. - if (Self->canThrow(E)) + if (Self->canThrow(S)) ComputedEST = EST_None; } @@ -1501,13 +1501,13 @@ void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) { // as pointers to member functions. if (const ReferenceType *R = NewType->getAs<ReferenceType>()) { NewType = R->getPointeeType(); - OldType = OldType->getAs<ReferenceType>()->getPointeeType(); + OldType = OldType->castAs<ReferenceType>()->getPointeeType(); } else if (const PointerType *P = NewType->getAs<PointerType>()) { NewType = P->getPointeeType(); - OldType = OldType->getAs<PointerType>()->getPointeeType(); + OldType = OldType->castAs<PointerType>()->getPointeeType(); } else if (const MemberPointerType *M = NewType->getAs<MemberPointerType>()) { NewType = M->getPointeeType(); - OldType = OldType->getAs<MemberPointerType>()->getPointeeType(); + OldType = OldType->castAs<MemberPointerType>()->getPointeeType(); } if (!NewType->isFunctionProtoType()) @@ -1627,14 +1627,13 @@ static bool CheckConstexprDestructorSubobjects(Sema &SemaRef, return true; } -// CheckConstexprParameterTypes - Check whether a function's parameter types -// are all literal types. If so, return true. If not, produce a suitable -// diagnostic and return false. +/// Check whether a function's parameter types are all literal types. If so, +/// return true. If not, produce a suitable diagnostic and return false. static bool CheckConstexprParameterTypes(Sema &SemaRef, const FunctionDecl *FD, Sema::CheckConstexprKind Kind) { unsigned ArgIndex = 0; - const FunctionProtoType *FT = FD->getType()->getAs<FunctionProtoType>(); + const auto *FT = FD->getType()->castAs<FunctionProtoType>(); for (FunctionProtoType::param_type_iterator i = FT->param_type_begin(), e = FT->param_type_end(); i != e; ++i, ++ArgIndex) { @@ -1649,6 +1648,17 @@ static bool CheckConstexprParameterTypes(Sema &SemaRef, return true; } +/// Check whether a function's return type is a literal type. If so, return +/// true. If not, produce a suitable diagnostic and return false. +static bool CheckConstexprReturnType(Sema &SemaRef, const FunctionDecl *FD, + Sema::CheckConstexprKind Kind) { + if (CheckLiteralType(SemaRef, Kind, FD->getLocation(), FD->getReturnType(), + diag::err_constexpr_non_literal_return, + FD->isConsteval())) + return false; + return true; +} + /// Get diagnostic %select index for tag kind for /// record diagnostic message. /// WARNING: Indexes apply to particular diagnostics only! @@ -1729,10 +1739,7 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD, } // - its return type shall be a literal type; - QualType RT = NewFD->getReturnType(); - if (CheckLiteralType(*this, Kind, NewFD->getLocation(), RT, - diag::err_constexpr_non_literal_return, - NewFD->isConsteval())) + if (!CheckConstexprReturnType(*this, NewFD, Kind)) return false; } @@ -3800,7 +3807,7 @@ namespace { const CXXRecordDecl *RD = Constructor->getParent(); - if (RD->getDescribedClassTemplate()) + if (RD->isDependentContext()) return; // Holds fields that are uninitialized. @@ -3861,6 +3868,26 @@ void Sema::ActOnStartCXXInClassMemberInitializer() { PushFunctionScope(); } +void Sema::ActOnStartTrailingRequiresClause(Scope *S, Declarator &D) { + if (!D.isFunctionDeclarator()) + return; + auto &FTI = D.getFunctionTypeInfo(); + if (!FTI.Params) + return; + for (auto &Param : ArrayRef<DeclaratorChunk::ParamInfo>(FTI.Params, + FTI.NumParams)) { + auto *ParamDecl = cast<NamedDecl>(Param.Param); + if (ParamDecl->getDeclName()) + PushOnScopeChains(ParamDecl, S, /*AddToContext=*/false); + } +} + +ExprResult Sema::ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr) { + if (ConstraintExpr.isInvalid()) + return ExprError(); + return CorrectDelayedTyposInExpr(ConstraintExpr); +} + /// This is invoked after parsing an in-class initializer for a /// non-static C++ class member, and after instantiating an in-class initializer /// in a class template. Such actions are deferred until the class is complete. @@ -6084,6 +6111,67 @@ void Sema::propagateDLLAttrToBaseClassTemplate( } } +/// Determine the kind of defaulting that would be done for a given function. +/// +/// If the function is both a default constructor and a copy / move constructor +/// (due to having a default argument for the first parameter), this picks +/// CXXDefaultConstructor. +/// +/// FIXME: Check that case is properly handled by all callers. +Sema::DefaultedFunctionKind +Sema::getDefaultedFunctionKind(const FunctionDecl *FD) { + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { + if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(FD)) { + if (Ctor->isDefaultConstructor()) + return Sema::CXXDefaultConstructor; + + if (Ctor->isCopyConstructor()) + return Sema::CXXCopyConstructor; + + if (Ctor->isMoveConstructor()) + return Sema::CXXMoveConstructor; + } + + if (MD->isCopyAssignmentOperator()) + return Sema::CXXCopyAssignment; + + if (MD->isMoveAssignmentOperator()) + return Sema::CXXMoveAssignment; + + if (isa<CXXDestructorDecl>(FD)) + return Sema::CXXDestructor; + } + + switch (FD->getDeclName().getCXXOverloadedOperator()) { + case OO_EqualEqual: + return DefaultedComparisonKind::Equal; + + case OO_ExclaimEqual: + return DefaultedComparisonKind::NotEqual; + + case OO_Spaceship: + // No point allowing this if <=> doesn't exist in the current language mode. + if (!getLangOpts().CPlusPlus2a) + break; + return DefaultedComparisonKind::ThreeWay; + + case OO_Less: + case OO_LessEqual: + case OO_Greater: + case OO_GreaterEqual: + // No point allowing this if <=> doesn't exist in the current language mode. + if (!getLangOpts().CPlusPlus2a) + break; + return DefaultedComparisonKind::Relational; + + default: + break; + } + + // Not defaultable. + return DefaultedFunctionKind(); +} + static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD, SourceLocation DefaultLoc) { switch (S.getSpecialMember(MD)) { @@ -6228,7 +6316,11 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, /// Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. -void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { +/// +/// \param S The scope in which the class was parsed. Null if we didn't just +/// parse a class definition. +/// \param Record The completed class. +void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { if (!Record) return; @@ -6330,10 +6422,30 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { if (HasTrivialABI) Record->setHasTrivialSpecialMemberForCall(); + // Explicitly-defaulted secondary comparison functions (!=, <, <=, >, >=). + // We check these last because they can depend on the properties of the + // primary comparison functions (==, <=>). + llvm::SmallVector<FunctionDecl*, 5> DefaultedSecondaryComparisons; + + auto CheckForDefaultedFunction = [&](FunctionDecl *FD) { + if (!FD || FD->isInvalidDecl() || !FD->isExplicitlyDefaulted()) + return; + + DefaultedFunctionKind DFK = getDefaultedFunctionKind(FD); + if (DFK.asComparison() == DefaultedComparisonKind::NotEqual || + DFK.asComparison() == DefaultedComparisonKind::Relational) + DefaultedSecondaryComparisons.push_back(FD); + else + CheckExplicitlyDefaultedFunction(S, FD); + }; + auto CompleteMemberFunction = [&](CXXMethodDecl *M) { - // Check whether the explicitly-defaulted special members are valid. - if (!M->isInvalidDecl() && M->isExplicitlyDefaulted()) - CheckExplicitlyDefaultedSpecialMember(M); + // Check whether the explicitly-defaulted members are valid. + CheckForDefaultedFunction(M); + + // Skip the rest of the checks for a member of a dependent class. + if (Record->isDependentType()) + return; // For an explicitly defaulted or deleted special member, we defer // determining triviality until the class is complete. That time is now! @@ -6379,40 +6491,52 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { DefineImplicitSpecialMember(*this, M, M->getLocation()); }; + // Check the destructor before any other member function. We need to + // determine whether it's trivial in order to determine whether the claas + // type is a literal type, which is a prerequisite for determining whether + // other special member functions are valid and whether they're implicitly + // 'constexpr'. + if (CXXDestructorDecl *Dtor = Record->getDestructor()) + CompleteMemberFunction(Dtor); + bool HasMethodWithOverrideControl = false, HasOverridingMethodWithoutOverrideControl = false; - if (!Record->isDependentType()) { - // Check the destructor before any other member function. We need to - // determine whether it's trivial in order to determine whether the claas - // type is a literal type, which is a prerequisite for determining whether - // other special member functions are valid and whether they're implicitly - // 'constexpr'. - if (CXXDestructorDecl *Dtor = Record->getDestructor()) - CompleteMemberFunction(Dtor); - - for (auto *M : Record->methods()) { - // See if a method overloads virtual methods in a base - // class without overriding any. - if (!M->isStatic()) - DiagnoseHiddenVirtualMethods(M); - if (M->hasAttr<OverrideAttr>()) - HasMethodWithOverrideControl = true; - else if (M->size_overridden_methods() > 0) - HasOverridingMethodWithoutOverrideControl = true; + for (auto *D : Record->decls()) { + if (auto *M = dyn_cast<CXXMethodDecl>(D)) { + // FIXME: We could do this check for dependent types with non-dependent + // bases. + if (!Record->isDependentType()) { + // See if a method overloads virtual methods in a base + // class without overriding any. + if (!M->isStatic()) + DiagnoseHiddenVirtualMethods(M); + if (M->hasAttr<OverrideAttr>()) + HasMethodWithOverrideControl = true; + else if (M->size_overridden_methods() > 0) + HasOverridingMethodWithoutOverrideControl = true; + } if (!isa<CXXDestructorDecl>(M)) CompleteMemberFunction(M); + } else if (auto *F = dyn_cast<FriendDecl>(D)) { + CheckForDefaultedFunction( + dyn_cast_or_null<FunctionDecl>(F->getFriendDecl())); } } if (HasMethodWithOverrideControl && HasOverridingMethodWithoutOverrideControl) { // At least one method has the 'override' control declared. - // Diagnose all other overridden methods which do not have 'override' specified on them. + // Diagnose all other overridden methods which do not have 'override' + // specified on them. for (auto *M : Record->methods()) DiagnoseAbsenceOfOverrideControl(M); } + // Check the defaulted secondary comparisons after any other member functions. + for (FunctionDecl *FD : DefaultedSecondaryComparisons) + CheckExplicitlyDefaultedFunction(S, FD); + // ms_struct is a request to use the same ABI rules as MSVC. Check // whether this class uses any C++ features that are implemented // completely differently in MSVC, and if so, emit a diagnostic. @@ -6710,20 +6834,50 @@ static bool defaultedSpecialMemberIsConstexpr( return true; } +namespace { +/// RAII object to register a defaulted function as having its exception +/// specification computed. +struct ComputingExceptionSpec { + Sema &S; + + ComputingExceptionSpec(Sema &S, FunctionDecl *FD, SourceLocation Loc) + : S(S) { + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::ExceptionSpecEvaluation; + Ctx.PointOfInstantiation = Loc; + Ctx.Entity = FD; + S.pushCodeSynthesisContext(Ctx); + } + ~ComputingExceptionSpec() { + S.popCodeSynthesisContext(); + } +}; +} + static Sema::ImplicitExceptionSpecification ComputeDefaultedSpecialMemberExceptionSpec( Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM, Sema::InheritedConstructorInfo *ICI); static Sema::ImplicitExceptionSpecification -computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) { - auto CSM = S.getSpecialMember(MD); - if (CSM != Sema::CXXInvalid) - return ComputeDefaultedSpecialMemberExceptionSpec(S, Loc, MD, CSM, nullptr); +ComputeDefaultedComparisonExceptionSpec(Sema &S, SourceLocation Loc, + FunctionDecl *FD, + Sema::DefaultedComparisonKind DCK); + +static Sema::ImplicitExceptionSpecification +computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, FunctionDecl *FD) { + auto DFK = S.getDefaultedFunctionKind(FD); + if (DFK.isSpecialMember()) + return ComputeDefaultedSpecialMemberExceptionSpec( + S, Loc, cast<CXXMethodDecl>(FD), DFK.asSpecialMember(), nullptr); + if (DFK.isComparison()) + return ComputeDefaultedComparisonExceptionSpec(S, Loc, FD, + DFK.asComparison()); - auto *CD = cast<CXXConstructorDecl>(MD); + auto *CD = cast<CXXConstructorDecl>(FD); assert(CD->getInheritedConstructor() && - "only special members have implicit exception specs"); + "only defaulted functions and inherited constructors have implicit " + "exception specs"); Sema::InheritedConstructorInfo ICI( S, Loc, CD->getInheritedConstructor().getShadowDecl()); return ComputeDefaultedSpecialMemberExceptionSpec( @@ -6745,34 +6899,46 @@ static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S, return EPI; } -void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) { - const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); +void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, FunctionDecl *FD) { + const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>(); if (FPT->getExceptionSpecType() != EST_Unevaluated) return; // Evaluate the exception specification. - auto IES = computeImplicitExceptionSpec(*this, Loc, MD); + auto IES = computeImplicitExceptionSpec(*this, Loc, FD); auto ESI = IES.getExceptionSpec(); // Update the type of the special member to use it. - UpdateExceptionSpec(MD, ESI); + UpdateExceptionSpec(FD, ESI); +} + +void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) { + assert(FD->isExplicitlyDefaulted() && "not explicitly-defaulted"); - // A user-provided destructor can be defined outside the class. When that - // happens, be sure to update the exception specification on both - // declarations. - const FunctionProtoType *CanonicalFPT = - MD->getCanonicalDecl()->getType()->castAs<FunctionProtoType>(); - if (CanonicalFPT->getExceptionSpecType() == EST_Unevaluated) - UpdateExceptionSpec(MD->getCanonicalDecl(), ESI); + DefaultedFunctionKind DefKind = getDefaultedFunctionKind(FD); + if (!DefKind) { + assert(FD->getDeclContext()->isDependentContext()); + return; + } + + if (DefKind.isSpecialMember() + ? CheckExplicitlyDefaultedSpecialMember(cast<CXXMethodDecl>(FD), + DefKind.asSpecialMember()) + : CheckExplicitlyDefaultedComparison(S, FD, DefKind.asComparison())) + FD->setInvalidDecl(); } -void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { +bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, + CXXSpecialMember CSM) { CXXRecordDecl *RD = MD->getParent(); - CXXSpecialMember CSM = getSpecialMember(MD); assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid && "not an explicitly-defaulted special member"); + // Defer all checking for special members of a dependent type. + if (RD->isDependentType()) + return false; + // Whether this was the first-declared instance of the constructor. // This affects whether we implicitly add an exception spec and constexpr. bool First = MD == MD->getCanonicalDecl(); @@ -6781,7 +6947,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { // C++11 [dcl.fct.def.default]p1: // A function that is explicitly defaulted shall - // -- be a special member function (checked elsewhere), + // -- be a special member function [...] (checked elsewhere), // -- have the same type (except for ref-qualifiers, and except that a // copy operation can take a non-const reference) as an implicit // declaration, and @@ -6960,8 +7126,1124 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { } } - if (HadError) - MD->setInvalidDecl(); + return HadError; +} + +namespace { +/// Helper class for building and checking a defaulted comparison. +/// +/// Defaulted functions are built in two phases: +/// +/// * First, the set of operations that the function will perform are +/// identified, and some of them are checked. If any of the checked +/// operations is invalid in certain ways, the comparison function is +/// defined as deleted and no body is built. +/// * Then, if the function is not defined as deleted, the body is built. +/// +/// This is accomplished by performing two visitation steps over the eventual +/// body of the function. +template<typename Derived, typename ResultList, typename Result, + typename Subobject> +class DefaultedComparisonVisitor { +public: + using DefaultedComparisonKind = Sema::DefaultedComparisonKind; + + DefaultedComparisonVisitor(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD, + DefaultedComparisonKind DCK) + : S(S), RD(RD), FD(FD), DCK(DCK) { + if (auto *Info = FD->getDefaultedFunctionInfo()) { + // FIXME: Change CreateOverloadedBinOp to take an ArrayRef instead of an + // UnresolvedSet to avoid this copy. + Fns.assign(Info->getUnqualifiedLookups().begin(), + Info->getUnqualifiedLookups().end()); + } + } + + ResultList visit() { + // The type of an lvalue naming a parameter of this function. + QualType ParamLvalType = + FD->getParamDecl(0)->getType().getNonReferenceType(); + + ResultList Results; + + switch (DCK) { + case DefaultedComparisonKind::None: + llvm_unreachable("not a defaulted comparison"); + + case DefaultedComparisonKind::Equal: + case DefaultedComparisonKind::ThreeWay: + getDerived().visitSubobjects(Results, RD, ParamLvalType.getQualifiers()); + return Results; + + case DefaultedComparisonKind::NotEqual: + case DefaultedComparisonKind::Relational: + Results.add(getDerived().visitExpandedSubobject( + ParamLvalType, getDerived().getCompleteObject())); + return Results; + } + llvm_unreachable(""); + } + +protected: + Derived &getDerived() { return static_cast<Derived&>(*this); } + + /// Visit the expanded list of subobjects of the given type, as specified in + /// C++2a [class.compare.default]. + /// + /// \return \c true if the ResultList object said we're done, \c false if not. + bool visitSubobjects(ResultList &Results, CXXRecordDecl *Record, + Qualifiers Quals) { + // C++2a [class.compare.default]p4: + // The direct base class subobjects of C + for (CXXBaseSpecifier &Base : Record->bases()) + if (Results.add(getDerived().visitSubobject( + S.Context.getQualifiedType(Base.getType(), Quals), + getDerived().getBase(&Base)))) + return true; + + // followed by the non-static data members of C + for (FieldDecl *Field : Record->fields()) { + // Recursively expand anonymous structs. + if (Field->isAnonymousStructOrUnion()) { + if (visitSubobjects(Results, Field->getType()->getAsCXXRecordDecl(), + Quals)) + return true; + continue; + } + + // Figure out the type of an lvalue denoting this field. + Qualifiers FieldQuals = Quals; + if (Field->isMutable()) + FieldQuals.removeConst(); + QualType FieldType = + S.Context.getQualifiedType(Field->getType(), FieldQuals); + + if (Results.add(getDerived().visitSubobject( + FieldType, getDerived().getField(Field)))) + return true; + } + + // form a list of subobjects. + return false; + } + + Result visitSubobject(QualType Type, Subobject Subobj) { + // In that list, any subobject of array type is recursively expanded + const ArrayType *AT = S.Context.getAsArrayType(Type); + if (auto *CAT = dyn_cast_or_null<ConstantArrayType>(AT)) + return getDerived().visitSubobjectArray(CAT->getElementType(), + CAT->getSize(), Subobj); + return getDerived().visitExpandedSubobject(Type, Subobj); + } + + Result visitSubobjectArray(QualType Type, const llvm::APInt &Size, + Subobject Subobj) { + return getDerived().visitSubobject(Type, Subobj); + } + +protected: + Sema &S; + CXXRecordDecl *RD; + FunctionDecl *FD; + DefaultedComparisonKind DCK; + UnresolvedSet<16> Fns; +}; + +/// Information about a defaulted comparison, as determined by +/// DefaultedComparisonAnalyzer. +struct DefaultedComparisonInfo { + bool Deleted = false; + bool Constexpr = true; + ComparisonCategoryType Category = ComparisonCategoryType::StrongOrdering; + + static DefaultedComparisonInfo deleted() { + DefaultedComparisonInfo Deleted; + Deleted.Deleted = true; + return Deleted; + } + + bool add(const DefaultedComparisonInfo &R) { + Deleted |= R.Deleted; + Constexpr &= R.Constexpr; + Category = commonComparisonType(Category, R.Category); + return Deleted; + } +}; + +/// An element in the expanded list of subobjects of a defaulted comparison, as +/// specified in C++2a [class.compare.default]p4. +struct DefaultedComparisonSubobject { + enum { CompleteObject, Member, Base } Kind; + NamedDecl *Decl; + SourceLocation Loc; +}; + +/// A visitor over the notional body of a defaulted comparison that determines +/// whether that body would be deleted or constexpr. +class DefaultedComparisonAnalyzer + : public DefaultedComparisonVisitor<DefaultedComparisonAnalyzer, + DefaultedComparisonInfo, + DefaultedComparisonInfo, + DefaultedComparisonSubobject> { +public: + enum DiagnosticKind { NoDiagnostics, ExplainDeleted, ExplainConstexpr }; + +private: + DiagnosticKind Diagnose; + +public: + using Base = DefaultedComparisonVisitor; + using Result = DefaultedComparisonInfo; + using Subobject = DefaultedComparisonSubobject; + + friend Base; + + DefaultedComparisonAnalyzer(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD, + DefaultedComparisonKind DCK, + DiagnosticKind Diagnose = NoDiagnostics) + : Base(S, RD, FD, DCK), Diagnose(Diagnose) {} + + Result visit() { + if ((DCK == DefaultedComparisonKind::Equal || + DCK == DefaultedComparisonKind::ThreeWay) && + RD->hasVariantMembers()) { + // C++2a [class.compare.default]p2 [P2002R0]: + // A defaulted comparison operator function for class C is defined as + // deleted if [...] C has variant members. + if (Diagnose == ExplainDeleted) { + S.Diag(FD->getLocation(), diag::note_defaulted_comparison_union) + << FD << RD->isUnion() << RD; + } + return Result::deleted(); + } + + return Base::visit(); + } + +private: + Subobject getCompleteObject() { + return Subobject{Subobject::CompleteObject, nullptr, FD->getLocation()}; + } + + Subobject getBase(CXXBaseSpecifier *Base) { + return Subobject{Subobject::Base, Base->getType()->getAsCXXRecordDecl(), + Base->getBaseTypeLoc()}; + } + + Subobject getField(FieldDecl *Field) { + return Subobject{Subobject::Member, Field, Field->getLocation()}; + } + + Result visitExpandedSubobject(QualType Type, Subobject Subobj) { + // C++2a [class.compare.default]p2 [P2002R0]: + // A defaulted <=> or == operator function for class C is defined as + // deleted if any non-static data member of C is of reference type + if (Type->isReferenceType()) { + if (Diagnose == ExplainDeleted) { + S.Diag(Subobj.Loc, diag::note_defaulted_comparison_reference_member) + << FD << RD; + } + return Result::deleted(); + } + + // [...] Let xi be an lvalue denoting the ith element [...] + OpaqueValueExpr Xi(FD->getLocation(), Type, VK_LValue); + Expr *Args[] = {&Xi, &Xi}; + + // All operators start by trying to apply that same operator recursively. + OverloadedOperatorKind OO = FD->getOverloadedOperator(); + assert(OO != OO_None && "not an overloaded operator!"); + return visitBinaryOperator(OO, Args, Subobj); + } + + Result + visitBinaryOperator(OverloadedOperatorKind OO, ArrayRef<Expr *> Args, + Subobject Subobj, + OverloadCandidateSet *SpaceshipCandidates = nullptr) { + // Note that there is no need to consider rewritten candidates here if + // we've already found there is no viable 'operator<=>' candidate (and are + // considering synthesizing a '<=>' from '==' and '<'). + OverloadCandidateSet CandidateSet( + FD->getLocation(), OverloadCandidateSet::CSK_Operator, + OverloadCandidateSet::OperatorRewriteInfo( + OO, /*AllowRewrittenCandidates=*/!SpaceshipCandidates)); + + /// C++2a [class.compare.default]p1 [P2002R0]: + /// [...] the defaulted function itself is never a candidate for overload + /// resolution [...] + CandidateSet.exclude(FD); + + S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args); + + Result R; + + OverloadCandidateSet::iterator Best; + switch (CandidateSet.BestViableFunction(S, FD->getLocation(), Best)) { + case OR_Success: { + // C++2a [class.compare.secondary]p2 [P2002R0]: + // The operator function [...] is defined as deleted if [...] the + // candidate selected by overload resolution is not a rewritten + // candidate. + if ((DCK == DefaultedComparisonKind::NotEqual || + DCK == DefaultedComparisonKind::Relational) && + !Best->RewriteKind) { + if (Diagnose == ExplainDeleted) { + S.Diag(Best->Function->getLocation(), + diag::note_defaulted_comparison_not_rewritten_callee) + << FD; + } + return Result::deleted(); + } + + // Throughout C++2a [class.compare]: if overload resolution does not + // result in a usable function, the candidate function is defined as + // deleted. This requires that we selected an accessible function. + // + // Note that this only considers the access of the function when named + // within the type of the subobject, and not the access path for any + // derived-to-base conversion. + CXXRecordDecl *ArgClass = Args[0]->getType()->getAsCXXRecordDecl(); + if (ArgClass && Best->FoundDecl.getDecl() && + Best->FoundDecl.getDecl()->isCXXClassMember()) { + QualType ObjectType = Subobj.Kind == Subobject::Member + ? Args[0]->getType() + : S.Context.getRecordType(RD); + if (!S.isMemberAccessibleForDeletion( + ArgClass, Best->FoundDecl, ObjectType, Subobj.Loc, + Diagnose == ExplainDeleted + ? S.PDiag(diag::note_defaulted_comparison_inaccessible) + << FD << Subobj.Kind << Subobj.Decl + : S.PDiag())) + return Result::deleted(); + } + + // C++2a [class.compare.default]p3 [P2002R0]: + // A defaulted comparison function is constexpr-compatible if [...] + // no overlod resolution performed [...] results in a non-constexpr + // function. + if (FunctionDecl *BestFD = Best->Function) { + assert(!BestFD->isDeleted() && "wrong overload resolution result"); + // If it's not constexpr, explain why not. + if (Diagnose == ExplainConstexpr && !BestFD->isConstexpr()) { + if (Subobj.Kind != Subobject::CompleteObject) + S.Diag(Subobj.Loc, diag::note_defaulted_comparison_not_constexpr) + << Subobj.Kind << Subobj.Decl; + S.Diag(BestFD->getLocation(), + diag::note_defaulted_comparison_not_constexpr_here); + // Bail out after explaining; we don't want any more notes. + return Result::deleted(); + } + R.Constexpr &= BestFD->isConstexpr(); + } + + if (OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType()) { + if (auto *BestFD = Best->Function) { + if (auto *Info = S.Context.CompCategories.lookupInfoForType( + BestFD->getCallResultType())) { + R.Category = Info->Kind; + } else { + if (Diagnose == ExplainDeleted) { + S.Diag(Subobj.Loc, diag::note_defaulted_comparison_cannot_deduce) + << Subobj.Kind << Subobj.Decl + << BestFD->getCallResultType().withoutLocalFastQualifiers(); + S.Diag(BestFD->getLocation(), + diag::note_defaulted_comparison_cannot_deduce_callee) + << Subobj.Kind << Subobj.Decl; + } + return Result::deleted(); + } + } else { + Optional<ComparisonCategoryType> Cat = + getComparisonCategoryForBuiltinCmp(Args[0]->getType()); + assert(Cat && "no category for builtin comparison?"); + R.Category = *Cat; + } + } + + // Note that we might be rewriting to a different operator. That call is + // not considered until we come to actually build the comparison function. + break; + } + + case OR_Ambiguous: + if (Diagnose == ExplainDeleted) { + unsigned Kind = 0; + if (FD->getOverloadedOperator() == OO_Spaceship && OO != OO_Spaceship) + Kind = OO == OO_EqualEqual ? 1 : 2; + CandidateSet.NoteCandidates( + PartialDiagnosticAt( + Subobj.Loc, S.PDiag(diag::note_defaulted_comparison_ambiguous) + << FD << Kind << Subobj.Kind << Subobj.Decl), + S, OCD_AmbiguousCandidates, Args); + } + R = Result::deleted(); + break; + + case OR_Deleted: + if (Diagnose == ExplainDeleted) { + if ((DCK == DefaultedComparisonKind::NotEqual || + DCK == DefaultedComparisonKind::Relational) && + !Best->RewriteKind) { + S.Diag(Best->Function->getLocation(), + diag::note_defaulted_comparison_not_rewritten_callee) + << FD; + } else { + S.Diag(Subobj.Loc, + diag::note_defaulted_comparison_calls_deleted) + << FD << Subobj.Kind << Subobj.Decl; + S.NoteDeletedFunction(Best->Function); + } + } + R = Result::deleted(); + break; + + case OR_No_Viable_Function: + // If there's no usable candidate, we're done unless we can rewrite a + // '<=>' in terms of '==' and '<'. + if (OO == OO_Spaceship && + S.Context.CompCategories.lookupInfoForType(FD->getReturnType())) { + // For any kind of comparison category return type, we need a usable + // '==' and a usable '<'. + if (!R.add(visitBinaryOperator(OO_EqualEqual, Args, Subobj, + &CandidateSet))) + R.add(visitBinaryOperator(OO_Less, Args, Subobj, &CandidateSet)); + break; + } + + if (Diagnose == ExplainDeleted) { + S.Diag(Subobj.Loc, diag::note_defaulted_comparison_no_viable_function) + << FD << Subobj.Kind << Subobj.Decl; + + // For a three-way comparison, list both the candidates for the + // original operator and the candidates for the synthesized operator. + if (SpaceshipCandidates) { + SpaceshipCandidates->NoteCandidates( + S, Args, + SpaceshipCandidates->CompleteCandidates(S, OCD_AllCandidates, + Args, FD->getLocation())); + S.Diag(Subobj.Loc, + diag::note_defaulted_comparison_no_viable_function_synthesized) + << (OO == OO_EqualEqual ? 0 : 1); + } + + CandidateSet.NoteCandidates( + S, Args, + CandidateSet.CompleteCandidates(S, OCD_AllCandidates, Args, + FD->getLocation())); + } + R = Result::deleted(); + break; + } + + return R; + } +}; + +/// A list of statements. +struct StmtListResult { + bool IsInvalid = false; + llvm::SmallVector<Stmt*, 16> Stmts; + + bool add(const StmtResult &S) { + IsInvalid |= S.isInvalid(); + if (IsInvalid) + return true; + Stmts.push_back(S.get()); + return false; + } +}; + +/// A visitor over the notional body of a defaulted comparison that synthesizes +/// the actual body. +class DefaultedComparisonSynthesizer + : public DefaultedComparisonVisitor<DefaultedComparisonSynthesizer, + StmtListResult, StmtResult, + std::pair<ExprResult, ExprResult>> { + SourceLocation Loc; + unsigned ArrayDepth = 0; + +public: + using Base = DefaultedComparisonVisitor; + using ExprPair = std::pair<ExprResult, ExprResult>; + + friend Base; + + DefaultedComparisonSynthesizer(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD, + DefaultedComparisonKind DCK, + SourceLocation BodyLoc) + : Base(S, RD, FD, DCK), Loc(BodyLoc) {} + + /// Build a suitable function body for this defaulted comparison operator. + StmtResult build() { + Sema::CompoundScopeRAII CompoundScope(S); + + StmtListResult Stmts = visit(); + if (Stmts.IsInvalid) + return StmtError(); + + ExprResult RetVal; + switch (DCK) { + case DefaultedComparisonKind::None: + llvm_unreachable("not a defaulted comparison"); + + case DefaultedComparisonKind::Equal: { + // C++2a [class.eq]p3: + // [...] compar[e] the corresponding elements [...] until the first + // index i where xi == yi yields [...] false. If no such index exists, + // V is true. Otherwise, V is false. + // + // Join the comparisons with '&&'s and return the result. Use a right + // fold (traversing the conditions right-to-left), because that + // short-circuits more naturally. + auto OldStmts = std::move(Stmts.Stmts); + Stmts.Stmts.clear(); + ExprResult CmpSoFar; + // Finish a particular comparison chain. + auto FinishCmp = [&] { + if (Expr *Prior = CmpSoFar.get()) { + // Convert the last expression to 'return ...;' + if (RetVal.isUnset() && Stmts.Stmts.empty()) + RetVal = CmpSoFar; + // Convert any prior comparison to 'if (!(...)) return false;' + else if (Stmts.add(buildIfNotCondReturnFalse(Prior))) + return true; + CmpSoFar = ExprResult(); + } + return false; + }; + for (Stmt *EAsStmt : llvm::reverse(OldStmts)) { + Expr *E = dyn_cast<Expr>(EAsStmt); + if (!E) { + // Found an array comparison. + if (FinishCmp() || Stmts.add(EAsStmt)) + return StmtError(); + continue; + } + + if (CmpSoFar.isUnset()) { + CmpSoFar = E; + continue; + } + CmpSoFar = S.CreateBuiltinBinOp(Loc, BO_LAnd, E, CmpSoFar.get()); + if (CmpSoFar.isInvalid()) + return StmtError(); + } + if (FinishCmp()) + return StmtError(); + std::reverse(Stmts.Stmts.begin(), Stmts.Stmts.end()); + // If no such index exists, V is true. + if (RetVal.isUnset()) + RetVal = S.ActOnCXXBoolLiteral(Loc, tok::kw_true); + break; + } + + case DefaultedComparisonKind::ThreeWay: { + // Per C++2a [class.spaceship]p3, as a fallback add: + // return static_cast<R>(std::strong_ordering::equal); + QualType StrongOrdering = S.CheckComparisonCategoryType( + ComparisonCategoryType::StrongOrdering, Loc, + Sema::ComparisonCategoryUsage::DefaultedOperator); + if (StrongOrdering.isNull()) + return StmtError(); + VarDecl *EqualVD = S.Context.CompCategories.getInfoForType(StrongOrdering) + .getValueInfo(ComparisonCategoryResult::Equal) + ->VD; + RetVal = getDecl(EqualVD); + if (RetVal.isInvalid()) + return StmtError(); + RetVal = buildStaticCastToR(RetVal.get()); + break; + } + + case DefaultedComparisonKind::NotEqual: + case DefaultedComparisonKind::Relational: + RetVal = cast<Expr>(Stmts.Stmts.pop_back_val()); + break; + } + + // Build the final return statement. + if (RetVal.isInvalid()) + return StmtError(); + StmtResult ReturnStmt = S.BuildReturnStmt(Loc, RetVal.get()); + if (ReturnStmt.isInvalid()) + return StmtError(); + Stmts.Stmts.push_back(ReturnStmt.get()); + + return S.ActOnCompoundStmt(Loc, Loc, Stmts.Stmts, /*IsStmtExpr=*/false); + } + +private: + ExprResult getDecl(ValueDecl *VD) { + return S.BuildDeclarationNameExpr( + CXXScopeSpec(), DeclarationNameInfo(VD->getDeclName(), Loc), VD); + } + + ExprResult getParam(unsigned I) { + ParmVarDecl *PD = FD->getParamDecl(I); + return getDecl(PD); + } + + ExprPair getCompleteObject() { + unsigned Param = 0; + ExprResult LHS; + if (isa<CXXMethodDecl>(FD)) { + // LHS is '*this'. + LHS = S.ActOnCXXThis(Loc); + if (!LHS.isInvalid()) + LHS = S.CreateBuiltinUnaryOp(Loc, UO_Deref, LHS.get()); + } else { + LHS = getParam(Param++); + } + ExprResult RHS = getParam(Param++); + assert(Param == FD->getNumParams()); + return {LHS, RHS}; + } + + ExprPair getBase(CXXBaseSpecifier *Base) { + ExprPair Obj = getCompleteObject(); + if (Obj.first.isInvalid() || Obj.second.isInvalid()) + return {ExprError(), ExprError()}; + CXXCastPath Path = {Base}; + return {S.ImpCastExprToType(Obj.first.get(), Base->getType(), + CK_DerivedToBase, VK_LValue, &Path), + S.ImpCastExprToType(Obj.second.get(), Base->getType(), + CK_DerivedToBase, VK_LValue, &Path)}; + } + + ExprPair getField(FieldDecl *Field) { + ExprPair Obj = getCompleteObject(); + if (Obj.first.isInvalid() || Obj.second.isInvalid()) + return {ExprError(), ExprError()}; + + DeclAccessPair Found = DeclAccessPair::make(Field, Field->getAccess()); + DeclarationNameInfo NameInfo(Field->getDeclName(), Loc); + return {S.BuildFieldReferenceExpr(Obj.first.get(), /*IsArrow=*/false, Loc, + CXXScopeSpec(), Field, Found, NameInfo), + S.BuildFieldReferenceExpr(Obj.second.get(), /*IsArrow=*/false, Loc, + CXXScopeSpec(), Field, Found, NameInfo)}; + } + + // FIXME: When expanding a subobject, register a note in the code synthesis + // stack to say which subobject we're comparing. + + StmtResult buildIfNotCondReturnFalse(ExprResult Cond) { + if (Cond.isInvalid()) + return StmtError(); + + ExprResult NotCond = S.CreateBuiltinUnaryOp(Loc, UO_LNot, Cond.get()); + if (NotCond.isInvalid()) + return StmtError(); + + ExprResult False = S.ActOnCXXBoolLiteral(Loc, tok::kw_false); + assert(!False.isInvalid() && "should never fail"); + StmtResult ReturnFalse = S.BuildReturnStmt(Loc, False.get()); + if (ReturnFalse.isInvalid()) + return StmtError(); + + return S.ActOnIfStmt(Loc, false, nullptr, + S.ActOnCondition(nullptr, Loc, NotCond.get(), + Sema::ConditionKind::Boolean), + ReturnFalse.get(), SourceLocation(), nullptr); + } + + StmtResult visitSubobjectArray(QualType Type, llvm::APInt Size, + ExprPair Subobj) { + QualType SizeType = S.Context.getSizeType(); + Size = Size.zextOrTrunc(S.Context.getTypeSize(SizeType)); + + // Build 'size_t i$n = 0'. + IdentifierInfo *IterationVarName = nullptr; + { + SmallString<8> Str; + llvm::raw_svector_ostream OS(Str); + OS << "i" << ArrayDepth; + IterationVarName = &S.Context.Idents.get(OS.str()); + } + VarDecl *IterationVar = VarDecl::Create( + S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType, + S.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None); + llvm::APInt Zero(S.Context.getTypeSize(SizeType), 0); + IterationVar->setInit( + IntegerLiteral::Create(S.Context, Zero, SizeType, Loc)); + Stmt *Init = new (S.Context) DeclStmt(DeclGroupRef(IterationVar), Loc, Loc); + + auto IterRef = [&] { + ExprResult Ref = S.BuildDeclarationNameExpr( + CXXScopeSpec(), DeclarationNameInfo(IterationVarName, Loc), + IterationVar); + assert(!Ref.isInvalid() && "can't reference our own variable?"); + return Ref.get(); + }; + + // Build 'i$n != Size'. + ExprResult Cond = S.CreateBuiltinBinOp( + Loc, BO_NE, IterRef(), + IntegerLiteral::Create(S.Context, Size, SizeType, Loc)); + assert(!Cond.isInvalid() && "should never fail"); + + // Build '++i$n'. + ExprResult Inc = S.CreateBuiltinUnaryOp(Loc, UO_PreInc, IterRef()); + assert(!Inc.isInvalid() && "should never fail"); + + // Build 'a[i$n]' and 'b[i$n]'. + auto Index = [&](ExprResult E) { + if (E.isInvalid()) + return ExprError(); + return S.CreateBuiltinArraySubscriptExpr(E.get(), Loc, IterRef(), Loc); + }; + Subobj.first = Index(Subobj.first); + Subobj.second = Index(Subobj.second); + + // Compare the array elements. + ++ArrayDepth; + StmtResult Substmt = visitSubobject(Type, Subobj); + --ArrayDepth; + + if (Substmt.isInvalid()) + return StmtError(); + + // For the inner level of an 'operator==', build 'if (!cmp) return false;'. + // For outer levels or for an 'operator<=>' we already have a suitable + // statement that returns as necessary. + if (Expr *ElemCmp = dyn_cast<Expr>(Substmt.get())) { + assert(DCK == DefaultedComparisonKind::Equal && + "should have non-expression statement"); + Substmt = buildIfNotCondReturnFalse(ElemCmp); + if (Substmt.isInvalid()) + return StmtError(); + } + + // Build 'for (...) ...' + return S.ActOnForStmt(Loc, Loc, Init, + S.ActOnCondition(nullptr, Loc, Cond.get(), + Sema::ConditionKind::Boolean), + S.MakeFullDiscardedValueExpr(Inc.get()), Loc, + Substmt.get()); + } + + StmtResult visitExpandedSubobject(QualType Type, ExprPair Obj) { + if (Obj.first.isInvalid() || Obj.second.isInvalid()) + return StmtError(); + + OverloadedOperatorKind OO = FD->getOverloadedOperator(); + ExprResult Op = S.CreateOverloadedBinOp( + Loc, BinaryOperator::getOverloadedOpcode(OO), Fns, + Obj.first.get(), Obj.second.get(), /*PerformADL=*/true, + /*AllowRewrittenCandidates=*/true, FD); + if (Op.isInvalid()) + return StmtError(); + + switch (DCK) { + case DefaultedComparisonKind::None: + llvm_unreachable("not a defaulted comparison"); + + case DefaultedComparisonKind::Equal: + // Per C++2a [class.eq]p2, each comparison is individually contextually + // converted to bool. + Op = S.PerformContextuallyConvertToBool(Op.get()); + if (Op.isInvalid()) + return StmtError(); + return Op.get(); + + case DefaultedComparisonKind::ThreeWay: { + // Per C++2a [class.spaceship]p3, form: + // if (R cmp = static_cast<R>(op); cmp != 0) + // return cmp; + QualType R = FD->getReturnType(); + Op = buildStaticCastToR(Op.get()); + if (Op.isInvalid()) + return StmtError(); + + // R cmp = ...; + IdentifierInfo *Name = &S.Context.Idents.get("cmp"); + VarDecl *VD = + VarDecl::Create(S.Context, S.CurContext, Loc, Loc, Name, R, + S.Context.getTrivialTypeSourceInfo(R, Loc), SC_None); + S.AddInitializerToDecl(VD, Op.get(), /*DirectInit=*/false); + Stmt *InitStmt = new (S.Context) DeclStmt(DeclGroupRef(VD), Loc, Loc); + + // cmp != 0 + ExprResult VDRef = getDecl(VD); + if (VDRef.isInvalid()) + return StmtError(); + llvm::APInt ZeroVal(S.Context.getIntWidth(S.Context.IntTy), 0); + Expr *Zero = + IntegerLiteral::Create(S.Context, ZeroVal, S.Context.IntTy, Loc); + ExprResult Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(), + Zero, true, true, FD); + if (Comp.isInvalid()) + return StmtError(); + Sema::ConditionResult Cond = S.ActOnCondition( + nullptr, Loc, Comp.get(), Sema::ConditionKind::Boolean); + if (Cond.isInvalid()) + return StmtError(); + + // return cmp; + VDRef = getDecl(VD); + if (VDRef.isInvalid()) + return StmtError(); + StmtResult ReturnStmt = S.BuildReturnStmt(Loc, VDRef.get()); + if (ReturnStmt.isInvalid()) + return StmtError(); + + // if (...) + return S.ActOnIfStmt(Loc, /*IsConstexpr=*/false, InitStmt, Cond, + ReturnStmt.get(), /*ElseLoc=*/SourceLocation(), + /*Else=*/nullptr); + } + + case DefaultedComparisonKind::NotEqual: + case DefaultedComparisonKind::Relational: + // C++2a [class.compare.secondary]p2: + // Otherwise, the operator function yields x @ y. + return Op.get(); + } + llvm_unreachable(""); + } + + /// Build "static_cast<R>(E)". + ExprResult buildStaticCastToR(Expr *E) { + QualType R = FD->getReturnType(); + assert(!R->isUndeducedType() && "type should have been deduced already"); + + // Don't bother forming a no-op cast in the common case. + if (E->isRValue() && S.Context.hasSameType(E->getType(), R)) + return E; + return S.BuildCXXNamedCast(Loc, tok::kw_static_cast, + S.Context.getTrivialTypeSourceInfo(R, Loc), E, + SourceRange(Loc, Loc), SourceRange(Loc, Loc)); + } +}; +} + +/// Perform the unqualified lookups that might be needed to form a defaulted +/// comparison function for the given operator. +static void lookupOperatorsForDefaultedComparison(Sema &Self, Scope *S, + UnresolvedSetImpl &Operators, + OverloadedOperatorKind Op) { + auto Lookup = [&](OverloadedOperatorKind OO) { + Self.LookupOverloadedOperatorName(OO, S, QualType(), QualType(), Operators); + }; + + // Every defaulted operator looks up itself. + Lookup(Op); + // ... and the rewritten form of itself, if any. + if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(Op)) + Lookup(ExtraOp); + + // For 'operator<=>', we also form a 'cmp != 0' expression, and might + // synthesize a three-way comparison from '<' and '=='. In a dependent + // context, we also need to look up '==' in case we implicitly declare a + // defaulted 'operator=='. + if (Op == OO_Spaceship) { + Lookup(OO_ExclaimEqual); + Lookup(OO_Less); + Lookup(OO_EqualEqual); + } +} + +bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, + DefaultedComparisonKind DCK) { + assert(DCK != DefaultedComparisonKind::None && "not a defaulted comparison"); + + CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(FD->getLexicalDeclContext()); + assert(RD && "defaulted comparison is not defaulted in a class"); + + // Perform any unqualified lookups we're going to need to default this + // function. + if (S) { + UnresolvedSet<32> Operators; + lookupOperatorsForDefaultedComparison(*this, S, Operators, + FD->getOverloadedOperator()); + FD->setDefaultedFunctionInfo(FunctionDecl::DefaultedFunctionInfo::Create( + Context, Operators.pairs())); + } + + // C++2a [class.compare.default]p1: + // A defaulted comparison operator function for some class C shall be a + // non-template function declared in the member-specification of C that is + // -- a non-static const member of C having one parameter of type + // const C&, or + // -- a friend of C having two parameters of type const C& or two + // parameters of type C. + QualType ExpectedParmType1 = Context.getRecordType(RD); + QualType ExpectedParmType2 = + Context.getLValueReferenceType(ExpectedParmType1.withConst()); + if (isa<CXXMethodDecl>(FD)) + ExpectedParmType1 = ExpectedParmType2; + for (const ParmVarDecl *Param : FD->parameters()) { + if (!Param->getType()->isDependentType() && + !Context.hasSameType(Param->getType(), ExpectedParmType1) && + !Context.hasSameType(Param->getType(), ExpectedParmType2)) { + // Don't diagnose an implicit 'operator=='; we will have diagnosed the + // corresponding defaulted 'operator<=>' already. + if (!FD->isImplicit()) { + Diag(FD->getLocation(), diag::err_defaulted_comparison_param) + << (int)DCK << Param->getType() << ExpectedParmType1 + << !isa<CXXMethodDecl>(FD) + << ExpectedParmType2 << Param->getSourceRange(); + } + return true; + } + } + if (FD->getNumParams() == 2 && + !Context.hasSameType(FD->getParamDecl(0)->getType(), + FD->getParamDecl(1)->getType())) { + if (!FD->isImplicit()) { + Diag(FD->getLocation(), diag::err_defaulted_comparison_param_mismatch) + << (int)DCK + << FD->getParamDecl(0)->getType() + << FD->getParamDecl(0)->getSourceRange() + << FD->getParamDecl(1)->getType() + << FD->getParamDecl(1)->getSourceRange(); + } + return true; + } + + // ... non-static const member ... + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { + assert(!MD->isStatic() && "comparison function cannot be a static member"); + if (!MD->isConst()) { + SourceLocation InsertLoc; + if (FunctionTypeLoc Loc = MD->getFunctionTypeLoc()) + InsertLoc = getLocForEndOfToken(Loc.getRParenLoc()); + // Don't diagnose an implicit 'operator=='; we will have diagnosed the + // corresponding defaulted 'operator<=>' already. + if (!MD->isImplicit()) { + Diag(MD->getLocation(), diag::err_defaulted_comparison_non_const) + << (int)DCK << FixItHint::CreateInsertion(InsertLoc, " const"); + } + + // Add the 'const' to the type to recover. + const auto *FPT = MD->getType()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.TypeQuals.addConst(); + MD->setType(Context.getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI)); + } + } else { + // A non-member function declared in a class must be a friend. + assert(FD->getFriendObjectKind() && "expected a friend declaration"); + } + + // C++2a [class.eq]p1, [class.rel]p1: + // A [defaulted comparison other than <=>] shall have a declared return + // type bool. + if (DCK != DefaultedComparisonKind::ThreeWay && + !FD->getDeclaredReturnType()->isDependentType() && + !Context.hasSameType(FD->getDeclaredReturnType(), Context.BoolTy)) { + Diag(FD->getLocation(), diag::err_defaulted_comparison_return_type_not_bool) + << (int)DCK << FD->getDeclaredReturnType() << Context.BoolTy + << FD->getReturnTypeSourceRange(); + return true; + } + // C++2a [class.spaceship]p2 [P2002R0]: + // Let R be the declared return type [...]. If R is auto, [...]. Otherwise, + // R shall not contain a placeholder type. + if (DCK == DefaultedComparisonKind::ThreeWay && + FD->getDeclaredReturnType()->getContainedDeducedType() && + !Context.hasSameType(FD->getDeclaredReturnType(), + Context.getAutoDeductType())) { + Diag(FD->getLocation(), + diag::err_defaulted_comparison_deduced_return_type_not_auto) + << (int)DCK << FD->getDeclaredReturnType() << Context.AutoDeductTy + << FD->getReturnTypeSourceRange(); + return true; + } + + // For a defaulted function in a dependent class, defer all remaining checks + // until instantiation. + if (RD->isDependentType()) + return false; + + // Determine whether the function should be defined as deleted. + DefaultedComparisonInfo Info = + DefaultedComparisonAnalyzer(*this, RD, FD, DCK).visit(); + + bool First = FD == FD->getCanonicalDecl(); + + // If we want to delete the function, then do so; there's nothing else to + // check in that case. + if (Info.Deleted) { + if (!First) { + // C++11 [dcl.fct.def.default]p4: + // [For a] user-provided explicitly-defaulted function [...] if such a + // function is implicitly defined as deleted, the program is ill-formed. + // + // This is really just a consequence of the general rule that you can + // only delete a function on its first declaration. + Diag(FD->getLocation(), diag::err_non_first_default_compare_deletes) + << FD->isImplicit() << (int)DCK; + DefaultedComparisonAnalyzer(*this, RD, FD, DCK, + DefaultedComparisonAnalyzer::ExplainDeleted) + .visit(); + return true; + } + + SetDeclDeleted(FD, FD->getLocation()); + if (!inTemplateInstantiation() && !FD->isImplicit()) { + Diag(FD->getLocation(), diag::warn_defaulted_comparison_deleted) + << (int)DCK; + DefaultedComparisonAnalyzer(*this, RD, FD, DCK, + DefaultedComparisonAnalyzer::ExplainDeleted) + .visit(); + } + return false; + } + + // C++2a [class.spaceship]p2: + // The return type is deduced as the common comparison type of R0, R1, ... + if (DCK == DefaultedComparisonKind::ThreeWay && + FD->getDeclaredReturnType()->isUndeducedAutoType()) { + SourceLocation RetLoc = FD->getReturnTypeSourceRange().getBegin(); + if (RetLoc.isInvalid()) + RetLoc = FD->getBeginLoc(); + // FIXME: Should we really care whether we have the complete type and the + // 'enumerator' constants here? A forward declaration seems sufficient. + QualType Cat = CheckComparisonCategoryType( + Info.Category, RetLoc, ComparisonCategoryUsage::DefaultedOperator); + if (Cat.isNull()) + return true; + Context.adjustDeducedFunctionResultType( + FD, SubstAutoType(FD->getDeclaredReturnType(), Cat)); + } + + // C++2a [dcl.fct.def.default]p3 [P2002R0]: + // An explicitly-defaulted function that is not defined as deleted may be + // declared constexpr or consteval only if it is constexpr-compatible. + // C++2a [class.compare.default]p3 [P2002R0]: + // A defaulted comparison function is constexpr-compatible if it satisfies + // the requirements for a constexpr function [...] + // The only relevant requirements are that the parameter and return types are + // literal types. The remaining conditions are checked by the analyzer. + if (FD->isConstexpr()) { + if (CheckConstexprReturnType(*this, FD, CheckConstexprKind::Diagnose) && + CheckConstexprParameterTypes(*this, FD, CheckConstexprKind::Diagnose) && + !Info.Constexpr) { + Diag(FD->getBeginLoc(), + diag::err_incorrect_defaulted_comparison_constexpr) + << FD->isImplicit() << (int)DCK << FD->isConsteval(); + DefaultedComparisonAnalyzer(*this, RD, FD, DCK, + DefaultedComparisonAnalyzer::ExplainConstexpr) + .visit(); + } + } + + // C++2a [dcl.fct.def.default]p3 [P2002R0]: + // If a constexpr-compatible function is explicitly defaulted on its first + // declaration, it is implicitly considered to be constexpr. + // FIXME: Only applying this to the first declaration seems problematic, as + // simple reorderings can affect the meaning of the program. + if (First && !FD->isConstexpr() && Info.Constexpr) + FD->setConstexprKind(CSK_constexpr); + + // C++2a [except.spec]p3: + // If a declaration of a function does not have a noexcept-specifier + // [and] is defaulted on its first declaration, [...] the exception + // specification is as specified below + if (FD->getExceptionSpecType() == EST_None) { + auto *FPT = FD->getType()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExceptionSpec.Type = EST_Unevaluated; + EPI.ExceptionSpec.SourceDecl = FD; + FD->setType(Context.getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI)); + } + + return false; +} + +void Sema::DeclareImplicitEqualityComparison(CXXRecordDecl *RD, + FunctionDecl *Spaceship) { + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::DeclaringImplicitEqualityComparison; + Ctx.PointOfInstantiation = Spaceship->getEndLoc(); + Ctx.Entity = Spaceship; + pushCodeSynthesisContext(Ctx); + + if (FunctionDecl *EqualEqual = SubstSpaceshipAsEqualEqual(RD, Spaceship)) + EqualEqual->setImplicit(); + + popCodeSynthesisContext(); +} + +void Sema::DefineDefaultedComparison(SourceLocation UseLoc, FunctionDecl *FD, + DefaultedComparisonKind DCK) { + assert(FD->isDefaulted() && !FD->isDeleted() && + !FD->doesThisDeclarationHaveABody()); + if (FD->willHaveBody() || FD->isInvalidDecl()) + return; + + SynthesizedFunctionScope Scope(*this, FD); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(UseLoc); + + { + // Build and set up the function body. + CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getLexicalParent()); + SourceLocation BodyLoc = + FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation(); + StmtResult Body = + DefaultedComparisonSynthesizer(*this, RD, FD, DCK, BodyLoc).build(); + if (Body.isInvalid()) { + FD->setInvalidDecl(); + return; + } + FD->setBody(Body.get()); + FD->markUsed(Context); + } + + // The exception specification is needed because we are defining the + // function. Note that this will reuse the body we just built. + ResolveExceptionSpec(UseLoc, FD->getType()->castAs<FunctionProtoType>()); + + if (ASTMutationListener *L = getASTMutationListener()) + L->CompletedImplicitDefinition(FD); +} + +static Sema::ImplicitExceptionSpecification +ComputeDefaultedComparisonExceptionSpec(Sema &S, SourceLocation Loc, + FunctionDecl *FD, + Sema::DefaultedComparisonKind DCK) { + ComputingExceptionSpec CES(S, FD, Loc); + Sema::ImplicitExceptionSpecification ExceptSpec(S); + + if (FD->isInvalidDecl()) + return ExceptSpec; + + // The common case is that we just defined the comparison function. In that + // case, just look at whether the body can throw. + if (FD->hasBody()) { + ExceptSpec.CalledStmt(FD->getBody()); + } else { + // Otherwise, build a body so we can check it. This should ideally only + // happen when we're not actually marking the function referenced. (This is + // only really important for efficiency: we don't want to build and throw + // away bodies for comparison functions more than we strictly need to.) + + // Pretend to synthesize the function body in an unevaluated context. + // Note that we can't actually just go ahead and define the function here: + // we are not permitted to mark its callees as referenced. + Sema::SynthesizedFunctionScope Scope(S, FD); + EnterExpressionEvaluationContext Context( + S, Sema::ExpressionEvaluationContext::Unevaluated); + + CXXRecordDecl *RD = cast<CXXRecordDecl>(FD->getLexicalParent()); + SourceLocation BodyLoc = + FD->getEndLoc().isValid() ? FD->getEndLoc() : FD->getLocation(); + StmtResult Body = + DefaultedComparisonSynthesizer(S, RD, FD, DCK, BodyLoc).build(); + if (!Body.isInvalid()) + ExceptSpec.CalledStmt(Body.get()); + + // FIXME: Can we hold onto this body and just transform it to potentially + // evaluated when we're asked to define the function rather than rebuilding + // it? Either that, or we should only build the bits of the body that we + // need (the expressions, not the statements). + } + + return ExceptSpec; } void Sema::CheckDelayedMemberExceptionSpecs() { @@ -7157,7 +8439,8 @@ bool SpecialMemberDeletionInfo::isAccessible(Subobject Subobj, objectTy = S.Context.getTypeDeclType(target->getParent()); } - return S.isSpecialMemberAccessibleForDeletion(target, access, objectTy); + return S.isMemberAccessibleForDeletion( + target->getParent(), DeclAccessPair::make(target, access), objectTy); } /// Check whether we should delete a special member due to the implicit @@ -7568,6 +8851,22 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, return false; } +void Sema::DiagnoseDeletedDefaultedFunction(FunctionDecl *FD) { + DefaultedFunctionKind DFK = getDefaultedFunctionKind(FD); + assert(DFK && "not a defaultable function"); + assert(FD->isDefaulted() && FD->isDeleted() && "not defaulted and deleted"); + + if (DFK.isSpecialMember()) { + ShouldDeleteSpecialMember(cast<CXXMethodDecl>(FD), DFK.asSpecialMember(), + nullptr, /*Diagnose=*/true); + } else { + DefaultedComparisonAnalyzer( + *this, cast<CXXRecordDecl>(FD->getLexicalDeclContext()), FD, + DFK.asComparison(), DefaultedComparisonAnalyzer::ExplainDeleted) + .visit(); + } +} + /// Perform lookup for a special member of the specified kind, and determine /// whether it is trivial. If the triviality can be determined without the /// lookup, skip it. This is intended for use when determining whether a @@ -8187,7 +9486,45 @@ void Sema::ActOnFinishCXXMemberSpecification( reinterpret_cast<Decl**>(FieldCollector->getCurFields()), FieldCollector->getCurNumFields()), LBrac, RBrac, AttrList); - CheckCompletedCXXClass(cast<CXXRecordDecl>(TagDecl)); + CheckCompletedCXXClass(S, cast<CXXRecordDecl>(TagDecl)); +} + +/// Find the equality comparison functions that should be implicitly declared +/// in a given class definition, per C++2a [class.compare.default]p3. +static void findImplicitlyDeclaredEqualityComparisons( + ASTContext &Ctx, CXXRecordDecl *RD, + llvm::SmallVectorImpl<FunctionDecl *> &Spaceships) { + DeclarationName EqEq = Ctx.DeclarationNames.getCXXOperatorName(OO_EqualEqual); + if (!RD->lookup(EqEq).empty()) + // Member operator== explicitly declared: no implicit operator==s. + return; + + // Traverse friends looking for an '==' or a '<=>'. + for (FriendDecl *Friend : RD->friends()) { + FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(Friend->getFriendDecl()); + if (!FD) continue; + + if (FD->getOverloadedOperator() == OO_EqualEqual) { + // Friend operator== explicitly declared: no implicit operator==s. + Spaceships.clear(); + return; + } + + if (FD->getOverloadedOperator() == OO_Spaceship && + FD->isExplicitlyDefaulted()) + Spaceships.push_back(FD); + } + + // Look for members named 'operator<=>'. + DeclarationName Cmp = Ctx.DeclarationNames.getCXXOperatorName(OO_Spaceship); + for (NamedDecl *ND : RD->lookup(Cmp)) { + // Note that we could find a non-function here (either a function template + // or a using-declaration). Neither case results in an implicit + // 'operator=='. + if (auto *FD = dyn_cast<FunctionDecl>(ND)) + if (FD->isExplicitlyDefaulted()) + Spaceships.push_back(FD); + } } /// AddImplicitlyDeclaredMembersToClass - Adds any implicitly-declared @@ -8267,6 +9604,20 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { ClassDecl->needsOverloadResolutionForDestructor()) DeclareImplicitDestructor(ClassDecl); } + + // C++2a [class.compare.default]p3: + // If the member-specification does not explicitly declare any member or + // friend named operator==, an == operator function is declared implicitly + // for each defaulted three-way comparison operator function defined in the + // member-specification + // FIXME: Consider doing this lazily. + if (getLangOpts().CPlusPlus2a) { + llvm::SmallVector<FunctionDecl*, 4> DefaultedSpaceships; + findImplicitlyDeclaredEqualityComparisons(Context, ClassDecl, + DefaultedSpaceships); + for (auto *FD : DefaultedSpaceships) + DeclareImplicitEqualityComparison(ClassDecl, FD); + } } unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { @@ -8478,7 +9829,7 @@ QualType Sema::CheckConstructorDeclarator(Declarator &D, QualType R, // Rebuild the function type "R" without any type qualifiers (in // case any of the errors above fired) and with "void" as the // return type, since constructors don't have return types. - const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); + const FunctionProtoType *Proto = R->castAs<FunctionProtoType>(); if (Proto->getReturnType() == Context.VoidTy && !D.isInvalidType()) return R; @@ -8676,7 +10027,7 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, if (!D.isInvalidType()) return R; - const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); + const FunctionProtoType *Proto = R->castAs<FunctionProtoType>(); FunctionProtoType::ExtProtoInfo EPI = Proto->getExtProtoInfo(); EPI.Variadic = false; EPI.TypeQuals = Qualifiers(); @@ -8750,7 +10101,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, D.setInvalidType(); } - const FunctionProtoType *Proto = R->getAs<FunctionProtoType>(); + const auto *Proto = R->castAs<FunctionProtoType>(); // Make sure we don't have any parameters. if (Proto->getNumParams() > 0) { @@ -9334,22 +10685,37 @@ struct InvalidSTLDiagnoser { } // namespace QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind, - SourceLocation Loc) { + SourceLocation Loc, + ComparisonCategoryUsage Usage) { assert(getLangOpts().CPlusPlus && "Looking for comparison category type outside of C++."); + // Use an elaborated type for diagnostics which has a name containing the + // prepended 'std' namespace but not any inline namespace names. + auto TyForDiags = [&](ComparisonCategoryInfo *Info) { + auto *NNS = + NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()); + return Context.getElaboratedType(ETK_None, NNS, Info->getType()); + }; + // Check if we've already successfully checked the comparison category type // before. If so, skip checking it again. ComparisonCategoryInfo *Info = Context.CompCategories.lookupInfo(Kind); - if (Info && FullyCheckedComparisonCategories[static_cast<unsigned>(Kind)]) + if (Info && FullyCheckedComparisonCategories[static_cast<unsigned>(Kind)]) { + // The only thing we need to check is that the type has a reachable + // definition in the current context. + if (RequireCompleteType(Loc, TyForDiags(Info), diag::err_incomplete_type)) + return QualType(); + return Info->getType(); + } // If lookup failed if (!Info) { std::string NameForDiags = "std::"; NameForDiags += ComparisonCategories::getCategoryString(Kind); Diag(Loc, diag::err_implied_comparison_category_type_not_found) - << NameForDiags; + << NameForDiags << (int)Usage; return QualType(); } @@ -9361,18 +10727,10 @@ QualType Sema::CheckComparisonCategoryType(ComparisonCategoryType Kind, if (Info->Record->hasDefinition()) Info->Record = Info->Record->getDefinition(); - // Use an elaborated type for diagnostics which has a name containing the - // prepended 'std' namespace but not any inline namespace names. - QualType TyForDiags = [&]() { - auto *NNS = - NestedNameSpecifier::Create(Context, nullptr, getStdNamespace()); - return Context.getElaboratedType(ETK_None, NNS, Info->getType()); - }(); - - if (RequireCompleteType(Loc, TyForDiags, diag::err_incomplete_type)) + if (RequireCompleteType(Loc, TyForDiags(Info), diag::err_incomplete_type)) return QualType(); - InvalidSTLDiagnoser UnsupportedSTLError{*this, Loc, TyForDiags}; + InvalidSTLDiagnoser UnsupportedSTLError{*this, Loc, TyForDiags(Info)}; if (!Info->Record->isTriviallyCopyable()) return UnsupportedSTLError(USS_NonTrivial); @@ -11070,25 +12428,6 @@ void SpecialMemberExceptionSpecInfo::visitSubobjectCall( ExceptSpec.CalledDecl(getSubobjectLoc(Subobj), MD); } -namespace { -/// RAII object to register a special member as being currently declared. -struct ComputingExceptionSpec { - Sema &S; - - ComputingExceptionSpec(Sema &S, CXXMethodDecl *MD, SourceLocation Loc) - : S(S) { - Sema::CodeSynthesisContext Ctx; - Ctx.Kind = Sema::CodeSynthesisContext::ExceptionSpecEvaluation; - Ctx.PointOfInstantiation = Loc; - Ctx.Entity = MD; - S.pushCodeSynthesisContext(Ctx); - } - ~ComputingExceptionSpec() { - S.popCodeSynthesisContext(); - } -}; -} - bool Sema::tryResolveExplicitSpecifier(ExplicitSpecifier &ExplicitSpec) { llvm::APSInt Result; ExprResult Converted = CheckConvertedConstantExpression( @@ -11222,10 +12561,9 @@ void Sema::setupImplicitSpecialMemberType(CXXMethodDecl *SpecialMem, // Build an exception specification pointing back at this constructor. FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, SpecialMem); - if (getLangOpts().OpenCLCPlusPlus) { - // OpenCL: Implicitly defaulted special member are of the generic address - // space. - EPI.TypeQuals.addAddressSpace(LangAS::opencl_generic); + LangAS AS = getDefaultCXXMethodAddrSpace(); + if (AS != LangAS::Default) { + EPI.TypeQuals.addAddressSpace(AS); } auto QT = Context.getFunctionType(ResultTy, Args, EPI); @@ -11384,7 +12722,8 @@ Sema::findInheritingConstructor(SourceLocation Loc, BaseCtor->getExplicitSpecifier(), /*isInline=*/true, /*isImplicitlyDeclared=*/true, Constexpr ? BaseCtor->getConstexprKind() : CSK_unspecified, - InheritedConstructor(Shadow, BaseCtor)); + InheritedConstructor(Shadow, BaseCtor), + BaseCtor->getTrailingRequiresClause()); if (Shadow->isInvalidDecl()) DerivedCtor->setInvalidDecl(); @@ -11635,7 +12974,7 @@ void Sema::ActOnFinishCXXMemberDecls() { } } -void Sema::ActOnFinishCXXNonNestedClass(Decl *D) { +void Sema::ActOnFinishCXXNonNestedClass() { referenceDLLExportedClassMethods(); if (!DelayedDllExportMemberFunctions.empty()) { @@ -11676,8 +13015,7 @@ void Sema::AdjustDestructorExceptionSpec(CXXDestructorDecl *Destructor) { // A declaration of a destructor that does not have an exception- // specification is implicitly considered to have the same exception- // specification as an implicit declaration. - const FunctionProtoType *DtorType = Destructor->getType()-> - getAs<FunctionProtoType>(); + const auto *DtorType = Destructor->getType()->castAs<FunctionProtoType>(); if (DtorType->hasExceptionSpec()) return; @@ -12135,8 +13473,9 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { return nullptr; QualType ArgType = Context.getTypeDeclType(ClassDecl); - if (Context.getLangOpts().OpenCLCPlusPlus) - ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic); + LangAS AS = getDefaultCXXMethodAddrSpace(); + if (AS != LangAS::Default) + ArgType = Context.getAddrSpaceQualType(ArgType, AS); QualType RetType = Context.getLValueReferenceType(ArgType); bool Const = ClassDecl->implicitCopyAssignmentHasConstParam(); if (Const) @@ -12237,11 +13576,12 @@ static void diagnoseDeprecatedCopyOperation(Sema &S, CXXMethodDecl *CopyOp) { assert(UserDeclaredOperation); } - if (UserDeclaredOperation) { + if (UserDeclaredOperation && UserDeclaredOperation->isUserProvided()) { S.Diag(UserDeclaredOperation->getLocation(), - diag::warn_deprecated_copy_operation) - << RD << /*copy assignment*/!isa<CXXConstructorDecl>(CopyOp) - << /*destructor*/isa<CXXDestructorDecl>(UserDeclaredOperation); + isa<CXXDestructorDecl>(UserDeclaredOperation) + ? diag::warn_deprecated_copy_dtor_operation + : diag::warn_deprecated_copy_operation) + << RD << /*copy assignment*/ !isa<CXXConstructorDecl>(CopyOp); } } @@ -12460,8 +13800,9 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { // constructor rules. QualType ArgType = Context.getTypeDeclType(ClassDecl); - if (Context.getLangOpts().OpenCLCPlusPlus) - ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic); + LangAS AS = getDefaultCXXMethodAddrSpace(); + if (AS != LangAS::Default) + ArgType = Context.getAddrSpaceQualType(ArgType, AS); QualType RetType = Context.getLValueReferenceType(ArgType); ArgType = Context.getRValueReferenceType(ArgType); @@ -12654,8 +13995,8 @@ void Sema::DefineImplicitMoveAssignment(SourceLocation CurrentLocation, // The parameter for the "other" object, which we are move from. ParmVarDecl *Other = MoveAssignOperator->getParamDecl(0); - QualType OtherRefType = Other->getType()-> - getAs<RValueReferenceType>()->getPointeeType(); + QualType OtherRefType = + Other->getType()->castAs<RValueReferenceType>()->getPointeeType(); // Our location for everything implicitly-generated. SourceLocation Loc = MoveAssignOperator->getEndLoc().isValid() @@ -12838,8 +14179,9 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( if (Const) ArgType = ArgType.withConst(); - if (Context.getLangOpts().OpenCLCPlusPlus) - ArgType = Context.getAddrSpaceQualType(ArgType, LangAS::opencl_generic); + LangAS AS = getDefaultCXXMethodAddrSpace(); + if (AS != LangAS::Default) + ArgType = Context.getAddrSpaceQualType(ArgType, AS); ArgType = Context.getLValueReferenceType(ArgType); @@ -12970,8 +14312,9 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( QualType ClassType = Context.getTypeDeclType(ClassDecl); QualType ArgType = ClassType; - if (Context.getLangOpts().OpenCLCPlusPlus) - ArgType = Context.getAddrSpaceQualType(ClassType, LangAS::opencl_generic); + LangAS AS = getDefaultCXXMethodAddrSpace(); + if (AS != LangAS::Default) + ArgType = Context.getAddrSpaceQualType(ClassType, AS); ArgType = Context.getRValueReferenceType(ArgType); bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, @@ -13447,9 +14790,7 @@ Sema::CompleteConstructorCall(CXXConstructorDecl *Constructor, unsigned NumArgs = ArgsPtr.size(); Expr **Args = ArgsPtr.data(); - const FunctionProtoType *Proto - = Constructor->getType()->getAs<FunctionProtoType>(); - assert(Proto && "Constructor without a prototype?"); + const auto *Proto = Constructor->getType()->castAs<FunctionProtoType>(); unsigned NumParams = Proto->getNumParams(); // If too few arguments are available, we'll fill in the rest with defaults. @@ -13512,7 +14853,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, unsigned DependentParamTypeDiag, unsigned InvalidParamTypeDiag) { QualType ResultType = - FnDecl->getType()->getAs<FunctionType>()->getReturnType(); + FnDecl->getType()->castAs<FunctionType>()->getReturnType(); // Check that the result type is not dependent. if (ResultType->isDependentType()) @@ -13741,7 +15082,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // Overloaded operators other than operator() cannot be variadic. if (Op != OO_Call && - FnDecl->getType()->getAs<FunctionProtoType>()->isVariadic()) { + FnDecl->getType()->castAs<FunctionProtoType>()->isVariadic()) { return Diag(FnDecl->getLocation(), diag::err_operator_overload_variadic) << FnDecl->getDeclName(); } @@ -14010,10 +15351,6 @@ Decl *Sema::ActOnStartLinkageSpecification(Scope *S, SourceLocation ExternLoc, Language = LinkageSpecDecl::lang_c; else if (Lang == "C++") Language = LinkageSpecDecl::lang_cxx; - else if (Lang == "C++11") - Language = LinkageSpecDecl::lang_cxx_11; - else if (Lang == "C++14") - Language = LinkageSpecDecl::lang_cxx_14; else { Diag(LangStr->getExprLoc(), diag::err_language_linkage_spec_unknown) << LangStr->getSourceRange(); @@ -14291,8 +15628,16 @@ Decl *Sema::BuildStaticAssertDeclaration(SourceLocation StaticAssertLoc, std::string InnerCondDescription; std::tie(InnerCond, InnerCondDescription) = findFailedBooleanCondition(Converted.get()); - if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond) - && !isa<IntegerLiteral>(InnerCond)) { + if (InnerCond && isa<ConceptSpecializationExpr>(InnerCond)) { + // Drill down into concept specialization expressions to see why they + // weren't satisfied. + Diag(StaticAssertLoc, diag::err_static_assert_failed) + << !AssertMessage << Msg.str() << AssertExpr->getSourceRange(); + ConstraintSatisfaction Satisfaction; + if (!CheckConstraintSatisfaction(InnerCond, Satisfaction)) + DiagnoseUnsatisfiedConstraint(Satisfaction); + } else if (InnerCond && !isa<CXXBoolLiteralExpr>(InnerCond) + && !isa<IntegerLiteral>(InnerCond)) { Diag(StaticAssertLoc, diag::err_static_assert_requirement_failed) << InnerCondDescription << !AssertMessage << Msg.str() << InnerCond->getSourceRange(); @@ -14974,6 +16319,16 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { if (Fn->isDeleted()) return; + // C++11 [basic.start.main]p3: + // A program that defines main as deleted [...] is ill-formed. + if (Fn->isMain()) + Diag(DelLoc, diag::err_deleted_main); + + // C++11 [dcl.fct.def.delete]p4: + // A deleted function is implicitly inline. + Fn->setImplicitlyInline(); + Fn->setDeletedAsWritten(); + // See if we're deleting a function which is already known to override a // non-deleted virtual function. if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) { @@ -14990,67 +16345,93 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { // If this function was implicitly deleted because it was defaulted, // explain why it was deleted. if (IssuedDiagnostic && MD->isDefaulted()) - ShouldDeleteSpecialMember(MD, getSpecialMember(MD), nullptr, - /*Diagnose*/true); + DiagnoseDeletedDefaultedFunction(MD); } - - // C++11 [basic.start.main]p3: - // A program that defines main as deleted [...] is ill-formed. - if (Fn->isMain()) - Diag(DelLoc, diag::err_deleted_main); - - // C++11 [dcl.fct.def.delete]p4: - // A deleted function is implicitly inline. - Fn->setImplicitlyInline(); - Fn->setDeletedAsWritten(); } void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { - CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(Dcl); + if (!Dcl || Dcl->isInvalidDecl()) + return; - if (MD) { - if (MD->getParent()->isDependentType()) { - MD->setDefaulted(); - MD->setExplicitlyDefaulted(); - return; + auto *FD = dyn_cast<FunctionDecl>(Dcl); + if (!FD) { + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(Dcl)) { + if (getDefaultedFunctionKind(FTD->getTemplatedDecl()).isComparison()) { + Diag(DefaultLoc, diag::err_defaulted_comparison_template); + return; + } } - CXXSpecialMember Member = getSpecialMember(MD); - if (Member == CXXInvalid) { - if (!MD->isInvalidDecl()) - Diag(DefaultLoc, diag::err_default_special_members); - return; - } + Diag(DefaultLoc, diag::err_default_special_members) + << getLangOpts().CPlusPlus2a; + return; + } + + // Reject if this can't possibly be a defaultable function. + DefaultedFunctionKind DefKind = getDefaultedFunctionKind(FD); + if (!DefKind && + // A dependent function that doesn't locally look defaultable can + // still instantiate to a defaultable function if it's a constructor + // or assignment operator. + (!FD->isDependentContext() || + (!isa<CXXConstructorDecl>(FD) && + FD->getDeclName().getCXXOverloadedOperator() != OO_Equal))) { + Diag(DefaultLoc, diag::err_default_special_members) + << getLangOpts().CPlusPlus2a; + return; + } + + if (DefKind.isComparison() && + !isa<CXXRecordDecl>(FD->getLexicalDeclContext())) { + Diag(FD->getLocation(), diag::err_defaulted_comparison_out_of_class) + << (int)DefKind.asComparison(); + return; + } - MD->setDefaulted(); - MD->setExplicitlyDefaulted(); + // Issue compatibility warning. We already warned if the operator is + // 'operator<=>' when parsing the '<=>' token. + if (DefKind.isComparison() && + DefKind.asComparison() != DefaultedComparisonKind::ThreeWay) { + Diag(DefaultLoc, getLangOpts().CPlusPlus2a + ? diag::warn_cxx17_compat_defaulted_comparison + : diag::ext_defaulted_comparison); + } - // Unset that we will have a body for this function. We might not, - // if it turns out to be trivial, and we don't need this marking now - // that we've marked it as defaulted. - MD->setWillHaveBody(false); + FD->setDefaulted(); + FD->setExplicitlyDefaulted(); - // If this definition appears within the record, do the checking when - // the record is complete. - const FunctionDecl *Primary = MD; - if (const FunctionDecl *Pattern = MD->getTemplateInstantiationPattern()) - // Ask the template instantiation pattern that actually had the - // '= default' on it. - Primary = Pattern; + // Defer checking functions that are defaulted in a dependent context. + if (FD->isDependentContext()) + return; - // If the method was defaulted on its first declaration, we will have - // already performed the checking in CheckCompletedCXXClass. Such a - // declaration doesn't trigger an implicit definition. - if (Primary->getCanonicalDecl()->isDefaulted()) - return; + // Unset that we will have a body for this function. We might not, + // if it turns out to be trivial, and we don't need this marking now + // that we've marked it as defaulted. + FD->setWillHaveBody(false); - CheckExplicitlyDefaultedSpecialMember(MD); + // If this definition appears within the record, do the checking when + // the record is complete. This is always the case for a defaulted + // comparison. + if (DefKind.isComparison()) + return; + auto *MD = cast<CXXMethodDecl>(FD); - if (!MD->isInvalidDecl()) - DefineImplicitSpecialMember(*this, MD, DefaultLoc); - } else { - Diag(DefaultLoc, diag::err_default_special_members); - } + const FunctionDecl *Primary = FD; + if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern()) + // Ask the template instantiation pattern that actually had the + // '= default' on it. + Primary = Pattern; + + // If the method was defaulted on its first declaration, we will have + // already performed the checking in CheckCompletedCXXClass. Such a + // declaration doesn't trigger an implicit definition. + if (Primary->getCanonicalDecl()->isDefaulted()) + return; + + if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember())) + MD->setInvalidDecl(); + else + DefineImplicitSpecialMember(*this, MD, DefaultLoc); } static void SearchForReturnInStmt(Sema &Self, Stmt *S) { @@ -15074,8 +16455,8 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) { bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - const auto *NewFT = New->getType()->getAs<FunctionProtoType>(); - const auto *OldFT = Old->getType()->getAs<FunctionProtoType>(); + const auto *NewFT = New->getType()->castAs<FunctionProtoType>(); + const auto *OldFT = Old->getType()->castAs<FunctionProtoType>(); if (OldFT->hasExtParameterInfos()) { for (unsigned I = 0, E = OldFT->getNumParams(); I != E; ++I) @@ -15122,8 +16503,8 @@ bool Sema::CheckOverridingFunctionAttributes(const CXXMethodDecl *New, bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, const CXXMethodDecl *Old) { - QualType NewTy = New->getType()->getAs<FunctionType>()->getReturnType(); - QualType OldTy = Old->getType()->getAs<FunctionType>()->getReturnType(); + QualType NewTy = New->getType()->castAs<FunctionType>()->getReturnType(); + QualType OldTy = Old->getType()->castAs<FunctionType>()->getReturnType(); if (Context.hasSameType(NewTy, OldTy) || NewTy->isDependentType() || OldTy->isDependentType()) @@ -15729,6 +17110,11 @@ bool Sema::checkThisInStaticMemberFunctionType(CXXMethodDecl *Method) { if (checkThisInStaticMemberFunctionExceptionSpec(Method)) return true; + // Check the trailing requires clause + if (Expr *E = Method->getTrailingRequiresClause()) + if (!Finder.TraverseStmt(E)) + return true; + return checkThisInStaticMemberFunctionAttributes(Method); } diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index db594bbd21dd..5fdf6aeed5b4 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -2828,6 +2828,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, "Expected to find the method through lookup as well"); // ImpMethodDecl may be null as in a @dynamic property. if (ImpMethodDecl) { + // Skip property accessor function stubs. + if (ImpMethodDecl->isSynthesizedAccessorStub()) + continue; if (!WarnCategoryMethodImpl) WarnConflictingTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl)); @@ -2854,6 +2857,9 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, "Expected to find the method through lookup as well"); // ImpMethodDecl may be null as in a @dynamic property. if (ImpMethodDecl) { + // Skip property accessor function stubs. + if (ImpMethodDecl->isSynthesizedAccessorStub()) + continue; if (!WarnCategoryMethodImpl) WarnConflictingTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl)); @@ -3233,6 +3239,9 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, if (left->isHidden() || right->isHidden()) return false; + if (left->isDirectMethod() != right->isDirectMethod()) + return false; + if (getLangOpts().ObjCAutoRefCount && (left->hasAttr<NSReturnsRetainedAttr>() != right->hasAttr<NSReturnsRetainedAttr>() || @@ -3424,6 +3433,9 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen, if (!chosen->isInstanceMethod()) return false; + if (chosen->isDirectMethod() != other->isDirectMethod()) + return false; + Selector sel = chosen->getSelector(); if (!sel.isUnarySelector() || sel.getNameForSlot(0) != "length") return false; @@ -3903,6 +3915,25 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, || isa<ObjCProtocolDecl>(ClassDecl); bool checkIdenticalMethods = isa<ObjCImplementationDecl>(ClassDecl); + // Make synthesized accessor stub functions visible. + // ActOnPropertyImplDecl() creates them as not visible in case + // they are overridden by an explicit method that is encountered + // later. + if (auto *OID = dyn_cast<ObjCImplementationDecl>(CurContext)) { + for (auto PropImpl : OID->property_impls()) { + if (auto *Getter = PropImpl->getGetterMethodDecl()) + if (Getter->isSynthesizedAccessorStub()) { + OID->makeDeclVisibleInContext(Getter); + OID->addDecl(Getter); + } + if (auto *Setter = PropImpl->getSetterMethodDecl()) + if (Setter->isSynthesizedAccessorStub()) { + OID->makeDeclVisibleInContext(Setter); + OID->addDecl(Setter); + } + } + } + // FIXME: Remove these and use the ObjCContainerDecl/DeclContext. llvm::DenseMap<Selector, const ObjCMethodDecl*> InsMap; llvm::DenseMap<Selector, const ObjCMethodDecl*> ClsMap; @@ -4001,8 +4032,8 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, continue; for (const auto *Ext : IDecl->visible_extensions()) { - if (ObjCMethodDecl *GetterMethod - = Ext->getInstanceMethod(Property->getGetterName())) + if (ObjCMethodDecl *GetterMethod = + Ext->getInstanceMethod(Property->getGetterName())) GetterMethod->setPropertyAccessor(true); if (!Property->isReadOnly()) if (ObjCMethodDecl *SetterMethod @@ -4314,6 +4345,18 @@ private: }; } // end anonymous namespace +void Sema::CheckObjCMethodDirectOverrides(ObjCMethodDecl *method, + ObjCMethodDecl *overridden) { + if (const auto *attr = overridden->getAttr<ObjCDirectAttr>()) { + Diag(method->getLocation(), diag::err_objc_override_direct_method); + Diag(attr->getLocation(), diag::note_previous_declaration); + } else if (const auto *attr = method->getAttr<ObjCDirectAttr>()) { + Diag(attr->getLocation(), diag::err_objc_direct_on_override) + << isa<ObjCProtocolDecl>(overridden->getDeclContext()); + Diag(overridden->getLocation(), diag::note_previous_declaration); + } +} + void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, ObjCInterfaceDecl *CurrentClass, ResultTypeCompatibilityKind RTC) { @@ -4332,8 +4375,8 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, if (isa<ObjCProtocolDecl>(overridden->getDeclContext()) || CurrentClass != overridden->getClassInterface() || overridden->isOverriding()) { + CheckObjCMethodDirectOverrides(ObjCMethod, overridden); hasOverriddenMethodsInBaseOrProtocol = true; - } else if (isa<ObjCImplDecl>(ObjCMethod->getDeclContext())) { // OverrideSearch will return as "overridden" the same method in the // interface. For hasOverriddenMethodsInBaseOrProtocol, we need to @@ -4357,6 +4400,7 @@ void Sema::CheckObjCMethodOverrides(ObjCMethodDecl *ObjCMethod, for (ObjCMethodDecl *SuperOverridden : overrides) { if (isa<ObjCProtocolDecl>(SuperOverridden->getDeclContext()) || CurrentClass != SuperOverridden->getClassInterface()) { + CheckObjCMethodDirectOverrides(ObjCMethod, SuperOverridden); hasOverriddenMethodsInBaseOrProtocol = true; overridden->setOverriding(true); break; @@ -4551,6 +4595,7 @@ Decl *Sema::ActOnMethodDeclaration( Diag(MethodLoc, diag::err_missing_method_context); return nullptr; } + Decl *ClassDecl = cast<ObjCContainerDecl>(CurContext); QualType resultDeclType; @@ -4574,7 +4619,7 @@ Decl *Sema::ActOnMethodDeclaration( ObjCMethodDecl *ObjCMethod = ObjCMethodDecl::Create( Context, MethodLoc, EndLoc, Sel, resultDeclType, ReturnTInfo, CurContext, MethodType == tok::minus, isVariadic, - /*isPropertyAccessor=*/false, + /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/false, /*isDefined=*/false, MethodDeclKind == tok::objc_optional ? ObjCMethodDecl::Optional : ObjCMethodDecl::Required, @@ -4666,6 +4711,41 @@ Decl *Sema::ActOnMethodDeclaration( ImpDecl->addClassMethod(ObjCMethod); } + // If this method overrides a previous @synthesize declaration, + // register it with the property. Linear search through all + // properties here, because the autosynthesized stub hasn't been + // made visible yet, so it can be overriden by a later + // user-specified implementation. + for (ObjCPropertyImplDecl *PropertyImpl : ImpDecl->property_impls()) { + if (auto *Setter = PropertyImpl->getSetterMethodDecl()) + if (Setter->getSelector() == Sel && + Setter->isInstanceMethod() == ObjCMethod->isInstanceMethod()) { + assert(Setter->isSynthesizedAccessorStub() && "autosynth stub expected"); + PropertyImpl->setSetterMethodDecl(ObjCMethod); + } + if (auto *Getter = PropertyImpl->getGetterMethodDecl()) + if (Getter->getSelector() == Sel && + Getter->isInstanceMethod() == ObjCMethod->isInstanceMethod()) { + assert(Getter->isSynthesizedAccessorStub() && "autosynth stub expected"); + PropertyImpl->setGetterMethodDecl(ObjCMethod); + break; + } + } + + // A method is either tagged direct explicitly, or inherits it from its + // canonical declaration. + // + // We have to do the merge upfront and not in mergeInterfaceMethodToImpl() + // because IDecl->lookupMethod() returns more possible matches than just + // the canonical declaration. + if (!ObjCMethod->isDirectMethod()) { + const ObjCMethodDecl *CanonicalMD = ObjCMethod->getCanonicalDecl(); + if (const auto *attr = CanonicalMD->getAttr<ObjCDirectAttr>()) { + ObjCMethod->addAttr( + ObjCDirectAttr::CreateImplicit(Context, attr->getLocation())); + } + } + // Merge information from the @interface declaration into the // @implementation. if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) { @@ -4673,12 +4753,64 @@ Decl *Sema::ActOnMethodDeclaration( ObjCMethod->isInstanceMethod())) { mergeInterfaceMethodToImpl(*this, ObjCMethod, IMD); + // The Idecl->lookupMethod() above will find declarations for ObjCMethod + // in one of these places: + // + // (1) the canonical declaration in an @interface container paired + // with the ImplDecl, + // (2) non canonical declarations in @interface not paired with the + // ImplDecl for the same Class, + // (3) any superclass container. + // + // Direct methods only allow for canonical declarations in the matching + // container (case 1). + // + // Direct methods overriding a superclass declaration (case 3) is + // handled during overrides checks in CheckObjCMethodOverrides(). + // + // We deal with same-class container mismatches (Case 2) here. + if (IDecl == IMD->getClassInterface()) { + auto diagContainerMismatch = [&] { + int decl = 0, impl = 0; + + if (auto *Cat = dyn_cast<ObjCCategoryDecl>(IMD->getDeclContext())) + decl = Cat->IsClassExtension() ? 1 : 2; + + if (isa<ObjCCategoryImplDecl>(ImpDecl)) + impl = 1 + (decl != 0); + + Diag(ObjCMethod->getLocation(), + diag::err_objc_direct_impl_decl_mismatch) + << decl << impl; + Diag(IMD->getLocation(), diag::note_previous_declaration); + }; + + if (const auto *attr = ObjCMethod->getAttr<ObjCDirectAttr>()) { + if (ObjCMethod->getCanonicalDecl() != IMD) { + diagContainerMismatch(); + } else if (!IMD->isDirectMethod()) { + Diag(attr->getLocation(), diag::err_objc_direct_missing_on_decl); + Diag(IMD->getLocation(), diag::note_previous_declaration); + } + } else if (const auto *attr = IMD->getAttr<ObjCDirectAttr>()) { + if (ObjCMethod->getCanonicalDecl() != IMD) { + diagContainerMismatch(); + } else { + ObjCMethod->addAttr( + ObjCDirectAttr::CreateImplicit(Context, attr->getLocation())); + } + } + } + // Warn about defining -dealloc in a category. if (isa<ObjCCategoryImplDecl>(ImpDecl) && IMD->isOverriding() && ObjCMethod->getSelector().getMethodFamily() == OMF_dealloc) { Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category) << ObjCMethod->getDeclName(); } + } else if (ImpDecl->hasAttr<ObjCDirectMembersAttr>()) { + ObjCMethod->addAttr( + ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation())); } // Warn if a method declared in a protocol to which a category or @@ -4698,6 +4830,42 @@ Decl *Sema::ActOnMethodDeclaration( } } } else { + if (!isa<ObjCProtocolDecl>(ClassDecl)) { + if (!ObjCMethod->isDirectMethod() && + ClassDecl->hasAttr<ObjCDirectMembersAttr>()) { + ObjCMethod->addAttr( + ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation())); + } + + // There can be a single declaration in any @interface container + // for a given direct method, look for clashes as we add them. + // + // For valid code, we should always know the primary interface + // declaration by now, however for invalid code we'll keep parsing + // but we won't find the primary interface and IDecl will be nil. + ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl); + if (!IDecl) + IDecl = cast<ObjCCategoryDecl>(ClassDecl)->getClassInterface(); + + if (IDecl) + if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(), + ObjCMethod->isInstanceMethod(), + /*shallowCategoryLookup=*/false, + /*followSuper=*/false)) { + if (isa<ObjCProtocolDecl>(IMD->getDeclContext())) { + // Do not emit a diagnostic for the Protocol case: + // diag::err_objc_direct_on_protocol has already been emitted + // during parsing for these with a nicer diagnostic. + } else if (ObjCMethod->isDirectMethod() || IMD->isDirectMethod()) { + Diag(ObjCMethod->getLocation(), + diag::err_objc_direct_duplicate_decl) + << ObjCMethod->isDirectMethod() << IMD->isDirectMethod() + << ObjCMethod->getDeclName(); + Diag(IMD->getLocation(), diag::note_previous_declaration); + } + } + } + cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod); } @@ -4783,6 +4951,9 @@ Decl *Sema::ActOnMethodDeclaration( } } + // Insert the invisible arguments, self and _cmd! + ObjCMethod->createImplicitParams(Context, ObjCMethod->getClassInterface()); + ActOnDocumentableDecl(ObjCMethod); return ObjCMethod; @@ -5063,6 +5234,9 @@ void Sema::DiagnoseUnusedBackingIvarInAccessor(Scope *S, if (!IV) continue; + if (CurMethod->isSynthesizedAccessorStub()) + continue; + UnusedBackingIvarChecker Checker(*this, CurMethod, IV); Checker.TraverseStmt(CurMethod->getBody()); if (Checker.AccessedIvar) diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index c1abf099e9f2..5aedbe7644e4 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -15,6 +15,7 @@ #include "clang/AST/CXXInheritance.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/StmtObjC.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" @@ -80,8 +81,16 @@ ExprResult Sema::ActOnNoexceptSpec(SourceLocation NoexceptLoc, ExceptionSpecificationType &EST) { // FIXME: This is bogus, a noexcept expression is not a condition. ExprResult Converted = CheckBooleanCondition(NoexceptLoc, NoexceptExpr); - if (Converted.isInvalid()) - return Converted; + if (Converted.isInvalid()) { + EST = EST_NoexceptFalse; + + // Fill in an expression of 'false' as a fixup. + auto *BoolExpr = new (Context) + CXXBoolLiteralExpr(false, Context.BoolTy, NoexceptExpr->getBeginLoc()); + llvm::APSInt Value{1}; + Value = 0; + return ConstantExpr::Create(Context, BoolExpr, APValue{Value}); + } if (Converted.get()->isValueDependent()) { EST = EST_DependentNoexcept; @@ -204,7 +213,7 @@ Sema::ResolveExceptionSpec(SourceLocation Loc, const FunctionProtoType *FPT) { // Compute or instantiate the exception specification now. if (SourceFPT->getExceptionSpecType() == EST_Unevaluated) - EvaluateImplicitExceptionSpec(Loc, cast<CXXMethodDecl>(SourceDecl)); + EvaluateImplicitExceptionSpec(Loc, SourceDecl); else InstantiateExceptionSpec(Loc, SourceDecl); @@ -970,17 +979,22 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, New->getLocation()); } -static CanThrowResult canSubExprsThrow(Sema &S, const Expr *E) { +static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) { CanThrowResult R = CT_Cannot; - for (const Stmt *SubStmt : E->children()) { - R = mergeCanThrow(R, S.canThrow(cast<Expr>(SubStmt))); + for (const Stmt *SubStmt : S->children()) { + if (!SubStmt) + continue; + R = mergeCanThrow(R, Self.canThrow(SubStmt)); if (R == CT_Can) break; } return R; } -static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) { +/// Determine whether the callee of a particular function call can throw. +/// E and D are both optional, but at least one of E and Loc must be specified. +static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D, + SourceLocation Loc = SourceLocation()) { // As an extension, we assume that __attribute__((nothrow)) functions don't // throw. if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) @@ -989,7 +1003,7 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) { QualType T; // In C++1z, just look at the function type of the callee. - if (S.getLangOpts().CPlusPlus17 && isa<CallExpr>(E)) { + if (S.getLangOpts().CPlusPlus17 && E && isa<CallExpr>(E)) { E = cast<CallExpr>(E)->getCallee(); T = E->getType(); if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) { @@ -1026,13 +1040,41 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) { if (!FT) return CT_Can; - FT = S.ResolveExceptionSpec(E->getBeginLoc(), FT); + FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT); if (!FT) return CT_Can; return FT->canThrow(); } +static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) { + CanThrowResult CT = CT_Cannot; + + // Initialization might throw. + if (!VD->isUsableInConstantExpressions(Self.Context)) + if (const Expr *Init = VD->getInit()) + CT = mergeCanThrow(CT, Self.canThrow(Init)); + + // Destructor might throw. + if (VD->needsDestruction(Self.Context) == QualType::DK_cxx_destructor) { + if (auto *RD = + VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) { + if (auto *Dtor = RD->getDestructor()) { + CT = mergeCanThrow( + CT, canCalleeThrow(Self, nullptr, Dtor, VD->getLocation())); + } + } + } + + // If this is a decomposition declaration, bindings might throw. + if (auto *DD = dyn_cast<DecompositionDecl>(VD)) + for (auto *B : DD->bindings()) + if (auto *HD = B->getHoldingVar()) + CT = mergeCanThrow(CT, canVarDeclThrow(Self, HD)); + + return CT; +} + static CanThrowResult canDynamicCastThrow(const CXXDynamicCastExpr *DC) { if (DC->isTypeDependent()) return CT_Dependent; @@ -1067,13 +1109,13 @@ static CanThrowResult canTypeidThrow(Sema &S, const CXXTypeidExpr *DC) { return CT_Can; } -CanThrowResult Sema::canThrow(const Expr *E) { +CanThrowResult Sema::canThrow(const Stmt *S) { // C++ [expr.unary.noexcept]p3: // [Can throw] if in a potentially-evaluated context the expression would // contain: - switch (E->getStmtClass()) { + switch (S->getStmtClass()) { case Expr::ConstantExprClass: - return canThrow(cast<ConstantExpr>(E)->getSubExpr()); + return canThrow(cast<ConstantExpr>(S)->getSubExpr()); case Expr::CXXThrowExprClass: // - a potentially evaluated throw-expression @@ -1082,16 +1124,20 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::CXXDynamicCastExprClass: { // - a potentially evaluated dynamic_cast expression dynamic_cast<T>(v), // where T is a reference type, that requires a run-time check - CanThrowResult CT = canDynamicCastThrow(cast<CXXDynamicCastExpr>(E)); + auto *CE = cast<CXXDynamicCastExpr>(S); + // FIXME: Properly determine whether a variably-modified type can throw. + if (CE->getType()->isVariablyModifiedType()) + return CT_Can; + CanThrowResult CT = canDynamicCastThrow(CE); if (CT == CT_Can) return CT; - return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); } case Expr::CXXTypeidExprClass: // - a potentially evaluated typeid expression applied to a glvalue // expression whose type is a polymorphic class type - return canTypeidThrow(*this, cast<CXXTypeidExpr>(E)); + return canTypeidThrow(*this, cast<CXXTypeidExpr>(S)); // - a potentially evaluated call to a function, member function, function // pointer, or member function pointer that does not have a non-throwing @@ -1100,34 +1146,38 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::CXXMemberCallExprClass: case Expr::CXXOperatorCallExprClass: case Expr::UserDefinedLiteralClass: { - const CallExpr *CE = cast<CallExpr>(E); + const CallExpr *CE = cast<CallExpr>(S); CanThrowResult CT; - if (E->isTypeDependent()) + if (CE->isTypeDependent()) CT = CT_Dependent; else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) CT = CT_Cannot; else - CT = canCalleeThrow(*this, E, CE->getCalleeDecl()); + CT = canCalleeThrow(*this, CE, CE->getCalleeDecl()); if (CT == CT_Can) return CT; - return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); } case Expr::CXXConstructExprClass: case Expr::CXXTemporaryObjectExprClass: { - CanThrowResult CT = canCalleeThrow(*this, E, - cast<CXXConstructExpr>(E)->getConstructor()); + auto *CE = cast<CXXConstructExpr>(S); + // FIXME: Properly determine whether a variably-modified type can throw. + if (CE->getType()->isVariablyModifiedType()) + return CT_Can; + CanThrowResult CT = canCalleeThrow(*this, CE, CE->getConstructor()); if (CT == CT_Can) return CT; - return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + return mergeCanThrow(CT, canSubStmtsThrow(*this, CE)); } - case Expr::CXXInheritedCtorInitExprClass: - return canCalleeThrow(*this, E, - cast<CXXInheritedCtorInitExpr>(E)->getConstructor()); + case Expr::CXXInheritedCtorInitExprClass: { + auto *ICIE = cast<CXXInheritedCtorInitExpr>(S); + return canCalleeThrow(*this, ICIE, ICIE->getConstructor()); + } case Expr::LambdaExprClass: { - const LambdaExpr *Lambda = cast<LambdaExpr>(E); + const LambdaExpr *Lambda = cast<LambdaExpr>(S); CanThrowResult CT = CT_Cannot; for (LambdaExpr::const_capture_init_iterator Cap = Lambda->capture_init_begin(), @@ -1138,43 +1188,56 @@ CanThrowResult Sema::canThrow(const Expr *E) { } case Expr::CXXNewExprClass: { + auto *NE = cast<CXXNewExpr>(S); CanThrowResult CT; - if (E->isTypeDependent()) + if (NE->isTypeDependent()) CT = CT_Dependent; else - CT = canCalleeThrow(*this, E, cast<CXXNewExpr>(E)->getOperatorNew()); + CT = canCalleeThrow(*this, NE, NE->getOperatorNew()); if (CT == CT_Can) return CT; - return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + return mergeCanThrow(CT, canSubStmtsThrow(*this, NE)); } case Expr::CXXDeleteExprClass: { + auto *DE = cast<CXXDeleteExpr>(S); CanThrowResult CT; - QualType DTy = cast<CXXDeleteExpr>(E)->getDestroyedType(); + QualType DTy = DE->getDestroyedType(); if (DTy.isNull() || DTy->isDependentType()) { CT = CT_Dependent; } else { - CT = canCalleeThrow(*this, E, - cast<CXXDeleteExpr>(E)->getOperatorDelete()); + CT = canCalleeThrow(*this, DE, DE->getOperatorDelete()); if (const RecordType *RT = DTy->getAs<RecordType>()) { const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); const CXXDestructorDecl *DD = RD->getDestructor(); if (DD) - CT = mergeCanThrow(CT, canCalleeThrow(*this, E, DD)); + CT = mergeCanThrow(CT, canCalleeThrow(*this, DE, DD)); } if (CT == CT_Can) return CT; } - return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + return mergeCanThrow(CT, canSubStmtsThrow(*this, DE)); } case Expr::CXXBindTemporaryExprClass: { + auto *BTE = cast<CXXBindTemporaryExpr>(S); // The bound temporary has to be destroyed again, which might throw. - CanThrowResult CT = canCalleeThrow(*this, E, - cast<CXXBindTemporaryExpr>(E)->getTemporary()->getDestructor()); + CanThrowResult CT = + canCalleeThrow(*this, BTE, BTE->getTemporary()->getDestructor()); if (CT == CT_Can) return CT; - return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + return mergeCanThrow(CT, canSubStmtsThrow(*this, BTE)); + } + + case Expr::PseudoObjectExprClass: { + auto *POE = cast<PseudoObjectExpr>(S); + CanThrowResult CT = CT_Cannot; + for (const Expr *E : POE->semantics()) { + CT = mergeCanThrow(CT, canThrow(E)); + if (CT == CT_Can) + break; + } + return CT; } // ObjC message sends are like function calls, but never have exception @@ -1196,12 +1259,8 @@ CanThrowResult Sema::canThrow(const Expr *E) { // Some are simple: case Expr::CoawaitExprClass: case Expr::ConditionalOperatorClass: - case Expr::CompoundLiteralExprClass: case Expr::CoyieldExprClass: - case Expr::CXXConstCastExprClass: - case Expr::CXXReinterpretCastExprClass: case Expr::CXXRewrittenBinaryOperatorClass: - case Expr::BuiltinBitCastExprClass: case Expr::CXXStdInitializerListExprClass: case Expr::DesignatedInitExprClass: case Expr::DesignatedInitUpdateExprClass: @@ -1215,9 +1274,19 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ParenExprClass: case Expr::ParenListExprClass: case Expr::ShuffleVectorExprClass: + case Expr::StmtExprClass: case Expr::ConvertVectorExprClass: case Expr::VAArgExprClass: - return canSubExprsThrow(*this, E); + return canSubStmtsThrow(*this, S); + + case Expr::CompoundLiteralExprClass: + case Expr::CXXConstCastExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::BuiltinBitCastExprClass: + // FIXME: Properly determine whether a variably-modified type can throw. + if (cast<Expr>(S)->getType()->isVariablyModifiedType()) + return CT_Can; + return canSubStmtsThrow(*this, S); // Some might be dependent for other reasons. case Expr::ArraySubscriptExprClass: @@ -1231,29 +1300,32 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ImplicitCastExprClass: case Expr::MaterializeTemporaryExprClass: case Expr::UnaryOperatorClass: { - CanThrowResult CT = E->isTypeDependent() ? CT_Dependent : CT_Cannot; - return mergeCanThrow(CT, canSubExprsThrow(*this, E)); + // FIXME: Properly determine whether a variably-modified type can throw. + if (auto *CE = dyn_cast<CastExpr>(S)) + if (CE->getType()->isVariablyModifiedType()) + return CT_Can; + CanThrowResult CT = + cast<Expr>(S)->isTypeDependent() ? CT_Dependent : CT_Cannot; + return mergeCanThrow(CT, canSubStmtsThrow(*this, S)); } - // FIXME: We should handle StmtExpr, but that opens a MASSIVE can of worms. - case Expr::StmtExprClass: - return CT_Can; - case Expr::CXXDefaultArgExprClass: - return canThrow(cast<CXXDefaultArgExpr>(E)->getExpr()); + return canThrow(cast<CXXDefaultArgExpr>(S)->getExpr()); case Expr::CXXDefaultInitExprClass: - return canThrow(cast<CXXDefaultInitExpr>(E)->getExpr()); + return canThrow(cast<CXXDefaultInitExpr>(S)->getExpr()); - case Expr::ChooseExprClass: - if (E->isTypeDependent() || E->isValueDependent()) + case Expr::ChooseExprClass: { + auto *CE = cast<ChooseExpr>(S); + if (CE->isTypeDependent() || CE->isValueDependent()) return CT_Dependent; - return canThrow(cast<ChooseExpr>(E)->getChosenSubExpr()); + return canThrow(CE->getChosenSubExpr()); + } case Expr::GenericSelectionExprClass: - if (cast<GenericSelectionExpr>(E)->isResultDependent()) + if (cast<GenericSelectionExpr>(S)->isResultDependent()) return CT_Dependent; - return canThrow(cast<GenericSelectionExpr>(E)->getResultExpr()); + return canThrow(cast<GenericSelectionExpr>(S)->getResultExpr()); // Some expressions are always dependent. case Expr::CXXDependentScopeMemberExprClass: @@ -1274,7 +1346,6 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ObjCAvailabilityCheckExprClass: case Expr::OffsetOfExprClass: case Expr::PackExpansionExprClass: - case Expr::PseudoObjectExprClass: case Expr::SubstNonTypeTemplateParmExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: case Expr::FunctionParmPackExprClass: @@ -1282,7 +1353,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: case Expr::TypoExprClass: - // FIXME: Can any of the above throw? If so, when? + // FIXME: Many of the above can throw. return CT_Cannot; case Expr::AddrLabelExprClass: @@ -1322,14 +1393,170 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::MSPropertySubscriptExprClass: llvm_unreachable("Invalid class for expression"); -#define STMT(CLASS, PARENT) case Expr::CLASS##Class: -#define STMT_RANGE(Base, First, Last) -#define LAST_STMT_RANGE(BASE, FIRST, LAST) -#define EXPR(CLASS, PARENT) -#define ABSTRACT_STMT(STMT) -#include "clang/AST/StmtNodes.inc" - case Expr::NoStmtClass: - llvm_unreachable("Invalid class for expression"); + // Most statements can throw if any substatement can throw. + case Stmt::AttributedStmtClass: + case Stmt::BreakStmtClass: + case Stmt::CapturedStmtClass: + case Stmt::CaseStmtClass: + case Stmt::CompoundStmtClass: + case Stmt::ContinueStmtClass: + case Stmt::CoreturnStmtClass: + case Stmt::CoroutineBodyStmtClass: + case Stmt::CXXCatchStmtClass: + case Stmt::CXXForRangeStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::DoStmtClass: + case Stmt::ForStmtClass: + case Stmt::GCCAsmStmtClass: + case Stmt::GotoStmtClass: + case Stmt::IndirectGotoStmtClass: + case Stmt::LabelStmtClass: + case Stmt::MSAsmStmtClass: + case Stmt::MSDependentExistsStmtClass: + case Stmt::NullStmtClass: + case Stmt::ObjCAtCatchStmtClass: + case Stmt::ObjCAtFinallyStmtClass: + case Stmt::ObjCAtSynchronizedStmtClass: + case Stmt::ObjCAutoreleasePoolStmtClass: + case Stmt::ObjCForCollectionStmtClass: + case Stmt::OMPAtomicDirectiveClass: + case Stmt::OMPBarrierDirectiveClass: + case Stmt::OMPCancelDirectiveClass: + case Stmt::OMPCancellationPointDirectiveClass: + case Stmt::OMPCriticalDirectiveClass: + case Stmt::OMPDistributeDirectiveClass: + case Stmt::OMPDistributeParallelForDirectiveClass: + case Stmt::OMPDistributeParallelForSimdDirectiveClass: + case Stmt::OMPDistributeSimdDirectiveClass: + case Stmt::OMPFlushDirectiveClass: + case Stmt::OMPForDirectiveClass: + case Stmt::OMPForSimdDirectiveClass: + case Stmt::OMPMasterDirectiveClass: + case Stmt::OMPMasterTaskLoopDirectiveClass: + case Stmt::OMPMasterTaskLoopSimdDirectiveClass: + case Stmt::OMPOrderedDirectiveClass: + case Stmt::OMPParallelDirectiveClass: + case Stmt::OMPParallelForDirectiveClass: + case Stmt::OMPParallelForSimdDirectiveClass: + case Stmt::OMPParallelMasterDirectiveClass: + case Stmt::OMPParallelMasterTaskLoopDirectiveClass: + case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass: + case Stmt::OMPParallelSectionsDirectiveClass: + case Stmt::OMPSectionDirectiveClass: + case Stmt::OMPSectionsDirectiveClass: + case Stmt::OMPSimdDirectiveClass: + case Stmt::OMPSingleDirectiveClass: + case Stmt::OMPTargetDataDirectiveClass: + case Stmt::OMPTargetDirectiveClass: + case Stmt::OMPTargetEnterDataDirectiveClass: + case Stmt::OMPTargetExitDataDirectiveClass: + case Stmt::OMPTargetParallelDirectiveClass: + case Stmt::OMPTargetParallelForDirectiveClass: + case Stmt::OMPTargetParallelForSimdDirectiveClass: + case Stmt::OMPTargetSimdDirectiveClass: + case Stmt::OMPTargetTeamsDirectiveClass: + case Stmt::OMPTargetTeamsDistributeDirectiveClass: + case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass: + case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass: + case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass: + case Stmt::OMPTargetUpdateDirectiveClass: + case Stmt::OMPTaskDirectiveClass: + case Stmt::OMPTaskgroupDirectiveClass: + case Stmt::OMPTaskLoopDirectiveClass: + case Stmt::OMPTaskLoopSimdDirectiveClass: + case Stmt::OMPTaskwaitDirectiveClass: + case Stmt::OMPTaskyieldDirectiveClass: + case Stmt::OMPTeamsDirectiveClass: + case Stmt::OMPTeamsDistributeDirectiveClass: + case Stmt::OMPTeamsDistributeParallelForDirectiveClass: + case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass: + case Stmt::OMPTeamsDistributeSimdDirectiveClass: + case Stmt::ReturnStmtClass: + case Stmt::SEHExceptStmtClass: + case Stmt::SEHFinallyStmtClass: + case Stmt::SEHLeaveStmtClass: + case Stmt::SEHTryStmtClass: + case Stmt::SwitchStmtClass: + case Stmt::WhileStmtClass: + return canSubStmtsThrow(*this, S); + + case Stmt::DeclStmtClass: { + CanThrowResult CT = CT_Cannot; + for (const Decl *D : cast<DeclStmt>(S)->decls()) { + if (auto *VD = dyn_cast<VarDecl>(D)) + CT = mergeCanThrow(CT, canVarDeclThrow(*this, VD)); + + // FIXME: Properly determine whether a variably-modified type can throw. + if (auto *TND = dyn_cast<TypedefNameDecl>(D)) + if (TND->getUnderlyingType()->isVariablyModifiedType()) + return CT_Can; + if (auto *VD = dyn_cast<ValueDecl>(D)) + if (VD->getType()->isVariablyModifiedType()) + return CT_Can; + } + return CT; + } + + case Stmt::IfStmtClass: { + auto *IS = cast<IfStmt>(S); + CanThrowResult CT = CT_Cannot; + if (const Stmt *Init = IS->getInit()) + CT = mergeCanThrow(CT, canThrow(Init)); + if (const Stmt *CondDS = IS->getConditionVariableDeclStmt()) + CT = mergeCanThrow(CT, canThrow(CondDS)); + CT = mergeCanThrow(CT, canThrow(IS->getCond())); + + // For 'if constexpr', consider only the non-discarded case. + // FIXME: We should add a DiscardedStmt marker to the AST. + if (Optional<const Stmt *> Case = IS->getNondiscardedCase(Context)) + return *Case ? mergeCanThrow(CT, canThrow(*Case)) : CT; + + CanThrowResult Then = canThrow(IS->getThen()); + CanThrowResult Else = IS->getElse() ? canThrow(IS->getElse()) : CT_Cannot; + if (Then == Else) + return mergeCanThrow(CT, Then); + + // For a dependent 'if constexpr', the result is dependent if it depends on + // the value of the condition. + return mergeCanThrow(CT, IS->isConstexpr() ? CT_Dependent + : mergeCanThrow(Then, Else)); + } + + case Stmt::CXXTryStmtClass: { + auto *TS = cast<CXXTryStmt>(S); + // try /*...*/ catch (...) { H } can throw only if H can throw. + // Any other try-catch can throw if any substatement can throw. + const CXXCatchStmt *FinalHandler = TS->getHandler(TS->getNumHandlers() - 1); + if (!FinalHandler->getExceptionDecl()) + return canThrow(FinalHandler->getHandlerBlock()); + return canSubStmtsThrow(*this, S); + } + + case Stmt::ObjCAtThrowStmtClass: + return CT_Can; + + case Stmt::ObjCAtTryStmtClass: { + auto *TS = cast<ObjCAtTryStmt>(S); + + // @catch(...) need not be last in Objective-C. Walk backwards until we + // see one or hit the @try. + CanThrowResult CT = CT_Cannot; + if (const Stmt *Finally = TS->getFinallyStmt()) + CT = mergeCanThrow(CT, canThrow(Finally)); + for (unsigned I = TS->getNumCatchStmts(); I != 0; --I) { + const ObjCAtCatchStmt *Catch = TS->getCatchStmt(I - 1); + CT = mergeCanThrow(CT, canThrow(Catch)); + // If we reach a @catch(...), no earlier exceptions can escape. + if (Catch->hasEllipsis()) + return CT; + } + + // Didn't find an @catch(...). Exceptions from the @try body can escape. + return mergeCanThrow(CT, canThrow(TS->getTryBody())); + } + + case Stmt::NoStmtClass: + llvm_unreachable("Invalid class for statement"); } llvm_unreachable("Bogus StmtClass"); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e41cd5b6653a..5f4071924d3f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -25,6 +25,7 @@ #include "clang/AST/ExprOpenMP.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/FixedPoint.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceManager.h" @@ -97,21 +98,16 @@ static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { /// Emit a note explaining that this function is deleted. void Sema::NoteDeletedFunction(FunctionDecl *Decl) { - assert(Decl->isDeleted()); + assert(Decl && Decl->isDeleted()); - CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Decl); - - if (Method && Method->isDeleted() && Method->isDefaulted()) { + if (Decl->isDefaulted()) { // If the method was explicitly defaulted, point at that declaration. - if (!Method->isImplicit()) + if (!Decl->isImplicit()) Diag(Decl->getLocation(), diag::note_implicitly_deleted); // Try to diagnose why this special member function was implicitly // deleted. This might fail, if that reason no longer applies. - CXXSpecialMember CSM = getSpecialMember(Method); - if (CSM != CXXInvalid) - ShouldDeleteSpecialMember(Method, CSM, nullptr, /*Diagnose=*/true); - + DiagnoseDeletedDefaultedFunction(Decl); return; } @@ -330,6 +326,30 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc); + // [expr.prim.id]p4 + // A program that refers explicitly or implicitly to a function with a + // trailing requires-clause whose constraint-expression is not satisfied, + // other than to declare it, is ill-formed. [...] + // + // See if this is a function with constraints that need to be satisfied. + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (Expr *RC = FD->getTrailingRequiresClause()) { + ConstraintSatisfaction Satisfaction; + bool Failed = CheckConstraintSatisfaction(RC, Satisfaction); + if (Failed) + // A diagnostic will have already been generated (non-constant + // constraint expression, for example) + return true; + if (!Satisfaction.IsSatisfied) { + Diag(Loc, + diag::err_reference_to_function_with_unsatisfied_constraints) + << D; + DiagnoseUnsatisfiedConstraint(Satisfaction); + return true; + } + } + } + return false; } @@ -481,16 +501,22 @@ static void CheckForNullPointerDereference(Sema &S, Expr *E) { // optimizer will delete, so warn about it. People sometimes try to use this // to get a deterministic trap and are surprised by clang's behavior. This // only handles the pattern "*null", which is a very syntactic check. - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts())) - if (UO->getOpcode() == UO_Deref && - UO->getSubExpr()->IgnoreParenCasts()-> - isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull) && + const auto *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts()); + if (UO && UO->getOpcode() == UO_Deref && + UO->getSubExpr()->getType()->isPointerType()) { + const LangAS AS = + UO->getSubExpr()->getType()->getPointeeType().getAddressSpace(); + if ((!isTargetAddressSpace(AS) || + (isTargetAddressSpace(AS) && toTargetAddressSpace(AS) == 0)) && + UO->getSubExpr()->IgnoreParenCasts()->isNullPointerConstant( + S.Context, Expr::NPC_ValueDependentIsNotNull) && !UO->getType().isVolatileQualified()) { - S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, - S.PDiag(diag::warn_indirection_through_null) - << UO->getSubExpr()->getSourceRange()); - S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, - S.PDiag(diag::note_indirection_through_null)); + S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, + S.PDiag(diag::warn_indirection_through_null) + << UO->getSubExpr()->getSourceRange()); + S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, + S.PDiag(diag::note_indirection_through_null)); + } } } @@ -1331,13 +1357,72 @@ static QualType handleFixedPointConversion(Sema &S, QualType LHSTy, return ResultTy; } +/// Check that the usual arithmetic conversions can be performed on this pair of +/// expressions that might be of enumeration type. +static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS, + SourceLocation Loc, + Sema::ArithConvKind ACK) { + // C++2a [expr.arith.conv]p1: + // If one operand is of enumeration type and the other operand is of a + // different enumeration type or a floating-point type, this behavior is + // deprecated ([depr.arith.conv.enum]). + // + // Warn on this in all language modes. Produce a deprecation warning in C++20. + // Eventually we will presumably reject these cases (in C++23 onwards?). + QualType L = LHS->getType(), R = RHS->getType(); + bool LEnum = L->isUnscopedEnumerationType(), + REnum = R->isUnscopedEnumerationType(); + bool IsCompAssign = ACK == Sema::ACK_CompAssign; + if ((!IsCompAssign && LEnum && R->isFloatingType()) || + (REnum && L->isFloatingType())) { + S.Diag(Loc, S.getLangOpts().CPlusPlus2a + ? diag::warn_arith_conv_enum_float_cxx2a + : diag::warn_arith_conv_enum_float) + << LHS->getSourceRange() << RHS->getSourceRange() + << (int)ACK << LEnum << L << R; + } else if (!IsCompAssign && LEnum && REnum && + !S.Context.hasSameUnqualifiedType(L, R)) { + unsigned DiagID; + if (!L->castAs<EnumType>()->getDecl()->hasNameForLinkage() || + !R->castAs<EnumType>()->getDecl()->hasNameForLinkage()) { + // If either enumeration type is unnamed, it's less likely that the + // user cares about this, but this situation is still deprecated in + // C++2a. Use a different warning group. + DiagID = S.getLangOpts().CPlusPlus2a + ? diag::warn_arith_conv_mixed_anon_enum_types_cxx2a + : diag::warn_arith_conv_mixed_anon_enum_types; + } else if (ACK == Sema::ACK_Conditional) { + // Conditional expressions are separated out because they have + // historically had a different warning flag. + DiagID = S.getLangOpts().CPlusPlus2a + ? diag::warn_conditional_mixed_enum_types_cxx2a + : diag::warn_conditional_mixed_enum_types; + } else if (ACK == Sema::ACK_Comparison) { + // Comparison expressions are separated out because they have + // historically had a different warning flag. + DiagID = S.getLangOpts().CPlusPlus2a + ? diag::warn_comparison_mixed_enum_types_cxx2a + : diag::warn_comparison_mixed_enum_types; + } else { + DiagID = S.getLangOpts().CPlusPlus2a + ? diag::warn_arith_conv_mixed_enum_types_cxx2a + : diag::warn_arith_conv_mixed_enum_types; + } + S.Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange() + << (int)ACK << L << R; + } +} + /// UsualArithmeticConversions - Performs various conversions that are common to /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this /// routine returns the first non-arithmetic type found. The client is /// responsible for emitting appropriate error diagnostics. QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, - bool IsCompAssign) { - if (!IsCompAssign) { + SourceLocation Loc, + ArithConvKind ACK) { + checkEnumArithmeticConversions(*this, LHS.get(), RHS.get(), Loc, ACK); + + if (ACK != ACK_CompAssign) { LHS = UsualUnaryConversions(LHS.get()); if (LHS.isInvalid()) return QualType(); @@ -1374,7 +1459,7 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(LHS.get()); if (!LHSBitfieldPromoteTy.isNull()) LHSType = LHSBitfieldPromoteTy; - if (LHSType != LHSUnpromotedType && !IsCompAssign) + if (LHSType != LHSUnpromotedType && ACK != ACK_CompAssign) LHS = ImpCastExprToType(LHS.get(), LHSType, CK_IntegralCast); // If both types are identical, no conversion is needed. @@ -1391,24 +1476,24 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, // Handle complex types first (C99 6.3.1.8p1). if (LHSType->isComplexType() || RHSType->isComplexType()) return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType, - IsCompAssign); + ACK == ACK_CompAssign); // Now handle "real" floating types (i.e. float, double, long double). if (LHSType->isRealFloatingType() || RHSType->isRealFloatingType()) return handleFloatConversion(*this, LHS, RHS, LHSType, RHSType, - IsCompAssign); + ACK == ACK_CompAssign); // Handle GCC complex int extension. if (LHSType->isComplexIntegerType() || RHSType->isComplexIntegerType()) return handleComplexIntConversion(*this, LHS, RHS, LHSType, RHSType, - IsCompAssign); + ACK == ACK_CompAssign); if (LHSType->isFixedPointType() || RHSType->isFixedPointType()) return handleFixedPointConversion(*this, LHSType, RHSType); // Finally, we have two differing integer types. return handleIntegerConversion<doIntegralCast, doIntegralCast> - (*this, LHS, RHS, LHSType, RHSType, IsCompAssign); + (*this, LHS, RHS, LHSType, RHSType, ACK == ACK_CompAssign); } //===----------------------------------------------------------------------===// @@ -1825,6 +1910,25 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, VK, FoundD, TemplateArgs, getNonOdrUseReasonInCurrentContext(D)); MarkDeclRefReferenced(E); + // C++ [except.spec]p17: + // An exception-specification is considered to be needed when: + // - in an expression, the function is the unique lookup result or + // the selected member of a set of overloaded functions. + // + // We delay doing this until after we've built the function reference and + // marked it as used so that: + // a) if the function is defaulted, we get errors from defining it before / + // instead of errors from computing its exception specification, and + // b) if the function is a defaulted comparison, we can use the body we + // build when defining it as input to the exception specification + // computation rather than computing a new body. + if (auto *FPT = Ty->getAs<FunctionProtoType>()) { + if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) { + if (auto *NewFPT = ResolveExceptionSpec(NameInfo.getLoc(), FPT)) + E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers())); + } + } + if (getLangOpts().ObjCWeak && isa<VarDecl>(D) && Ty.getObjCLifetime() == Qualifiers::OCL_Weak && !isUnevaluatedContext() && !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getBeginLoc())) @@ -2704,6 +2808,20 @@ Sema::PerformObjectMemberConversion(Expr *From, FromRecordType = FromType; DestType = DestRecordType; } + + LangAS FromAS = FromRecordType.getAddressSpace(); + LangAS DestAS = DestRecordType.getAddressSpace(); + if (FromAS != DestAS) { + QualType FromRecordTypeWithoutAS = + Context.removeAddrSpaceQualType(FromRecordType); + QualType FromTypeWithDestAS = + Context.getAddrSpaceQualType(FromRecordTypeWithoutAS, DestAS); + if (PointerConversions) + FromTypeWithDestAS = Context.getPointerType(FromTypeWithDestAS); + From = ImpCastExprToType(From, FromTypeWithDestAS, + CK_AddressSpaceConversion, From->getValueKind()) + .get(); + } } else { // No conversion necessary. return From; @@ -2993,14 +3111,6 @@ ExprResult Sema::BuildDeclarationNameExpr( QualType type = VD->getType(); if (type.isNull()) return ExprError(); - if (auto *FPT = type->getAs<FunctionProtoType>()) { - // C++ [except.spec]p17: - // An exception-specification is considered to be needed when: - // - in an expression, the function is the unique lookup result or - // the selected member of a set of overloaded functions. - ResolveExceptionSpec(Loc, FPT); - type = VD->getType(); - } ExprValueKind valueKind = VK_RValue; switch (D->getKind()) { @@ -5231,6 +5341,9 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, for (Expr *A : Args.slice(ArgIx)) { ExprResult Arg = DefaultVariadicArgumentPromotion(A, CallType, FDecl); Invalid |= Arg.isInvalid(); + // Copy blocks to the heap. + if (A->getType()->isBlockPointerType()) + maybeExtendBlockObject(Arg); AllArgs.push_back(Arg.get()); } } @@ -5424,15 +5537,15 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, Expr *Arg = ArgRes.get(); QualType ArgType = Arg->getType(); if (!ParamType->isPointerType() || - ParamType.getQualifiers().hasAddressSpace() || + ParamType.hasAddressSpace() || !ArgType->isPointerType() || - !ArgType->getPointeeType().getQualifiers().hasAddressSpace()) { + !ArgType->getPointeeType().hasAddressSpace()) { OverloadParams.push_back(ParamType); continue; } QualType PointeeType = ParamType->getPointeeType(); - if (PointeeType.getQualifiers().hasAddressSpace()) + if (PointeeType.hasAddressSpace()) continue; NeedsNewDecl = true; @@ -7363,7 +7476,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, /*AllowBothBool*/true, /*AllowBoolConversions*/false); - QualType ResTy = UsualArithmeticConversions(LHS, RHS); + QualType ResTy = + UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); @@ -7639,7 +7753,7 @@ static bool IsArithmeticBinaryExpr(Expr *E, BinaryOperatorKind *Opcode, E = E->IgnoreConversionOperator(); E = E->IgnoreImpCasts(); if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) { - E = MTE->GetTemporaryExpr(); + E = MTE->getSubExpr(); E = E->IgnoreImpCasts(); } @@ -8695,7 +8809,7 @@ namespace { struct OriginalOperand { explicit OriginalOperand(Expr *Op) : Orig(Op), Conversion(nullptr) { if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Op)) - Op = MTE->GetTemporaryExpr(); + Op = MTE->getSubExpr(); if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Op)) Op = BTE->getSubExpr(); if (auto *ICE = dyn_cast<ImplicitCastExpr>(Op)) { @@ -8957,6 +9071,12 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, return true; ScalarCast = CK_IntegralCast; + } else if (VectorEltTy->isIntegralType(S.Context) && + ScalarTy->isRealFloatingType()) { + if (S.Context.getTypeSize(VectorEltTy) == S.Context.getTypeSize(ScalarTy)) + ScalarCast = CK_FloatingToIntegral; + else + return true; } else if (VectorEltTy->isRealFloatingType()) { if (ScalarTy->isRealFloatingType()) { @@ -9276,7 +9396,8 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS, /*AllowBothBool*/getLangOpts().AltiVec, /*AllowBoolConversions*/false); - QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign); + QualType compType = UsualArithmeticConversions( + LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); @@ -9304,7 +9425,8 @@ QualType Sema::CheckRemainderOperands( return InvalidOperands(Loc, LHS, RHS); } - QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign); + QualType compType = UsualArithmeticConversions( + LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); @@ -9593,7 +9715,8 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, return compType; } - QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy); + QualType compType = UsualArithmeticConversions( + LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); @@ -9687,7 +9810,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, return compType; } - QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy); + QualType compType = UsualArithmeticConversions( + LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); @@ -10018,35 +10142,6 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, return LHSType; } -/// If two different enums are compared, raise a warning. -static void checkEnumComparison(Sema &S, SourceLocation Loc, Expr *LHS, - Expr *RHS) { - QualType LHSStrippedType = LHS->IgnoreParenImpCasts()->getType(); - QualType RHSStrippedType = RHS->IgnoreParenImpCasts()->getType(); - - const EnumType *LHSEnumType = LHSStrippedType->getAs<EnumType>(); - if (!LHSEnumType) - return; - const EnumType *RHSEnumType = RHSStrippedType->getAs<EnumType>(); - if (!RHSEnumType) - return; - - // Ignore anonymous enums. - if (!LHSEnumType->getDecl()->getIdentifier() && - !LHSEnumType->getDecl()->getTypedefNameForAnonDecl()) - return; - if (!RHSEnumType->getDecl()->getIdentifier() && - !RHSEnumType->getDecl()->getTypedefNameForAnonDecl()) - return; - - if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType)) - return; - - S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types) - << LHSStrippedType << RHSStrippedType - << LHS->getSourceRange() << RHS->getSourceRange(); -} - /// Diagnose bad pointer comparisons. static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc, ExprResult &LHS, ExprResult &RHS, @@ -10085,8 +10180,6 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc, return true; } - LHS = S.ImpCastExprToType(LHS.get(), T, CK_BitCast); - RHS = S.ImpCastExprToType(RHS.get(), T, CK_BitCast); return false; } @@ -10317,7 +10410,6 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, QualType RHSType = RHS->getType(); if (LHSType->hasFloatingRepresentation() || (LHSType->isBlockPointerType() && !BinaryOperator::isEqualityOp(Opc)) || - LHS->getBeginLoc().isMacroID() || RHS->getBeginLoc().isMacroID() || S.inTemplateInstantiation()) return; @@ -10345,45 +10437,64 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, AlwaysEqual, // std::strong_ordering::equal from operator<=> }; - if (Expr::isSameComparisonOperand(LHS, RHS)) { - unsigned Result; - switch (Opc) { - case BO_EQ: case BO_LE: case BO_GE: - Result = AlwaysTrue; - break; - case BO_NE: case BO_LT: case BO_GT: - Result = AlwaysFalse; - break; - case BO_Cmp: - Result = AlwaysEqual; - break; - default: - Result = AlwaysConstant; - break; - } - S.DiagRuntimeBehavior(Loc, nullptr, - S.PDiag(diag::warn_comparison_always) - << 0 /*self-comparison*/ - << Result); - } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) { - // What is it always going to evaluate to? - unsigned Result; - switch(Opc) { - case BO_EQ: // e.g. array1 == array2 - Result = AlwaysFalse; - break; - case BO_NE: // e.g. array1 != array2 - Result = AlwaysTrue; - break; - default: // e.g. array1 <= array2 - // The best we can say is 'a constant' - Result = AlwaysConstant; - break; + // C++2a [depr.array.comp]: + // Equality and relational comparisons ([expr.eq], [expr.rel]) between two + // operands of array type are deprecated. + if (S.getLangOpts().CPlusPlus2a && LHSStripped->getType()->isArrayType() && + RHSStripped->getType()->isArrayType()) { + S.Diag(Loc, diag::warn_depr_array_comparison) + << LHS->getSourceRange() << RHS->getSourceRange() + << LHSStripped->getType() << RHSStripped->getType(); + // Carry on to produce the tautological comparison warning, if this + // expression is potentially-evaluated, we can resolve the array to a + // non-weak declaration, and so on. + } + + if (!LHS->getBeginLoc().isMacroID() && !RHS->getBeginLoc().isMacroID()) { + if (Expr::isSameComparisonOperand(LHS, RHS)) { + unsigned Result; + switch (Opc) { + case BO_EQ: + case BO_LE: + case BO_GE: + Result = AlwaysTrue; + break; + case BO_NE: + case BO_LT: + case BO_GT: + Result = AlwaysFalse; + break; + case BO_Cmp: + Result = AlwaysEqual; + break; + default: + Result = AlwaysConstant; + break; + } + S.DiagRuntimeBehavior(Loc, nullptr, + S.PDiag(diag::warn_comparison_always) + << 0 /*self-comparison*/ + << Result); + } else if (checkForArray(LHSStripped) && checkForArray(RHSStripped)) { + // What is it always going to evaluate to? + unsigned Result; + switch (Opc) { + case BO_EQ: // e.g. array1 == array2 + Result = AlwaysFalse; + break; + case BO_NE: // e.g. array1 != array2 + Result = AlwaysTrue; + break; + default: // e.g. array1 <= array2 + // The best we can say is 'a constant' + Result = AlwaysConstant; + break; + } + S.DiagRuntimeBehavior(Loc, nullptr, + S.PDiag(diag::warn_comparison_always) + << 1 /*array comparison*/ + << Result); } - S.DiagRuntimeBehavior(Loc, nullptr, - S.PDiag(diag::warn_comparison_always) - << 1 /*array comparison*/ - << Result); } if (isa<CastExpr>(LHSStripped)) @@ -10392,7 +10503,7 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, RHSStripped = RHSStripped->IgnoreParenCasts(); // Warn about comparisons against a string constant (unless the other - // operand is null); the user probably wants strcmp. + // operand is null); the user probably wants string comparison function. Expr *LiteralString = nullptr; Expr *LiteralStringStripped = nullptr; if ((isa<StringLiteral>(LHSStripped) || isa<ObjCEncodeExpr>(LHSStripped)) && @@ -10500,8 +10611,6 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { - using CCT = ComparisonCategoryType; - QualType LHSType = LHS.get()->getType(); QualType RHSType = RHS.get()->getType(); // Dig out the original argument type and expression before implicit casts @@ -10519,6 +10628,7 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, return QualType(); } + // FIXME: Consider combining this with checkEnumArithmeticConversions. int NumEnumArgs = (int)LHSStrippedType->isEnumeralType() + RHSStrippedType->isEnumeralType(); if (NumEnumArgs == 1) { @@ -10554,12 +10664,17 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, // C++2a [expr.spaceship]p4: If both operands have arithmetic types, the // usual arithmetic conversions are applied to the operands. - QualType Type = S.UsualArithmeticConversions(LHS, RHS); + QualType Type = + S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (Type.isNull()) return S.InvalidOperands(Loc, LHS, RHS); - assert(Type->isArithmeticType() || Type->isEnumeralType()); + + Optional<ComparisonCategoryType> CCT = + getComparisonCategoryForBuiltinCmp(Type); + if (!CCT) + return S.InvalidOperands(Loc, LHS, RHS); bool HasNarrowing = checkThreeWayNarrowingConversion( S, Type, LHS.get(), LHSType, LHS.get()->getBeginLoc()); @@ -10570,20 +10685,8 @@ static QualType checkArithmeticOrEnumeralThreeWayCompare(Sema &S, assert(!Type.isNull() && "composite type for <=> has not been set"); - auto TypeKind = [&]() { - if (const ComplexType *CT = Type->getAs<ComplexType>()) { - if (CT->getElementType()->hasFloatingRepresentation()) - return CCT::WeakEquality; - return CCT::StrongEquality; - } - if (Type->isIntegralOrEnumerationType()) - return CCT::StrongOrdering; - if (Type->hasFloatingRepresentation()) - return CCT::PartialOrdering; - llvm_unreachable("other types are unimplemented"); - }(); - - return S.CheckComparisonCategoryType(TypeKind, Loc); + return S.CheckComparisonCategoryType( + *CCT, Loc, Sema::ComparisonCategoryUsage::OperatorInExpression); } static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS, @@ -10594,15 +10697,14 @@ static QualType checkArithmeticOrEnumeralCompare(Sema &S, ExprResult &LHS, return checkArithmeticOrEnumeralThreeWayCompare(S, LHS, RHS, Loc); // C99 6.5.8p3 / C99 6.5.9p4 - QualType Type = S.UsualArithmeticConversions(LHS, RHS); + QualType Type = + S.UsualArithmeticConversions(LHS, RHS, Loc, Sema::ACK_Comparison); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (Type.isNull()) return S.InvalidOperands(Loc, LHS, RHS); assert(Type->isArithmeticType() || Type->isEnumeralType()); - checkEnumComparison(S, Loc, LHS.get(), RHS.get()); - if (Type->isAnyComplexType() && BinaryOperator::isRelationalOp(Opc)) return S.InvalidOperands(Loc, LHS, RHS); @@ -10646,6 +10748,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, BinaryOperatorKind Opc) { bool IsRelational = BinaryOperator::isRelationalOp(Opc); bool IsThreeWay = Opc == BO_Cmp; + bool IsOrdered = IsRelational || IsThreeWay; auto IsAnyPointerType = [](ExprResult E) { QualType Ty = E.get()->getType(); return Ty->isPointerType() || Ty->isMemberPointerType(); @@ -10708,36 +10811,26 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, QualType CompositeTy = LHS.get()->getType(); assert(!CompositeTy->isReferenceType()); - auto buildResultTy = [&](ComparisonCategoryType Kind) { - return CheckComparisonCategoryType(Kind, Loc); - }; - - // C++2a [expr.spaceship]p7: If the composite pointer type is a function - // pointer type, a pointer-to-member type, or std::nullptr_t, the - // result is of type std::strong_equality - if (CompositeTy->isFunctionPointerType() || - CompositeTy->isMemberPointerType() || CompositeTy->isNullPtrType()) - // FIXME: consider making the function pointer case produce - // strong_ordering not strong_equality, per P0946R0-Jax18 discussion - // and direction polls - return buildResultTy(ComparisonCategoryType::StrongEquality); + Optional<ComparisonCategoryType> CCT = + getComparisonCategoryForBuiltinCmp(CompositeTy); + if (!CCT) + return InvalidOperands(Loc, LHS, RHS); - // C++2a [expr.spaceship]p8: If the composite pointer type is an object - // pointer type, p <=> q is of type std::strong_ordering. - if (CompositeTy->isPointerType()) { + if (CompositeTy->isPointerType() && LHSIsNull != RHSIsNull) { // P0946R0: Comparisons between a null pointer constant and an object - // pointer result in std::strong_equality - if (LHSIsNull != RHSIsNull) - return buildResultTy(ComparisonCategoryType::StrongEquality); - return buildResultTy(ComparisonCategoryType::StrongOrdering); + // pointer result in std::strong_equality, which is ill-formed under + // P1959R0. + Diag(Loc, diag::err_typecheck_three_way_comparison_of_pointer_and_zero) + << (LHSIsNull ? LHS.get()->getSourceRange() + : RHS.get()->getSourceRange()); + return QualType(); } - // C++2a [expr.spaceship]p9: Otherwise, the program is ill-formed. - // TODO: Extend support for operator<=> to ObjC types. - return InvalidOperands(Loc, LHS, RHS); - }; + return CheckComparisonCategoryType( + *CCT, Loc, ComparisonCategoryUsage::OperatorInExpression); + }; - if (!IsRelational && LHSIsNull != RHSIsNull) { + if (!IsOrdered && LHSIsNull != RHSIsNull) { bool IsEquality = Opc == BO_EQ; if (RHSIsNull) DiagnoseAlwaysNonNullPointer(LHS.get(), RHSNullKind, IsEquality, @@ -10756,7 +10849,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // but we allow it as an extension. // FIXME: If we really want to allow this, should it be part of composite // pointer type computation so it works in conditionals too? - if (!IsRelational && + if (!IsOrdered && ((LHSType->isFunctionPointerType() && RHSType->isVoidPointerType()) || (RHSType->isFunctionPointerType() && LHSType->isVoidPointerType()))) { // This is a gcc extension compatibility comparison. @@ -10781,8 +10874,11 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // C++ [expr.rel]p2: // If both operands are pointers, [...] bring them to their composite // pointer type. + // For <=>, the only valid non-pointer types are arrays and functions, and + // we already decayed those, so this is really the same as the relational + // comparison rule. if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >= - (IsRelational ? 2 : 1) && + (IsOrdered ? 2 : 1) && (!LangOpts.ObjCAutoRefCount || !(LHSType->isObjCObjectPointerType() || RHSType->isObjCObjectPointerType()))) { if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) @@ -10845,7 +10941,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // C++ [expr.eq]p4: // Two operands of type std::nullptr_t or one operand of type // std::nullptr_t and the other a null pointer constant compare equal. - if (!IsRelational && LHSIsNull && RHSIsNull) { + if (!IsOrdered && LHSIsNull && RHSIsNull) { if (LHSType->isNullPtrType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); @@ -10858,12 +10954,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // Comparison of Objective-C pointers and block pointers against nullptr_t. // These aren't covered by the composite pointer type rules. - if (!IsRelational && RHSType->isNullPtrType() && + if (!IsOrdered && RHSType->isNullPtrType() && (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); } - if (!IsRelational && LHSType->isNullPtrType() && + if (!IsOrdered && LHSType->isNullPtrType() && (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return computeResultTy(); @@ -10897,7 +10993,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // C++ [expr.eq]p2: // If at least one operand is a pointer to member, [...] bring them to // their composite pointer type. - if (!IsRelational && + if (!IsOrdered && (LHSType->isMemberPointerType() || RHSType->isMemberPointerType())) { if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); @@ -10907,7 +11003,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } // Handle block pointer types. - if (!IsRelational && LHSType->isBlockPointerType() && + if (!IsOrdered && LHSType->isBlockPointerType() && RHSType->isBlockPointerType()) { QualType lpointee = LHSType->castAs<BlockPointerType>()->getPointeeType(); QualType rpointee = RHSType->castAs<BlockPointerType>()->getPointeeType(); @@ -10923,7 +11019,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } // Allow block pointers to be compared with null pointer constants. - if (!IsRelational + if (!IsOrdered && ((LHSType->isBlockPointerType() && RHSType->isPointerType()) || (LHSType->isPointerType() && RHSType->isBlockPointerType()))) { if (!LHSIsNull && !RHSIsNull) { @@ -10959,6 +11055,9 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false); } + // FIXME: If LPtrToVoid, we should presumably convert the LHS rather than + // the RHS, but we have test coverage for this behavior. + // FIXME: Consider using convertPointersToCompositeType in C++. if (LHSIsNull && !RHSIsNull) { Expr *E = LHS.get(); if (getLangOpts().ObjCAutoRefCount) @@ -10993,12 +11092,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, return computeResultTy(); } - if (!IsRelational && LHSType->isBlockPointerType() && + if (!IsOrdered && LHSType->isBlockPointerType() && RHSType->isBlockCompatibleObjCPointerType(Context)) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_BlockPointerToObjCPointerCast); return computeResultTy(); - } else if (!IsRelational && + } else if (!IsOrdered && LHSType->isBlockCompatibleObjCPointerType(Context) && RHSType->isBlockPointerType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, @@ -11015,7 +11114,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // since users tend to want to compare addresses. } else if ((LHSIsNull && LHSType->isIntegerType()) || (RHSIsNull && RHSType->isIntegerType())) { - if (IsRelational) { + if (IsOrdered) { isError = getLangOpts().CPlusPlus; DiagID = isError ? diag::err_typecheck_ordered_comparison_of_pointer_and_zero @@ -11024,7 +11123,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } else if (getLangOpts().CPlusPlus) { DiagID = diag::err_typecheck_comparison_of_pointer_integer; isError = true; - } else if (IsRelational) + } else if (IsOrdered) DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer; else DiagID = diag::ext_typecheck_comparison_of_pointer_integer; @@ -11047,12 +11146,12 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } // Handle block pointers. - if (!IsRelational && RHSIsNull + if (!IsOrdered && RHSIsNull && LHSType->isBlockPointerType() && RHSType->isIntegerType()) { RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return computeResultTy(); } - if (!IsRelational && LHSIsNull + if (!IsOrdered && LHSIsNull && LHSType->isIntegerType() && RHSType->isBlockPointerType()) { LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return computeResultTy(); @@ -11129,6 +11228,11 @@ QualType Sema::GetSignedVectorType(QualType V) { QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { + if (Opc == BO_Cmp) { + Diag(Loc, diag::err_three_way_vector_comparison); + return QualType(); + } + // Check to make sure we're operating on vectors of the same type and width, // Allowing one side to be a scalar of element type. QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false, @@ -11318,9 +11422,13 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, if (Opc == BO_And) diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc); + if (LHS.get()->getType()->hasFloatingRepresentation() || + RHS.get()->getType()->hasFloatingRepresentation()) + return InvalidOperands(Loc, LHS, RHS); + ExprResult LHSResult = LHS, RHSResult = RHS; - QualType compType = UsualArithmeticConversions(LHSResult, RHSResult, - IsCompAssign); + QualType compType = UsualArithmeticConversions( + LHSResult, RHSResult, Loc, IsCompAssign ? ACK_CompAssign : ACK_BitwiseOp); if (LHSResult.isInvalid() || RHSResult.isInvalid()) return QualType(); LHS = LHSResult.get(); @@ -13011,6 +13119,14 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid()) return ExprError(); + if (ResultTy->isRealFloatingType() && + (getLangOpts().getFPRoundingMode() != LangOptions::FPR_ToNearest || + getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore)) + // Mark the current function as usng floating point constrained intrinsics + if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) { + F->setUsesFPIntrin(true); + } + // Some of the binary operations require promoting operands of half vector to // float vectors and truncating the result back to half vector. For now, we do // this only when HalfArgsAndReturn is set (that is, when the target is arm or @@ -15268,8 +15384,7 @@ static bool funcHasParameterSizeMangling(Sema &S, FunctionDecl *FD) { // These manglings don't do anything on non-Windows or non-x86 platforms, so // we don't need parameter type sizes. const llvm::Triple &TT = S.Context.getTargetInfo().getTriple(); - if (!TT.isOSWindows() || (TT.getArch() != llvm::Triple::x86 && - TT.getArch() != llvm::Triple::x86_64)) + if (!TT.isOSWindows() || !TT.isX86()) return false; // If this is C++ and this isn't an extern "C" function, parameters do not @@ -15385,9 +15500,8 @@ static OdrUseContext isOdrUseContext(Sema &SemaRef) { } static bool isImplicitlyDefinableConstexprFunction(FunctionDecl *Func) { - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func); return Func->isConstexpr() && - (Func->isImplicitlyInstantiable() || (MD && !MD->isUserProvided())); + (Func->isImplicitlyInstantiable() || !Func->isUserProvided()); } /// Mark a function referenced, and check whether it is odr-used @@ -15467,19 +15581,6 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, Func->getMemberSpecializationInfo())) checkSpecializationVisibility(Loc, Func); - // C++14 [except.spec]p17: - // An exception-specification is considered to be needed when: - // - the function is odr-used or, if it appears in an unevaluated operand, - // would be odr-used if the expression were potentially-evaluated; - // - // Note, we do this even if MightBeOdrUse is false. That indicates that the - // function is a pure virtual function we're calling, and in that case the - // function was selected by overload resolution and we need to resolve its - // exception specification for a different reason. - const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>(); - if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) - ResolveExceptionSpec(Loc, FPT); - if (getLangOpts().CUDA) CheckCUDACall(Loc, Func); @@ -15535,6 +15636,12 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, MarkVTableUsed(Loc, MethodDecl->getParent()); } + if (Func->isDefaulted() && !Func->isDeleted()) { + DefaultedComparisonKind DCK = getDefaultedComparisonKind(Func); + if (DCK != DefaultedComparisonKind::None) + DefineDefaultedComparison(Loc, Func, DCK); + } + // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { @@ -15582,6 +15689,19 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, }); } + // C++14 [except.spec]p17: + // An exception-specification is considered to be needed when: + // - the function is odr-used or, if it appears in an unevaluated operand, + // would be odr-used if the expression were potentially-evaluated; + // + // Note, we do this even if MightBeOdrUse is false. That indicates that the + // function is a pure virtual function we're calling, and in that case the + // function was selected by overload resolution and we need to resolve its + // exception specification for a different reason. + const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>(); + if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) + ResolveExceptionSpec(Loc, FPT); + // If this is the first "real" use, act on that. if (OdrUse == OdrUseContext::Used && !Func->isUsed(/*CheckUsedAttr=*/false)) { // Keep track of used but undefined functions. @@ -17880,7 +18000,7 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization // leaves Result unchanged on failure. Result = E; - if (resolveAndFixAddressOfOnlyViableOverloadCandidate(Result)) + if (resolveAndFixAddressOfSingleOverloadCandidate(Result)) return Result; // If that failed, try to recover with a call. @@ -18017,3 +18137,8 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( return new (Context) ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); } + +bool Sema::IsDependentFunctionNameExpr(Expr *E) { + assert(E->isTypeDependent()); + return isa<UnresolvedLookupExpr>(E); +} diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 9aae9289b514..a73e6906fceb 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -921,7 +921,7 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, // cannot be a simple walk of the class's decls. Instead, we must perform // lookup and overload resolution. CXXConstructorDecl *CD = LookupCopyingConstructor(Subobject, 0); - if (!CD) + if (!CD || CD->isDeleted()) continue; // Mark the constructor referenced as it is used by this throw expression. @@ -2323,7 +2323,7 @@ static bool resolveAllocationOverload( PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_ambiguous_call) << R.getLookupName() << Range), - S, OCD_ViableCandidates, Args); + S, OCD_AmbiguousCandidates, Args); } return true; @@ -3513,7 +3513,7 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall, PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_ambiguous_call) << R.getLookupName() << Range), - S, OCD_ViableCandidates, Args); + S, OCD_AmbiguousCandidates, Args); return true; case OR_Deleted: { @@ -4095,9 +4095,26 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, << From->getSourceRange(); } + // Defer address space conversion to the third conversion. + QualType FromPteeType = From->getType()->getPointeeType(); + QualType ToPteeType = ToType->getPointeeType(); + QualType NewToType = ToType; + if (!FromPteeType.isNull() && !ToPteeType.isNull() && + FromPteeType.getAddressSpace() != ToPteeType.getAddressSpace()) { + NewToType = Context.removeAddrSpaceQualType(ToPteeType); + NewToType = Context.getAddrSpaceQualType(NewToType, + FromPteeType.getAddressSpace()); + if (ToType->isObjCObjectPointerType()) + NewToType = Context.getObjCObjectPointerType(NewToType); + else if (ToType->isBlockPointerType()) + NewToType = Context.getBlockPointerType(NewToType); + else + NewToType = Context.getPointerType(NewToType); + } + CastKind Kind; CXXCastPath BasePath; - if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) + if (CheckPointerConversion(From, NewToType, Kind, BasePath, CStyle)) return ExprError(); // Make sure we extend blocks if necessary. @@ -4108,8 +4125,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, From = E.get(); } if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers()) - CheckObjCConversion(SourceRange(), ToType, From, CCK); - From = ImpCastExprToType(From, ToType, Kind, VK_RValue, &BasePath, CCK) + CheckObjCConversion(SourceRange(), NewToType, From, CCK); + From = ImpCastExprToType(From, NewToType, Kind, VK_RValue, &BasePath, CCK) .get(); break; } @@ -5730,38 +5747,157 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { return false; } +// Check the condition operand of ?: to see if it is valid for the GCC +// extension. +static bool isValidVectorForConditionalCondition(ASTContext &Ctx, + QualType CondTy) { + if (!CondTy->isVectorType() || CondTy->isExtVectorType()) + return false; + const QualType EltTy = + cast<VectorType>(CondTy.getCanonicalType())->getElementType(); + + assert(!EltTy->isBooleanType() && !EltTy->isEnumeralType() && + "Vectors cant be boolean or enum types"); + return EltTy->isIntegralType(Ctx); +} + +QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, + ExprResult &RHS, + SourceLocation QuestionLoc) { + LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); + RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); + + QualType CondType = Cond.get()->getType(); + const auto *CondVT = CondType->getAs<VectorType>(); + QualType CondElementTy = CondVT->getElementType(); + unsigned CondElementCount = CondVT->getNumElements(); + QualType LHSType = LHS.get()->getType(); + const auto *LHSVT = LHSType->getAs<VectorType>(); + QualType RHSType = RHS.get()->getType(); + const auto *RHSVT = RHSType->getAs<VectorType>(); + + QualType ResultType; + + // FIXME: In the future we should define what the Extvector conditional + // operator looks like. + if (LHSVT && isa<ExtVectorType>(LHSVT)) { + Diag(QuestionLoc, diag::err_conditional_vector_operand_type) + << /*isExtVector*/ true << LHSType; + return {}; + } + + if (RHSVT && isa<ExtVectorType>(RHSVT)) { + Diag(QuestionLoc, diag::err_conditional_vector_operand_type) + << /*isExtVector*/ true << RHSType; + return {}; + } + + if (LHSVT && RHSVT) { + // If both are vector types, they must be the same type. + if (!Context.hasSameType(LHSType, RHSType)) { + Diag(QuestionLoc, diag::err_conditional_vector_mismatched_vectors) + << LHSType << RHSType; + return {}; + } + ResultType = LHSType; + } else if (LHSVT || RHSVT) { + ResultType = CheckVectorOperands( + LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true, + /*AllowBoolConversions*/ false); + if (ResultType.isNull()) + return {}; + } else { + // Both are scalar. + QualType ResultElementTy; + LHSType = LHSType.getCanonicalType().getUnqualifiedType(); + RHSType = RHSType.getCanonicalType().getUnqualifiedType(); + + if (Context.hasSameType(LHSType, RHSType)) + ResultElementTy = LHSType; + else + ResultElementTy = + UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); + + if (ResultElementTy->isEnumeralType()) { + Diag(QuestionLoc, diag::err_conditional_vector_operand_type) + << /*isExtVector*/ false << ResultElementTy; + return {}; + } + ResultType = Context.getVectorType( + ResultElementTy, CondType->getAs<VectorType>()->getNumElements(), + VectorType::GenericVector); + + LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat); + RHS = ImpCastExprToType(RHS.get(), ResultType, CK_VectorSplat); + } + + assert(!ResultType.isNull() && ResultType->isVectorType() && + "Result should have been a vector type"); + QualType ResultElementTy = ResultType->getAs<VectorType>()->getElementType(); + unsigned ResultElementCount = + ResultType->getAs<VectorType>()->getNumElements(); + + if (ResultElementCount != CondElementCount) { + Diag(QuestionLoc, diag::err_conditional_vector_size) << CondType + << ResultType; + return {}; + } + + if (Context.getTypeSize(ResultElementTy) != + Context.getTypeSize(CondElementTy)) { + Diag(QuestionLoc, diag::err_conditional_vector_element_size) << CondType + << ResultType; + return {}; + } + + return ResultType; +} + /// Check the operands of ?: under C++ semantics. /// /// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y /// extension. In this case, LHS == Cond. (But they're not aliases.) +/// +/// This function also implements GCC's vector extension for conditionals. +/// GCC's vector extension permits the use of a?b:c where the type of +/// a is that of a integer vector with the same number of elements and +/// size as the vectors of b and c. If one of either b or c is a scalar +/// it is implicitly converted to match the type of the vector. +/// Otherwise the expression is ill-formed. If both b and c are scalars, +/// then b and c are checked and converted to the type of a if possible. +/// Unlike the OpenCL ?: operator, the expression is evaluated as +/// (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]). QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, SourceLocation QuestionLoc) { - // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++ - // interface pointers. + // FIXME: Handle C99's complex types, block pointers and Obj-C++ interface + // pointers. + + // Assume r-value. + VK = VK_RValue; + OK = OK_Ordinary; + bool IsVectorConditional = + isValidVectorForConditionalCondition(Context, Cond.get()->getType()); // C++11 [expr.cond]p1 // The first expression is contextually converted to bool. - // - // FIXME; GCC's vector extension permits the use of a?b:c where the type of - // a is that of a integer vector with the same number of elements and - // size as the vectors of b and c. If one of either b or c is a scalar - // it is implicitly converted to match the type of the vector. - // Otherwise the expression is ill-formed. If both b and c are scalars, - // then b and c are checked and converted to the type of a if possible. - // Unlike the OpenCL ?: operator, the expression is evaluated as - // (a[0] != 0 ? b[0] : c[0], .. , a[n] != 0 ? b[n] : c[n]). if (!Cond.get()->isTypeDependent()) { - ExprResult CondRes = CheckCXXBooleanCondition(Cond.get()); + ExprResult CondRes = IsVectorConditional + ? DefaultFunctionArrayLvalueConversion(Cond.get()) + : CheckCXXBooleanCondition(Cond.get()); if (CondRes.isInvalid()) return QualType(); Cond = CondRes; + } else { + // To implement C++, the first expression typically doesn't alter the result + // type of the conditional, however the GCC compatible vector extension + // changes the result type to be that of the conditional. Since we cannot + // know if this is a vector extension here, delay the conversion of the + // LHS/RHS below until later. + return Context.DependentTy; } - // Assume r-value. - VK = VK_RValue; - OK = OK_Ordinary; // Either of the arguments dependent? if (LHS.get()->isTypeDependent() || RHS.get()->isTypeDependent()) @@ -5780,6 +5916,17 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // and value category of the other. bool LThrow = isa<CXXThrowExpr>(LHS.get()->IgnoreParenImpCasts()); bool RThrow = isa<CXXThrowExpr>(RHS.get()->IgnoreParenImpCasts()); + + // Void expressions aren't legal in the vector-conditional expressions. + if (IsVectorConditional) { + SourceRange DiagLoc = + LVoid ? LHS.get()->getSourceRange() : RHS.get()->getSourceRange(); + bool IsThrow = LVoid ? LThrow : RThrow; + Diag(DiagLoc.getBegin(), diag::err_conditional_vector_has_void) + << DiagLoc << IsThrow; + return QualType(); + } + if (LThrow != RThrow) { Expr *NonThrow = LThrow ? RHS.get() : LHS.get(); VK = NonThrow->getValueKind(); @@ -5802,6 +5949,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, } // Neither is void. + if (IsVectorConditional) + return CheckGNUVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc); // C++11 [expr.cond]p3 // Otherwise, if the second and third operand have different types, and @@ -5845,29 +5994,33 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // FIXME: // Resolving a defect in P0012R1: we extend this to cover all cases where // one of the operands is reference-compatible with the other, in order - // to support conditionals between functions differing in noexcept. + // to support conditionals between functions differing in noexcept. This + // will similarly cover difference in array bounds after P0388R4. + // FIXME: If LTy and RTy have a composite pointer type, should we convert to + // that instead? ExprValueKind LVK = LHS.get()->getValueKind(); ExprValueKind RVK = RHS.get()->getValueKind(); if (!Context.hasSameType(LTy, RTy) && LVK == RVK && LVK != VK_RValue) { // DerivedToBase was already handled by the class-specific case above. // FIXME: Should we allow ObjC conversions here? - bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion, - FunctionConversion; - if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, DerivedToBase, - ObjCConversion, ObjCLifetimeConversion, - FunctionConversion) == Ref_Compatible && - !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion && + const ReferenceConversions AllowedConversions = + ReferenceConversions::Qualification | + ReferenceConversions::NestedQualification | + ReferenceConversions::Function; + + ReferenceConversions RefConv; + if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, &RefConv) == + Ref_Compatible && + !(RefConv & ~AllowedConversions) && // [...] subject to the constraint that the reference must bind // directly [...] !RHS.get()->refersToBitField() && !RHS.get()->refersToVectorElement()) { RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK); RTy = RHS.get()->getType(); - } else if (CompareReferenceRelationship( - QuestionLoc, RTy, LTy, DerivedToBase, ObjCConversion, - ObjCLifetimeConversion, - FunctionConversion) == Ref_Compatible && - !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion && + } else if (CompareReferenceRelationship(QuestionLoc, RTy, LTy, &RefConv) == + Ref_Compatible && + !(RefConv & ~AllowedConversions) && !LHS.get()->refersToBitField() && !LHS.get()->refersToVectorElement()) { LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK); @@ -5976,7 +6129,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // the usual arithmetic conversions are performed to bring them to a // common type, and the result is of that type. if (LTy->isArithmeticType() && RTy->isArithmeticType()) { - QualType ResTy = UsualArithmeticConversions(LHS, RHS); + QualType ResTy = + UsualArithmeticConversions(LHS, RHS, QuestionLoc, ACK_Conditional); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); if (ResTy.isNull()) { @@ -6098,10 +6252,10 @@ mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, /// Find a merged pointer type and convert the two expressions to it. /// -/// This finds the composite pointer type (or member pointer type) for @p E1 -/// and @p E2 according to C++1z 5p14. It converts both expressions to this -/// type and returns it. -/// It does not emit diagnostics. +/// This finds the composite pointer type for \p E1 and \p E2 according to +/// C++2a [expr.type]p3. It converts both expressions to this type and returns +/// it. It does not emit diagnostics (FIXME: that's not true if \p ConvertArgs +/// is \c true). /// /// \param Loc The location of the operator requiring these two expressions to /// be converted to the composite pointer type. @@ -6154,60 +6308,117 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, assert(!T1->isNullPtrType() && !T2->isNullPtrType() && "nullptr_t should be a null pointer constant"); - // - if T1 or T2 is "pointer to cv1 void" and the other type is - // "pointer to cv2 T", "pointer to cv12 void", where cv12 is - // the union of cv1 and cv2; - // - if T1 or T2 is "pointer to noexcept function" and the other type is - // "pointer to function", where the function types are otherwise the same, - // "pointer to function"; - // FIXME: This rule is defective: it should also permit removing noexcept - // from a pointer to member function. As a Clang extension, we also - // permit removing 'noreturn', so we generalize this rule to; - // - [Clang] If T1 and T2 are both of type "pointer to function" or - // "pointer to member function" and the pointee types can be unified - // by a function pointer conversion, that conversion is applied - // before checking the following rules. + struct Step { + enum Kind { Pointer, ObjCPointer, MemberPointer, Array } K; + // Qualifiers to apply under the step kind. + Qualifiers Quals; + /// The class for a pointer-to-member; a constant array type with a bound + /// (if any) for an array. + const Type *ClassOrBound; + + Step(Kind K, const Type *ClassOrBound = nullptr) + : K(K), Quals(), ClassOrBound(ClassOrBound) {} + QualType rebuild(ASTContext &Ctx, QualType T) const { + T = Ctx.getQualifiedType(T, Quals); + switch (K) { + case Pointer: + return Ctx.getPointerType(T); + case MemberPointer: + return Ctx.getMemberPointerType(T, ClassOrBound); + case ObjCPointer: + return Ctx.getObjCObjectPointerType(T); + case Array: + if (auto *CAT = cast_or_null<ConstantArrayType>(ClassOrBound)) + return Ctx.getConstantArrayType(T, CAT->getSize(), nullptr, + ArrayType::Normal, 0); + else + return Ctx.getIncompleteArrayType(T, ArrayType::Normal, 0); + } + llvm_unreachable("unknown step kind"); + } + }; + + SmallVector<Step, 8> Steps; + // - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1 // is reference-related to C2 or C2 is reference-related to C1 (8.6.3), // the cv-combined type of T1 and T2 or the cv-combined type of T2 and T1, // respectively; // - if T1 is "pointer to member of C1 of type cv1 U1" and T2 is "pointer - // to member of C2 of type cv2 U2" where C1 is reference-related to C2 or - // C2 is reference-related to C1 (8.6.3), the cv-combined type of T2 and - // T1 or the cv-combined type of T1 and T2, respectively; + // to member of C2 of type cv2 U2" for some non-function type U, where + // C1 is reference-related to C2 or C2 is reference-related to C1, the + // cv-combined type of T2 and T1 or the cv-combined type of T1 and T2, + // respectively; // - if T1 and T2 are similar types (4.5), the cv-combined type of T1 and // T2; // - // If looked at in the right way, these bullets all do the same thing. - // What we do here is, we build the two possible cv-combined types, and try - // the conversions in both directions. If only one works, or if the two - // composite types are the same, we have succeeded. - // FIXME: extended qualifiers? - // - // Note that this will fail to find a composite pointer type for "pointer - // to void" and "pointer to function". We can't actually perform the final - // conversion in this case, even though a composite pointer type formally - // exists. - SmallVector<unsigned, 4> QualifierUnion; - SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass; + // Dismantle T1 and T2 to simultaneously determine whether they are similar + // and to prepare to form the cv-combined type if so. QualType Composite1 = T1; QualType Composite2 = T2; unsigned NeedConstBefore = 0; while (true) { + assert(!Composite1.isNull() && !Composite2.isNull()); + + Qualifiers Q1, Q2; + Composite1 = Context.getUnqualifiedArrayType(Composite1, Q1); + Composite2 = Context.getUnqualifiedArrayType(Composite2, Q2); + + // Top-level qualifiers are ignored. Merge at all lower levels. + if (!Steps.empty()) { + // Find the qualifier union: (approximately) the unique minimal set of + // qualifiers that is compatible with both types. + Qualifiers Quals = Qualifiers::fromCVRUMask(Q1.getCVRUQualifiers() | + Q2.getCVRUQualifiers()); + + // Under one level of pointer or pointer-to-member, we can change to an + // unambiguous compatible address space. + if (Q1.getAddressSpace() == Q2.getAddressSpace()) { + Quals.setAddressSpace(Q1.getAddressSpace()); + } else if (Steps.size() == 1) { + bool MaybeQ1 = Q1.isAddressSpaceSupersetOf(Q2); + bool MaybeQ2 = Q2.isAddressSpaceSupersetOf(Q1); + if (MaybeQ1 == MaybeQ2) + return QualType(); // No unique best address space. + Quals.setAddressSpace(MaybeQ1 ? Q1.getAddressSpace() + : Q2.getAddressSpace()); + } else { + return QualType(); + } + + // FIXME: In C, we merge __strong and none to __strong at the top level. + if (Q1.getObjCGCAttr() == Q2.getObjCGCAttr()) + Quals.setObjCGCAttr(Q1.getObjCGCAttr()); + else + return QualType(); + + // Mismatched lifetime qualifiers never compatibly include each other. + if (Q1.getObjCLifetime() == Q2.getObjCLifetime()) + Quals.setObjCLifetime(Q1.getObjCLifetime()); + else + return QualType(); + + Steps.back().Quals = Quals; + if (Q1 != Quals || Q2 != Quals) + NeedConstBefore = Steps.size() - 1; + } + + // FIXME: Can we unify the following with UnwrapSimilarTypes? const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs<PointerType>()) && (Ptr2 = Composite2->getAs<PointerType>())) { Composite1 = Ptr1->getPointeeType(); Composite2 = Ptr2->getPointeeType(); + Steps.emplace_back(Step::Pointer); + continue; + } - // If we're allowed to create a non-standard composite type, keep track - // of where we need to fill in additional 'const' qualifiers. - if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) - NeedConstBefore = QualifierUnion.size(); - - QualifierUnion.push_back( - Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); - MemberOfClass.push_back(std::make_pair(nullptr, nullptr)); + const ObjCObjectPointerType *ObjPtr1, *ObjPtr2; + if ((ObjPtr1 = Composite1->getAs<ObjCObjectPointerType>()) && + (ObjPtr2 = Composite2->getAs<ObjCObjectPointerType>())) { + Composite1 = ObjPtr1->getPointeeType(); + Composite2 = ObjPtr2->getPointeeType(); + Steps.emplace_back(Step::ObjCPointer); continue; } @@ -6217,34 +6428,79 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, Composite1 = MemPtr1->getPointeeType(); Composite2 = MemPtr2->getPointeeType(); - // If we're allowed to create a non-standard composite type, keep track - // of where we need to fill in additional 'const' qualifiers. - if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) - NeedConstBefore = QualifierUnion.size(); + // At the top level, we can perform a base-to-derived pointer-to-member + // conversion: + // + // - [...] where C1 is reference-related to C2 or C2 is + // reference-related to C1 + // + // (Note that the only kinds of reference-relatedness in scope here are + // "same type or derived from".) At any other level, the class must + // exactly match. + const Type *Class = nullptr; + QualType Cls1(MemPtr1->getClass(), 0); + QualType Cls2(MemPtr2->getClass(), 0); + if (Context.hasSameType(Cls1, Cls2)) + Class = MemPtr1->getClass(); + else if (Steps.empty()) + Class = IsDerivedFrom(Loc, Cls1, Cls2) ? MemPtr1->getClass() : + IsDerivedFrom(Loc, Cls2, Cls1) ? MemPtr2->getClass() : nullptr; + if (!Class) + return QualType(); + + Steps.emplace_back(Step::MemberPointer, Class); + continue; + } - QualifierUnion.push_back( - Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers()); - MemberOfClass.push_back(std::make_pair(MemPtr1->getClass(), - MemPtr2->getClass())); + // Special case: at the top level, we can decompose an Objective-C pointer + // and a 'cv void *'. Unify the qualifiers. + if (Steps.empty() && ((Composite1->isVoidPointerType() && + Composite2->isObjCObjectPointerType()) || + (Composite1->isObjCObjectPointerType() && + Composite2->isVoidPointerType()))) { + Composite1 = Composite1->getPointeeType(); + Composite2 = Composite2->getPointeeType(); + Steps.emplace_back(Step::Pointer); continue; } + // FIXME: arrays + // FIXME: block pointer types? // Cannot unwrap any more types. break; } - // Apply the function pointer conversion to unify the types. We've already - // unwrapped down to the function types, and we want to merge rather than - // just convert, so do this ourselves rather than calling + // - if T1 or T2 is "pointer to noexcept function" and the other type is + // "pointer to function", where the function types are otherwise the same, + // "pointer to function"; + // - if T1 or T2 is "pointer to member of C1 of type function", the other + // type is "pointer to member of C2 of type noexcept function", and C1 + // is reference-related to C2 or C2 is reference-related to C1, where + // the function types are otherwise the same, "pointer to member of C2 of + // type function" or "pointer to member of C1 of type function", + // respectively; + // + // We also support 'noreturn' here, so as a Clang extension we generalize the + // above to: + // + // - [Clang] If T1 and T2 are both of type "pointer to function" or + // "pointer to member function" and the pointee types can be unified + // by a function pointer conversion, that conversion is applied + // before checking the following rules. + // + // We've already unwrapped down to the function types, and we want to merge + // rather than just convert, so do this ourselves rather than calling // IsFunctionConversion. // // FIXME: In order to match the standard wording as closely as possible, we // currently only do this under a single level of pointers. Ideally, we would // allow this in general, and set NeedConstBefore to the relevant depth on - // the side(s) where we changed anything. - if (QualifierUnion.size() == 1) { + // the side(s) where we changed anything. If we permit that, we should also + // consider this conversion when determining type similarity and model it as + // a qualification conversion. + if (Steps.size() == 1) { if (auto *FPT1 = Composite1->getAs<FunctionProtoType>()) { if (auto *FPT2 = Composite2->getAs<FunctionProtoType>()) { FunctionProtoType::ExtProtoInfo EPI1 = FPT1->getExtProtoInfo(); @@ -6270,88 +6526,72 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, } } - if (NeedConstBefore) { - // Extension: Add 'const' to qualifiers that come before the first qualifier - // mismatch, so that our (non-standard!) composite type meets the - // requirements of C++ [conv.qual]p4 bullet 3. - for (unsigned I = 0; I != NeedConstBefore; ++I) - if ((QualifierUnion[I] & Qualifiers::Const) == 0) - QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const; + // There are some more conversions we can perform under exactly one pointer. + if (Steps.size() == 1 && Steps.front().K == Step::Pointer && + !Context.hasSameType(Composite1, Composite2)) { + // - if T1 or T2 is "pointer to cv1 void" and the other type is + // "pointer to cv2 T", where T is an object type or void, + // "pointer to cv12 void", where cv12 is the union of cv1 and cv2; + if (Composite1->isVoidType() && Composite2->isObjectType()) + Composite2 = Composite1; + else if (Composite2->isVoidType() && Composite1->isObjectType()) + Composite1 = Composite2; + // - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1 + // is reference-related to C2 or C2 is reference-related to C1 (8.6.3), + // the cv-combined type of T1 and T2 or the cv-combined type of T2 and + // T1, respectively; + // + // The "similar type" handling covers all of this except for the "T1 is a + // base class of T2" case in the definition of reference-related. + else if (IsDerivedFrom(Loc, Composite1, Composite2)) + Composite1 = Composite2; + else if (IsDerivedFrom(Loc, Composite2, Composite1)) + Composite2 = Composite1; } - // Rewrap the composites as pointers or member pointers with the union CVRs. - auto MOC = MemberOfClass.rbegin(); - for (unsigned CVR : llvm::reverse(QualifierUnion)) { - Qualifiers Quals = Qualifiers::fromCVRMask(CVR); - auto Classes = *MOC++; - if (Classes.first && Classes.second) { - // Rebuild member pointer type - Composite1 = Context.getMemberPointerType( - Context.getQualifiedType(Composite1, Quals), Classes.first); - Composite2 = Context.getMemberPointerType( - Context.getQualifiedType(Composite2, Quals), Classes.second); - } else { - // Rebuild pointer type - Composite1 = - Context.getPointerType(Context.getQualifiedType(Composite1, Quals)); - Composite2 = - Context.getPointerType(Context.getQualifiedType(Composite2, Quals)); - } - } + // At this point, either the inner types are the same or we have failed to + // find a composite pointer type. + if (!Context.hasSameType(Composite1, Composite2)) + return QualType(); - struct Conversion { - Sema &S; - Expr *&E1, *&E2; - QualType Composite; - InitializedEntity Entity; - InitializationKind Kind; - InitializationSequence E1ToC, E2ToC; - bool Viable; + // Per C++ [conv.qual]p3, add 'const' to every level before the last + // differing qualifier. + for (unsigned I = 0; I != NeedConstBefore; ++I) + Steps[I].Quals.addConst(); - Conversion(Sema &S, SourceLocation Loc, Expr *&E1, Expr *&E2, - QualType Composite) - : S(S), E1(E1), E2(E2), Composite(Composite), - Entity(InitializedEntity::InitializeTemporary(Composite)), - Kind(InitializationKind::CreateCopy(Loc, SourceLocation())), - E1ToC(S, Entity, Kind, E1), E2ToC(S, Entity, Kind, E2), - Viable(E1ToC && E2ToC) {} + // Rebuild the composite type. + QualType Composite = Composite1; + for (auto &S : llvm::reverse(Steps)) + Composite = S.rebuild(Context, Composite); - bool perform() { - ExprResult E1Result = E1ToC.Perform(S, Entity, Kind, E1); - if (E1Result.isInvalid()) - return true; - E1 = E1Result.getAs<Expr>(); + if (ConvertArgs) { + // Convert the expressions to the composite pointer type. + InitializedEntity Entity = + InitializedEntity::InitializeTemporary(Composite); + InitializationKind Kind = + InitializationKind::CreateCopy(Loc, SourceLocation()); - ExprResult E2Result = E2ToC.Perform(S, Entity, Kind, E2); - if (E2Result.isInvalid()) - return true; - E2 = E2Result.getAs<Expr>(); + InitializationSequence E1ToC(*this, Entity, Kind, E1); + if (!E1ToC) + return QualType(); - return false; - } - }; + InitializationSequence E2ToC(*this, Entity, Kind, E2); + if (!E2ToC) + return QualType(); - // Try to convert to each composite pointer type. - Conversion C1(*this, Loc, E1, E2, Composite1); - if (C1.Viable && Context.hasSameType(Composite1, Composite2)) { - if (ConvertArgs && C1.perform()) + // FIXME: Let the caller know if these fail to avoid duplicate diagnostics. + ExprResult E1Result = E1ToC.Perform(*this, Entity, Kind, E1); + if (E1Result.isInvalid()) return QualType(); - return C1.Composite; - } - Conversion C2(*this, Loc, E1, E2, Composite2); + E1 = E1Result.get(); - if (C1.Viable == C2.Viable) { - // Either Composite1 and Composite2 are viable and are different, or - // neither is viable. - // FIXME: How both be viable and different? - return QualType(); + ExprResult E2Result = E2ToC.Perform(*this, Entity, Kind, E2); + if (E2Result.isInvalid()) + return QualType(); + E2 = E2Result.get(); } - // Convert to the chosen type. - if (ConvertArgs && (C1.Viable ? C1 : C2).perform()) - return QualType(); - - return C1.Viable ? C1.Composite : C2.Composite; + return Composite; } ExprResult Sema::MaybeBindToTemporary(Expr *E) { @@ -7780,8 +8020,9 @@ class TransformTypos : public TreeTransform<TransformTypos> { // If we found a valid result, double check to make sure it's not ambiguous. if (!IsAmbiguous && !Res.isInvalid() && !AmbiguousTypoExprs.empty()) { - auto SavedTransformCache = std::move(TransformCache); - TransformCache.clear(); + auto SavedTransformCache = + llvm::SmallDenseMap<TypoExpr *, ExprResult, 2>(TransformCache); + // Ensure none of the TypoExprs have multiple typo correction candidates // with the same edit length that pass all the checks and filters. while (!AmbiguousTypoExprs.empty()) { diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 87114a0fac63..ebfc1ec4b974 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -919,6 +919,18 @@ MemberExpr *Sema::BuildMemberExpr( VK, OK, getNonOdrUseReasonInCurrentContext(Member)); E->setHadMultipleCandidates(HadMultipleCandidates); MarkMemberReferenced(E); + + // C++ [except.spec]p17: + // An exception-specification is considered to be needed when: + // - in an expression the function is the unique lookup result or the + // selected member of a set of overloaded functions + if (auto *FPT = Ty->getAs<FunctionProtoType>()) { + if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) { + if (auto *NewFPT = ResolveExceptionSpec(MemberNameInfo.getLoc(), FPT)) + E->setType(Context.getQualifiedType(NewFPT, Ty.getQualifiers())); + } + } + return E; } diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index e18621e42a6b..c61b13cf5980 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -10,13 +10,13 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeLoc.h" #include "clang/Analysis/DomainSpecific/CocoaConventions.h" +#include "clang/Basic/Builtins.h" #include "clang/Edit/Commit.h" #include "clang/Edit/Rewriters.h" #include "clang/Lex/Preprocessor.h" @@ -24,6 +24,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ConvertUTF.h" @@ -288,6 +289,7 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, S.NSNumberPointer, ReturnTInfo, S.NSNumberDecl, /*isInstance=*/false, /*isVariadic=*/false, /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, /*HasRelatedResultType=*/false); @@ -563,6 +565,7 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { NSStringPointer, ReturnTInfo, NSStringDecl, /*isInstance=*/false, /*isVariadic=*/false, /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, /*HasRelatedResultType=*/false); @@ -671,20 +674,15 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { // Debugger needs to work even if NSValue hasn't been defined. TypeSourceInfo *ReturnTInfo = nullptr; ObjCMethodDecl *M = ObjCMethodDecl::Create( - Context, - SourceLocation(), - SourceLocation(), - ValueWithBytesObjCType, - NSValuePointer, - ReturnTInfo, - NSValueDecl, - /*isInstance=*/false, - /*isVariadic=*/false, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/true, - /*isDefined=*/false, - ObjCMethodDecl::Required, - /*HasRelatedResultType=*/false); + Context, SourceLocation(), SourceLocation(), ValueWithBytesObjCType, + NSValuePointer, ReturnTInfo, NSValueDecl, + /*isInstance=*/false, + /*isVariadic=*/false, + /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, + /*isDefined=*/false, ObjCMethodDecl::Required, + /*HasRelatedResultType=*/false); SmallVector<ParmVarDecl *, 2> Params; @@ -815,7 +813,7 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { Context, SourceLocation(), SourceLocation(), Sel, IdT, ReturnTInfo, Context.getTranslationUnitDecl(), false /*Instance*/, false /*isVariadic*/, - /*isPropertyAccessor=*/false, + /*isPropertyAccessor=*/false, /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, false); SmallVector<ParmVarDecl *, 2> Params; @@ -916,16 +914,14 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, NSAPI::NSDict_dictionaryWithObjectsForKeysCount); ObjCMethodDecl *Method = NSDictionaryDecl->lookupClassMethod(Sel); if (!Method && getLangOpts().DebuggerObjCLiteral) { - Method = ObjCMethodDecl::Create(Context, - SourceLocation(), SourceLocation(), Sel, - IdT, - nullptr /*TypeSourceInfo */, - Context.getTranslationUnitDecl(), - false /*Instance*/, false/*isVariadic*/, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/true, /*isDefined=*/false, - ObjCMethodDecl::Required, - false); + Method = ObjCMethodDecl::Create( + Context, SourceLocation(), SourceLocation(), Sel, IdT, + nullptr /*TypeSourceInfo */, Context.getTranslationUnitDecl(), + false /*Instance*/, false /*isVariadic*/, + /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, /*isDefined=*/false, + ObjCMethodDecl::Required, false); SmallVector<ParmVarDecl *, 3> Params; ParmVarDecl *objects = ParmVarDecl::Create(Context, Method, SourceLocation(), @@ -1174,6 +1170,35 @@ static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc, } } +static void HelperToDiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc, + Selector Sel, + ObjCMethodList &MethList, + bool &onlyDirect) { + ObjCMethodList *M = &MethList; + for (M = M->getNext(); M; M = M->getNext()) { + ObjCMethodDecl *Method = M->getMethod(); + if (Method->getSelector() != Sel) + continue; + if (!Method->isDirectMethod()) + onlyDirect = false; + } +} + +static void DiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc, + Selector Sel, bool &onlyDirect) { + for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(), + e = S.MethodPool.end(); b != e; b++) { + // first, instance methods + ObjCMethodList &InstMethList = b->second.first; + HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, InstMethList, + onlyDirect); + + // second, class methods + ObjCMethodList &ClsMethList = b->second.second; + HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, ClsMethList, onlyDirect); + } +} + ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, SourceLocation AtLoc, SourceLocation SelLoc, @@ -1196,9 +1221,18 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, } else Diag(SelLoc, diag::warn_undeclared_selector) << Sel; - } else + } else { + bool onlyDirect = Method->isDirectMethod(); + DiagnoseDirectSelectorsExpr(*this, AtLoc, Sel, onlyDirect); DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc, WarnMultipleSelectors); + if (onlyDirect) { + Diag(AtLoc, diag::err_direct_selector_expression) + << Method->getSelector(); + Diag(Method->getLocation(), diag::note_direct_method_declared_at) + << Method->getDeclName(); + } + } if (Method && Method->getImplementationControl() != ObjCMethodDecl::Optional && @@ -1608,15 +1642,14 @@ bool Sema::CheckMessageArgumentTypes( << Sel << isClassMessage << SourceRange(SelectorLocs.front(), SelectorLocs.back()); // Find the class to which we are sending this message. - if (ReceiverType->isObjCObjectPointerType()) { - if (ObjCInterfaceDecl *ThisClass = - ReceiverType->getAs<ObjCObjectPointerType>()->getInterfaceDecl()) { + if (auto *ObjPT = ReceiverType->getAs<ObjCObjectPointerType>()) { + if (ObjCInterfaceDecl *ThisClass = ObjPT->getInterfaceDecl()) { Diag(ThisClass->getLocation(), diag::note_receiver_class_declared); if (!RecRange.isInvalid()) if (ThisClass->lookupClassMethod(Sel)) - Diag(RecRange.getBegin(),diag::note_receiver_expr_here) - << FixItHint::CreateReplacement(RecRange, - ThisClass->getNameAsString()); + Diag(RecRange.getBegin(), diag::note_receiver_expr_here) + << FixItHint::CreateReplacement(RecRange, + ThisClass->getNameAsString()); } } } @@ -2365,7 +2398,6 @@ static void checkFoundationAPI(Sema &S, SourceLocation Loc, return; QualType Ret = ImpliedMethod->getReturnType(); if (Ret->isRecordType() || Ret->isVectorType() || Ret->isExtVectorType()) { - QualType Ret = ImpliedMethod->getReturnType(); S.Diag(Loc, diag::warn_objc_unsafe_perform_selector) << Method->getSelector() << (!Ret->isRecordType() @@ -2771,9 +2803,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } } - if (ReceiverType->isObjCIdType() && !isImplicit) - Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id); - // There's a somewhat weird interaction here where we assume that we // won't actually have a method unless we also don't need to do some // of the more detailed type-checking on the receiver. @@ -2975,6 +3004,30 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, (Method && Method->getMethodFamily() == OMF_init) ? getEnclosingFunction() : nullptr; + if (Method && Method->isDirectMethod()) { + if (ReceiverType->isObjCIdType() && !isImplicit) { + Diag(Receiver->getExprLoc(), + diag::err_messaging_unqualified_id_with_direct_method); + Diag(Method->getLocation(), diag::note_direct_method_declared_at) + << Method->getDeclName(); + } + + if (ReceiverType->isObjCClassType() && !isImplicit) { + Diag(Receiver->getExprLoc(), + diag::err_messaging_class_with_direct_method); + Diag(Method->getLocation(), diag::note_direct_method_declared_at) + << Method->getDeclName(); + } + + if (SuperLoc.isValid()) { + Diag(SuperLoc, diag::err_messaging_super_with_direct_method); + Diag(Method->getLocation(), diag::note_direct_method_declared_at) + << Method->getDeclName(); + } + } else if (ReceiverType->isObjCIdType() && !isImplicit) { + Diag(Receiver->getExprLoc(), diag::warn_messaging_unqualified_id); + } + if (DIFunctionScopeInfo && DIFunctionScopeInfo->ObjCIsDesignatedInit && (SuperLoc.isValid() || isSelfExpr(Receiver))) { @@ -4358,7 +4411,7 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) { SmallVector<TypeSourceInfo *, 4> subTypes; subExprs.reserve(n); subTypes.reserve(n); - for (const GenericSelectionExpr::Association &assoc : gse->associations()) { + for (const GenericSelectionExpr::Association assoc : gse->associations()) { subTypes.push_back(assoc.getTypeSourceInfo()); Expr *sub = assoc.getAssociationExpr(); if (assoc.isSelected()) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 10cb7acad567..785637761e71 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3877,9 +3877,6 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, if (!Info.Constructor || Info.Constructor->isInvalidDecl()) continue; - if (!AllowExplicit && Info.Constructor->isExplicit()) - continue; - if (OnlyListConstructors && !S.isInitListConstructor(Info.Constructor)) continue; @@ -3951,18 +3948,16 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, else Conv = cast<CXXConversionDecl>(D); - if (AllowExplicit || !Conv->isExplicit()) { - if (ConvTemplate) - S.AddTemplateConversionCandidate( - ConvTemplate, I.getPair(), ActingDC, Initializer, DestType, - CandidateSet, AllowExplicit, AllowExplicit, - /*AllowResultConversion*/ false); - else - S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer, - DestType, CandidateSet, AllowExplicit, - AllowExplicit, - /*AllowResultConversion*/ false); - } + if (ConvTemplate) + S.AddTemplateConversionCandidate( + ConvTemplate, I.getPair(), ActingDC, Initializer, DestType, + CandidateSet, AllowExplicit, AllowExplicit, + /*AllowResultConversion*/ false); + else + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer, + DestType, CandidateSet, AllowExplicit, + AllowExplicit, + /*AllowResultConversion*/ false); } } } @@ -4064,7 +4059,7 @@ static void TryConstructorInitialization(Sema &S, // If the initializer list has no elements and T has a default constructor, // the first phase is omitted. - if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor())) + if (!(UnwrappedArgs.empty() && S.LookupDefaultConstructor(DestRecordDecl))) Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, CandidateSet, DestType, Ctors, Best, CopyInitialization, AllowExplicit, @@ -4229,10 +4224,8 @@ static void TryReferenceListInitialization(Sema &S, return; SourceLocation DeclLoc = Initializer->getBeginLoc(); - bool dummy1, dummy2, dummy3, dummy4; Sema::ReferenceCompareResult RefRelationship - = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1, - dummy2, dummy3, dummy4); + = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2); if (RefRelationship >= Sema::Ref_Related) { // Try to bind the reference here. TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1, @@ -4350,7 +4343,7 @@ static void TryListInitialization(Sema &S, // value-initialized. if (InitList->getNumInits() == 0) { CXXRecordDecl *RD = DestType->getAsCXXRecordDecl(); - if (RD->hasDefaultConstructor()) { + if (S.LookupDefaultConstructor(RD)) { TryValueInitialization(S, Entity, Kind, Sequence, InitList); return; } @@ -4469,18 +4462,8 @@ static OverloadingResult TryRefInitWithConversionFunction( QualType cv2T2 = Initializer->getType(); QualType T2 = cv2T2.getUnqualifiedType(); - bool DerivedToBase; - bool ObjCConversion; - bool ObjCLifetimeConversion; - bool FunctionConversion; - assert(!S.CompareReferenceRelationship( - Initializer->getBeginLoc(), T1, T2, DerivedToBase, ObjCConversion, - ObjCLifetimeConversion, FunctionConversion) && + assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2) && "Must have incompatible references when binding via conversion"); - (void)DerivedToBase; - (void)ObjCConversion; - (void)ObjCLifetimeConversion; - (void)FunctionConversion; // Build the candidate set directly in the initialization sequence // structure, so that it will persist if we fail. @@ -4507,7 +4490,7 @@ static OverloadingResult TryRefInitWithConversionFunction( continue; if (!Info.Constructor->isInvalidDecl() && - Info.Constructor->isConvertingConstructor(AllowExplicitCtors)) { + Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) { if (Info.ConstructorTmpl) S.AddTemplateOverloadCandidate( Info.ConstructorTmpl, Info.FoundDecl, @@ -4552,8 +4535,7 @@ static OverloadingResult TryRefInitWithConversionFunction( // FIXME: Do we need to make sure that we only consider conversion // candidates with reference-compatible results? That might be needed to // break recursion. - if ((AllowExplicitConvs || !Conv->isExplicit()) && - (AllowRValues || + if ((AllowRValues || Conv->getConversionType()->isLValueReferenceType())) { if (ConvTemplate) S.AddTemplateConversionCandidate( @@ -4604,14 +4586,9 @@ static OverloadingResult TryRefInitWithConversionFunction( // Determine whether we'll need to perform derived-to-base adjustments or // other conversions. - bool NewDerivedToBase = false; - bool NewObjCConversion = false; - bool NewObjCLifetimeConversion = false; - bool NewFunctionConversion = false; + Sema::ReferenceConversions RefConv; Sema::ReferenceCompareResult NewRefRelationship = - S.CompareReferenceRelationship( - DeclLoc, T1, cv3T3, NewDerivedToBase, NewObjCConversion, - NewObjCLifetimeConversion, NewFunctionConversion); + S.CompareReferenceRelationship(DeclLoc, T1, cv3T3, &RefConv); // Add the final conversion sequence, if necessary. if (NewRefRelationship == Sema::Ref_Incompatible) { @@ -4641,12 +4618,16 @@ static OverloadingResult TryRefInitWithConversionFunction( Sequence.AddReferenceBindingStep(cv1T4, VK == VK_RValue); VK = IsLValueRef ? VK_LValue : VK_XValue; - if (NewDerivedToBase) + if (RefConv & Sema::ReferenceConversions::DerivedToBase) Sequence.AddDerivedToBaseCastStep(cv1T1, VK); - else if (NewObjCConversion) + else if (RefConv & Sema::ReferenceConversions::ObjC) Sequence.AddObjCObjectConversionStep(cv1T1); - else if (NewFunctionConversion) + else if (RefConv & Sema::ReferenceConversions::Function) Sequence.AddQualificationConversionStep(cv1T1, VK); + else if (RefConv & Sema::ReferenceConversions::Qualification) { + if (!S.Context.hasSameType(cv1T4, cv1T1)) + Sequence.AddQualificationConversionStep(cv1T1, VK); + } return OR_Success; } @@ -4700,17 +4681,15 @@ static void TryReferenceInitializationCore(Sema &S, InitializationSequence &Sequence) { QualType DestType = Entity.getType(); SourceLocation DeclLoc = Initializer->getBeginLoc(); + // Compute some basic properties of the types and the initializer. bool isLValueRef = DestType->isLValueReferenceType(); bool isRValueRef = !isLValueRef; - bool DerivedToBase = false; - bool ObjCConversion = false; - bool ObjCLifetimeConversion = false; - bool FunctionConversion = false; Expr::Classification InitCategory = Initializer->Classify(S.Context); - Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship( - DeclLoc, cv1T1, cv2T2, DerivedToBase, ObjCConversion, - ObjCLifetimeConversion, FunctionConversion); + + Sema::ReferenceConversions RefConv; + Sema::ReferenceCompareResult RefRelationship = + S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, &RefConv); // C++0x [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression of type @@ -4730,19 +4709,25 @@ static void TryReferenceInitializationCore(Sema &S, RefRelationship == Sema::Ref_Related))) { // - is an lvalue (but is not a bit-field), and "cv1 T1" is // reference-compatible with "cv2 T2," or - if (T1Quals != T2Quals) - // Convert to cv1 T2. This should only add qualifiers unless this is a - // c-style cast. The removal of qualifiers in that case notionally - // happens after the reference binding, but that doesn't matter. - Sequence.AddQualificationConversionStep( - S.Context.getQualifiedType(T2, T1Quals), - Initializer->getValueKind()); - if (DerivedToBase) - Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue); - else if (ObjCConversion) - Sequence.AddObjCObjectConversionStep(cv1T1); - else if (FunctionConversion) - Sequence.AddQualificationConversionStep(cv1T1, VK_LValue); + if (RefConv & (Sema::ReferenceConversions::DerivedToBase | + Sema::ReferenceConversions::ObjC)) { + // If we're converting the pointee, add any qualifiers first; + // these qualifiers must all be top-level, so just convert to "cv1 T2". + if (RefConv & (Sema::ReferenceConversions::Qualification)) + Sequence.AddQualificationConversionStep( + S.Context.getQualifiedType(T2, T1Quals), + Initializer->getValueKind()); + if (RefConv & Sema::ReferenceConversions::DerivedToBase) + Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue); + else + Sequence.AddObjCObjectConversionStep(cv1T1); + } else if (RefConv & (Sema::ReferenceConversions::Qualification | + Sema::ReferenceConversions::Function)) { + // Perform a (possibly multi-level) qualification conversion. + // FIXME: Should we use a different step kind for function conversions? + Sequence.AddQualificationConversionStep(cv1T1, + Initializer->getValueKind()); + } // We only create a temporary here when binding a reference to a // bit-field or vector element. Those cases are't supposed to be @@ -4873,14 +4858,19 @@ static void TryReferenceInitializationCore(Sema &S, T4Quals.addAddressSpace(T1Quals.getAddressSpace()); QualType cv1T4WithAS = S.Context.getQualifiedType(T2, T4Quals); Sequence.AddQualificationConversionStep(cv1T4WithAS, ValueKind); + cv1T4 = cv1T4WithAS; } // In any case, the reference is bound to the resulting glvalue (or to // an appropriate base class subobject). - if (DerivedToBase) + if (RefConv & Sema::ReferenceConversions::DerivedToBase) Sequence.AddDerivedToBaseCastStep(cv1T1, ValueKind); - else if (ObjCConversion) + else if (RefConv & Sema::ReferenceConversions::ObjC) Sequence.AddObjCObjectConversionStep(cv1T1); + else if (RefConv & Sema::ReferenceConversions::Qualification) { + if (!S.Context.hasSameType(cv1T4, cv1T1)) + Sequence.AddQualificationConversionStep(cv1T1, ValueKind); + } return; } @@ -5157,7 +5147,7 @@ static void TryUserDefinedConversion(Sema &S, continue; if (!Info.Constructor->isInvalidDecl() && - Info.Constructor->isConvertingConstructor(AllowExplicit)) { + Info.Constructor->isConvertingConstructor(/*AllowExplicit*/true)) { if (Info.ConstructorTmpl) S.AddTemplateOverloadCandidate( Info.ConstructorTmpl, Info.FoundDecl, @@ -5201,16 +5191,14 @@ static void TryUserDefinedConversion(Sema &S, else Conv = cast<CXXConversionDecl>(D); - if (AllowExplicit || !Conv->isExplicit()) { - if (ConvTemplate) - S.AddTemplateConversionCandidate( - ConvTemplate, I.getPair(), ActingDC, Initializer, DestType, - CandidateSet, AllowExplicit, AllowExplicit); - else - S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer, - DestType, CandidateSet, AllowExplicit, - AllowExplicit); - } + if (ConvTemplate) + S.AddTemplateConversionCandidate( + ConvTemplate, I.getPair(), ActingDC, Initializer, DestType, + CandidateSet, AllowExplicit, AllowExplicit); + else + S.AddConversionCandidate(Conv, I.getPair(), ActingDC, Initializer, + DestType, CandidateSet, AllowExplicit, + AllowExplicit); } } } @@ -6154,7 +6142,7 @@ static ExprResult CopyObject(Sema &S, << (int)Entity.getKind() << CurInitExpr->getType() << CurInitExpr->getSourceRange()), - S, OCD_ViableCandidates, CurInitExpr); + S, OCD_AmbiguousCandidates, CurInitExpr); return ExprError(); case OR_Deleted: @@ -6295,7 +6283,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, case OR_Ambiguous: CandidateSet.NoteCandidates(PartialDiagnosticAt(Loc, Diag), S, - OCD_ViableCandidates, CurInitExpr); + OCD_AmbiguousCandidates, CurInitExpr); break; case OR_Deleted: @@ -6653,6 +6641,7 @@ struct IndirectLocalPathEntry { VarInit, LValToRVal, LifetimeBoundCall, + GslReferenceInit, GslPointerInit } Kind; Expr *E; @@ -6783,12 +6772,24 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) { static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call, LocalVisitor Visit) { - auto VisitPointerArg = [&](const Decl *D, Expr *Arg) { + auto VisitPointerArg = [&](const Decl *D, Expr *Arg, bool Value) { // We are not interested in the temporary base objects of gsl Pointers: // Temp().ptr; // Here ptr might not dangle. if (isa<MemberExpr>(Arg->IgnoreImpCasts())) return; - Path.push_back({IndirectLocalPathEntry::GslPointerInit, Arg, D}); + // Once we initialized a value with a reference, it can no longer dangle. + if (!Value) { + for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) { + if (It->Kind == IndirectLocalPathEntry::GslReferenceInit) + continue; + if (It->Kind == IndirectLocalPathEntry::GslPointerInit) + return; + break; + } + } + Path.push_back({Value ? IndirectLocalPathEntry::GslPointerInit + : IndirectLocalPathEntry::GslReferenceInit, + Arg, D}); if (Arg->isGLValue()) visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding, Visit, @@ -6802,18 +6803,21 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call, if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) { const auto *MD = cast_or_null<CXXMethodDecl>(MCE->getDirectCallee()); if (MD && shouldTrackImplicitObjectArg(MD)) - VisitPointerArg(MD, MCE->getImplicitObjectArgument()); + VisitPointerArg(MD, MCE->getImplicitObjectArgument(), + !MD->getReturnType()->isReferenceType()); return; } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call)) { FunctionDecl *Callee = OCE->getDirectCallee(); if (Callee && Callee->isCXXInstanceMember() && shouldTrackImplicitObjectArg(cast<CXXMethodDecl>(Callee))) - VisitPointerArg(Callee, OCE->getArg(0)); + VisitPointerArg(Callee, OCE->getArg(0), + !Callee->getReturnType()->isReferenceType()); return; } else if (auto *CE = dyn_cast<CallExpr>(Call)) { FunctionDecl *Callee = CE->getDirectCallee(); if (Callee && shouldTrackFirstArgument(Callee)) - VisitPointerArg(Callee, CE->getArg(0)); + VisitPointerArg(Callee, CE->getArg(0), + !Callee->getReturnType()->isReferenceType()); return; } @@ -6821,7 +6825,7 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call, const auto *Ctor = CCE->getConstructor(); const CXXRecordDecl *RD = Ctor->getParent(); if (CCE->getNumArgs() > 0 && RD->hasAttr<PointerAttr>()) - VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0]); + VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0], true); } } @@ -6946,8 +6950,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) { if (Visit(Path, Local(MTE), RK)) - visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), Visit, - true, EnableLifetimeWarnings); + visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit, true, + EnableLifetimeWarnings); } if (isa<CallExpr>(Init)) { @@ -7067,9 +7071,8 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, } } else if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L)) { if (MTE->getType().isConstQualified()) - visitLocalsRetainedByInitializer(Path, MTE->GetTemporaryExpr(), - Visit, true, - EnableLifetimeWarnings); + visitLocalsRetainedByInitializer(Path, MTE->getSubExpr(), Visit, + true, EnableLifetimeWarnings); } return false; }, EnableLifetimeWarnings); @@ -7288,6 +7291,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I, case IndirectLocalPathEntry::AddressOf: case IndirectLocalPathEntry::LValToRVal: case IndirectLocalPathEntry::LifetimeBoundCall: + case IndirectLocalPathEntry::GslReferenceInit: case IndirectLocalPathEntry::GslPointerInit: // These exist primarily to mark the path as not permitting or // supporting lifetime extension. @@ -7310,7 +7314,8 @@ static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) { continue; if (It->Kind == IndirectLocalPathEntry::AddressOf) continue; - return It->Kind == IndirectLocalPathEntry::GslPointerInit; + return It->Kind == IndirectLocalPathEntry::GslPointerInit || + It->Kind == IndirectLocalPathEntry::GslReferenceInit; } return false; } @@ -7533,6 +7538,7 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity, case IndirectLocalPathEntry::LifetimeBoundCall: case IndirectLocalPathEntry::GslPointerInit: + case IndirectLocalPathEntry::GslReferenceInit: // FIXME: Consider adding a note for these. break; @@ -7835,9 +7841,8 @@ ExprResult InitializationSequence::Perform(Sema &S, // OpenCL v2.0 s6.13.11.1. atomic variables can be initialized in global scope QualType ETy = Entity.getType(); - Qualifiers TyQualifiers = ETy.getQualifiers(); - bool HasGlobalAS = TyQualifiers.hasAddressSpace() && - TyQualifiers.getAddressSpace() == LangAS::opencl_global; + bool HasGlobalAS = ETy.hasAddressSpace() && + ETy.getAddressSpace() == LangAS::opencl_global; if (S.getLangOpts().OpenCLVersion >= 200 && ETy->isAtomicType() && !HasGlobalAS && @@ -8806,7 +8811,7 @@ bool InitializationSequence::Diagnose(Sema &S, : (S.PDiag(diag::err_ref_init_ambiguous) << DestType << OnlyArg->getType() << Args[0]->getSourceRange())), - S, OCD_ViableCandidates, Args); + S, OCD_AmbiguousCandidates, Args); break; case OR_No_Viable_Function: { @@ -8906,11 +8911,17 @@ bool InitializationSequence::Diagnose(Sema &S, S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) << NonRefType << SourceType << 1 /*addr space*/ << Args[0]->getSourceRange(); - else + else if (DroppedQualifiers.hasQualifiers()) S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) << NonRefType << SourceType << 0 /*cv quals*/ << Qualifiers::fromCVRMask(DroppedQualifiers.getCVRQualifiers()) << DroppedQualifiers.getCVRQualifiers() << Args[0]->getSourceRange(); + else + // FIXME: Consider decomposing the type and explaining which qualifiers + // were dropped where, or on which level a 'const' is missing, etc. + S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals) + << NonRefType << SourceType << 2 /*incompatible quals*/ + << Args[0]->getSourceRange(); break; } @@ -9000,7 +9011,7 @@ bool InitializationSequence::Diagnose(Sema &S, PartialDiagnosticAt(Kind.getLocation(), S.PDiag(diag::err_ovl_ambiguous_init) << DestType << ArgsRange), - S, OCD_ViableCandidates, Args); + S, OCD_AmbiguousCandidates, Args); break; case OR_No_Viable_Function: @@ -9765,9 +9776,8 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // C++ [over.match.copy]p1: (non-list copy-initialization from class) // The converting constructors of T are candidate functions. if (!AllowExplicit) { - // Only consider converting constructors. - if (GD->isExplicit()) - continue; + // Overload resolution checks whether the deduction guide is declared + // explicit for us. // When looking for a converting constructor, deduction guides that // could never be called with one argument are not interesting to @@ -9863,7 +9873,7 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( Kind.getLocation(), PDiag(diag::err_deduced_class_template_ctor_ambiguous) << TemplateName), - *this, OCD_ViableCandidates, Inits); + *this, OCD_AmbiguousCandidates, Inits); return QualType(); case OR_No_Viable_Function: { diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index c6b19a0b195c..c2d14a44f53d 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -361,7 +361,8 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc, ArrayRef<ParmVarDecl *> Params, - ConstexprSpecKind ConstexprKind) { + ConstexprSpecKind ConstexprKind, + Expr *TrailingRequiresClause) { QualType MethodType = MethodTypeInfo->getType(); TemplateParameterList *TemplateParams = getGenericLambdaTemplateParameterList(getCurLambda(), *this); @@ -395,7 +396,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, DeclarationNameInfo(MethodName, IntroducerRange.getBegin(), MethodNameLoc), MethodType, MethodTypeInfo, SC_None, - /*isInline=*/true, ConstexprKind, EndLoc); + /*isInline=*/true, ConstexprKind, EndLoc, TrailingRequiresClause); Method->setAccess(AS_public); if (!TemplateParams) Class->addDecl(Method); @@ -917,6 +918,10 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, /*IsVariadic=*/false, /*IsCXXMethod=*/true)); EPI.HasTrailingReturn = true; EPI.TypeQuals.addConst(); + LangAS AS = getDefaultCXXMethodAddrSpace(); + if (AS != LangAS::Default) + EPI.TypeQuals.addAddressSpace(AS); + // C++1y [expr.prim.lambda]: // The lambda return type is 'auto', which is replaced by the // trailing-return type if provided and/or deduced from 'return' @@ -968,7 +973,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, KnownDependent, Intro.Default); CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params, - ParamInfo.getDeclSpec().getConstexprSpecifier()); + ParamInfo.getDeclSpec().getConstexprSpecifier(), + ParamInfo.getTrailingRequiresClause()); if (ExplicitParams) CheckCXXDefaultArguments(Method); @@ -1248,7 +1254,7 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, SmallVector<Decl*, 4> Fields(Class->fields()); ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(), SourceLocation(), ParsedAttributesView()); - CheckCompletedCXXClass(Class); + CheckCompletedCXXClass(nullptr, Class); PopFunctionScopeInfo(); } @@ -1794,7 +1800,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, SmallVector<Decl*, 4> Fields(Class->fields()); ActOnFields(nullptr, Class->getLocation(), Class, Fields, SourceLocation(), SourceLocation(), ParsedAttributesView()); - CheckCompletedCXXClass(Class); + CheckCompletedCXXClass(nullptr, Class); } Cleanup.mergeFrom(LambdaCleanup); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index d56c5980237c..0ed51de0cc13 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -739,6 +739,18 @@ static void GetOpenCLBuiltinFctOverloads( } } +/// Add extensions to the function declaration. +/// \param S (in/out) The Sema instance. +/// \param BIDecl (in) Description of the builtin. +/// \param FDecl (in/out) FunctionDecl instance. +static void AddOpenCLExtensions(Sema &S, const OpenCLBuiltinStruct &BIDecl, + FunctionDecl *FDecl) { + // Fetch extension associated with a function prototype. + StringRef E = FunctionExtensionTable[BIDecl.Extension]; + if (E != "") + S.setOpenCLExtensionForDecl(FDecl, E); +} + /// When trying to resolve a function name, if isOpenCLBuiltin() returns a /// non-null <Index, Len> pair, then the name is referencing an OpenCL /// builtin function. Add all candidate signatures to the LookUpResult. @@ -765,10 +777,13 @@ static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR, ASTContext &Context = S.Context; // Ignore this BIF if its version does not match the language options. - if (Context.getLangOpts().OpenCLVersion < OpenCLBuiltin.MinVersion) + unsigned OpenCLVersion = Context.getLangOpts().OpenCLVersion; + if (Context.getLangOpts().OpenCLCPlusPlus) + OpenCLVersion = 200; + if (OpenCLVersion < OpenCLBuiltin.MinVersion) continue; if ((OpenCLBuiltin.MaxVersion != 0) && - (Context.getLangOpts().OpenCLVersion >= OpenCLBuiltin.MaxVersion)) + (OpenCLVersion >= OpenCLBuiltin.MaxVersion)) continue; SmallVector<QualType, 1> RetTypes; @@ -812,9 +827,20 @@ static void InsertOCLBuiltinDeclarationsFromTable(Sema &S, LookupResult &LR, } NewOpenCLBuiltin->setParams(ParmList); } - if (!S.getLangOpts().OpenCLCPlusPlus) { + + // Add function attributes. + if (OpenCLBuiltin.IsPure) + NewOpenCLBuiltin->addAttr(PureAttr::CreateImplicit(Context)); + if (OpenCLBuiltin.IsConst) + NewOpenCLBuiltin->addAttr(ConstAttr::CreateImplicit(Context)); + if (OpenCLBuiltin.IsConv) + NewOpenCLBuiltin->addAttr(ConvergentAttr::CreateImplicit(Context)); + + if (!S.getLangOpts().OpenCLCPlusPlus) NewOpenCLBuiltin->addAttr(OverloadableAttr::CreateImplicit(Context)); - } + + AddOpenCLExtensions(S, OpenCLBuiltin, NewOpenCLBuiltin); + LR.addDecl(NewOpenCLBuiltin); } } @@ -3101,11 +3127,10 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, }); } CXXDestructorDecl *DD = RD->getDestructor(); - assert(DD && "record without a destructor"); Result->setMethod(DD); - Result->setKind(DD->isDeleted() ? - SpecialMemberOverloadResult::NoMemberOrDeleted : - SpecialMemberOverloadResult::Success); + Result->setKind(DD && !DD->isDeleted() + ? SpecialMemberOverloadResult::Success + : SpecialMemberOverloadResult::NoMemberOrDeleted); return *Result; } diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index 1fca351bfb09..10de0ca91221 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -31,8 +31,6 @@ static void checkModuleImportContext(Sema &S, Module *M, ExternCLoc = LSD->getBeginLoc(); break; case LinkageSpecDecl::lang_cxx: - case LinkageSpecDecl::lang_cxx_11: - case LinkageSpecDecl::lang_cxx_14: break; } DC = LSD->getParent(); diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index ac810745d2f5..f6717f4cbe5e 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -306,6 +306,8 @@ makePropertyAttributesAsWritten(unsigned Attributes) { attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic; if (Attributes & ObjCDeclSpec::DQ_PR_class) attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_class; + if (Attributes & ObjCDeclSpec::DQ_PR_direct) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_direct; return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten; } @@ -705,9 +707,21 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable); - if (Attributes & ObjCDeclSpec::DQ_PR_class) + if (Attributes & ObjCDeclSpec::DQ_PR_class) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class); + if ((Attributes & ObjCDeclSpec::DQ_PR_direct) || + CDecl->hasAttr<ObjCDirectMembersAttr>()) { + if (isa<ObjCProtocolDecl>(CDecl)) { + Diag(PDecl->getLocation(), diag::err_objc_direct_on_protocol) << true; + } else if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) { + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_direct); + } else { + Diag(PDecl->getLocation(), diag::warn_objc_direct_property_ignored) + << PDecl->getDeclName(); + } + } + return PDecl; } @@ -1037,6 +1051,33 @@ static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop, return false; } +/// Create a synthesized property accessor stub inside the \@implementation. +static ObjCMethodDecl * +RedeclarePropertyAccessor(ASTContext &Context, ObjCImplementationDecl *Impl, + ObjCMethodDecl *AccessorDecl, SourceLocation AtLoc, + SourceLocation PropertyLoc) { + ObjCMethodDecl *Decl = AccessorDecl; + ObjCMethodDecl *ImplDecl = ObjCMethodDecl::Create( + Context, AtLoc.isValid() ? AtLoc : Decl->getBeginLoc(), + PropertyLoc.isValid() ? PropertyLoc : Decl->getEndLoc(), + Decl->getSelector(), Decl->getReturnType(), + Decl->getReturnTypeSourceInfo(), Impl, Decl->isInstanceMethod(), + Decl->isVariadic(), Decl->isPropertyAccessor(), + /* isSynthesized*/ true, Decl->isImplicit(), Decl->isDefined(), + Decl->getImplementationControl(), Decl->hasRelatedResultType()); + ImplDecl->getMethodFamily(); + if (Decl->hasAttrs()) + ImplDecl->setAttrs(Decl->getAttrs()); + ImplDecl->setSelfDecl(Decl->getSelfDecl()); + ImplDecl->setCmdDecl(Decl->getCmdDecl()); + SmallVector<SourceLocation, 1> SelLocs; + Decl->getSelectorLocs(SelLocs); + ImplDecl->setMethodParams(Context, Decl->parameters(), SelLocs); + ImplDecl->setLexicalDeclContext(Impl); + ImplDecl->setDefined(false); + return ImplDecl; +} + /// ActOnPropertyImplDecl - This routine performs semantic checks and /// builds the AST node for a property implementation declaration; declared /// as \@synthesize or \@dynamic. @@ -1404,6 +1445,18 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (ObjCMethodDecl *getterMethod = property->getGetterMethodDecl()) { getterMethod->createImplicitParams(Context, IDecl); + + // Redeclare the getter within the implementation as DeclContext. + if (Synthesize) { + // If the method hasn't been overridden, create a synthesized implementation. + ObjCMethodDecl *OMD = ClassImpDecl->getMethod( + getterMethod->getSelector(), getterMethod->isInstanceMethod()); + if (!OMD) + OMD = RedeclarePropertyAccessor(Context, IC, getterMethod, AtLoc, + PropertyLoc); + PIDecl->setGetterMethodDecl(OMD); + } + if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr && Ivar->getType()->isRecordType()) { // For Objective-C++, need to synthesize the AST for the IVAR object to be @@ -1456,8 +1509,20 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, break; } } + if (ObjCMethodDecl *setterMethod = property->getSetterMethodDecl()) { setterMethod->createImplicitParams(Context, IDecl); + + // Redeclare the setter within the implementation as DeclContext. + if (Synthesize) { + ObjCMethodDecl *OMD = ClassImpDecl->getMethod( + setterMethod->getSelector(), setterMethod->isInstanceMethod()); + if (!OMD) + OMD = RedeclarePropertyAccessor(Context, IC, setterMethod, + AtLoc, PropertyLoc); + PIDecl->setSetterMethodDecl(OMD); + } + if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr && Ivar->getType()->isRecordType()) { // FIXME. Eventually we want to do this for Objective-C as well. @@ -1852,10 +1917,12 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, if (IMPDecl->FindPropertyImplDecl( Prop->getIdentifier(), Prop->getQueryKind())) continue; - if (IMPDecl->getInstanceMethod(Prop->getGetterName())) { + ObjCMethodDecl *ImpMethod = IMPDecl->getInstanceMethod(Prop->getGetterName()); + if (ImpMethod && !ImpMethod->getBody()) { if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly) continue; - if (IMPDecl->getInstanceMethod(Prop->getSetterName())) + ImpMethod = IMPDecl->getInstanceMethod(Prop->getSetterName()); + if (ImpMethod && !ImpMethod->getBody()) continue; } if (ObjCPropertyImplDecl *PID = @@ -2083,7 +2150,6 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) { for (const auto *propertyImpl : impDecl->property_impls()) { const auto *property = propertyImpl->getPropertyDecl(); - // Warn about null_resettable properties with synthesized setters, // because the setter won't properly handle nil. if (propertyImpl->getPropertyImplementation() @@ -2092,16 +2158,16 @@ void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) ObjCPropertyDecl::OBJC_PR_null_resettable) && property->getGetterMethodDecl() && property->getSetterMethodDecl()) { - auto *getterMethod = property->getGetterMethodDecl(); - auto *setterMethod = property->getSetterMethodDecl(); - if (!impDecl->getInstanceMethod(setterMethod->getSelector()) && - !impDecl->getInstanceMethod(getterMethod->getSelector())) { + auto *getterImpl = propertyImpl->getGetterMethodDecl(); + auto *setterImpl = propertyImpl->getSetterMethodDecl(); + if ((!getterImpl || getterImpl->isSynthesizedAccessorStub()) && + (!setterImpl || setterImpl->isSynthesizedAccessorStub())) { SourceLocation loc = propertyImpl->getLocation(); if (loc.isInvalid()) loc = impDecl->getBeginLoc(); Diag(loc, diag::warn_null_resettable_setter) - << setterMethod->getSelector() << property->getDeclName(); + << setterImpl->getSelector() << property->getDeclName(); } } } @@ -2125,7 +2191,6 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, const ObjCPropertyDecl *Property = I->second; ObjCMethodDecl *GetterMethod = nullptr; ObjCMethodDecl *SetterMethod = nullptr; - bool LookedUpGetterSetter = false; unsigned Attributes = Property->getPropertyAttributes(); unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten(); @@ -2138,7 +2203,10 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, SetterMethod = Property->isClassProperty() ? IMPDecl->getClassMethod(Property->getSetterName()) : IMPDecl->getInstanceMethod(Property->getSetterName()); - LookedUpGetterSetter = true; + if (GetterMethod && GetterMethod->isSynthesizedAccessorStub()) + GetterMethod = nullptr; + if (SetterMethod && SetterMethod->isSynthesizedAccessorStub()) + SetterMethod = nullptr; if (GetterMethod) { Diag(GetterMethod->getLocation(), diag::warn_default_atomic_custom_getter_setter) @@ -2161,15 +2229,13 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, Property->getIdentifier(), Property->getQueryKind())) { if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) continue; - if (!LookedUpGetterSetter) { - GetterMethod = Property->isClassProperty() ? - IMPDecl->getClassMethod(Property->getGetterName()) : - IMPDecl->getInstanceMethod(Property->getGetterName()); - SetterMethod = Property->isClassProperty() ? - IMPDecl->getClassMethod(Property->getSetterName()) : - IMPDecl->getInstanceMethod(Property->getSetterName()); - } - if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) { + GetterMethod = PIDecl->getGetterMethodDecl(); + SetterMethod = PIDecl->getSetterMethodDecl(); + if (GetterMethod && GetterMethod->isSynthesizedAccessorStub()) + GetterMethod = nullptr; + if (SetterMethod && SetterMethod->isSynthesizedAccessorStub()) + SetterMethod = nullptr; + if ((bool)GetterMethod ^ (bool)SetterMethod) { SourceLocation MethodLoc = (GetterMethod ? GetterMethod->getLocation() : SetterMethod->getLocation()); @@ -2210,8 +2276,10 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D for (const auto *PID : D->property_impls()) { const ObjCPropertyDecl *PD = PID->getPropertyDecl(); if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() && - !PD->isClassProperty() && - !D->getInstanceMethod(PD->getGetterName())) { + !PD->isClassProperty()) { + ObjCMethodDecl *IM = PID->getGetterMethodDecl(); + if (IM && !IM->isSynthesizedAccessorStub()) + continue; ObjCMethodDecl *method = PD->getGetterMethodDecl(); if (!method) continue; @@ -2396,20 +2464,21 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { } } - GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, - property->getGetterName(), - resultTy, nullptr, CD, - !IsClassProperty, /*isVariadic=*/false, - /*isPropertyAccessor=*/true, - /*isImplicitlyDeclared=*/true, /*isDefined=*/false, - (property->getPropertyImplementation() == - ObjCPropertyDecl::Optional) ? - ObjCMethodDecl::Optional : - ObjCMethodDecl::Required); + GetterMethod = ObjCMethodDecl::Create( + Context, Loc, Loc, property->getGetterName(), resultTy, nullptr, CD, + !IsClassProperty, /*isVariadic=*/false, + /*isPropertyAccessor=*/true, /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, /*isDefined=*/false, + (property->getPropertyImplementation() == ObjCPropertyDecl::Optional) + ? ObjCMethodDecl::Optional + : ObjCMethodDecl::Required); CD->addDecl(GetterMethod); AddPropertyAttrs(*this, GetterMethod, property); + if (property->isDirectProperty()) + GetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc)); + if (property->hasAttr<NSReturnsNotRetainedAttr>()) GetterMethod->addAttr(NSReturnsNotRetainedAttr::CreateImplicit(Context, Loc)); @@ -2429,6 +2498,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { // A user declared getter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation GetterMethod->setPropertyAccessor(true); + + GetterMethod->createImplicitParams(Context, + GetterMethod->getClassInterface()); property->setGetterMethodDecl(GetterMethod); // Skip setter if property is read-only. @@ -2447,6 +2519,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { nullptr, CD, !IsClassProperty, /*isVariadic=*/false, /*isPropertyAccessor=*/true, + /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, (property->getPropertyImplementation() == @@ -2483,6 +2556,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { AddPropertyAttrs(*this, SetterMethod, property); + if (property->isDirectProperty()) + SetterMethod->addAttr(ObjCDirectAttr::CreateImplicit(Context, Loc)); + CD->addDecl(SetterMethod); if (const SectionAttr *SA = property->getAttr<SectionAttr>()) SetterMethod->addAttr(SectionAttr::CreateImplicit( @@ -2496,6 +2572,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { // A user declared setter will be synthesize when @synthesize of // the property with the same name is seen in the @implementation SetterMethod->setPropertyAccessor(true); + + SetterMethod->createImplicitParams(Context, + SetterMethod->getClassInterface()); property->setSetterMethodDecl(SetterMethod); } // Add any synthesized methods to the global pool. This allows us to diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index c7e0d2aee036..3fce0e27e9b3 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -23,13 +23,17 @@ #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeOrdering.h" #include "clang/Basic/OpenMPKinds.h" +#include "clang/Basic/PartialDiagnostic.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" +#include "llvm/ADT/IndexedMap.h" #include "llvm/ADT/PointerEmbeddedInt.h" +#include "llvm/Frontend/OpenMP/OMPConstants.h" using namespace clang; +using namespace llvm::omp; //===----------------------------------------------------------------------===// // Stack of data-sharing attributes for variables @@ -48,12 +52,6 @@ enum DefaultDataSharingAttributes { DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'. }; -/// Attributes of the defaultmap clause. -enum DefaultMapAttributes { - DMA_unspecified, /// Default mapping is not specified. - DMA_tofrom_scalar, /// Default mapping is 'tofrom:scalar'. -}; - /// Stack for tracking declarations used in OpenMP directives and /// clauses and their data-sharing attributes. class DSAStackTy { @@ -85,7 +83,7 @@ private: DeclRefExpr *PrivateCopy = nullptr; }; using DeclSAMapTy = llvm::SmallDenseMap<const ValueDecl *, DSAInfo, 8>; - using AlignedMapTy = llvm::SmallDenseMap<const ValueDecl *, const Expr *, 8>; + using UsedRefMapTy = llvm::SmallDenseMap<const ValueDecl *, const Expr *, 8>; using LCDeclInfo = std::pair<unsigned, VarDecl *>; using LoopControlVariablesMapTy = llvm::SmallDenseMap<const ValueDecl *, LCDeclInfo, 8>; @@ -115,17 +113,25 @@ private: }; using DeclReductionMapTy = llvm::SmallDenseMap<const ValueDecl *, ReductionData, 4>; + struct DefaultmapInfo { + OpenMPDefaultmapClauseModifier ImplicitBehavior = + OMPC_DEFAULTMAP_MODIFIER_unknown; + SourceLocation SLoc; + DefaultmapInfo() = default; + DefaultmapInfo(OpenMPDefaultmapClauseModifier M, SourceLocation Loc) + : ImplicitBehavior(M), SLoc(Loc) {} + }; struct SharingMapTy { DeclSAMapTy SharingMap; DeclReductionMapTy ReductionMap; - AlignedMapTy AlignedMap; + UsedRefMapTy AlignedMap; + UsedRefMapTy NontemporalMap; MappedExprComponentsTy MappedExprComponents; LoopControlVariablesMapTy LCVMap; DefaultDataSharingAttributes DefaultAttr = DSA_unspecified; SourceLocation DefaultAttrLoc; - DefaultMapAttributes DefaultMapAttr = DMA_unspecified; - SourceLocation DefaultMapAttrLoc; + DefaultmapInfo DefaultmapMap[OMPC_DEFAULTMAP_unknown]; OpenMPDirectiveKind Directive = OMPD_unknown; DeclarationNameInfo DirectiveName; Scope *CurScope = nullptr; @@ -416,6 +422,10 @@ public: /// add it and return NULL; otherwise return previous occurrence's expression /// for diagnostics. const Expr *addUniqueAligned(const ValueDecl *D, const Expr *NewDE); + /// If 'nontemporal' declaration for given variable \a D was not seen yet, + /// add it and return NULL; otherwise return previous occurrence's expression + /// for diagnostics. + const Expr *addUniqueNontemporal(const ValueDecl *D, const Expr *NewDE); /// Register specified variable as loop control variable. void addLoopControlVariable(const ValueDecl *D, VarDecl *Capture); @@ -592,10 +602,18 @@ public: getTopOfStack().DefaultAttr = DSA_shared; getTopOfStack().DefaultAttrLoc = Loc; } - /// Set default data mapping attribute to 'tofrom:scalar'. - void setDefaultDMAToFromScalar(SourceLocation Loc) { - getTopOfStack().DefaultMapAttr = DMA_tofrom_scalar; - getTopOfStack().DefaultMapAttrLoc = Loc; + /// Set default data mapping attribute to Modifier:Kind + void setDefaultDMAAttr(OpenMPDefaultmapClauseModifier M, + OpenMPDefaultmapClauseKind Kind, + SourceLocation Loc) { + DefaultmapInfo &DMI = getTopOfStack().DefaultmapMap[Kind]; + DMI.ImplicitBehavior = M; + DMI.SLoc = Loc; + } + /// Check whether the implicit-behavior has been set in defaultmap + bool checkDefaultmapCategory(OpenMPDefaultmapClauseKind VariableCategory) { + return getTopOfStack().DefaultmapMap[VariableCategory].ImplicitBehavior != + OMPC_DEFAULTMAP_MODIFIER_unknown; } DefaultDataSharingAttributes getDefaultDSA() const { @@ -606,16 +624,53 @@ public: return isStackEmpty() ? SourceLocation() : getTopOfStack().DefaultAttrLoc; } - DefaultMapAttributes getDefaultDMA() const { - return isStackEmpty() ? DMA_unspecified - : getTopOfStack().DefaultMapAttr; + OpenMPDefaultmapClauseModifier + getDefaultmapModifier(OpenMPDefaultmapClauseKind Kind) const { + return isStackEmpty() + ? OMPC_DEFAULTMAP_MODIFIER_unknown + : getTopOfStack().DefaultmapMap[Kind].ImplicitBehavior; } - DefaultMapAttributes getDefaultDMAAtLevel(unsigned Level) const { - return getStackElemAtLevel(Level).DefaultMapAttr; + OpenMPDefaultmapClauseModifier + getDefaultmapModifierAtLevel(unsigned Level, + OpenMPDefaultmapClauseKind Kind) const { + return getStackElemAtLevel(Level).DefaultmapMap[Kind].ImplicitBehavior; } - SourceLocation getDefaultDMALocation() const { - return isStackEmpty() ? SourceLocation() - : getTopOfStack().DefaultMapAttrLoc; + bool isDefaultmapCapturedByRef(unsigned Level, + OpenMPDefaultmapClauseKind Kind) const { + OpenMPDefaultmapClauseModifier M = + getDefaultmapModifierAtLevel(Level, Kind); + if (Kind == OMPC_DEFAULTMAP_scalar || Kind == OMPC_DEFAULTMAP_pointer) { + return (M == OMPC_DEFAULTMAP_MODIFIER_alloc) || + (M == OMPC_DEFAULTMAP_MODIFIER_to) || + (M == OMPC_DEFAULTMAP_MODIFIER_from) || + (M == OMPC_DEFAULTMAP_MODIFIER_tofrom); + } + return true; + } + static bool mustBeFirstprivateBase(OpenMPDefaultmapClauseModifier M, + OpenMPDefaultmapClauseKind Kind) { + switch (Kind) { + case OMPC_DEFAULTMAP_scalar: + case OMPC_DEFAULTMAP_pointer: + return (M == OMPC_DEFAULTMAP_MODIFIER_unknown) || + (M == OMPC_DEFAULTMAP_MODIFIER_firstprivate) || + (M == OMPC_DEFAULTMAP_MODIFIER_default); + case OMPC_DEFAULTMAP_aggregate: + return M == OMPC_DEFAULTMAP_MODIFIER_firstprivate; + default: + break; + } + llvm_unreachable("Unexpected OpenMPDefaultmapClauseKind enum"); + } + bool mustBeFirstprivateAtLevel(unsigned Level, + OpenMPDefaultmapClauseKind Kind) const { + OpenMPDefaultmapClauseModifier M = + getDefaultmapModifierAtLevel(Level, Kind); + return mustBeFirstprivateBase(M, Kind); + } + bool mustBeFirstprivate(OpenMPDefaultmapClauseKind Kind) const { + OpenMPDefaultmapClauseModifier M = getDefaultmapModifier(Kind); + return mustBeFirstprivateBase(M, Kind); } /// Checks if the specified variable is a threadprivate. @@ -862,7 +917,7 @@ static const Expr *getExprAsWritten(const Expr *E) { E = FE->getSubExpr(); if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E)) - E = MTE->GetTemporaryExpr(); + E = MTE->getSubExpr(); while (const auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E)) E = Binder->getSubExpr(); @@ -1023,6 +1078,21 @@ const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D, return It->second; } +const Expr *DSAStackTy::addUniqueNontemporal(const ValueDecl *D, + const Expr *NewDE) { + assert(!isStackEmpty() && "Data sharing attributes stack is empty"); + D = getCanonicalDecl(D); + SharingMapTy &StackElem = getTopOfStack(); + auto It = StackElem.NontemporalMap.find(D); + if (It == StackElem.NontemporalMap.end()) { + assert(NewDE && "Unexpected nullptr expr to be added into aligned map"); + StackElem.NontemporalMap[D] = NewDE; + return nullptr; + } + assert(It->second && "Unexpected nullptr expr in the aligned map"); + return It->second; +} + void DSAStackTy::addLoopControlVariable(const ValueDecl *D, VarDecl *Capture) { assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); @@ -1716,6 +1786,20 @@ void Sema::checkOpenMPDeviceExpr(const Expr *E) { << Context.getTargetInfo().getTriple().str() << E->getSourceRange(); } +static OpenMPDefaultmapClauseKind +getVariableCategoryFromDecl(const LangOptions &LO, const ValueDecl *VD) { + if (LO.OpenMP <= 45) { + if (VD->getType().getNonReferenceType()->isScalarType()) + return OMPC_DEFAULTMAP_scalar; + return OMPC_DEFAULTMAP_aggregate; + } + if (VD->getType().getNonReferenceType()->isAnyPointerType()) + return OMPC_DEFAULTMAP_pointer; + if (VD->getType().getNonReferenceType()->isScalarType()) + return OMPC_DEFAULTMAP_scalar; + return OMPC_DEFAULTMAP_aggregate; +} + bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, unsigned OpenMPCaptureLevel) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); @@ -1834,11 +1918,13 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, } else { // By default, all the data that has a scalar type is mapped by copy // (except for reduction variables). + // Defaultmap scalar is mutual exclusive to defaultmap pointer IsByRef = (DSAStack->isForceCaptureByReferenceInTargetExecutable() && !Ty->isAnyPointerType()) || !Ty->isScalarType() || - DSAStack->getDefaultDMAAtLevel(Level) == DMA_tofrom_scalar || + DSAStack->isDefaultmapCapturedByRef( + Level, getVariableCategoryFromDecl(LangOpts, D)) || DSAStack->hasExplicitDSA( D, [](OpenMPClauseKind K) { return K == OMPC_reduction; }, Level); } @@ -1894,6 +1980,11 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, assert(LangOpts.OpenMP && "OpenMP is not allowed"); D = getCanonicalDecl(D); + auto *VD = dyn_cast<VarDecl>(D); + // Do not capture constexpr variables. + if (VD && VD->isConstexpr()) + return nullptr; + // If we want to determine whether the variable should be captured from the // perspective of the current capturing scope, and we've already left all the // capturing scopes of the top directive on the stack, check from the @@ -1904,7 +1995,6 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, // If we are attempting to capture a global variable in a directive with // 'target' we return true so that this global is also mapped to the device. // - auto *VD = dyn_cast<VarDecl>(D); if (VD && !VD->hasLocalStorage() && (getCurCapturedRegion() || getCurBlock() || getCurLambda())) { if (isInOpenMPDeclareTargetContext()) { @@ -2051,9 +2141,8 @@ void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D, if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, NewLevel)) { OMPC = OMPC_map; - if (D->getType()->isScalarType() && - DSAStack->getDefaultDMAAtLevel(NewLevel) != - DefaultMapAttributes::DMA_tofrom_scalar) + if (DSAStack->mustBeFirstprivateAtLevel( + NewLevel, getVariableCategoryFromDecl(LangOpts, D))) OMPC = OMPC_firstprivate; break; } @@ -2141,6 +2230,11 @@ void Sema::EndOpenMPClause() { static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, ArrayRef<OMPClause *> Clauses); +static std::pair<ValueDecl *, bool> +getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, + SourceRange &ERange, bool AllowArraySection = false); +static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr, + bool WithInit); void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // OpenMP [2.14.3.5, Restrictions, C/C++, p.1] @@ -2185,6 +2279,31 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { } } Clause->setPrivateCopies(PrivateCopies); + continue; + } + // Finalize nontemporal clause by handling private copies, if any. + if (auto *Clause = dyn_cast<OMPNontemporalClause>(C)) { + SmallVector<Expr *, 8> PrivateRefs; + for (Expr *RefExpr : Clause->varlists()) { + assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); + if (Res.second) + // It will be analyzed later. + PrivateRefs.push_back(RefExpr); + ValueDecl *D = Res.first; + if (!D) + continue; + + const DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(D, /*FromParent=*/false); + PrivateRefs.push_back(DVar.PrivateCopy ? DVar.PrivateCopy + : SimpleRefExpr); + } + Clause->setPrivateRefs(PrivateRefs); + continue; } } // Check allocate clauses. @@ -2759,14 +2878,51 @@ static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack, } } +static OpenMPMapClauseKind +getMapClauseKindFromModifier(OpenMPDefaultmapClauseModifier M, + bool IsAggregateOrDeclareTarget) { + OpenMPMapClauseKind Kind = OMPC_MAP_unknown; + switch (M) { + case OMPC_DEFAULTMAP_MODIFIER_alloc: + Kind = OMPC_MAP_alloc; + break; + case OMPC_DEFAULTMAP_MODIFIER_to: + Kind = OMPC_MAP_to; + break; + case OMPC_DEFAULTMAP_MODIFIER_from: + Kind = OMPC_MAP_from; + break; + case OMPC_DEFAULTMAP_MODIFIER_tofrom: + Kind = OMPC_MAP_tofrom; + break; + case OMPC_DEFAULTMAP_MODIFIER_firstprivate: + case OMPC_DEFAULTMAP_MODIFIER_last: + llvm_unreachable("Unexpected defaultmap implicit behavior"); + case OMPC_DEFAULTMAP_MODIFIER_none: + case OMPC_DEFAULTMAP_MODIFIER_default: + case OMPC_DEFAULTMAP_MODIFIER_unknown: + // IsAggregateOrDeclareTarget could be true if: + // 1. the implicit behavior for aggregate is tofrom + // 2. it's a declare target link + if (IsAggregateOrDeclareTarget) { + Kind = OMPC_MAP_tofrom; + break; + } + llvm_unreachable("Unexpected defaultmap implicit behavior"); + } + assert(Kind != OMPC_MAP_unknown && "Expect map kind to be known"); + return Kind; +} + namespace { class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> { DSAStackTy *Stack; Sema &SemaRef; bool ErrorFound = false; + bool TryCaptureCXXThisMembers = false; CapturedStmt *CS = nullptr; llvm::SmallVector<Expr *, 4> ImplicitFirstprivate; - llvm::SmallVector<Expr *, 4> ImplicitMap; + llvm::SmallVector<Expr *, 4> ImplicitMap[OMPC_MAP_delete]; Sema::VarsWithInheritedDSAType VarsWithInheritedDSA; llvm::SmallDenseSet<const ValueDecl *, 4> ImplicitDeclarations; @@ -2775,12 +2931,26 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> { if (!S->hasAssociatedStmt() || !S->getAssociatedStmt()) return; visitSubCaptures(S->getInnermostCapturedStmt()); + // Try to capture inner this->member references to generate correct mappings + // and diagnostics. + if (TryCaptureCXXThisMembers || + (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) && + llvm::any_of(S->getInnermostCapturedStmt()->captures(), + [](const CapturedStmt::Capture &C) { + return C.capturesThis(); + }))) { + bool SavedTryCaptureCXXThisMembers = TryCaptureCXXThisMembers; + TryCaptureCXXThisMembers = true; + Visit(S->getInnermostCapturedStmt()->getCapturedStmt()); + TryCaptureCXXThisMembers = SavedTryCaptureCXXThisMembers; + } } public: void VisitDeclRefExpr(DeclRefExpr *E) { - if (E->isTypeDependent() || E->isValueDependent() || - E->containsUnexpandedParameterPack() || E->isInstantiationDependent()) + if (TryCaptureCXXThisMembers || E->isTypeDependent() || + E->isValueDependent() || E->containsUnexpandedParameterPack() || + E->isInstantiationDependent()) return; if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) { // Check the datasharing rules for the expressions in the clauses. @@ -2825,6 +2995,39 @@ public: return; } + // OpenMP 5.0 [2.19.7.2, defaultmap clause, Description] + // If implicit-behavior is none, each variable referenced in the + // construct that does not have a predetermined data-sharing attribute + // and does not appear in a to or link clause on a declare target + // directive must be listed in a data-mapping attribute clause, a + // data-haring attribute clause (including a data-sharing attribute + // clause on a combined construct where target. is one of the + // constituent constructs), or an is_device_ptr clause. + OpenMPDefaultmapClauseKind ClauseKind = + getVariableCategoryFromDecl(SemaRef.getLangOpts(), VD); + if (SemaRef.getLangOpts().OpenMP >= 50) { + bool IsModifierNone = Stack->getDefaultmapModifier(ClauseKind) == + OMPC_DEFAULTMAP_MODIFIER_none; + if (DVar.CKind == OMPC_unknown && IsModifierNone && + VarsWithInheritedDSA.count(VD) == 0 && !Res) { + // Only check for data-mapping attribute and is_device_ptr here + // since we have already make sure that the declaration does not + // have a data-sharing attribute above + if (!Stack->checkMappableExprComponentListsForDecl( + VD, /*CurrentRegionOnly=*/true, + [VD](OMPClauseMappableExprCommon::MappableExprComponentListRef + MapExprComponents, + OpenMPClauseKind) { + auto MI = MapExprComponents.rbegin(); + auto ME = MapExprComponents.rend(); + return MI != ME && MI->getAssociatedDeclaration() == VD; + })) { + VarsWithInheritedDSA[VD] = E; + return; + } + } + } + if (isOpenMPTargetExecutionDirective(DKind) && !Stack->isLoopControlVariable(VD).first) { if (!Stack->checkMappableExprComponentListsForDecl( @@ -2854,13 +3057,16 @@ public: VD->getType().getNonReferenceType()->getAsCXXRecordDecl()) IsFirstprivate = RD->isLambda(); IsFirstprivate = - IsFirstprivate || - (VD->getType().getNonReferenceType()->isScalarType() && - Stack->getDefaultDMA() != DMA_tofrom_scalar && !Res); - if (IsFirstprivate) + IsFirstprivate || (Stack->mustBeFirstprivate(ClauseKind) && !Res); + if (IsFirstprivate) { ImplicitFirstprivate.emplace_back(E); - else - ImplicitMap.emplace_back(E); + } else { + OpenMPDefaultmapClauseModifier M = + Stack->getDefaultmapModifier(ClauseKind); + OpenMPMapClauseKind Kind = getMapClauseKindFromModifier( + M, ClauseKind == OMPC_DEFAULTMAP_aggregate || Res); + ImplicitMap[Kind].emplace_back(E); + } return; } } @@ -2939,7 +3145,11 @@ public: if (Stack->isClassPreviouslyMapped(TE->getType())) return; - ImplicitMap.emplace_back(E); + OpenMPDefaultmapClauseModifier Modifier = + Stack->getDefaultmapModifier(OMPC_DEFAULTMAP_aggregate); + OpenMPMapClauseKind Kind = getMapClauseKindFromModifier( + Modifier, /*IsAggregateOrDeclareTarget*/ true); + ImplicitMap[Kind].emplace_back(E); return; } @@ -3014,7 +3224,7 @@ public: })) { Visit(E->getBase()); } - } else { + } else if (!TryCaptureCXXThisMembers) { Visit(E->getBase()); } } @@ -3068,7 +3278,9 @@ public: ArrayRef<Expr *> getImplicitFirstprivate() const { return ImplicitFirstprivate; } - ArrayRef<Expr *> getImplicitMap() const { return ImplicitMap; } + ArrayRef<Expr *> getImplicitMap(OpenMPDefaultmapClauseKind Kind) const { + return ImplicitMap[Kind]; + } const Sema::VarsWithInheritedDSAType &getVarsWithInheritedDSA() const { return VarsWithInheritedDSA; } @@ -3090,6 +3302,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_parallel_sections: + case OMPD_parallel_master: case OMPD_teams: case OMPD_teams_distribute: case OMPD_teams_distribute_simd: { @@ -3282,7 +3495,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { AlwaysInlineAttr::Keyword_forceinline)); break; } - case OMPD_parallel_master_taskloop: { + case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1) .withConst(); @@ -3779,7 +3993,10 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, ShouldBeInTargetRegion, ShouldBeInTeamsRegion } Recommend = NoRecommend; - if (isOpenMPSimdDirective(ParentRegion) && CurrentRegion != OMPD_ordered) { + if (isOpenMPSimdDirective(ParentRegion) && + ((SemaRef.LangOpts.OpenMP <= 45 && CurrentRegion != OMPD_ordered) || + (SemaRef.LangOpts.OpenMP >= 50 && CurrentRegion != OMPD_ordered && + CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic))) { // OpenMP [2.16, Nesting of Regions] // OpenMP constructs may not be nested inside a simd region. // OpenMP [2.8.1,simd Construct, Restrictions] @@ -3788,9 +4005,14 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, // Allowing a SIMD construct nested in another SIMD construct is an // extension. The OpenMP 4.5 spec does not allow it. Issue a warning // message. + // OpenMP 5.0 [2.9.3.1, simd Construct, Restrictions] + // The only OpenMP constructs that can be encountered during execution of + // a simd region are the atomic construct, the loop construct, the simd + // construct and the ordered construct with the simd clause. SemaRef.Diag(StartLoc, (CurrentRegion != OMPD_simd) ? diag::err_omp_prohibited_region_simd - : diag::warn_omp_nesting_simd); + : diag::warn_omp_nesting_simd) + << (SemaRef.LangOpts.OpenMP >= 50 ? 1 : 0); return CurrentRegion != OMPD_simd; } if (ParentRegion == OMPD_atomic) { @@ -3888,6 +4110,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || isOpenMPTaskingDirective(ParentRegion) || ParentRegion == OMPD_master || + ParentRegion == OMPD_parallel_master || ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered; } else if (isOpenMPWorksharingDirective(CurrentRegion) && @@ -3899,6 +4122,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || isOpenMPTaskingDirective(ParentRegion) || ParentRegion == OMPD_master || + ParentRegion == OMPD_parallel_master || ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered; Recommend = ShouldBeInParallelRegion; @@ -3982,13 +4206,17 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, return false; } +struct Kind2Unsigned { + using argument_type = OpenMPDirectiveKind; + unsigned operator()(argument_type DK) { return unsigned(DK); } +}; static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, ArrayRef<OMPClause *> Clauses, ArrayRef<OpenMPDirectiveKind> AllowedNameModifiers) { bool ErrorFound = false; unsigned NamedModifiersNumber = 0; - SmallVector<const OMPIfClause *, OMPC_unknown + 1> FoundNameModifiers( - OMPD_unknown + 1); + llvm::IndexedMap<const OMPIfClause *, Kind2Unsigned> FoundNameModifiers; + FoundNameModifiers.resize(unsigned(OMPD_unknown) + 1); SmallVector<SourceLocation, 4> NameModifierLoc; for (const OMPClause *C : Clauses) { if (const auto *IC = dyn_cast_or_null<OMPIfClause>(C)) { @@ -4064,9 +4292,10 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, return ErrorFound; } -static std::pair<ValueDecl *, bool> -getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, - SourceRange &ERange, bool AllowArraySection = false) { +static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, + SourceLocation &ELoc, + SourceRange &ERange, + bool AllowArraySection) { if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || RefExpr->containsUnexpandedParameterPack()) return std::make_pair(nullptr, true); @@ -4271,8 +4500,12 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( SmallVector<Expr *, 4> ImplicitFirstprivates( DSAChecker.getImplicitFirstprivate().begin(), DSAChecker.getImplicitFirstprivate().end()); - SmallVector<Expr *, 4> ImplicitMaps(DSAChecker.getImplicitMap().begin(), - DSAChecker.getImplicitMap().end()); + SmallVector<Expr *, 4> ImplicitMaps[OMPC_MAP_delete]; + for (unsigned I = 0; I < OMPC_MAP_delete; ++I) { + ArrayRef<Expr *> ImplicitMap = + DSAChecker.getImplicitMap(static_cast<OpenMPDefaultmapClauseKind>(I)); + ImplicitMaps[I].append(ImplicitMap.begin(), ImplicitMap.end()); + } // Mark taskgroup task_reduction descriptors as implicitly firstprivate. for (OMPClause *C : Clauses) { if (auto *IRC = dyn_cast<OMPInReductionClause>(C)) { @@ -4292,16 +4525,21 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( ErrorFound = true; } } - if (!ImplicitMaps.empty()) { + int ClauseKindCnt = -1; + for (ArrayRef<Expr *> ImplicitMap : ImplicitMaps) { + ++ClauseKindCnt; + if (ImplicitMap.empty()) + continue; CXXScopeSpec MapperIdScopeSpec; DeclarationNameInfo MapperId; + auto Kind = static_cast<OpenMPMapClauseKind>(ClauseKindCnt); if (OMPClause *Implicit = ActOnOpenMPMapClause( - llvm::None, llvm::None, MapperIdScopeSpec, MapperId, - OMPC_MAP_tofrom, /*IsMapTypeImplicit=*/true, SourceLocation(), - SourceLocation(), ImplicitMaps, OMPVarListLocTy())) { + llvm::None, llvm::None, MapperIdScopeSpec, MapperId, Kind, + /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(), + ImplicitMap, OMPVarListLocTy())) { ClausesWithImplicit.emplace_back(Implicit); ErrorFound |= - cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size(); + cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMap.size(); } else { ErrorFound = true; } @@ -4318,6 +4556,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_simd: Res = ActOnOpenMPSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_for: Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, @@ -4326,6 +4566,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_for_simd: Res = ActOnOpenMPForSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_sections: Res = ActOnOpenMPSectionsDirective(ClausesWithImplicit, AStmt, StartLoc, @@ -4358,6 +4600,13 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPParallelForSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_parallel); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); + break; + case OMPD_parallel_master: + Res = ActOnOpenMPParallelMasterDirective(ClausesWithImplicit, AStmt, + StartLoc, EndLoc); + AllowedNameModifiers.push_back(OMPD_parallel); break; case OMPD_parallel_sections: Res = ActOnOpenMPParallelSectionsDirective(ClausesWithImplicit, AStmt, @@ -4466,6 +4715,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPTaskLoopSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_taskloop); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_master_taskloop: Res = ActOnOpenMPMasterTaskLoopDirective( @@ -4476,6 +4727,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPMasterTaskLoopSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_taskloop); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_parallel_master_taskloop: Res = ActOnOpenMPParallelMasterTaskLoopDirective( @@ -4483,6 +4736,14 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( AllowedNameModifiers.push_back(OMPD_taskloop); AllowedNameModifiers.push_back(OMPD_parallel); break; + case OMPD_parallel_master_taskloop_simd: + Res = ActOnOpenMPParallelMasterTaskLoopSimdDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_taskloop); + AllowedNameModifiers.push_back(OMPD_parallel); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); + break; case OMPD_distribute: Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); @@ -4501,21 +4762,29 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPDistributeParallelForSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_parallel); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_distribute_simd: Res = ActOnOpenMPDistributeSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_target_parallel_for_simd: Res = ActOnOpenMPTargetParallelForSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_target); AllowedNameModifiers.push_back(OMPD_parallel); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_target_simd: Res = ActOnOpenMPTargetSimdDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_target); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_teams_distribute: Res = ActOnOpenMPTeamsDistributeDirective( @@ -4524,11 +4793,15 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_teams_distribute_simd: Res = ActOnOpenMPTeamsDistributeSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_teams_distribute_parallel_for_simd: Res = ActOnOpenMPTeamsDistributeParallelForSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_parallel); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_teams_distribute_parallel_for: Res = ActOnOpenMPTeamsDistributeParallelForDirective( @@ -4556,11 +4829,15 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_target); AllowedNameModifiers.push_back(OMPD_parallel); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_target_teams_distribute_simd: Res = ActOnOpenMPTargetTeamsDistributeSimdDirective( ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); AllowedNameModifiers.push_back(OMPD_target); + if (LangOpts.OpenMP >= 50) + AllowedNameModifiers.push_back(OMPD_simd); break; case OMPD_declare_target: case OMPD_end_declare_target: @@ -4586,13 +4863,17 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_num_threads: case OMPC_dist_schedule: // Do not analyse if no parent teams directive. - if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective())) + if (isOpenMPTeamsDirective(Kind)) break; continue; case OMPC_if: - if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective()) && + if (isOpenMPTeamsDirective(Kind) && cast<OMPIfClause>(C)->getNameModifier() != OMPD_target) break; + if (isOpenMPParallelDirective(Kind) && + isOpenMPTaskLoopDirective(Kind) && + cast<OMPIfClause>(C)->getNameModifier() != OMPD_parallel) + break; continue; case OMPC_schedule: break; @@ -4601,7 +4882,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_final: case OMPC_priority: // Do not analyze if no parent parallel directive. - if (isOpenMPParallelDirective(DSAStack->getCurrentDirective())) + if (isOpenMPParallelDirective(Kind)) break; continue; case OMPC_ordered: @@ -4644,6 +4925,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_from: case OMPC_use_device_ptr: case OMPC_is_device_ptr: + case OMPC_nontemporal: continue; case OMPC_allocator: case OMPC_flush: @@ -4671,9 +4953,17 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( if (P.getFirst()->isImplicit() || isa<OMPCapturedExprDecl>(P.getFirst())) continue; ErrorFound = true; - Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable) - << P.first << P.second->getSourceRange(); - Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none); + if (DSAStack->getDefaultDSA() == DSA_none) { + Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable) + << P.first << P.second->getSourceRange(); + Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none); + } else if (getLangOpts().OpenMP >= 50) { + Diag(P.second->getExprLoc(), + diag::err_omp_defaultmap_no_attr_for_variable) + << P.first << P.second->getSourceRange(); + Diag(DSAStack->getDefaultDSALocation(), + diag::note_omp_defaultmap_attr_none); + } } if (!AllowedNameModifiers.empty()) @@ -4781,8 +5071,9 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( // OpenMP [2.8.1, simd construct, Restrictions] // A list-item cannot appear in more than one aligned clause. if (AlignedArgs.count(CanonPVD) > 0) { - Diag(E->getExprLoc(), diag::err_omp_aligned_twice) - << 1 << E->getSourceRange(); + Diag(E->getExprLoc(), diag::err_omp_used_in_clause_twice) + << 1 << getOpenMPClauseName(OMPC_aligned) + << E->getSourceRange(); Diag(AlignedArgs[CanonPVD]->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(OMPC_aligned); @@ -4804,8 +5095,8 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( } if (isa<CXXThisExpr>(E)) { if (AlignedThis) { - Diag(E->getExprLoc(), diag::err_omp_aligned_twice) - << 2 << E->getSourceRange(); + Diag(E->getExprLoc(), diag::err_omp_used_in_clause_twice) + << 2 << getOpenMPClauseName(OMPC_aligned) << E->getSourceRange(); Diag(AlignedThis->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(OMPC_aligned); } @@ -4950,6 +5241,29 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( return DG; } +static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto, + QualType NewType) { + assert(NewType->isFunctionProtoType() && + "Expected function type with prototype."); + assert(FD->getType()->isFunctionNoProtoType() && + "Expected function with type with no prototype."); + assert(FDWithProto->getType()->isFunctionProtoType() && + "Expected function with prototype."); + // Synthesize parameters with the same types. + FD->setType(NewType); + SmallVector<ParmVarDecl *, 16> Params; + for (const ParmVarDecl *P : FDWithProto->parameters()) { + auto *Param = ParmVarDecl::Create(S.getASTContext(), FD, SourceLocation(), + SourceLocation(), nullptr, P->getType(), + /*TInfo=*/nullptr, SC_None, nullptr); + Param->setScopeInfo(0, Params.size()); + Param->setImplicit(); + Params.push_back(Param); + } + + FD->setParams(Params); +} + Optional<std::pair<FunctionDecl *, Expr *>> Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, Expr *VariantRef, SourceRange SR) { @@ -5048,7 +5362,9 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, if (ICS.isFailure()) { Diag(VariantRef->getExprLoc(), diag::err_omp_declare_variant_incompat_types) - << VariantRef->getType() << FnPtrType << VariantRef->getSourceRange(); + << VariantRef->getType() + << ((Method && !Method->isStatic()) ? FnPtrType : FD->getType()) + << VariantRef->getSourceRange(); return None; } VariantRefCast = PerformImplicitConversion( @@ -5088,6 +5404,24 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, return None; } + // Check if function types are compatible in C. + if (!LangOpts.CPlusPlus) { + QualType NewType = + Context.mergeFunctionTypes(FD->getType(), NewFD->getType()); + if (NewType.isNull()) { + Diag(VariantRef->getExprLoc(), + diag::err_omp_declare_variant_incompat_types) + << NewFD->getType() << FD->getType() << VariantRef->getSourceRange(); + return None; + } + if (NewType->isFunctionProtoType()) { + if (FD->getType()->isFunctionNoProtoType()) + setPrototype(*this, FD, NewFD, NewType); + else if (NewFD->getType()->isFunctionNoProtoType()) + setPrototype(*this, NewFD, FD, NewType); + } + } + // Check if variant function is not marked with declare variant directive. if (NewFD->hasAttrs() && NewFD->hasAttr<OMPDeclareVariantAttr>()) { Diag(VariantRef->getExprLoc(), @@ -5148,10 +5482,9 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, // Check general compatibility. if (areMultiversionVariantFunctionsCompatible( - FD, NewFD, PDiag(diag::err_omp_declare_variant_noproto), - PartialDiagnosticAt( - SR.getBegin(), - PDiag(diag::note_omp_declare_variant_specified_here) << SR), + FD, NewFD, PartialDiagnostic::NullDiagnostic(), + PartialDiagnosticAt(SourceLocation(), + PartialDiagnostic::NullDiagnostic()), PartialDiagnosticAt( VariantRef->getExprLoc(), PDiag(diag::err_omp_declare_variant_doesnt_support)), @@ -5166,28 +5499,73 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, void Sema::ActOnOpenMPDeclareVariantDirective( FunctionDecl *FD, Expr *VariantRef, SourceRange SR, - const Sema::OpenMPDeclareVariantCtsSelectorData &Data) { - if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown || - Data.Ctx == OMPDeclareVariantAttr::CtxUnknown) + ArrayRef<OMPCtxSelectorData> Data) { + if (Data.empty()) return; - Expr *Score = nullptr; - OMPDeclareVariantAttr::ScoreType ST = OMPDeclareVariantAttr::ScoreUnknown; - if (Data.CtxScore.isUsable()) { - ST = OMPDeclareVariantAttr::ScoreSpecified; - Score = Data.CtxScore.get(); - if (!Score->isTypeDependent() && !Score->isValueDependent() && - !Score->isInstantiationDependent() && - !Score->containsUnexpandedParameterPack()) { - llvm::APSInt Result; - ExprResult ICE = VerifyIntegerConstantExpression(Score, &Result); - if (ICE.isInvalid()) - return; + SmallVector<Expr *, 4> CtxScores; + SmallVector<unsigned, 4> CtxSets; + SmallVector<unsigned, 4> Ctxs; + SmallVector<StringRef, 4> ImplVendors, DeviceKinds; + bool IsError = false; + for (const OMPCtxSelectorData &D : Data) { + OpenMPContextSelectorSetKind CtxSet = D.CtxSet; + OpenMPContextSelectorKind Ctx = D.Ctx; + if (CtxSet == OMP_CTX_SET_unknown || Ctx == OMP_CTX_unknown) + return; + Expr *Score = nullptr; + if (D.Score.isUsable()) { + Score = D.Score.get(); + if (!Score->isTypeDependent() && !Score->isValueDependent() && + !Score->isInstantiationDependent() && + !Score->containsUnexpandedParameterPack()) { + Score = + PerformOpenMPImplicitIntegerConversion(Score->getExprLoc(), Score) + .get(); + if (Score) + Score = VerifyIntegerConstantExpression(Score).get(); + } + } else { + // OpenMP 5.0, 2.3.3 Matching and Scoring Context Selectors. + // The kind, arch, and isa selectors are given the values 2^l, 2^(l+1) and + // 2^(l+2), respectively, where l is the number of traits in the construct + // set. + // TODO: implement correct logic for isa and arch traits. + // TODO: take the construct context set into account when it is + // implemented. + int L = 0; // Currently set the number of traits in construct set to 0, + // since the construct trait set in not supported yet. + if (CtxSet == OMP_CTX_SET_device && Ctx == OMP_CTX_kind) + Score = ActOnIntegerConstant(SourceLocation(), std::pow(2, L)).get(); + else + Score = ActOnIntegerConstant(SourceLocation(), 0).get(); + } + switch (Ctx) { + case OMP_CTX_vendor: + assert(CtxSet == OMP_CTX_SET_implementation && + "Expected implementation context selector set."); + ImplVendors.append(D.Names.begin(), D.Names.end()); + break; + case OMP_CTX_kind: + assert(CtxSet == OMP_CTX_SET_device && + "Expected device context selector set."); + DeviceKinds.append(D.Names.begin(), D.Names.end()); + break; + case OMP_CTX_unknown: + llvm_unreachable("Unknown context selector kind."); } + IsError = IsError || !Score; + CtxSets.push_back(CtxSet); + Ctxs.push_back(Ctx); + CtxScores.push_back(Score); + } + if (!IsError) { + auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( + Context, VariantRef, CtxScores.begin(), CtxScores.size(), + CtxSets.begin(), CtxSets.size(), Ctxs.begin(), Ctxs.size(), + ImplVendors.begin(), ImplVendors.size(), DeviceKinds.begin(), + DeviceKinds.size(), SR); + FD->addAttr(NewAttr); } - auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( - Context, VariantRef, Score, Data.CtxSet, ST, Data.Ctx, - Data.ImplVendors.begin(), Data.ImplVendors.size(), SR); - FD->addAttr(NewAttr); } void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc, @@ -5200,7 +5578,7 @@ void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc, Func->specific_attrs<OMPDeclareVariantAttr>()) { // TODO: add checks for active OpenMP context where possible. Expr *VariantRef = A->getVariantFuncRef(); - auto *DRE = dyn_cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts()); + auto *DRE = cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts()); auto *F = cast<FunctionDecl>(DRE->getDecl()); if (!F->isDefined() && F->isTemplateInstantiation()) InstantiateFunctionDefinition(Loc, F->getFirstDecl()); @@ -6953,7 +7331,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, "Expected canonical for or range-based for loops."); CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); } - CurStmt = CurStmt->IgnoreContainers(); + CurStmt = OMPLoopDirective::tryToFindNextInnerLoop( + CurStmt, SemaRef.LangOpts.OpenMP >= 50); } for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) { if (checkOpenMPIterationSpace( @@ -6980,7 +7359,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, "Expected canonical for or range-based for loops."); CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody(); } - CurStmt = CurStmt->IgnoreContainers(); + CurStmt = OMPLoopDirective::tryToFindNextInnerLoop( + CurStmt, SemaRef.LangOpts.OpenMP >= 50); } Built.clear(/* size */ NestedLoopCount); @@ -7995,6 +8375,28 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective( } StmtResult +Sema::ActOnOpenMPParallelMasterDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + auto *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + setFunctionHasBranchProtectedScope(); + + return OMPParallelMasterDirective::Create(Context, StartLoc, EndLoc, Clauses, + AStmt); +} + +StmtResult Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { @@ -8137,7 +8539,8 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, // OpenMP [2.8.1,simd Construct, Restrictions] // An ordered construct with the simd clause is the only OpenMP construct // that can appear in the simd region. - Diag(StartLoc, diag::err_omp_prohibited_region_simd); + Diag(StartLoc, diag::err_omp_prohibited_region_simd) + << (LangOpts.OpenMP >= 50 ? 1 : 0); ErrorFound = true; } else if (DependFound && (TC || SC)) { Diag(DependFound->getBeginLoc(), diag::err_omp_depend_clause_thread_simd) @@ -9467,6 +9870,74 @@ StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } +StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + auto *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + for (int ThisCaptureLevel = + getOpenMPCaptureLevels(OMPD_parallel_master_taskloop_simd); + ThisCaptureLevel > 1; --ThisCaptureLevel) { + CS = cast<CapturedStmt>(CS->getCapturedStmt()); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + } + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' or 'ordered' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = checkOpenMPLoop( + OMPD_parallel_master_taskloop_simd, getCollapseNumberExpr(Clauses), + /*OrderedLoopCountExpr=*/nullptr, CS, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for loop exprs were not built"); + + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (OMPClause *C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + + // OpenMP, [2.9.2 taskloop Construct, Restrictions] + // The grainsize clause and num_tasks clause are mutually exclusive and may + // 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(); + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + + setFunctionHasBranchProtectedScope(); + return OMPParallelMasterTaskLoopSimdDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + StmtResult Sema::ActOnOpenMPDistributeDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) { @@ -10317,6 +10788,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + case OMPC_nontemporal: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10328,29 +10800,47 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, // A return value of OMPD_unknown signifies that the expression should not // be captured. static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( - OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, + OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, unsigned OpenMPVersion, OpenMPDirectiveKind NameModifier = OMPD_unknown) { OpenMPDirectiveKind CaptureRegion = OMPD_unknown; switch (CKind) { case OMPC_if: switch (DKind) { + case OMPD_target_parallel_for_simd: + if (OpenMPVersion >= 50 && + (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) { + CaptureRegion = OMPD_parallel; + break; + } + LLVM_FALLTHROUGH; case OMPD_target_parallel: case OMPD_target_parallel_for: - case OMPD_target_parallel_for_simd: // If this clause applies to the nested 'parallel' region, capture within // the 'target' region, otherwise do not capture. if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel) CaptureRegion = OMPD_target; break; - case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: + if (OpenMPVersion >= 50 && + (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) { + CaptureRegion = OMPD_parallel; + break; + } + LLVM_FALLTHROUGH; + case OMPD_target_teams_distribute_parallel_for: // If this clause applies to the nested 'parallel' region, capture within // the 'teams' region, otherwise do not capture. if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel) CaptureRegion = OMPD_teams; break; - case OMPD_teams_distribute_parallel_for: case OMPD_teams_distribute_parallel_for_simd: + if (OpenMPVersion >= 50 && + (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) { + CaptureRegion = OMPD_parallel; + break; + } + LLVM_FALLTHROUGH; + case OMPD_teams_distribute_parallel_for: CaptureRegion = OMPD_teams; break; case OMPD_target_update: @@ -10362,24 +10852,63 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( if (NameModifier == OMPD_unknown || NameModifier == OMPD_taskloop) CaptureRegion = OMPD_parallel; break; + case OMPD_parallel_master_taskloop_simd: + if ((OpenMPVersion <= 45 && NameModifier == OMPD_unknown) || + NameModifier == OMPD_taskloop) { + CaptureRegion = OMPD_parallel; + break; + } + if (OpenMPVersion <= 45) + break; + if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd) + CaptureRegion = OMPD_taskloop; + break; + case OMPD_parallel_for_simd: + if (OpenMPVersion <= 45) + break; + if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd) + CaptureRegion = OMPD_parallel; + break; + case OMPD_taskloop_simd: + case OMPD_master_taskloop_simd: + if (OpenMPVersion <= 45) + break; + if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd) + CaptureRegion = OMPD_taskloop; + break; + case OMPD_distribute_parallel_for_simd: + if (OpenMPVersion <= 45) + break; + if (NameModifier == OMPD_unknown || NameModifier == OMPD_simd) + CaptureRegion = OMPD_parallel; + break; + case OMPD_target_simd: + if (OpenMPVersion >= 50 && + (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) + CaptureRegion = OMPD_target; + break; + case OMPD_teams_distribute_simd: + case OMPD_target_teams_distribute_simd: + if (OpenMPVersion >= 50 && + (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) + CaptureRegion = OMPD_teams; + break; case OMPD_cancel: case OMPD_parallel: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_parallel_for: - case OMPD_parallel_for_simd: case OMPD_target: - case OMPD_target_simd: case OMPD_target_teams: case OMPD_target_teams_distribute: - case OMPD_target_teams_distribute_simd: case OMPD_distribute_parallel_for: - case OMPD_distribute_parallel_for_simd: case OMPD_task: case OMPD_taskloop: - case OMPD_taskloop_simd: case OMPD_master_taskloop: - case OMPD_master_taskloop_simd: case OMPD_target_data: + case OMPD_simd: + case OMPD_for_simd: + case OMPD_distribute_simd: // Do not capture if-clause expressions. break; case OMPD_threadprivate: @@ -10396,9 +10925,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: - case OMPD_simd: case OMPD_for: - case OMPD_for_simd: case OMPD_sections: case OMPD_section: case OMPD_single: @@ -10408,9 +10935,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_distribute: case OMPD_ordered: case OMPD_atomic: - case OMPD_distribute_simd: case OMPD_teams_distribute: - case OMPD_teams_distribute_simd: case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with if-clause"); case OMPD_unknown: @@ -10431,12 +10956,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( CaptureRegion = OMPD_teams; break; case OMPD_parallel: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_distribute_parallel_for: case OMPD_distribute_parallel_for_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: // Do not capture num_threads-clause expressions. break; case OMPD_target_data: @@ -10513,12 +11040,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: case OMPD_target_update: case OMPD_cancel: case OMPD_parallel: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_parallel_for: case OMPD_parallel_for_simd: @@ -10583,12 +11112,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: case OMPD_target_update: case OMPD_cancel: case OMPD_parallel: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_parallel_for: case OMPD_parallel_for_simd: @@ -10653,6 +11184,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: @@ -10667,6 +11199,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_parallel: case OMPD_cancel: case OMPD_parallel: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_threadprivate: case OMPD_allocate: @@ -10727,6 +11260,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_target_data: case OMPD_target_enter_data: case OMPD_target_exit_data: @@ -10737,6 +11271,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_target_parallel: case OMPD_cancel: case OMPD_parallel: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_threadprivate: case OMPD_allocate: @@ -10802,8 +11337,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_master_taskloop: case OMPD_master_taskloop_simd: case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: case OMPD_cancel: case OMPD_parallel: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_parallel_for: case OMPD_parallel_for_simd: @@ -10851,6 +11388,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_master_taskloop_simd: break; case OMPD_parallel_master_taskloop: + case OMPD_parallel_master_taskloop_simd: CaptureRegion = OMPD_parallel; break; case OMPD_target_update: @@ -10876,6 +11414,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_distribute_parallel_for_simd: case OMPD_cancel: case OMPD_parallel: + case OMPD_parallel_master: case OMPD_parallel_sections: case OMPD_parallel_for: case OMPD_parallel_for_simd: @@ -10960,6 +11499,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + case OMPC_nontemporal: llvm_unreachable("Unexpected OpenMP clause."); } return CaptureRegion; @@ -10984,8 +11524,8 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, ValExpr = Val.get(); OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); - CaptureRegion = - getOpenMPCaptureRegionForClause(DKind, OMPC_if, NameModifier); + CaptureRegion = getOpenMPCaptureRegionForClause( + DKind, OMPC_if, LangOpts.OpenMP, NameModifier); if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); llvm::MapVector<const Expr *, DeclRefExpr *> Captures; @@ -11016,7 +11556,8 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, ValExpr = MakeFullExpr(Val.get()).get(); OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); - CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_final); + CaptureRegion = + getOpenMPCaptureRegionForClause(DKind, OMPC_final, LangOpts.OpenMP); if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); llvm::MapVector<const Expr *, DeclRefExpr *> Captures; @@ -11101,7 +11642,8 @@ isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind, } if (!BuildCapture) return true; - *CaptureRegion = getOpenMPCaptureRegionForClause(DKind, CKind); + *CaptureRegion = + getOpenMPCaptureRegionForClause(DKind, CKind, SemaRef.LangOpts.OpenMP); if (*CaptureRegion != OMPD_unknown && !SemaRef.CurContext->isDependentContext()) { ValExpr = SemaRef.MakeFullExpr(ValExpr).get(); @@ -11128,7 +11670,7 @@ OMPClause *Sema::ActOnOpenMPNumThreadsClause(Expr *NumThreads, OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); OpenMPDirectiveKind CaptureRegion = - getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads); + getOpenMPCaptureRegionForClause(DKind, OMPC_num_threads, LangOpts.OpenMP); if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); llvm::MapVector<const Expr *, DeclRefExpr *> Captures; @@ -11315,9 +11857,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_proc_bind: - Res = ActOnOpenMPProcBindClause( - static_cast<OpenMPProcBindClauseKind>(Argument), ArgumentLoc, StartLoc, - LParenLoc, EndLoc); + Res = ActOnOpenMPProcBindClause(static_cast<ProcBindKind>(Argument), + ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_atomic_default_mem_order: Res = ActOnOpenMPAtomicDefaultMemOrderClause( @@ -11381,6 +11922,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_dynamic_allocators: case OMPC_device_type: case OMPC_match: + case OMPC_nontemporal: llvm_unreachable("Clause is not allowed."); } return Res; @@ -11391,7 +11933,6 @@ getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last, ArrayRef<unsigned> Exclude = llvm::None) { SmallString<256> Buffer; llvm::raw_svector_ostream Out(Buffer); - unsigned Bound = Last >= 2 ? Last - 2 : 0; unsigned Skipped = Exclude.size(); auto S = Exclude.begin(), E = Exclude.end(); for (unsigned I = First; I < Last; ++I) { @@ -11400,9 +11941,9 @@ getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last, continue; } Out << "'" << getOpenMPSimpleClauseTypeName(K, I) << "'"; - if (I == Bound - Skipped) + if (I + Skipped + 2 == Last) Out << " or "; - else if (I != Bound + 1 - Skipped) + else if (I + Skipped + 1 != Last) Out << ", "; } return Out.str(); @@ -11437,15 +11978,16 @@ OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); } -OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind, +OMPClause *Sema::ActOnOpenMPProcBindClause(ProcBindKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { - if (Kind == OMPC_PROC_BIND_unknown) { + if (Kind == OMP_PROC_BIND_unknown) { Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) - << getListOfPossibleValues(OMPC_proc_bind, /*First=*/0, - /*Last=*/OMPC_PROC_BIND_unknown) + << getListOfPossibleValues(OMPC_proc_bind, + /*First=*/unsigned(OMP_PROC_BIND_master), + /*Last=*/5) << getOpenMPClauseName(OMPC_proc_bind); return nullptr; } @@ -11561,6 +12103,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + case OMPC_nontemporal: llvm_unreachable("Clause is not allowed."); } return Res; @@ -11659,8 +12202,8 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( return nullptr; } } else if (getOpenMPCaptureRegionForClause( - DSAStack->getCurrentDirective(), OMPC_schedule) != - OMPD_unknown && + DSAStack->getCurrentDirective(), OMPC_schedule, + LangOpts.OpenMP) != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); llvm::MapVector<const Expr *, DeclRefExpr *> Captures; @@ -11772,6 +12315,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + case OMPC_nontemporal: llvm_unreachable("Clause is not allowed."); } return Res; @@ -11857,11 +12401,10 @@ OMPClause *Sema::ActOnOpenMPVarListClause( OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr, const OMPVarListLocTy &Locs, SourceLocation ColonLoc, CXXScopeSpec &ReductionOrMapperIdScopeSpec, - DeclarationNameInfo &ReductionOrMapperId, OpenMPDependClauseKind DepKind, - OpenMPLinearClauseKind LinKind, + DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, - ArrayRef<SourceLocation> MapTypeModifiersLoc, OpenMPMapClauseKind MapType, - bool IsMapTypeImplicit, SourceLocation DepLinMapLoc) { + ArrayRef<SourceLocation> MapTypeModifiersLoc, bool IsMapTypeImplicit, + SourceLocation DepLinMapLastLoc) { SourceLocation StartLoc = Locs.StartLoc; SourceLocation LParenLoc = Locs.LParenLoc; SourceLocation EndLoc = Locs.EndLoc; @@ -11874,7 +12417,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_lastprivate: - Res = ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc, EndLoc); + assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LASTPRIVATE_unknown && + "Unexpected lastprivate modifier."); + Res = ActOnOpenMPLastprivateClause( + VarList, static_cast<OpenMPLastprivateModifier>(ExtraModifier), + DepLinMapLastLoc, ColonLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_shared: Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc); @@ -11895,8 +12442,12 @@ OMPClause *Sema::ActOnOpenMPVarListClause( ReductionOrMapperId); break; case OMPC_linear: - Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc, - LinKind, DepLinMapLoc, ColonLoc, EndLoc); + assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LINEAR_unknown && + "Unexpected linear modifier."); + Res = ActOnOpenMPLinearClause( + VarList, TailExpr, StartLoc, LParenLoc, + static_cast<OpenMPLinearClauseKind>(ExtraModifier), DepLinMapLastLoc, + ColonLoc, EndLoc); break; case OMPC_aligned: Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc, @@ -11912,14 +12463,19 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_depend: - Res = ActOnOpenMPDependClause(DepKind, DepLinMapLoc, ColonLoc, VarList, - StartLoc, LParenLoc, EndLoc); + assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown && + "Unexpected depend modifier."); + Res = ActOnOpenMPDependClause( + static_cast<OpenMPDependClauseKind>(ExtraModifier), DepLinMapLastLoc, + ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_map: - Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc, - ReductionOrMapperIdScopeSpec, - ReductionOrMapperId, MapType, IsMapTypeImplicit, - DepLinMapLoc, ColonLoc, VarList, Locs); + assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown && + "Unexpected map modifier."); + Res = ActOnOpenMPMapClause( + MapTypeModifiers, MapTypeModifiersLoc, ReductionOrMapperIdScopeSpec, + ReductionOrMapperId, static_cast<OpenMPMapClauseKind>(ExtraModifier), + IsMapTypeImplicit, DepLinMapLastLoc, ColonLoc, VarList, Locs); break; case OMPC_to: Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec, @@ -11939,6 +12495,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc, ColonLoc, EndLoc); break; + case OMPC_nontemporal: + Res = ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -12442,10 +13001,19 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, buildPreInits(Context, ExprCaptures)); } -OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc) { +OMPClause *Sema::ActOnOpenMPLastprivateClause( + ArrayRef<Expr *> VarList, OpenMPLastprivateModifier LPKind, + SourceLocation LPKindLoc, SourceLocation ColonLoc, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + if (LPKind == OMPC_LASTPRIVATE_unknown && LPKindLoc.isValid()) { + assert(ColonLoc.isValid() && "Colon location must be valid."); + Diag(LPKindLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_lastprivate, /*First=*/0, + /*Last=*/OMPC_LASTPRIVATE_unknown) + << getOpenMPClauseName(OMPC_lastprivate); + return nullptr; + } + SmallVector<Expr *, 8> Vars; SmallVector<Expr *, 8> SrcExprs; SmallVector<Expr *, 8> DstExprs; @@ -12491,6 +13059,19 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, if (rejectConstNotMutableType(*this, D, Type, OMPC_lastprivate, ELoc)) continue; + // OpenMP 5.0 [2.19.4.5 lastprivate Clause, Restrictions] + // A list item that appears in a lastprivate clause with the conditional + // modifier must be a scalar variable. + if (LPKind == OMPC_LASTPRIVATE_conditional && !Type->isScalarType()) { + Diag(ELoc, diag::err_omp_lastprivate_conditional_non_scalar); + bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; + continue; + } + OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] @@ -12599,6 +13180,7 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, SrcExprs, DstExprs, AssignmentOps, + LPKind, LPKindLoc, ColonLoc, buildPreInits(Context, ExprCaptures), buildPostUpdate(*this, ExprPostUpdates)); } @@ -12916,7 +13498,8 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, } } if (ReductionIdScopeSpec.isSet()) { - SemaRef.Diag(Loc, diag::err_omp_not_resolved_reduction_identifier) << Range; + SemaRef.Diag(Loc, diag::err_omp_not_resolved_reduction_identifier) + << Ty << Range; return ExprError(); } return ExprEmpty(); @@ -13771,8 +14354,8 @@ bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc, // A list item must be of integral or pointer type. Type = Type.getUnqualifiedType().getCanonicalType(); const auto *Ty = Type.getTypePtrOrNull(); - if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) && - !Ty->isPointerType())) { + if (!Ty || (LinKind != OMPC_LINEAR_ref && !Ty->isDependentType() && + !Ty->isIntegralType(Context) && !Ty->isPointerType())) { Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type; if (D) { bool IsDecl = @@ -14066,7 +14649,8 @@ OMPClause *Sema::ActOnOpenMPAlignedClause( // OpenMP [2.8.1, simd construct, Restrictions] // A list-item cannot appear in more than one aligned clause. if (const Expr *PrevRef = DSAStack->addUniqueAligned(D, SimpleRefExpr)) { - Diag(ELoc, diag::err_omp_aligned_twice) << 0 << ERange; + Diag(ELoc, diag::err_omp_used_in_clause_twice) + << 0 << getOpenMPClauseName(OMPC_aligned) << ERange; Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(OMPC_aligned); continue; @@ -14437,6 +15021,22 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, } OpsOffs.emplace_back(RHS, OOK); } else { + // OpenMP 5.0 [2.17.11, Restrictions] + // List items used in depend clauses cannot be zero-length array sections. + const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); + if (OASE) { + const Expr *Length = OASE->getLength(); + Expr::EvalResult Result; + if (Length && !Length->isValueDependent() && + Length->EvaluateAsInt(Result, Context) && + Result.Val.getInt().isNullValue()) { + Diag(ELoc, + diag::err_omp_depend_zero_length_array_section_not_allowed) + << SimpleExpr->getSourceRange(); + continue; + } + } + auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); if (!RefExpr->IgnoreParenImpCasts()->isLValue() || (ASE && @@ -14496,7 +15096,7 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); OpenMPDirectiveKind CaptureRegion = - getOpenMPCaptureRegionForClause(DKind, OMPC_device); + getOpenMPCaptureRegionForClause(DKind, OMPC_device, LangOpts.OpenMP); if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); llvm::MapVector<const Expr *, DeclRefExpr *> Captures; @@ -14517,7 +15117,7 @@ static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, return false; } if (FullCheck && !SemaRef.CurContext->isDependentContext() && - !QTy.isTrivialType(SemaRef.Context)) + !QTy.isTriviallyCopyableType(SemaRef.Context)) SemaRef.Diag(SL, diag::warn_omp_non_trivial_type_mapped) << QTy << SR; return true; } @@ -15408,8 +16008,22 @@ static void checkMappableExpressionList( return MC.getAssociatedDeclaration(); }); assert(I != CurComponents.end() && "Null decl on map clause."); - QualType Type = - I->getAssociatedDeclaration()->getType().getNonReferenceType(); + QualType Type; + auto *ASE = dyn_cast<ArraySubscriptExpr>(VE->IgnoreParens()); + auto *OASE = dyn_cast<OMPArraySectionExpr>(VE->IgnoreParens()); + if (ASE) { + Type = ASE->getType().getNonReferenceType(); + } else if (OASE) { + QualType BaseType = + OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); + if (const auto *ATy = BaseType->getAsArrayTypeUnsafe()) + Type = ATy->getElementType(); + else + Type = BaseType->getPointeeType(); + Type = Type.getNonReferenceType(); + } else { + Type = VE->getType(); + } // OpenMP 4.5 [2.10.5, target update Construct, Restrictions, p.4] // A list item in a to or from clause must have a mappable type. @@ -15419,6 +16033,8 @@ static void checkMappableExpressionList( DSAS, Type)) continue; + Type = I->getAssociatedDeclaration()->getType().getNonReferenceType(); + if (CKind == OMPC_map) { // target enter data // OpenMP [2.10.2, Restrictions, p. 99] @@ -15948,7 +16564,7 @@ OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); OpenMPDirectiveKind CaptureRegion = - getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams); + getOpenMPCaptureRegionForClause(DKind, OMPC_num_teams, LangOpts.OpenMP); if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); llvm::MapVector<const Expr *, DeclRefExpr *> Captures; @@ -15974,8 +16590,8 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, return nullptr; OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); - OpenMPDirectiveKind CaptureRegion = - getOpenMPCaptureRegionForClause(DKind, OMPC_thread_limit); + OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause( + DKind, OMPC_thread_limit, LangOpts.OpenMP); if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); llvm::MapVector<const Expr *, DeclRefExpr *> Captures; @@ -16100,8 +16716,8 @@ OMPClause *Sema::ActOnOpenMPDistScheduleClause( return nullptr; } } else if (getOpenMPCaptureRegionForClause( - DSAStack->getCurrentDirective(), OMPC_dist_schedule) != - OMPD_unknown && + DSAStack->getCurrentDirective(), OMPC_dist_schedule, + LangOpts.OpenMP) != OMPD_unknown && !CurContext->isDependentContext()) { ValExpr = MakeFullExpr(ValExpr).get(); llvm::MapVector<const Expr *, DeclRefExpr *> Captures; @@ -16120,26 +16736,57 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause( OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, SourceLocation KindLoc, SourceLocation EndLoc) { - // OpenMP 4.5 only supports 'defaultmap(tofrom: scalar)' - if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom || Kind != OMPC_DEFAULTMAP_scalar) { - std::string Value; - SourceLocation Loc; - Value += "'"; - if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) { - Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap, - OMPC_DEFAULTMAP_MODIFIER_tofrom); - Loc = MLoc; - } else { - Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap, - OMPC_DEFAULTMAP_scalar); - Loc = KindLoc; + if (getLangOpts().OpenMP < 50) { + if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom || + Kind != OMPC_DEFAULTMAP_scalar) { + std::string Value; + SourceLocation Loc; + Value += "'"; + if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) { + Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap, + OMPC_DEFAULTMAP_MODIFIER_tofrom); + Loc = MLoc; + } else { + Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap, + OMPC_DEFAULTMAP_scalar); + Loc = KindLoc; + } + Value += "'"; + Diag(Loc, diag::err_omp_unexpected_clause_value) + << Value << getOpenMPClauseName(OMPC_defaultmap); + return nullptr; + } + } else { + bool isDefaultmapModifier = (M != OMPC_DEFAULTMAP_MODIFIER_unknown); + bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown); + if (!isDefaultmapKind || !isDefaultmapModifier) { + std::string ModifierValue = "'alloc', 'from', 'to', 'tofrom', " + "'firstprivate', 'none', 'default'"; + std::string KindValue = "'scalar', 'aggregate', 'pointer'"; + if (!isDefaultmapKind && isDefaultmapModifier) { + Diag(KindLoc, diag::err_omp_unexpected_clause_value) + << KindValue << getOpenMPClauseName(OMPC_defaultmap); + } else if (isDefaultmapKind && !isDefaultmapModifier) { + Diag(MLoc, diag::err_omp_unexpected_clause_value) + << ModifierValue << getOpenMPClauseName(OMPC_defaultmap); + } else { + Diag(MLoc, diag::err_omp_unexpected_clause_value) + << ModifierValue << getOpenMPClauseName(OMPC_defaultmap); + Diag(KindLoc, diag::err_omp_unexpected_clause_value) + << KindValue << getOpenMPClauseName(OMPC_defaultmap); + } + return nullptr; + } + + // OpenMP [5.0, 2.12.5, Restrictions, p. 174] + // At most one defaultmap clause for each category can appear on the + // directive. + if (DSAStack->checkDefaultmapCategory(Kind)) { + Diag(StartLoc, diag::err_omp_one_defaultmap_each_category); + return nullptr; } - Value += "'"; - Diag(Loc, diag::err_omp_unexpected_clause_value) - << Value << getOpenMPClauseName(OMPC_defaultmap); - return nullptr; } - DSAStack->setDefaultDMAToFromScalar(StartLoc); + DSAStack->setDefaultDMAAttr(M, Kind, StartLoc); return new (Context) OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M); @@ -16604,3 +17251,42 @@ OMPClause *Sema::ActOnOpenMPAllocateClause( return OMPAllocateClause::Create(Context, StartLoc, LParenLoc, Allocator, ColonLoc, EndLoc, Vars); } + +OMPClause *Sema::ActOnOpenMPNontemporalClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector<Expr *, 8> Vars; + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); + if (Res.second) + // It will be analyzed later. + Vars.push_back(RefExpr); + ValueDecl *D = Res.first; + if (!D) + continue; + + // OpenMP 5.0, 2.9.3.1 simd Construct, Restrictions. + // A list-item cannot appear in more than one nontemporal clause. + if (const Expr *PrevRef = + DSAStack->addUniqueNontemporal(D, SimpleRefExpr)) { + Diag(ELoc, diag::err_omp_used_in_clause_twice) + << 0 << getOpenMPClauseName(OMPC_nontemporal) << ERange; + Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(OMPC_nontemporal); + continue; + } + + Vars.push_back(RefExpr); + } + + if (Vars.empty()) + return nullptr; + + return OMPNontemporalClause::Create(Context, StartLoc, LParenLoc, EndLoc, + Vars); +} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 47c1e3cec0ea..0fd932fac970 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -60,14 +60,18 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, // being used. if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc)) return ExprError(); - if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>()) - S.ResolveExceptionSpec(Loc, FPT); DeclRefExpr *DRE = new (S.Context) DeclRefExpr(S.Context, Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo); if (HadMultipleCandidates) DRE->setHadMultipleCandidates(true); S.MarkDeclRefReferenced(DRE, Base); + if (auto *FPT = DRE->getType()->getAs<FunctionProtoType>()) { + if (isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) { + S.ResolveExceptionSpec(Loc, FPT); + DRE->setType(Fn->getType()); + } + } return S.ImpCastExprToType(DRE, S.Context.getPointerType(DRE->getType()), CK_FunctionToPointerDecay); } @@ -591,6 +595,12 @@ namespace { TemplateArgumentList *TemplateArgs; unsigned CallArgIndex; }; + // Structure used by DeductionFailureInfo to store information about + // unsatisfied constraints. + struct CNSInfo { + TemplateArgumentList *TemplateArgs; + ConstraintSatisfaction Satisfaction; + }; } /// Convert from Sema's representation of template deduction information @@ -661,6 +671,14 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, } break; + case Sema::TDK_ConstraintsNotSatisfied: { + CNSInfo *Saved = new (Context) CNSInfo; + Saved->TemplateArgs = Info.take(); + Saved->Satisfaction = Info.AssociatedConstraintsSatisfaction; + Result.Data = Saved; + break; + } + case Sema::TDK_Success: case Sema::TDK_NonDependentConversionFailure: llvm_unreachable("not a deduction failure"); @@ -701,6 +719,15 @@ void DeductionFailureInfo::Destroy() { } break; + case Sema::TDK_ConstraintsNotSatisfied: + // FIXME: Destroy the template argument list? + Data = nullptr; + if (PartialDiagnosticAt *Diag = getSFINAEDiagnostic()) { + Diag->~PartialDiagnosticAt(); + HasDiagnostic = false; + } + break; + // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: break; @@ -726,6 +753,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() { case Sema::TDK_NonDeducedMismatch: case Sema::TDK_CUDATargetMismatch: case Sema::TDK_NonDependentConversionFailure: + case Sema::TDK_ConstraintsNotSatisfied: return TemplateParameter(); case Sema::TDK_Incomplete: @@ -769,6 +797,9 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() { case Sema::TDK_SubstitutionFailure: return static_cast<TemplateArgumentList*>(Data); + case Sema::TDK_ConstraintsNotSatisfied: + return static_cast<CNSInfo*>(Data)->TemplateArgs; + // Unhandled case Sema::TDK_MiscellaneousDeductionFailure: break; @@ -789,6 +820,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() { case Sema::TDK_SubstitutionFailure: case Sema::TDK_CUDATargetMismatch: case Sema::TDK_NonDependentConversionFailure: + case Sema::TDK_ConstraintsNotSatisfied: return nullptr; case Sema::TDK_IncompletePack: @@ -820,6 +852,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() { case Sema::TDK_SubstitutionFailure: case Sema::TDK_CUDATargetMismatch: case Sema::TDK_NonDependentConversionFailure: + case Sema::TDK_ConstraintsNotSatisfied: return nullptr; case Sema::TDK_Inconsistent: @@ -1104,7 +1137,8 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, } bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, - bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs) { + bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs, + bool ConsiderRequiresClauses) { // C++ [basic.start.main]p2: This function shall not be overloaded. if (New->isMain()) return false; @@ -1240,19 +1274,36 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, if (getLangOpts().CUDA && ConsiderCudaAttrs) { // Don't allow overloading of destructors. (In theory we could, but it // would be a giant change to clang.) - if (isa<CXXDestructorDecl>(New)) - return false; + if (!isa<CXXDestructorDecl>(New)) { + CUDAFunctionTarget NewTarget = IdentifyCUDATarget(New), + OldTarget = IdentifyCUDATarget(Old); + if (NewTarget != CFT_InvalidTarget) { + assert((OldTarget != CFT_InvalidTarget) && + "Unexpected invalid target."); - CUDAFunctionTarget NewTarget = IdentifyCUDATarget(New), - OldTarget = IdentifyCUDATarget(Old); - if (NewTarget == CFT_InvalidTarget) - return false; + // Allow overloading of functions with same signature and different CUDA + // target attributes. + if (NewTarget != OldTarget) + return true; + } + } + } - assert((OldTarget != CFT_InvalidTarget) && "Unexpected invalid target."); + if (ConsiderRequiresClauses) { + Expr *NewRC = New->getTrailingRequiresClause(), + *OldRC = Old->getTrailingRequiresClause(); + if ((NewRC != nullptr) != (OldRC != nullptr)) + // RC are most certainly different - these are overloads. + return true; - // Allow overloading of functions with same signature and different CUDA - // target attributes. - return NewTarget != OldTarget; + if (NewRC) { + llvm::FoldingSetNodeID NewID, OldID; + NewRC->Profile(NewID, Context, /*Canonical=*/true); + OldRC->Profile(OldID, Context, /*Canonical=*/true); + if (NewID != OldID) + // RCs are not equivalent - these are overloads. + return true; + } } // The signatures match; this is not an overload. @@ -1326,7 +1377,7 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType, ICS.Ambiguous.setToType(ToType); for (OverloadCandidateSet::iterator Cand = Conversions.begin(); Cand != Conversions.end(); ++Cand) - if (Cand->Viable) + if (Cand->Best) ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function); break; @@ -2802,8 +2853,8 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, // Get the function type from the pointers. if (FromType->isMemberPointerType() && ToType->isMemberPointerType()) { - const MemberPointerType *FromMember = FromType->getAs<MemberPointerType>(), - *ToMember = ToType->getAs<MemberPointerType>(); + const auto *FromMember = FromType->castAs<MemberPointerType>(), + *ToMember = ToType->castAs<MemberPointerType>(); if (!Context.hasSameType(FromMember->getClass(), ToMember->getClass())) { PDiag << ft_different_class << QualType(ToMember->getClass(), 0) << QualType(FromMember->getClass(), 0); @@ -2898,8 +2949,12 @@ bool Sema::FunctionParamTypesAreEqual(const FunctionProtoType *OldType, N = NewType->param_type_begin(), E = OldType->param_type_end(); O && (O != E); ++O, ++N) { - if (!Context.hasSameType(O->getUnqualifiedType(), - N->getUnqualifiedType())) { + // Ignore address spaces in pointee type. This is to disallow overloading + // on __ptr32/__ptr64 address spaces. + QualType Old = Context.removePtrSizeAddrSpace(O->getUnqualifiedType()); + QualType New = Context.removePtrSizeAddrSpace(N->getUnqualifiedType()); + + if (!Context.hasSameType(Old, New)) { if (ArgPos) *ArgPos = O - OldType->param_type_begin(); return false; @@ -3114,6 +3169,70 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals, return true; } +/// Perform a single iteration of the loop for checking if a qualification +/// conversion is valid. +/// +/// Specifically, check whether any change between the qualifiers of \p +/// FromType and \p ToType is permissible, given knowledge about whether every +/// outer layer is const-qualified. +static bool isQualificationConversionStep(QualType FromType, QualType ToType, + bool CStyle, + bool &PreviousToQualsIncludeConst, + bool &ObjCLifetimeConversion) { + Qualifiers FromQuals = FromType.getQualifiers(); + Qualifiers ToQuals = ToType.getQualifiers(); + + // Ignore __unaligned qualifier if this type is void. + if (ToType.getUnqualifiedType()->isVoidType()) + FromQuals.removeUnaligned(); + + // Objective-C ARC: + // Check Objective-C lifetime conversions. + if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime()) { + if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) { + if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals)) + ObjCLifetimeConversion = true; + FromQuals.removeObjCLifetime(); + ToQuals.removeObjCLifetime(); + } else { + // Qualification conversions cannot cast between different + // Objective-C lifetime qualifiers. + return false; + } + } + + // Allow addition/removal of GC attributes but not changing GC attributes. + if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() && + (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) { + FromQuals.removeObjCGCAttr(); + ToQuals.removeObjCGCAttr(); + } + + // -- for every j > 0, if const is in cv 1,j then const is in cv + // 2,j, and similarly for volatile. + if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals)) + return false; + + // For a C-style cast, just require the address spaces to overlap. + // FIXME: Does "superset" also imply the representation of a pointer is the + // same? We're assuming that it does here and in compatiblyIncludes. + if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) && + !FromQuals.isAddressSpaceSupersetOf(ToQuals)) + return false; + + // -- if the cv 1,j and cv 2,j are different, then const is in + // every cv for 0 < k < j. + if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers() && + !PreviousToQualsIncludeConst) + return false; + + // Keep track of whether all prior cv-qualifiers in the "to" type + // include const. + PreviousToQualsIncludeConst = + PreviousToQualsIncludeConst && ToQuals.hasConst(); + return true; +} + /// IsQualificationConversion - Determines whether the conversion from /// an rvalue of type FromType to ToType is a qualification conversion /// (C++ 4.4). @@ -3139,73 +3258,16 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, bool PreviousToQualsIncludeConst = true; bool UnwrappedAnyPointer = false; while (Context.UnwrapSimilarTypes(FromType, ToType)) { - // Within each iteration of the loop, we check the qualifiers to - // determine if this still looks like a qualification - // conversion. Then, if all is well, we unwrap one more level of - // pointers or pointers-to-members and do it all again - // until there are no more pointers or pointers-to-members left to - // unwrap. - UnwrappedAnyPointer = true; - - Qualifiers FromQuals = FromType.getQualifiers(); - Qualifiers ToQuals = ToType.getQualifiers(); - - // Ignore __unaligned qualifier if this type is void. - if (ToType.getUnqualifiedType()->isVoidType()) - FromQuals.removeUnaligned(); - - // Objective-C ARC: - // Check Objective-C lifetime conversions. - if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() && - UnwrappedAnyPointer) { - if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) { - if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals)) - ObjCLifetimeConversion = true; - FromQuals.removeObjCLifetime(); - ToQuals.removeObjCLifetime(); - } else { - // Qualification conversions cannot cast between different - // Objective-C lifetime qualifiers. - return false; - } - } - - // Allow addition/removal of GC attributes but not changing GC attributes. - if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() && - (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) { - FromQuals.removeObjCGCAttr(); - ToQuals.removeObjCGCAttr(); - } - - // -- for every j > 0, if const is in cv 1,j then const is in cv - // 2,j, and similarly for volatile. - if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals)) + if (!isQualificationConversionStep(FromType, ToType, CStyle, + PreviousToQualsIncludeConst, + ObjCLifetimeConversion)) return false; - - // -- if the cv 1,j and cv 2,j are different, then const is in - // every cv for 0 < k < j. - if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers() - && !PreviousToQualsIncludeConst) - return false; - - // Keep track of whether all prior cv-qualifiers in the "to" type - // include const. - PreviousToQualsIncludeConst - = PreviousToQualsIncludeConst && ToQuals.hasConst(); - } - - // Allows address space promotion by language rules implemented in - // Type::Qualifiers::isAddressSpaceSupersetOf. - Qualifiers FromQuals = FromType.getQualifiers(); - Qualifiers ToQuals = ToType.getQualifiers(); - if (!ToQuals.isAddressSpaceSupersetOf(FromQuals) && - !FromQuals.isAddressSpaceSupersetOf(ToQuals)) { - return false; + UnwrappedAnyPointer = true; } // We are left with FromType and ToType being the pointee types // after unwrapping the original FromType and ToType the same number - // of types. If we unwrapped any pointers, and if FromType and + // of times. If we unwrapped any pointers, and if FromType and // ToType have the same unqualified type (since we checked // qualifiers above), then this is a qualification conversion. return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType); @@ -3242,8 +3304,7 @@ static bool tryAtomicConversion(Sema &S, Expr *From, QualType ToType, static bool isFirstArgumentCompatibleWithType(ASTContext &Context, CXXConstructorDecl *Constructor, QualType Type) { - const FunctionProtoType *CtorType = - Constructor->getType()->getAs<FunctionProtoType>(); + const auto *CtorType = Constructor->getType()->castAs<FunctionProtoType>(); if (CtorType->getNumParams() > 0) { QualType FirstArg = CtorType->getParamType(0); if (Context.hasSameUnqualifiedType(Type, FirstArg.getNonReferenceType())) @@ -3265,8 +3326,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType, continue; bool Usable = !Info.Constructor->isInvalidDecl() && - S.isInitListConstructor(Info.Constructor) && - (AllowExplicit || !Info.Constructor->isExplicit()); + S.isInitListConstructor(Info.Constructor); if (Usable) { // If the first argument is (a reference to) the target type, // suppress conversions. @@ -3388,11 +3448,9 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, continue; bool Usable = !Info.Constructor->isInvalidDecl(); - if (ListInitializing) - Usable = Usable && (AllowExplicit || !Info.Constructor->isExplicit()); - else - Usable = Usable && - Info.Constructor->isConvertingConstructor(AllowExplicit); + if (!ListInitializing) + Usable = Usable && Info.Constructor->isConvertingConstructor( + /*AllowExplicit*/ true); if (Usable) { bool SuppressUserConversions = !ConstructorsOnly; if (SuppressUserConversions && ListInitializing) { @@ -3446,16 +3504,14 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, else Conv = cast<CXXConversionDecl>(D); - if (AllowExplicit || !Conv->isExplicit()) { - if (ConvTemplate) - S.AddTemplateConversionCandidate( - ConvTemplate, FoundDecl, ActingContext, From, ToType, - CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit); - else - S.AddConversionCandidate( - Conv, FoundDecl, ActingContext, From, ToType, CandidateSet, - AllowObjCConversionOnExplicit, AllowExplicit); - } + if (ConvTemplate) + S.AddTemplateConversionCandidate( + ConvTemplate, FoundDecl, ActingContext, From, ToType, + CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit); + else + S.AddConversionCandidate( + Conv, FoundDecl, ActingContext, From, ToType, CandidateSet, + AllowObjCConversionOnExplicit, AllowExplicit); } } } @@ -3547,7 +3603,10 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { (OvResult == OR_No_Viable_Function && !CandidateSet.empty()))) return false; - auto Cands = CandidateSet.CompleteCandidates(*this, OCD_AllCandidates, From); + auto Cands = CandidateSet.CompleteCandidates( + *this, + OvResult == OR_Ambiguous ? OCD_AmbiguousCandidates : OCD_AllCandidates, + From); if (OvResult == OR_Ambiguous) Diag(From->getBeginLoc(), diag::err_typecheck_ambiguous_condition) << From->getType() << ToType << From->getSourceRange(); @@ -3929,19 +3988,21 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc, } } - // Compare based on qualification conversions (C++ 13.3.3.2p3, - // bullet 3). - if (ImplicitConversionSequence::CompareKind QualCK - = CompareQualificationConversions(S, SCS1, SCS2)) - return QualCK; - if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { // Check for a better reference binding based on the kind of bindings. if (isBetterReferenceBindingKind(SCS1, SCS2)) return ImplicitConversionSequence::Better; else if (isBetterReferenceBindingKind(SCS2, SCS1)) return ImplicitConversionSequence::Worse; + } + // Compare based on qualification conversions (C++ 13.3.3.2p3, + // bullet 3). + if (ImplicitConversionSequence::CompareKind QualCK + = CompareQualificationConversions(S, SCS1, SCS2)) + return QualCK; + + if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) { // C++ [over.ics.rank]p3b4: // -- S1 and S2 are reference bindings (8.5.3), and the types to // which the references refer are the same type except for @@ -3973,7 +4034,7 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc, T2 = S.Context.getQualifiedType(UnqualT2, T2Quals); if (T2.isMoreQualifiedThan(T1)) return ImplicitConversionSequence::Better; - else if (T1.isMoreQualifiedThan(T2)) + if (T1.isMoreQualifiedThan(T2)) return ImplicitConversionSequence::Worse; } } @@ -4047,22 +4108,16 @@ CompareQualificationConversions(Sema &S, QualType T2 = SCS2.getToType(2); T1 = S.Context.getCanonicalType(T1); T2 = S.Context.getCanonicalType(T2); + assert(!T1->isReferenceType() && !T2->isReferenceType()); Qualifiers T1Quals, T2Quals; QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals); QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals); - // If the types are the same, we won't learn anything by unwrapped + // If the types are the same, we won't learn anything by unwrapping // them. if (UnqualT1 == UnqualT2) return ImplicitConversionSequence::Indistinguishable; - // If the type is an array type, promote the element qualifiers to the type - // for comparison. - if (isa<ArrayType>(T1) && T1Quals) - T1 = S.Context.getQualifiedType(UnqualT1, T1Quals); - if (isa<ArrayType>(T2) && T2Quals) - T2 = S.Context.getQualifiedType(UnqualT2, T2Quals); - ImplicitConversionSequence::CompareKind Result = ImplicitConversionSequence::Indistinguishable; @@ -4290,14 +4345,10 @@ CompareDerivedToBaseConversions(Sema &S, SourceLocation Loc, if (SCS1.Second == ICK_Pointer_Member && SCS2.Second == ICK_Pointer_Member && FromType1->isMemberPointerType() && FromType2->isMemberPointerType() && ToType1->isMemberPointerType() && ToType2->isMemberPointerType()) { - const MemberPointerType * FromMemPointer1 = - FromType1->getAs<MemberPointerType>(); - const MemberPointerType * ToMemPointer1 = - ToType1->getAs<MemberPointerType>(); - const MemberPointerType * FromMemPointer2 = - FromType2->getAs<MemberPointerType>(); - const MemberPointerType * ToMemPointer2 = - ToType2->getAs<MemberPointerType>(); + const auto *FromMemPointer1 = FromType1->castAs<MemberPointerType>(); + const auto *ToMemPointer1 = ToType1->castAs<MemberPointerType>(); + const auto *FromMemPointer2 = FromType2->castAs<MemberPointerType>(); + const auto *ToMemPointer2 = ToType2->castAs<MemberPointerType>(); const Type *FromPointeeType1 = FromMemPointer1->getClass(); const Type *ToPointeeType1 = ToMemPointer1->getClass(); const Type *FromPointeeType2 = FromMemPointer2->getClass(); @@ -4360,20 +4411,26 @@ static bool isTypeValid(QualType T) { return true; } +static QualType withoutUnaligned(ASTContext &Ctx, QualType T) { + if (!T.getQualifiers().hasUnaligned()) + return T; + + Qualifiers Q; + T = Ctx.getUnqualifiedArrayType(T, Q); + Q.removeUnaligned(); + return Ctx.getQualifiedType(T, Q); +} + /// CompareReferenceRelationship - Compare the two types T1 and T2 to -/// determine whether they are reference-related, -/// reference-compatible, reference-compatible with added -/// qualification, or incompatible, for use in C++ initialization by +/// determine whether they are reference-compatible, +/// reference-related, or incompatible, for use in C++ initialization by /// reference (C++ [dcl.ref.init]p4). Neither type can be a reference /// type, and the first type (T1) is the pointee type of the reference /// type being initialized. Sema::ReferenceCompareResult Sema::CompareReferenceRelationship(SourceLocation Loc, QualType OrigT1, QualType OrigT2, - bool &DerivedToBase, - bool &ObjCConversion, - bool &ObjCLifetimeConversion, - bool &FunctionConversion) { + ReferenceConversions *ConvOut) { assert(!OrigT1->isReferenceType() && "T1 must be the pointee type of the reference type"); assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); @@ -4384,76 +4441,84 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals); QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals); - // C++ [dcl.init.ref]p4: + ReferenceConversions ConvTmp; + ReferenceConversions &Conv = ConvOut ? *ConvOut : ConvTmp; + Conv = ReferenceConversions(); + + // C++2a [dcl.init.ref]p4: // Given types "cv1 T1" and "cv2 T2," "cv1 T1" is - // reference-related to "cv2 T2" if T1 is the same type as T2, or + // reference-related to "cv2 T2" if T1 is similar to T2, or // T1 is a base class of T2. - DerivedToBase = false; - ObjCConversion = false; - ObjCLifetimeConversion = false; + // "cv1 T1" is reference-compatible with "cv2 T2" if + // a prvalue of type "pointer to cv2 T2" can be converted to the type + // "pointer to cv1 T1" via a standard conversion sequence. + + // Check for standard conversions we can apply to pointers: derived-to-base + // conversions, ObjC pointer conversions, and function pointer conversions. + // (Qualification conversions are checked last.) QualType ConvertedT2; if (UnqualT1 == UnqualT2) { // Nothing to do. } else if (isCompleteType(Loc, OrigT2) && isTypeValid(UnqualT1) && isTypeValid(UnqualT2) && IsDerivedFrom(Loc, UnqualT2, UnqualT1)) - DerivedToBase = true; + Conv |= ReferenceConversions::DerivedToBase; else if (UnqualT1->isObjCObjectOrInterfaceType() && UnqualT2->isObjCObjectOrInterfaceType() && Context.canBindObjCObjectType(UnqualT1, UnqualT2)) - ObjCConversion = true; + Conv |= ReferenceConversions::ObjC; else if (UnqualT2->isFunctionType() && IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) { - // C++1z [dcl.init.ref]p4: - // cv1 T1" is reference-compatible with "cv2 T2" if [...] T2 is "noexcept - // function" and T1 is "function" - // - // We extend this to also apply to 'noreturn', so allow any function - // conversion between function types. - FunctionConversion = true; + Conv |= ReferenceConversions::Function; + // No need to check qualifiers; function types don't have them. return Ref_Compatible; - } else - return Ref_Incompatible; + } + bool ConvertedReferent = Conv != 0; - // At this point, we know that T1 and T2 are reference-related (at - // least). + // We can have a qualification conversion. Compute whether the types are + // similar at the same time. + bool PreviousToQualsIncludeConst = true; + bool TopLevel = true; + do { + if (T1 == T2) + break; - // If the type is an array type, promote the element qualifiers to the type - // for comparison. - if (isa<ArrayType>(T1) && T1Quals) - T1 = Context.getQualifiedType(UnqualT1, T1Quals); - if (isa<ArrayType>(T2) && T2Quals) - T2 = Context.getQualifiedType(UnqualT2, T2Quals); + // We will need a qualification conversion. + Conv |= ReferenceConversions::Qualification; - // C++ [dcl.init.ref]p4: - // "cv1 T1" is reference-compatible with "cv2 T2" if T1 is - // reference-related to T2 and cv1 is the same cv-qualification - // as, or greater cv-qualification than, cv2. For purposes of - // overload resolution, cases for which cv1 is greater - // cv-qualification than cv2 are identified as - // reference-compatible with added qualification (see 13.3.3.2). - // - // Note that we also require equivalence of Objective-C GC and address-space - // qualifiers when performing these computations, so that e.g., an int in - // address space 1 is not reference-compatible with an int in address - // space 2. - if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() && - T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) { - if (isNonTrivialObjCLifetimeConversion(T2Quals, T1Quals)) - ObjCLifetimeConversion = true; + // Track whether we performed a qualification conversion anywhere other + // than the top level. This matters for ranking reference bindings in + // overload resolution. + if (!TopLevel) + Conv |= ReferenceConversions::NestedQualification; - T1Quals.removeObjCLifetime(); - T2Quals.removeObjCLifetime(); - } + // MS compiler ignores __unaligned qualifier for references; do the same. + T1 = withoutUnaligned(Context, T1); + T2 = withoutUnaligned(Context, T2); - // MS compiler ignores __unaligned qualifier for references; do the same. - T1Quals.removeUnaligned(); - T2Quals.removeUnaligned(); + // If we find a qualifier mismatch, the types are not reference-compatible, + // but are still be reference-related if they're similar. + bool ObjCLifetimeConversion = false; + if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, + PreviousToQualsIncludeConst, + ObjCLifetimeConversion)) + return (ConvertedReferent || Context.hasSimilarType(T1, T2)) + ? Ref_Related + : Ref_Incompatible; - if (T1Quals.compatiblyIncludes(T2Quals)) - return Ref_Compatible; - else - return Ref_Related; + // FIXME: Should we track this for any level other than the first? + if (ObjCLifetimeConversion) + Conv |= ReferenceConversions::ObjCLifetime; + + TopLevel = false; + } while (Context.UnwrapSimilarTypes(T1, T2)); + + // At this point, if the types are reference-related, we must either have the + // same inner type (ignoring qualifiers), or must have already worked out how + // to convert the referent. + return (ConvertedReferent || Context.hasSameUnqualifiedType(T1, T2)) + ? Ref_Compatible + : Ref_Incompatible; } /// Look for a user-defined conversion to a value reference-compatible @@ -4464,8 +4529,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, Expr *Init, QualType T2, bool AllowRvalues, bool AllowExplicit) { assert(T2->isRecordType() && "Can only find conversions of record types."); - CXXRecordDecl *T2RecordDecl - = dyn_cast<CXXRecordDecl>(T2->castAs<RecordType>()->getDecl()); + auto *T2RecordDecl = cast<CXXRecordDecl>(T2->castAs<RecordType>()->getDecl()); OverloadCandidateSet CandidateSet( DeclLoc, OverloadCandidateSet::CSK_InitByUserDefinedConversion); @@ -4484,17 +4548,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, else Conv = cast<CXXConversionDecl>(D); - // If this is an explicit conversion, and we're not allowed to consider - // explicit conversions, skip it. - if (!AllowExplicit && Conv->isExplicit()) - continue; - if (AllowRvalues) { - bool DerivedToBase = false; - bool ObjCConversion = false; - bool ObjCLifetimeConversion = false; - bool FunctionConversion = false; - // If we are initializing an rvalue reference, don't permit conversion // functions that return lvalues. if (!ConvTemplate && DeclType->isRValueReferenceType()) { @@ -4510,9 +4564,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, Conv->getConversionType() .getNonReferenceType() .getUnqualifiedType(), - DeclType.getNonReferenceType().getUnqualifiedType(), - DerivedToBase, ObjCConversion, ObjCLifetimeConversion, - FunctionConversion) == Sema::Ref_Incompatible) + DeclType.getNonReferenceType().getUnqualifiedType()) == + Sema::Ref_Incompatible) continue; } else { // If the conversion function doesn't return a reference type, @@ -4571,7 +4624,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, ICS.setAmbiguous(); for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); Cand != CandidateSet.end(); ++Cand) - if (Cand->Viable) + if (Cand->Best) ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function); return true; @@ -4613,14 +4666,44 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // Compute some basic properties of the types and the initializer. bool isRValRef = DeclType->isRValueReferenceType(); - bool DerivedToBase = false; - bool ObjCConversion = false; - bool ObjCLifetimeConversion = false; - bool FunctionConversion = false; Expr::Classification InitCategory = Init->Classify(S.Context); - Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship( - DeclLoc, T1, T2, DerivedToBase, ObjCConversion, ObjCLifetimeConversion, - FunctionConversion); + + Sema::ReferenceConversions RefConv; + Sema::ReferenceCompareResult RefRelationship = + S.CompareReferenceRelationship(DeclLoc, T1, T2, &RefConv); + + auto SetAsReferenceBinding = [&](bool BindsDirectly) { + ICS.setStandard(); + ICS.Standard.First = ICK_Identity; + // FIXME: A reference binding can be a function conversion too. We should + // consider that when ordering reference-to-function bindings. + ICS.Standard.Second = (RefConv & Sema::ReferenceConversions::DerivedToBase) + ? ICK_Derived_To_Base + : (RefConv & Sema::ReferenceConversions::ObjC) + ? ICK_Compatible_Conversion + : ICK_Identity; + // FIXME: As a speculative fix to a defect introduced by CWG2352, we rank + // a reference binding that performs a non-top-level qualification + // conversion as a qualification conversion, not as an identity conversion. + ICS.Standard.Third = (RefConv & + Sema::ReferenceConversions::NestedQualification) + ? ICK_Qualification + : ICK_Identity; + ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS.Standard.setToType(0, T2); + ICS.Standard.setToType(1, T1); + ICS.Standard.setToType(2, T1); + ICS.Standard.ReferenceBinding = true; + ICS.Standard.DirectBinding = BindsDirectly; + ICS.Standard.IsLvalueReference = !isRValRef; + ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); + ICS.Standard.BindsToRvalue = InitCategory.isRValue(); + ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; + ICS.Standard.ObjCLifetimeConversionBinding = + (RefConv & Sema::ReferenceConversions::ObjCLifetime) != 0; + ICS.Standard.CopyConstructor = nullptr; + ICS.Standard.DeprecatedStringLiteralToCharPtr = false; + }; // C++0x [dcl.init.ref]p5: // A reference to type "cv1 T1" is initialized by an expression @@ -4640,25 +4723,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // has a type that is a derived class of the parameter type, // in which case the implicit conversion sequence is a // derived-to-base Conversion (13.3.3.1). - ICS.setStandard(); - ICS.Standard.First = ICK_Identity; - ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base - : ObjCConversion? ICK_Compatible_Conversion - : ICK_Identity; - ICS.Standard.Third = ICK_Identity; - ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS.Standard.setToType(0, T2); - ICS.Standard.setToType(1, T1); - ICS.Standard.setToType(2, T1); - ICS.Standard.ReferenceBinding = true; - ICS.Standard.DirectBinding = true; - ICS.Standard.IsLvalueReference = !isRValRef; - ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); - ICS.Standard.BindsToRvalue = false; - ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; - ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion; - ICS.Standard.CopyConstructor = nullptr; - ICS.Standard.DeprecatedStringLiteralToCharPtr = false; + SetAsReferenceBinding(/*BindsDirectly=*/true); // Nothing more to do: the inaccessibility/ambiguity check for // derived-to-base conversions is suppressed when we're @@ -4696,34 +4761,16 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or if (RefRelationship == Sema::Ref_Compatible && (InitCategory.isXValue() || - (InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) || + (InitCategory.isPRValue() && + (T2->isRecordType() || T2->isArrayType())) || (InitCategory.isLValue() && T2->isFunctionType()))) { - ICS.setStandard(); - ICS.Standard.First = ICK_Identity; - ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base - : ObjCConversion? ICK_Compatible_Conversion - : ICK_Identity; - ICS.Standard.Third = ICK_Identity; - ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); - ICS.Standard.setToType(0, T2); - ICS.Standard.setToType(1, T1); - ICS.Standard.setToType(2, T1); - ICS.Standard.ReferenceBinding = true; - // In C++0x, this is always a direct binding. In C++98/03, it's a direct + // In C++11, this is always a direct binding. In C++98/03, it's a direct // binding unless we're binding to a class prvalue. // Note: Although xvalues wouldn't normally show up in C++98/03 code, we // allow the use of rvalue references in C++98/03 for the benefit of // standard library implementors; therefore, we need the xvalue check here. - ICS.Standard.DirectBinding = - S.getLangOpts().CPlusPlus11 || - !(InitCategory.isPRValue() || T2->isRecordType()); - ICS.Standard.IsLvalueReference = !isRValRef; - ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType(); - ICS.Standard.BindsToRvalue = InitCategory.isRValue(); - ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false; - ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion; - ICS.Standard.CopyConstructor = nullptr; - ICS.Standard.DeprecatedStringLiteralToCharPtr = false; + SetAsReferenceBinding(/*BindsDirectly=*/S.getLangOpts().CPlusPlus11 || + !(InitCategory.isPRValue() || T2->isRecordType())); return ICS; } @@ -5042,13 +5089,8 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, } // Compute some basic properties of the types and the initializer. - bool dummy1 = false; - bool dummy2 = false; - bool dummy3 = false; - bool dummy4 = false; Sema::ReferenceCompareResult RefRelationship = - S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2, dummy1, - dummy2, dummy3, dummy4); + S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2); if (RefRelationship >= Sema::Ref_Related) { return TryReferenceInit(S, Init, ToType, /*FIXME*/ From->getBeginLoc(), @@ -5218,7 +5260,7 @@ TryObjectArgumentInitialization(Sema &S, SourceLocation Loc, QualType FromType, return ICS; } - if (FromTypeCanon.getQualifiers().hasAddressSpace()) { + if (FromTypeCanon.hasAddressSpace()) { Qualifiers QualsImplicitParamType = ImplicitParamType.getQualifiers(); Qualifiers QualsFromType = FromTypeCanon.getQualifiers(); if (!QualsImplicitParamType.isAddressSpaceSupersetOf(QualsFromType)) { @@ -5367,7 +5409,10 @@ Sema::PerformObjectArgumentInitialization(Expr *From, if (!Context.hasSameType(From->getType(), DestType)) { CastKind CK; - if (FromRecordType.getAddressSpace() != DestType.getAddressSpace()) + QualType PteeTy = DestType->getPointeeType(); + LangAS DestAS = + PteeTy.isNull() ? DestType.getAddressSpace() : PteeTy.getAddressSpace(); + if (FromRecordType.getAddressSpace() != DestAS) CK = CK_AddressSpaceConversion; else CK = CK_NoOp; @@ -6046,7 +6091,7 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context, if (T1->isRecordType() || (!T2.isNull() && T2->isRecordType())) return true; - const FunctionProtoType *Proto = Fn->getType()->getAs<FunctionProtoType>(); + const auto *Proto = Fn->getType()->castAs<FunctionProtoType>(); if (Proto->getNumParams() < 1) return false; @@ -6146,6 +6191,15 @@ void Sema::AddOverloadCandidate( Candidate.IgnoreObjectArgument = false; Candidate.ExplicitCallArguments = Args.size(); + // Explicit functions are not actually candidates at all if we're not + // allowing them in this context, but keep them around so we can point + // to them in diagnostics. + if (!AllowExplicit && ExplicitSpecifier::getFromDecl(Function).isExplicit()) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_explicit; + return; + } + if (Function->isMultiVersion() && Function->hasAttr<TargetAttr>() && !Function->getAttr<TargetAttr>()->isDefaultVersion()) { Candidate.Viable = false; @@ -6237,6 +6291,16 @@ void Sema::AddOverloadCandidate( return; } + if (Expr *RequiresClause = Function->getTrailingRequiresClause()) { + ConstraintSatisfaction Satisfaction; + if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + !Satisfaction.IsSatisfied) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_constraints_not_satisfied; + return; + } + } + // Determine the implicit conversion sequences for each of the // arguments. for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) { @@ -6269,15 +6333,6 @@ void Sema::AddOverloadCandidate( } } - if (!AllowExplicit) { - ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Function); - if (ES.getKind() != ExplicitSpecKind::ResolvedFalse) { - Candidate.Viable = false; - Candidate.FailureKind = ovl_fail_explicit_resolved; - return; - } - } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; @@ -6753,6 +6808,16 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, return; } + if (Expr *RequiresClause = Method->getTrailingRequiresClause()) { + ConstraintSatisfaction Satisfaction; + if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + !Satisfaction.IsSatisfied) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_constraints_not_satisfied; + return; + } + } + // Determine the implicit conversion sequences for each of the // arguments. for (unsigned ArgIdx = 0; ArgIdx < Args.size(); ++ArgIdx) { @@ -6866,6 +6931,12 @@ void Sema::AddMethodTemplateCandidate( Conversions, PO); } +/// Determine whether a given function template has a simple explicit specifier +/// or a non-value-dependent explicit-specification that evaluates to true. +static bool isNonDependentlyExplicit(FunctionTemplateDecl *FTD) { + return ExplicitSpecifier::getFromDecl(FTD->getTemplatedDecl()).isExplicit(); +} + /// Add a C++ function template specialization as a candidate /// in the candidate set, using template argument deduction to produce /// an appropriate function template specialization. @@ -6878,6 +6949,18 @@ void Sema::AddTemplateOverloadCandidate( if (!CandidateSet.isNewCandidate(FunctionTemplate, PO)) return; + // If the function template has a non-dependent explicit specification, + // exclude it now if appropriate; we are not permitted to perform deduction + // and substitution in this case. + if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) { + OverloadCandidate &Candidate = CandidateSet.addCandidate(); + Candidate.FoundDecl = FoundDecl; + Candidate.Function = FunctionTemplate->getTemplatedDecl(); + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_explicit; + return; + } + // C++ [over.match.funcs]p7: // In each case where a candidate is a function template, candidate // function template specializations are generated using template argument @@ -7065,6 +7148,9 @@ void Sema::AddConversionCandidate( // Per C++ [over.match.conv]p1, [over.match.ref]p1, an explicit conversion // operator is only a candidate if its return type is the target type or // can be converted to the target type with a qualification conversion. + // + // FIXME: Include such functions in the candidate list and explain why we + // can't select them. if (Conversion->isExplicit() && !isAllowableExplicitConversion(*this, ConvType, ToType, AllowObjCConversionOnExplicit)) @@ -7086,6 +7172,15 @@ void Sema::AddConversionCandidate( Candidate.Viable = true; Candidate.ExplicitCallArguments = 1; + // Explicit functions are not actually candidates at all if we're not + // allowing them in this context, but keep them around so we can point + // to them in diagnostics. + if (!AllowExplicit && Conversion->isExplicit()) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_explicit; + return; + } + // C++ [over.match.funcs]p4: // For conversion functions, the function is considered to be a member of // the class of the implicit implied object argument for the purpose of @@ -7109,6 +7204,17 @@ void Sema::AddConversionCandidate( return; } + Expr *RequiresClause = Conversion->getTrailingRequiresClause(); + if (RequiresClause) { + ConstraintSatisfaction Satisfaction; + if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + !Satisfaction.IsSatisfied) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_constraints_not_satisfied; + return; + } + } + // We won't go through a user-defined type conversion function to convert a // derived to base as such conversions are given Conversion Rank. They only // go through a copy constructor. 13.3.3.1.2-p4 [over.ics.user] @@ -7199,13 +7305,6 @@ void Sema::AddConversionCandidate( "Can only end up with a standard conversion sequence or failure"); } - if (!AllowExplicit && Conversion->getExplicitSpecifier().getKind() != - ExplicitSpecKind::ResolvedFalse) { - Candidate.Viable = false; - Candidate.FailureKind = ovl_fail_explicit_resolved; - return; - } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; @@ -7236,6 +7335,18 @@ void Sema::AddTemplateConversionCandidate( if (!CandidateSet.isNewCandidate(FunctionTemplate)) return; + // If the function template has a non-dependent explicit specification, + // exclude it now if appropriate; we are not permitted to perform deduction + // and substitution in this case. + if (!AllowExplicit && isNonDependentlyExplicit(FunctionTemplate)) { + OverloadCandidate &Candidate = CandidateSet.addCandidate(); + Candidate.FoundDecl = FoundDecl; + Candidate.Function = FunctionTemplate->getTemplatedDecl(); + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_explicit; + return; + } + TemplateDeductionInfo Info(CandidateSet.getLocation()); CXXConversionDecl *Specialization = nullptr; if (TemplateDeductionResult Result @@ -9440,6 +9551,35 @@ bool clang::isBetterOverloadCandidate( return BetterTemplate == Cand1.Function->getPrimaryTemplate(); } + // -— F1 and F2 are non-template functions with the same + // parameter-type-lists, and F1 is more constrained than F2 [...], + if (Cand1.Function && Cand2.Function && !Cand1IsSpecialization && + !Cand2IsSpecialization && Cand1.Function->hasPrototype() && + Cand2.Function->hasPrototype()) { + auto *PT1 = cast<FunctionProtoType>(Cand1.Function->getFunctionType()); + auto *PT2 = cast<FunctionProtoType>(Cand2.Function->getFunctionType()); + if (PT1->getNumParams() == PT2->getNumParams() && + PT1->isVariadic() == PT2->isVariadic() && + S.FunctionParamTypesAreEqual(PT1, PT2)) { + Expr *RC1 = Cand1.Function->getTrailingRequiresClause(); + Expr *RC2 = Cand2.Function->getTrailingRequiresClause(); + if (RC1 && RC2) { + bool AtLeastAsConstrained1, AtLeastAsConstrained2; + if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function, + {RC2}, AtLeastAsConstrained1)) + return false; + if (!AtLeastAsConstrained1) + return false; + if (S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function, + {RC1}, AtLeastAsConstrained2)) + return false; + if (!AtLeastAsConstrained2) + return true; + } else if (RC1 || RC2) + return RC1 != nullptr; + } + } + // -- F1 is a constructor for a class D, F2 is a constructor for a base // class B of D, and for all arguments the corresponding parameters of // F1 and F2 have the same type. @@ -9527,8 +9667,7 @@ bool Sema::isEquivalentInternalLinkageDeclaration(const NamedDecl *A, // entity in different modules. if (!VA->getDeclContext()->getRedeclContext()->Equals( VB->getDeclContext()->getRedeclContext()) || - getOwningModule(const_cast<ValueDecl *>(VA)) == - getOwningModule(const_cast<ValueDecl *>(VB)) || + getOwningModule(VA) == getOwningModule(VB) || VA->isExternallyVisible() || VB->isExternallyVisible()) return false; @@ -9565,12 +9704,12 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations( SourceLocation Loc, const NamedDecl *D, ArrayRef<const NamedDecl *> Equiv) { Diag(Loc, diag::ext_equivalent_internal_linkage_decl_in_modules) << D; - Module *M = getOwningModule(const_cast<NamedDecl*>(D)); + Module *M = getOwningModule(D); Diag(D->getLocation(), diag::note_equivalent_internal_linkage_decl) << !M << (M ? M->getFullModuleName() : ""); for (auto *E : Equiv) { - Module *M = getOwningModule(const_cast<NamedDecl*>(E)); + Module *M = getOwningModule(E); Diag(E->getLocation(), diag::note_equivalent_internal_linkage_decl) << !M << (M ? M->getFullModuleName() : ""); } @@ -9622,11 +9761,13 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, // Find the best viable function. Best = end(); - for (auto *Cand : Candidates) + for (auto *Cand : Candidates) { + Cand->Best = false; if (Cand->Viable) if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc, Kind)) Best = Cand; + } // If we didn't find any viable functions, abort. if (Best == end()) @@ -9634,22 +9775,33 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, llvm::SmallVector<const NamedDecl *, 4> EquivalentCands; + llvm::SmallVector<OverloadCandidate*, 4> PendingBest; + PendingBest.push_back(&*Best); + Best->Best = true; + // Make sure that this function is better than every other viable // function. If not, we have an ambiguity. - for (auto *Cand : Candidates) { - if (Cand->Viable && Cand != Best && - !isBetterOverloadCandidate(S, *Best, *Cand, Loc, Kind)) { - if (S.isEquivalentInternalLinkageDeclaration(Best->Function, - Cand->Function)) { - EquivalentCands.push_back(Cand->Function); - continue; - } + while (!PendingBest.empty()) { + auto *Curr = PendingBest.pop_back_val(); + for (auto *Cand : Candidates) { + if (Cand->Viable && !Cand->Best && + !isBetterOverloadCandidate(S, *Curr, *Cand, Loc, Kind)) { + PendingBest.push_back(Cand); + Cand->Best = true; - Best = end(); - return OR_Ambiguous; + if (S.isEquivalentInternalLinkageDeclaration(Cand->Function, + Curr->Function)) + EquivalentCands.push_back(Cand->Function); + else + Best = end(); + } } } + // If we found more than one best candidate, this is ambiguous. + if (Best == end()) + return OR_Ambiguous; + // Best is the best viable function. if (Best->Function && Best->Function->isDeleted()) return OR_Deleted; @@ -9673,6 +9825,7 @@ enum OverloadCandidateKind { oc_implicit_move_constructor, oc_implicit_copy_assignment, oc_implicit_move_assignment, + oc_implicit_equality_comparison, oc_inherited_constructor }; @@ -9701,6 +9854,9 @@ ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn, }(); OverloadCandidateKind Kind = [&]() { + if (Fn->isImplicit() && Fn->getOverloadedOperator() == OO_EqualEqual) + return oc_implicit_equality_comparison; + if (CRK & CRK_Reversed) return oc_reversed_binary_operator; @@ -9791,6 +9947,24 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD, return false; } + if (const Expr *RC = FD->getTrailingRequiresClause()) { + ConstraintSatisfaction Satisfaction; + if (S.CheckConstraintSatisfaction(RC, Satisfaction)) + return false; + if (!Satisfaction.IsSatisfied) { + if (Complain) { + if (InOverloadResolution) + S.Diag(FD->getBeginLoc(), + diag::note_ovl_candidate_unsatisfied_constraints); + else + S.Diag(Loc, diag::err_addrof_function_constraints_not_satisfied) + << FD; + S.DiagnoseUnsatisfiedConstraint(Satisfaction); + } + return false; + } + } + auto I = llvm::find_if(FD->parameters(), [](const ParmVarDecl *P) { return P->hasAttr<PassObjectSizeAttr>(); }); @@ -9848,6 +10022,55 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, MaybeEmitInheritedConstructorNote(*this, Found); } +static void +MaybeDiagnoseAmbiguousConstraints(Sema &S, ArrayRef<OverloadCandidate> Cands) { + // Perhaps the ambiguity was caused by two atomic constraints that are + // 'identical' but not equivalent: + // + // void foo() requires (sizeof(T) > 4) { } // #1 + // void foo() requires (sizeof(T) > 4) && T::value { } // #2 + // + // The 'sizeof(T) > 4' constraints are seemingly equivalent and should cause + // #2 to subsume #1, but these constraint are not considered equivalent + // according to the subsumption rules because they are not the same + // source-level construct. This behavior is quite confusing and we should try + // to help the user figure out what happened. + + SmallVector<const Expr *, 3> FirstAC, SecondAC; + FunctionDecl *FirstCand = nullptr, *SecondCand = nullptr; + for (auto I = Cands.begin(), E = Cands.end(); I != E; ++I) { + if (!I->Function) + continue; + SmallVector<const Expr *, 3> AC; + if (auto *Template = I->Function->getPrimaryTemplate()) + Template->getAssociatedConstraints(AC); + else + I->Function->getAssociatedConstraints(AC); + if (AC.empty()) + continue; + if (FirstCand == nullptr) { + FirstCand = I->Function; + FirstAC = AC; + } else if (SecondCand == nullptr) { + SecondCand = I->Function; + SecondAC = AC; + } else { + // We have more than one pair of constrained functions - this check is + // expensive and we'd rather not try to diagnose it. + return; + } + } + if (!SecondCand) + return; + // The diagnostic can only happen if there are associated constraints on + // both sides (there needs to be some identical atomic constraint). + if (S.MaybeEmitAmbiguousAtomicConstraintsDiagnostic(FirstCand, FirstAC, + SecondCand, SecondAC)) + // Just show the user one diagnostic, they'll probably figure it out + // from here. + return; +} + // Notes the location of all overload candidates designated through // OverloadedExpr void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType, @@ -9916,7 +10139,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, std::string FnDesc; std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = - ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind, + ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->getRewriteKind(), FnDesc); Expr *FromExpr = Conv.Bad.FromExpr; @@ -9959,10 +10182,17 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, Qualifiers ToQs = CToTy.getQualifiers(); if (FromQs.getAddressSpace() != ToQs.getAddressSpace()) { - S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace) - << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc - << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy - << ToTy << (unsigned)isObjectArgument << I + 1; + if (isObjectArgument) + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace_this) + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second + << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromQs.getAddressSpace() << ToQs.getAddressSpace(); + else + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_addrspace) + << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second + << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromQs.getAddressSpace() << ToQs.getAddressSpace() + << ToTy->isReferenceType() << I + 1; MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -10167,7 +10397,7 @@ static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, FunctionDecl *Fn = cast<FunctionDecl>(D); // TODO: treat calls to a missing default constructor as a special case - const FunctionProtoType *FnTy = Fn->getType()->getAs<FunctionProtoType>(); + const auto *FnTy = Fn->getType()->castAs<FunctionProtoType>(); unsigned MinParams = Fn->getMinRequiredArguments(); // at least / at most / exactly @@ -10303,6 +10533,16 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, which = 2; } + // Tweak the diagnostic if the problem is that we deduced packs of + // different arities. We'll print the actual packs anyway in case that + // includes additional useful information. + if (DeductionFailure.getFirstArg()->getKind() == TemplateArgument::Pack && + DeductionFailure.getSecondArg()->getKind() == TemplateArgument::Pack && + DeductionFailure.getFirstArg()->pack_size() != + DeductionFailure.getSecondArg()->pack_size()) { + which = 3; + } + S.Diag(Templated->getLocation(), diag::note_ovl_candidate_inconsistent_deduction) << which << ParamD->getDeclName() << *DeductionFailure.getFirstArg() @@ -10333,6 +10573,23 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, MaybeEmitInheritedConstructorNote(S, Found); return; + case Sema::TDK_ConstraintsNotSatisfied: { + // Format the template argument list into the argument string. + SmallString<128> TemplateArgString; + TemplateArgumentList *Args = DeductionFailure.getTemplateArgumentList(); + TemplateArgString = " "; + TemplateArgString += S.getTemplateArgumentBindingsText( + getDescribedTemplate(Templated)->getTemplateParameters(), *Args); + if (TemplateArgString.size() == 1) + TemplateArgString.clear(); + S.Diag(Templated->getLocation(), + diag::note_ovl_candidate_unsatisfied_constraints) + << TemplateArgString; + + S.DiagnoseUnsatisfiedConstraint( + static_cast<CNSInfo*>(DeductionFailure.Data)->Satisfaction); + return; + } case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: DiagnoseArityMismatch(S, Found, Templated, NumArgs); @@ -10352,6 +10609,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, TemplateArgString = " "; TemplateArgString += S.getTemplateArgumentBindingsText( getDescribedTemplate(Templated)->getTemplateParameters(), *Args); + if (TemplateArgString.size() == 1) + TemplateArgString.clear(); } // If this candidate was disabled by enable_if, say so. @@ -10401,6 +10660,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, TemplateArgString = " "; TemplateArgString += S.getTemplateArgumentBindingsText( getDescribedTemplate(Templated)->getTemplateParameters(), *Args); + if (TemplateArgString.size() == 1) + TemplateArgString.clear(); } S.Diag(Templated->getLocation(), diag::note_ovl_candidate_deduced_mismatch) @@ -10486,8 +10747,8 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { std::string FnDesc; std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = - ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, Cand->RewriteKind, - FnDesc); + ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, + Cand->getRewriteKind(), FnDesc); S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target) << (unsigned)FnKindPair.first << (unsigned)ocs_non_template @@ -10545,30 +10806,36 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) { } static void DiagnoseFailedExplicitSpec(Sema &S, OverloadCandidate *Cand) { - ExplicitSpecifier ES; - const char *DeclName; + ExplicitSpecifier ES = ExplicitSpecifier::getFromDecl(Cand->Function); + assert(ES.isExplicit() && "not an explicit candidate"); + + unsigned Kind; switch (Cand->Function->getDeclKind()) { case Decl::Kind::CXXConstructor: - ES = cast<CXXConstructorDecl>(Cand->Function)->getExplicitSpecifier(); - DeclName = "constructor"; + Kind = 0; break; case Decl::Kind::CXXConversion: - ES = cast<CXXConversionDecl>(Cand->Function)->getExplicitSpecifier(); - DeclName = "conversion operator"; + Kind = 1; break; case Decl::Kind::CXXDeductionGuide: - ES = cast<CXXDeductionGuideDecl>(Cand->Function)->getExplicitSpecifier(); - DeclName = "deductiong guide"; + Kind = Cand->Function->isImplicit() ? 0 : 2; break; default: llvm_unreachable("invalid Decl"); } - assert(ES.getExpr() && "null expression should be handled before"); - S.Diag(Cand->Function->getLocation(), - diag::note_ovl_candidate_explicit_forbidden) - << DeclName; - S.Diag(ES.getExpr()->getBeginLoc(), - diag::note_explicit_bool_resolved_to_true); + + // Note the location of the first (in-class) declaration; a redeclaration + // (particularly an out-of-class definition) will typically lack the + // 'explicit' specifier. + // FIXME: This is probably a good thing to do for all 'candidate' notes. + FunctionDecl *First = Cand->Function->getFirstDecl(); + if (FunctionDecl *Pattern = First->getTemplateInstantiationPattern()) + First = Pattern->getFirstDecl(); + + S.Diag(First->getLocation(), + diag::note_ovl_candidate_explicit) + << Kind << (ES.getExpr() ? 1 : 0) + << (ES.getExpr() ? ES.getExpr()->getSourceRange() : SourceRange()); } static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) { @@ -10605,8 +10872,8 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, if (Fn->isDeleted()) { std::string FnDesc; std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = - ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, Cand->RewriteKind, - FnDesc); + ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, + Cand->getRewriteKind(), FnDesc); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted) << (unsigned)FnKindPair.first << (unsigned)FnKindPair.second << FnDesc @@ -10616,7 +10883,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, } // We don't really have anything else to say about viable candidates. - S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind); + S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind()); return; } @@ -10649,7 +10916,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, case ovl_fail_trivial_conversion: case ovl_fail_bad_final_conversion: case ovl_fail_final_conversion_not_exact: - return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind); + return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind()); case ovl_fail_bad_conversion: { unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0); @@ -10660,7 +10927,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, // FIXME: this currently happens when we're called from SemaInit // when user-conversion overload fails. Figure out how to handle // those conditions and diagnose them well. - return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->RewriteKind); + return S.NoteOverloadCandidate(Cand->FoundDecl, Fn, Cand->getRewriteKind()); } case ovl_fail_bad_target: @@ -10669,7 +10936,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, case ovl_fail_enable_if: return DiagnoseFailedEnableIfAttr(S, Cand); - case ovl_fail_explicit_resolved: + case ovl_fail_explicit: return DiagnoseFailedExplicitSpec(S, Cand); case ovl_fail_ext_disabled: @@ -10695,6 +10962,23 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, case ovl_non_default_multiversion_function: // Do nothing, these should simply be ignored. break; + + case ovl_fail_constraints_not_satisfied: { + std::string FnDesc; + std::pair<OverloadCandidateKind, OverloadCandidateSelect> FnKindPair = + ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, + Cand->getRewriteKind(), FnDesc); + + S.Diag(Fn->getLocation(), + diag::note_ovl_candidate_constraints_not_satisfied) + << (unsigned)FnKindPair.first << (unsigned)ocs_non_template + << FnDesc /* Ignored */; + ConstraintSatisfaction Satisfaction; + if (S.CheckConstraintSatisfaction(Fn->getTrailingRequiresClause(), + Satisfaction)) + break; + S.DiagnoseUnsatisfiedConstraint(Satisfaction); + } } } @@ -10785,6 +11069,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) { case Sema::TDK_SubstitutionFailure: case Sema::TDK_DeducedMismatch: + case Sema::TDK_ConstraintsNotSatisfied: case Sema::TDK_DeducedMismatchNested: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_MiscellaneousDeductionFailure: @@ -10816,6 +11101,23 @@ struct CompareOverloadCandidatesForDisplay { OverloadCandidateSet::CandidateSetKind CSK) : S(S), NumArgs(NArgs), CSK(CSK) {} + OverloadFailureKind EffectiveFailureKind(const OverloadCandidate *C) const { + // If there are too many or too few arguments, that's the high-order bit we + // want to sort by, even if the immediate failure kind was something else. + if (C->FailureKind == ovl_fail_too_many_arguments || + C->FailureKind == ovl_fail_too_few_arguments) + return static_cast<OverloadFailureKind>(C->FailureKind); + + if (C->Function) { + if (NumArgs > C->Function->getNumParams() && !C->Function->isVariadic()) + return ovl_fail_too_many_arguments; + if (NumArgs < C->Function->getMinRequiredArguments()) + return ovl_fail_too_few_arguments; + } + + return static_cast<OverloadFailureKind>(C->FailureKind); + } + bool operator()(const OverloadCandidate *L, const OverloadCandidate *R) { // Fast-path this check. @@ -10839,34 +11141,37 @@ struct CompareOverloadCandidatesForDisplay { // Criteria by which we can sort non-viable candidates: if (!L->Viable) { + OverloadFailureKind LFailureKind = EffectiveFailureKind(L); + OverloadFailureKind RFailureKind = EffectiveFailureKind(R); + // 1. Arity mismatches come after other candidates. - if (L->FailureKind == ovl_fail_too_many_arguments || - L->FailureKind == ovl_fail_too_few_arguments) { - if (R->FailureKind == ovl_fail_too_many_arguments || - R->FailureKind == ovl_fail_too_few_arguments) { + if (LFailureKind == ovl_fail_too_many_arguments || + LFailureKind == ovl_fail_too_few_arguments) { + if (RFailureKind == ovl_fail_too_many_arguments || + RFailureKind == ovl_fail_too_few_arguments) { int LDist = std::abs((int)L->getNumParams() - (int)NumArgs); int RDist = std::abs((int)R->getNumParams() - (int)NumArgs); if (LDist == RDist) { - if (L->FailureKind == R->FailureKind) + if (LFailureKind == RFailureKind) // Sort non-surrogates before surrogates. return !L->IsSurrogate && R->IsSurrogate; // Sort candidates requiring fewer parameters than there were // arguments given after candidates requiring more parameters // than there were arguments given. - return L->FailureKind == ovl_fail_too_many_arguments; + return LFailureKind == ovl_fail_too_many_arguments; } return LDist < RDist; } return false; } - if (R->FailureKind == ovl_fail_too_many_arguments || - R->FailureKind == ovl_fail_too_few_arguments) + if (RFailureKind == ovl_fail_too_many_arguments || + RFailureKind == ovl_fail_too_few_arguments) return true; // 2. Bad conversions come first and are ordered by the number // of bad conversions and quality of good conversions. - if (L->FailureKind == ovl_fail_bad_conversion) { - if (R->FailureKind != ovl_fail_bad_conversion) + if (LFailureKind == ovl_fail_bad_conversion) { + if (RFailureKind != ovl_fail_bad_conversion) return true; // The conversion that can be fixed with a smaller number of changes, @@ -10904,17 +11209,17 @@ struct CompareOverloadCandidatesForDisplay { if (leftBetter > 0) return true; if (leftBetter < 0) return false; - } else if (R->FailureKind == ovl_fail_bad_conversion) + } else if (RFailureKind == ovl_fail_bad_conversion) return false; - if (L->FailureKind == ovl_fail_bad_deduction) { - if (R->FailureKind != ovl_fail_bad_deduction) + if (LFailureKind == ovl_fail_bad_deduction) { + if (RFailureKind != ovl_fail_bad_deduction) return true; if (L->DeductionFailure.Result != R->DeductionFailure.Result) return RankDeductionFailure(L->DeductionFailure) < RankDeductionFailure(R->DeductionFailure); - } else if (R->FailureKind == ovl_fail_bad_deduction) + } else if (RFailureKind == ovl_fail_bad_deduction) return false; // TODO: others? @@ -10943,7 +11248,8 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, assert(!Cand->Viable); // Don't do anything on failures other than bad conversion. - if (Cand->FailureKind != ovl_fail_bad_conversion) return; + if (Cand->FailureKind != ovl_fail_bad_conversion) + return; // We only want the FixIts if all the arguments can be corrected. bool Unfixable = false; @@ -10969,6 +11275,7 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, unsigned ConvIdx = 0; unsigned ArgIdx = 0; ArrayRef<QualType> ParamTypes; + bool Reversed = Cand->RewriteKind & CRK_Reversed; if (Cand->IsSurrogate) { QualType ConvType @@ -10982,10 +11289,11 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, ParamTypes = Cand->Function->getType()->castAs<FunctionProtoType>()->getParamTypes(); if (isa<CXXMethodDecl>(Cand->Function) && - !isa<CXXConstructorDecl>(Cand->Function)) { + !isa<CXXConstructorDecl>(Cand->Function) && !Reversed) { // Conversion 0 is 'this', which doesn't have a corresponding parameter. ConvIdx = 1; - if (CSK == OverloadCandidateSet::CSK_Operator) + if (CSK == OverloadCandidateSet::CSK_Operator && + Cand->Function->getDeclName().getCXXOverloadedOperator() != OO_Call) // Argument 0 is 'this', which doesn't have a corresponding parameter. ArgIdx = 1; } @@ -10996,13 +11304,13 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, } // Fill in the rest of the conversions. - bool Reversed = Cand->RewriteKind & CRK_Reversed; for (unsigned ParamIdx = Reversed ? ParamTypes.size() - 1 : 0; ConvIdx != ConvCount; ++ConvIdx, ++ArgIdx, ParamIdx += (Reversed ? -1 : 1)) { + assert(ArgIdx < Args.size() && "no argument for this arg conversion"); if (Cand->Conversions[ConvIdx].isInitialized()) { // We've already checked this conversion. - } else if (ArgIdx < ParamTypes.size()) { + } else if (ParamIdx < ParamTypes.size()) { if (ParamTypes[ParamIdx]->isDependentType()) Cand->Conversions[ConvIdx].setAsIdentityConversion( Args[ArgIdx]->getType()); @@ -11033,15 +11341,30 @@ SmallVector<OverloadCandidate *, 32> OverloadCandidateSet::CompleteCandidates( for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) { if (!Filter(*Cand)) continue; - if (Cand->Viable) - Cands.push_back(Cand); - else if (OCD == OCD_AllCandidates) { - CompleteNonViableCandidate(S, Cand, Args, Kind); - if (Cand->Function || Cand->IsSurrogate) - Cands.push_back(Cand); - // Otherwise, this a non-viable builtin candidate. We do not, in general, - // want to list every possible builtin candidate. + switch (OCD) { + case OCD_AllCandidates: + if (!Cand->Viable) { + if (!Cand->Function && !Cand->IsSurrogate) { + // This a non-viable builtin candidate. We do not, in general, + // want to list every possible builtin candidate. + continue; + } + CompleteNonViableCandidate(S, Cand, Args, Kind); + } + break; + + case OCD_ViableCandidates: + if (!Cand->Viable) + continue; + break; + + case OCD_AmbiguousCandidates: + if (!Cand->Best) + continue; + break; } + + Cands.push_back(Cand); } llvm::stable_sort( @@ -11062,6 +11385,9 @@ void OverloadCandidateSet::NoteCandidates(PartialDiagnosticAt PD, S.Diag(PD.first, PD.second); NoteCandidates(S, Args, Cands, Opc, OpLoc); + + if (OCD == OCD_AmbiguousCandidates) + MaybeDiagnoseAmbiguousConstraints(S, {begin(), end()}); } void OverloadCandidateSet::NoteCandidates(Sema &S, ArrayRef<Expr *> Args, @@ -11710,15 +12036,33 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, /// resolve that function to a single function that can have its address taken. /// This will modify `Pair` iff it returns non-null. /// -/// This routine can only realistically succeed if all but one candidates in the -/// overload set for SrcExpr cannot have their addresses taken. +/// This routine can only succeed if from all of the candidates in the overload +/// set for SrcExpr that can have their addresses taken, there is one candidate +/// that is more constrained than the rest. FunctionDecl * -Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E, - DeclAccessPair &Pair) { +Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) { OverloadExpr::FindResult R = OverloadExpr::find(E); OverloadExpr *Ovl = R.Expression; + bool IsResultAmbiguous = false; FunctionDecl *Result = nullptr; DeclAccessPair DAP; + SmallVector<FunctionDecl *, 2> AmbiguousDecls; + + auto CheckMoreConstrained = + [&] (FunctionDecl *FD1, FunctionDecl *FD2) -> Optional<bool> { + SmallVector<const Expr *, 1> AC1, AC2; + FD1->getAssociatedConstraints(AC1); + FD2->getAssociatedConstraints(AC2); + bool AtLeastAsConstrained1, AtLeastAsConstrained2; + if (IsAtLeastAsConstrained(FD1, AC1, FD2, AC2, AtLeastAsConstrained1)) + return None; + if (IsAtLeastAsConstrained(FD2, AC2, FD1, AC1, AtLeastAsConstrained2)) + return None; + if (AtLeastAsConstrained1 == AtLeastAsConstrained2) + return None; + return AtLeastAsConstrained1; + }; + // Don't use the AddressOfResolver because we're specifically looking for // cases where we have one overload candidate that lacks // enable_if/pass_object_size/... @@ -11730,32 +12074,54 @@ Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E, if (!checkAddressOfFunctionIsAvailable(FD)) continue; - // We have more than one result; quit. - if (Result) - return nullptr; + // We have more than one result - see if it is more constrained than the + // previous one. + if (Result) { + Optional<bool> MoreConstrainedThanPrevious = CheckMoreConstrained(FD, + Result); + if (!MoreConstrainedThanPrevious) { + IsResultAmbiguous = true; + AmbiguousDecls.push_back(FD); + continue; + } + if (!*MoreConstrainedThanPrevious) + continue; + // FD is more constrained - replace Result with it. + } + IsResultAmbiguous = false; DAP = I.getPair(); Result = FD; } - if (Result) + if (IsResultAmbiguous) + return nullptr; + + if (Result) { + SmallVector<const Expr *, 1> ResultAC; + // We skipped over some ambiguous declarations which might be ambiguous with + // the selected result. + for (FunctionDecl *Skipped : AmbiguousDecls) + if (!CheckMoreConstrained(Skipped, Result).hasValue()) + return nullptr; Pair = DAP; + } return Result; } /// Given an overloaded function, tries to turn it into a non-overloaded -/// function reference using resolveAddressOfOnlyViableOverloadCandidate. This +/// function reference using resolveAddressOfSingleOverloadCandidate. This /// will perform access checks, diagnose the use of the resultant decl, and, if /// requested, potentially perform a function-to-pointer decay. /// -/// Returns false if resolveAddressOfOnlyViableOverloadCandidate fails. +/// Returns false if resolveAddressOfSingleOverloadCandidate fails. /// Otherwise, returns true. This may emit diagnostics and return true. -bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate( +bool Sema::resolveAndFixAddressOfSingleOverloadCandidate( ExprResult &SrcExpr, bool DoFunctionPointerConverion) { Expr *E = SrcExpr.get(); assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload"); DeclAccessPair DAP; - FunctionDecl *Found = resolveAddressOfOnlyViableOverloadCandidate(E, DAP); + FunctionDecl *Found = resolveAddressOfSingleOverloadCandidate(E, DAP); if (!Found || Found->isCPUDispatchMultiVersion() || Found->isCPUSpecificMultiVersion()) return false; @@ -12406,7 +12772,7 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, PartialDiagnosticAt(Fn->getBeginLoc(), SemaRef.PDiag(diag::err_ovl_ambiguous_call) << ULE->getName() << Fn->getSourceRange()), - SemaRef, OCD_ViableCandidates, Args); + SemaRef, OCD_AmbiguousCandidates, Args); break; case OR_Deleted: { @@ -12652,7 +13018,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, PDiag(diag::err_ovl_ambiguous_oper_unary) << UnaryOperator::getOpcodeStr(Opc) << Input->getType() << Input->getSourceRange()), - *this, OCD_ViableCandidates, ArgsArray, + *this, OCD_AmbiguousCandidates, ArgsArray, UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); @@ -12672,6 +13038,70 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, return CreateBuiltinUnaryOp(OpLoc, Opc, Input); } +/// Perform lookup for an overloaded binary operator. +void Sema::LookupOverloadedBinOp(OverloadCandidateSet &CandidateSet, + OverloadedOperatorKind Op, + const UnresolvedSetImpl &Fns, + ArrayRef<Expr *> Args, bool PerformADL) { + SourceLocation OpLoc = CandidateSet.getLocation(); + + OverloadedOperatorKind ExtraOp = + CandidateSet.getRewriteInfo().AllowRewrittenCandidates + ? getRewrittenOverloadedOperator(Op) + : OO_None; + + // Add the candidates from the given function set. This also adds the + // rewritten candidates using these functions if necessary. + AddNonMemberOperatorCandidates(Fns, Args, CandidateSet); + + // Add operator candidates that are member functions. + AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet); + if (CandidateSet.getRewriteInfo().shouldAddReversed(Op)) + AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet, + OverloadCandidateParamOrder::Reversed); + + // In C++20, also add any rewritten member candidates. + if (ExtraOp) { + AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet); + if (CandidateSet.getRewriteInfo().shouldAddReversed(ExtraOp)) + AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]}, + CandidateSet, + OverloadCandidateParamOrder::Reversed); + } + + // Add candidates from ADL. Per [over.match.oper]p2, this lookup is not + // performed for an assignment operator (nor for operator[] nor operator->, + // which don't get here). + if (Op != OO_Equal && PerformADL) { + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); + AddArgumentDependentLookupCandidates(OpName, OpLoc, Args, + /*ExplicitTemplateArgs*/ nullptr, + CandidateSet); + if (ExtraOp) { + DeclarationName ExtraOpName = + Context.DeclarationNames.getCXXOperatorName(ExtraOp); + AddArgumentDependentLookupCandidates(ExtraOpName, OpLoc, Args, + /*ExplicitTemplateArgs*/ nullptr, + CandidateSet); + } + } + + // Add builtin operator candidates. + // + // FIXME: We don't add any rewritten candidates here. This is strictly + // incorrect; a builtin candidate could be hidden by a non-viable candidate, + // resulting in our selecting a rewritten builtin candidate. For example: + // + // enum class E { e }; + // bool operator!=(E, E) requires false; + // bool k = E::e != E::e; + // + // ... should select the rewritten builtin candidate 'operator==(E, E)'. But + // it seems unreasonable to consider rewritten builtin candidates. A core + // issue has been filed proposing to removed this requirement. + AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet); +} + /// Create a binary operation that may resolve to an overloaded /// operator. /// @@ -12688,11 +13118,19 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, /// /// \param LHS Left-hand argument. /// \param RHS Right-hand argument. +/// \param PerformADL Whether to consider operator candidates found by ADL. +/// \param AllowRewrittenCandidates Whether to consider candidates found by +/// C++20 operator rewrites. +/// \param DefaultedFn If we are synthesizing a defaulted operator function, +/// the function in question. Such a function is never a candidate in +/// our overload resolution. This also enables synthesizing a three-way +/// comparison from < and == as described in C++20 [class.spaceship]p1. ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, BinaryOperatorKind Opc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS, bool PerformADL, - bool AllowRewrittenCandidates) { + bool AllowRewrittenCandidates, + FunctionDecl *DefaultedFn) { Expr *Args[2] = { LHS, RHS }; LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple @@ -12700,7 +13138,6 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, AllowRewrittenCandidates = false; OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc); - DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); // If either side is type-dependent, create an appropriate dependent // expression. @@ -12722,6 +13159,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // FIXME: save results of ADL from here? CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators // TODO: provide better source location info in DNLoc component. + DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(Op); DeclarationNameInfo OpNameInfo(OpName, OpLoc); UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create( Context, NamingClass, NestedNameSpecifierLoc(), OpNameInfo, @@ -12755,63 +13193,13 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (Opc == BO_PtrMemD) return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); - // Build an empty overload set. + // Build the overload set. OverloadCandidateSet CandidateSet( OpLoc, OverloadCandidateSet::CSK_Operator, OverloadCandidateSet::OperatorRewriteInfo(Op, AllowRewrittenCandidates)); - - OverloadedOperatorKind ExtraOp = - AllowRewrittenCandidates ? getRewrittenOverloadedOperator(Op) : OO_None; - - // Add the candidates from the given function set. This also adds the - // rewritten candidates using these functions if necessary. - AddNonMemberOperatorCandidates(Fns, Args, CandidateSet); - - // Add operator candidates that are member functions. - AddMemberOperatorCandidates(Op, OpLoc, Args, CandidateSet); - if (CandidateSet.getRewriteInfo().shouldAddReversed(Op)) - AddMemberOperatorCandidates(Op, OpLoc, {Args[1], Args[0]}, CandidateSet, - OverloadCandidateParamOrder::Reversed); - - // In C++20, also add any rewritten member candidates. - if (ExtraOp) { - AddMemberOperatorCandidates(ExtraOp, OpLoc, Args, CandidateSet); - if (CandidateSet.getRewriteInfo().shouldAddReversed(ExtraOp)) - AddMemberOperatorCandidates(ExtraOp, OpLoc, {Args[1], Args[0]}, - CandidateSet, - OverloadCandidateParamOrder::Reversed); - } - - // Add candidates from ADL. Per [over.match.oper]p2, this lookup is not - // performed for an assignment operator (nor for operator[] nor operator->, - // which don't get here). - if (Opc != BO_Assign && PerformADL) { - AddArgumentDependentLookupCandidates(OpName, OpLoc, Args, - /*ExplicitTemplateArgs*/ nullptr, - CandidateSet); - if (ExtraOp) { - DeclarationName ExtraOpName = - Context.DeclarationNames.getCXXOperatorName(ExtraOp); - AddArgumentDependentLookupCandidates(ExtraOpName, OpLoc, Args, - /*ExplicitTemplateArgs*/ nullptr, - CandidateSet); - } - } - - // Add builtin operator candidates. - // - // FIXME: We don't add any rewritten candidates here. This is strictly - // incorrect; a builtin candidate could be hidden by a non-viable candidate, - // resulting in our selecting a rewritten builtin candidate. For example: - // - // enum class E { e }; - // bool operator!=(E, E) requires false; - // bool k = E::e != E::e; - // - // ... should select the rewritten builtin candidate 'operator==(E, E)'. But - // it seems unreasonable to consider rewritten builtin candidates. A core - // issue has been filed proposing to removed this requirement. - AddBuiltinOperatorCandidates(Op, OpLoc, Args, CandidateSet); + if (DefaultedFn) + CandidateSet.exclude(DefaultedFn); + LookupOverloadedBinOp(CandidateSet, Op, Fns, Args, PerformADL); bool HadMultipleCandidates = (CandidateSet.size() > 1); @@ -13018,6 +13406,15 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (Opc == BO_Comma) break; + // When defaulting an 'operator<=>', we can try to synthesize a three-way + // compare result using '==' and '<'. + if (DefaultedFn && Opc == BO_Cmp) { + ExprResult E = BuildSynthesizedThreeWayComparison(OpLoc, Fns, Args[0], + Args[1], DefaultedFn); + if (E.isInvalid() || E.isUsable()) + return E; + } + // For class as left operand for assignment or compound assignment // operator do not fall through to handling in built-in, but report that // no overloaded assignment operator found @@ -13061,20 +13458,26 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, << Args[1]->getType() << Args[0]->getSourceRange() << Args[1]->getSourceRange()), - *this, OCD_ViableCandidates, Args, BinaryOperator::getOpcodeStr(Opc), + *this, OCD_AmbiguousCandidates, Args, BinaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); case OR_Deleted: if (isImplicitlyDeleted(Best->Function)) { - CXXMethodDecl *Method = cast<CXXMethodDecl>(Best->Function); - Diag(OpLoc, diag::err_ovl_deleted_special_oper) - << Context.getRecordType(Method->getParent()) - << getSpecialMember(Method); + FunctionDecl *DeletedFD = Best->Function; + DefaultedFunctionKind DFK = getDefaultedFunctionKind(DeletedFD); + if (DFK.isSpecialMember()) { + Diag(OpLoc, diag::err_ovl_deleted_special_oper) + << Args[0]->getType() << DFK.asSpecialMember(); + } else { + assert(DFK.isComparison()); + Diag(OpLoc, diag::err_ovl_deleted_comparison) + << Args[0]->getType() << DeletedFD; + } // The user probably meant to call this special member. Just // explain why it's deleted. - NoteDeletedFunction(Method); + NoteDeletedFunction(DeletedFD); return ExprError(); } CandidateSet.NoteCandidates( @@ -13093,6 +13496,98 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, return CreateBuiltinBinOp(OpLoc, Opc, Args[0], Args[1]); } +ExprResult Sema::BuildSynthesizedThreeWayComparison( + SourceLocation OpLoc, const UnresolvedSetImpl &Fns, Expr *LHS, Expr *RHS, + FunctionDecl *DefaultedFn) { + const ComparisonCategoryInfo *Info = + Context.CompCategories.lookupInfoForType(DefaultedFn->getReturnType()); + // If we're not producing a known comparison category type, we can't + // synthesize a three-way comparison. Let the caller diagnose this. + if (!Info) + return ExprResult((Expr*)nullptr); + + // If we ever want to perform this synthesis more generally, we will need to + // apply the temporary materialization conversion to the operands. + assert(LHS->isGLValue() && RHS->isGLValue() && + "cannot use prvalue expressions more than once"); + Expr *OrigLHS = LHS; + Expr *OrigRHS = RHS; + + // Replace the LHS and RHS with OpaqueValueExprs; we're going to refer to + // each of them multiple times below. + LHS = new (Context) + OpaqueValueExpr(LHS->getExprLoc(), LHS->getType(), LHS->getValueKind(), + LHS->getObjectKind(), LHS); + RHS = new (Context) + OpaqueValueExpr(RHS->getExprLoc(), RHS->getType(), RHS->getValueKind(), + RHS->getObjectKind(), RHS); + + ExprResult Eq = CreateOverloadedBinOp(OpLoc, BO_EQ, Fns, LHS, RHS, true, true, + DefaultedFn); + if (Eq.isInvalid()) + return ExprError(); + + ExprResult Less = CreateOverloadedBinOp(OpLoc, BO_LT, Fns, LHS, RHS, true, + true, DefaultedFn); + if (Less.isInvalid()) + return ExprError(); + + ExprResult Greater; + if (Info->isPartial()) { + Greater = CreateOverloadedBinOp(OpLoc, BO_LT, Fns, RHS, LHS, true, true, + DefaultedFn); + if (Greater.isInvalid()) + return ExprError(); + } + + // Form the list of comparisons we're going to perform. + struct Comparison { + ExprResult Cmp; + ComparisonCategoryResult Result; + } Comparisons[4] = + { {Eq, Info->isStrong() ? ComparisonCategoryResult::Equal + : ComparisonCategoryResult::Equivalent}, + {Less, ComparisonCategoryResult::Less}, + {Greater, ComparisonCategoryResult::Greater}, + {ExprResult(), ComparisonCategoryResult::Unordered}, + }; + + int I = Info->isPartial() ? 3 : 2; + + // Combine the comparisons with suitable conditional expressions. + ExprResult Result; + for (; I >= 0; --I) { + // Build a reference to the comparison category constant. + auto *VI = Info->lookupValueInfo(Comparisons[I].Result); + // FIXME: Missing a constant for a comparison category. Diagnose this? + if (!VI) + return ExprResult((Expr*)nullptr); + ExprResult ThisResult = + BuildDeclarationNameExpr(CXXScopeSpec(), DeclarationNameInfo(), VI->VD); + if (ThisResult.isInvalid()) + return ExprError(); + + // Build a conditional unless this is the final case. + if (Result.get()) { + Result = ActOnConditionalOp(OpLoc, OpLoc, Comparisons[I].Cmp.get(), + ThisResult.get(), Result.get()); + if (Result.isInvalid()) + return ExprError(); + } else { + Result = ThisResult; + } + } + + // Build a PseudoObjectExpr to model the rewriting of an <=> operator, and to + // bind the OpaqueValueExprs before they're (repeatedly) used. + Expr *SyntacticForm = new (Context) + BinaryOperator(OrigLHS, OrigRHS, BO_Cmp, Result.get()->getType(), + Result.get()->getValueKind(), + Result.get()->getObjectKind(), OpLoc, FPFeatures); + Expr *SemanticForm[] = {LHS, RHS, Result.get()}; + return PseudoObjectExpr::Create(Context, SyntacticForm, SemanticForm, 2); +} + ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, SourceLocation RLoc, @@ -13246,7 +13741,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, << Args[1]->getType() << Args[0]->getSourceRange() << Args[1]->getSourceRange()), - *this, OCD_ViableCandidates, Args, "[]", LLoc); + *this, OCD_AmbiguousCandidates, Args, "[]", LLoc); return ExprError(); case OR_Deleted: @@ -13438,7 +13933,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, PartialDiagnosticAt(UnresExpr->getMemberLoc(), PDiag(diag::err_ovl_ambiguous_member_call) << DeclName << MemExprE->getSourceRange()), - *this, OCD_AllCandidates, Args); + *this, OCD_AmbiguousCandidates, Args); // FIXME: Leaking incoming expressions! return ExprError(); @@ -13469,7 +13964,7 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, ResultType = ResultType.getNonLValueExprType(Context); assert(Method && "Member call to something that isn't a method?"); - const auto *Proto = Method->getType()->getAs<FunctionProtoType>(); + const auto *Proto = Method->getType()->castAs<FunctionProtoType>(); CXXMemberCallExpr *TheCall = CXXMemberCallExpr::Create(Context, MemExprE, Args, ResultType, VK, RParenLoc, Proto->getNumParams()); @@ -13566,7 +14061,6 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, assert(Object.get()->getType()->isRecordType() && "Requires object type argument"); - const RecordType *Record = Object.get()->getType()->getAs<RecordType>(); // C++ [over.call.object]p1: // If the primary-expression E in the function call syntax @@ -13583,6 +14077,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, diag::err_incomplete_object_call, Object.get())) return true; + const auto *Record = Object.get()->getType()->castAs<RecordType>(); LookupResult R(*this, OpName, LParenLoc, LookupOrdinaryName); LookupQualifiedName(R, Record->getDecl()); R.suppressDiagnostics(); @@ -13670,7 +14165,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, PDiag(diag::err_ovl_ambiguous_object_call) << Object.get()->getType() << Object.get()->getSourceRange()), - *this, OCD_ViableCandidates, Args); + *this, OCD_AmbiguousCandidates, Args); break; case OR_Deleted: @@ -13730,9 +14225,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, if (Method->isInvalidDecl()) return ExprError(); - const FunctionProtoType *Proto = - Method->getType()->getAs<FunctionProtoType>(); - + const auto *Proto = Method->getType()->castAs<FunctionProtoType>(); unsigned NumParams = Proto->getNumParams(); DeclarationNameInfo OpLocInfo( @@ -13853,14 +14346,13 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, DeclarationName OpName = Context.DeclarationNames.getCXXOperatorName(OO_Arrow); OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Operator); - const RecordType *BaseRecord = Base->getType()->getAs<RecordType>(); if (RequireCompleteType(Loc, Base->getType(), diag::err_typecheck_incomplete_tag, Base)) return ExprError(); LookupResult R(*this, OpName, OpLoc, LookupOrdinaryName); - LookupQualifiedName(R, BaseRecord->getDecl()); + LookupQualifiedName(R, Base->getType()->castAs<RecordType>()->getDecl()); R.suppressDiagnostics(); for (LookupResult::iterator Oper = R.begin(), OperEnd = R.end(); @@ -13905,7 +14397,7 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_ambiguous_oper_unary) << "->" << Base->getType() << Base->getSourceRange()), - *this, OCD_ViableCandidates, Base); + *this, OCD_AmbiguousCandidates, Base); return ExprError(); case OR_Deleted: @@ -13985,7 +14477,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, CandidateSet.NoteCandidates( PartialDiagnosticAt(R.getNameLoc(), PDiag(diag::err_ovl_ambiguous_call) << R.getLookupName()), - *this, OCD_ViableCandidates, Args); + *this, OCD_AmbiguousCandidates, Args); return ExprError(); } @@ -14200,13 +14692,6 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, UnOp->getOperatorLoc(), false); } - // C++ [except.spec]p17: - // An exception-specification is considered to be needed when: - // - in an expression the function is the unique lookup result or the - // selected member of a set of overloaded functions - if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>()) - ResolveExceptionSpec(E->getExprLoc(), FPT); - if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { // FIXME: avoid copy. TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr; diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 06bcd8d00ded..5587e0d24c7f 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -145,7 +145,7 @@ namespace { assocExprs.reserve(numAssocs); assocTypes.reserve(numAssocs); - for (const GenericSelectionExpr::Association &assoc : + for (const GenericSelectionExpr::Association assoc : gse->associations()) { Expr *assocExpr = assoc.getAssociationExpr(); if (assoc.isSelected()) @@ -1190,16 +1190,15 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { true /*instance*/); if (!AtIndexGetter && S.getLangOpts().DebuggerObjCLiteral) { - AtIndexGetter = ObjCMethodDecl::Create(S.Context, SourceLocation(), - SourceLocation(), AtIndexGetterSelector, - S.Context.getObjCIdType() /*ReturnType*/, - nullptr /*TypeSourceInfo */, - S.Context.getTranslationUnitDecl(), - true /*Instance*/, false/*isVariadic*/, - /*isPropertyAccessor=*/false, - /*isImplicitlyDeclared=*/true, /*isDefined=*/false, - ObjCMethodDecl::Required, - false); + AtIndexGetter = ObjCMethodDecl::Create( + S.Context, SourceLocation(), SourceLocation(), AtIndexGetterSelector, + S.Context.getObjCIdType() /*ReturnType*/, nullptr /*TypeSourceInfo */, + S.Context.getTranslationUnitDecl(), true /*Instance*/, + false /*isVariadic*/, + /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, + /*isImplicitlyDeclared=*/true, /*isDefined=*/false, + ObjCMethodDecl::Required, false); ParmVarDecl *Argument = ParmVarDecl::Create(S.Context, AtIndexGetter, SourceLocation(), SourceLocation(), arrayRef ? &S.Context.Idents.get("index") @@ -1303,6 +1302,7 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { ReturnType, ReturnTInfo, S.Context.getTranslationUnitDecl(), true /*Instance*/, false /*isVariadic*/, /*isPropertyAccessor=*/false, + /*isSynthesizedAccessorStub=*/false, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, ObjCMethodDecl::Required, false); SmallVector<ParmVarDecl *, 2> Params; diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 6c680f29da4f..d6c3af9e84c8 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2724,7 +2724,7 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef, if (!MTE) return; - const Expr *E = MTE->GetTemporaryExpr()->IgnoreImpCasts(); + const Expr *E = MTE->getSubExpr()->IgnoreImpCasts(); // Searching for either UnaryOperator for dereference of a pointer or // CXXOperatorCallExpr for handling iterators. @@ -2736,7 +2736,7 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef, E = ME->getBase(); } else { const MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(E); - E = MTE->GetTemporaryExpr(); + E = MTE->getSubExpr(); } E = E->IgnoreImpCasts(); } @@ -2762,19 +2762,32 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef, QualType NewReferenceType = SemaRef.Context.getLValueReferenceType(E->getType().withConst()); SemaRef.Diag(VD->getBeginLoc(), diag::note_use_type_or_non_reference) - << NonReferenceType << NewReferenceType << VD->getSourceRange(); - } else { + << NonReferenceType << NewReferenceType << VD->getSourceRange() + << FixItHint::CreateRemoval(VD->getTypeSpecEndLoc()); + } else if (!VariableType->isRValueReferenceType()) { // The range always returns a copy, so a temporary is always created. // Suggest removing the reference from the loop variable. + // If the type is a rvalue reference do not warn since that changes the + // semantic of the code. SemaRef.Diag(VD->getLocation(), diag::warn_for_range_variable_always_copy) << VD << RangeInitType; QualType NonReferenceType = VariableType.getNonReferenceType(); NonReferenceType.removeLocalConst(); SemaRef.Diag(VD->getBeginLoc(), diag::note_use_non_reference_type) - << NonReferenceType << VD->getSourceRange(); + << NonReferenceType << VD->getSourceRange() + << FixItHint::CreateRemoval(VD->getTypeSpecEndLoc()); } } +/// Determines whether the @p VariableType's declaration is a record with the +/// clang::trivial_abi attribute. +static bool hasTrivialABIAttr(QualType VariableType) { + if (CXXRecordDecl *RD = VariableType->getAsCXXRecordDecl()) + return RD->hasAttr<TrivialABIAttr>(); + + return false; +} + // Warns when the loop variable can be changed to a reference type to // prevent a copy. For instance, if given "for (const Foo x : Range)" suggest // "for (const Foo &x : Range)" if this form does not make a copy. @@ -2796,10 +2809,13 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef, return; } - // TODO: Determine a maximum size that a POD type can be before a diagnostic - // should be emitted. Also, only ignore POD types with trivial copy - // constructors. - if (VariableType.isPODType(SemaRef.Context)) + // Small trivially copyable types are cheap to copy. Do not emit the + // diagnostic for these instances. 64 bytes is a common size of a cache line. + // (The function `getTypeSize` returns the size in bits.) + ASTContext &Ctx = SemaRef.Context; + if (Ctx.getTypeSize(VariableType) <= 64 * 8 && + (VariableType.isTriviallyCopyableType(Ctx) || + hasTrivialABIAttr(VariableType))) return; // Suggest changing from a const variable to a const reference variable @@ -2808,7 +2824,8 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef, << VD << VariableType << InitExpr->getType(); SemaRef.Diag(VD->getBeginLoc(), diag::note_use_reference_type) << SemaRef.Context.getLValueReferenceType(VariableType) - << VD->getSourceRange(); + << VD->getSourceRange() + << FixItHint::CreateInsertion(VD->getLocation(), "&"); } /// DiagnoseForRangeVariableCopies - Diagnose three cases and fixes for them. @@ -4184,19 +4201,16 @@ StmtResult Sema::ActOnSEHTryBlock(bool IsCXXTry, SourceLocation TryLoc, return SEHTryStmt::Create(Context, IsCXXTry, TryLoc, TryBlock, Handler); } -StmtResult -Sema::ActOnSEHExceptBlock(SourceLocation Loc, - Expr *FilterExpr, - Stmt *Block) { +StmtResult Sema::ActOnSEHExceptBlock(SourceLocation Loc, Expr *FilterExpr, + Stmt *Block) { assert(FilterExpr && Block); - - if(!FilterExpr->getType()->isIntegerType()) { - return StmtError(Diag(FilterExpr->getExprLoc(), - diag::err_filter_expression_integral) - << FilterExpr->getType()); + QualType FTy = FilterExpr->getType(); + if (!FTy->isIntegerType() && !FTy->isDependentType()) { + return StmtError( + Diag(FilterExpr->getExprLoc(), diag::err_filter_expression_integral) + << FTy); } - - return SEHExceptStmt::Create(Context,Loc,FilterExpr,Block); + return SEHExceptStmt::Create(Context, Loc, FilterExpr, Block); } void Sema::ActOnStartSEHFinallyBlock() { diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 9b051e02d127..93faf2d151f9 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ExprCXX.h" +#include "clang/AST/GlobalDecl.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/TargetInfo.h" @@ -255,6 +256,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, // The parser verifies that there is a string literal here. assert(AsmString->isAscii()); + FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext()); + llvm::StringMap<bool> FeatureMap; + Context.getFunctionFeatureMap(FeatureMap, FD); + for (unsigned i = 0; i != NumOutputs; i++) { StringLiteral *Literal = Constraints[i]; assert(Literal->isAscii()); @@ -325,8 +330,8 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, } unsigned Size = Context.getTypeSize(OutputExpr->getType()); - if (!Context.getTargetInfo().validateOutputSize(Literal->getString(), - Size)) { + if (!Context.getTargetInfo().validateOutputSize( + FeatureMap, Literal->getString(), Size)) { targetDiag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_output_size) << Info.getConstraintStr(); return new (Context) @@ -427,8 +432,8 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return StmtError(); unsigned Size = Context.getTypeSize(Ty); - if (!Context.getTargetInfo().validateInputSize(Literal->getString(), - Size)) + if (!Context.getTargetInfo().validateInputSize(FeatureMap, + Literal->getString(), Size)) return StmtResult( targetDiag(InputExpr->getBeginLoc(), diag::err_asm_invalid_input_size) << Info.getConstraintStr()); @@ -702,8 +707,13 @@ void Sema::FillInlineAsmIdentifierInfo(Expr *Res, if (T->isFunctionType() || T->isDependentType()) return Info.setLabel(Res); if (Res->isRValue()) { - if (isa<clang::EnumType>(T) && Res->EvaluateAsRValue(Eval, Context)) + bool IsEnum = isa<clang::EnumType>(T); + if (DeclRefExpr *DRE = dyn_cast<clang::DeclRefExpr>(Res)) + if (DRE->getDecl()->getKind() == Decl::EnumConstant) + IsEnum = true; + if (IsEnum && Res->EvaluateAsRValue(Eval, Context)) return Info.setEnum(Eval.Val.getInt().getSExtValue()); + return Info.setLabel(Res); } unsigned Size = Context.getTypeSizeInChars(T).getQuantity(); diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 3f2d38630c36..1184446796eb 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -976,20 +976,23 @@ ParsedTemplateArgument Sema::ActOnTemplateTypeArgument(TypeResult ParsedType) { /// If the type parameter has a default argument, it will be added /// later via ActOnTypeParameterDefault. NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, - SourceLocation EllipsisLoc, - SourceLocation KeyLoc, - IdentifierInfo *ParamName, - SourceLocation ParamNameLoc, - unsigned Depth, unsigned Position, - SourceLocation EqualLoc, - ParsedType DefaultArg) { + SourceLocation EllipsisLoc, + SourceLocation KeyLoc, + IdentifierInfo *ParamName, + SourceLocation ParamNameLoc, + unsigned Depth, unsigned Position, + SourceLocation EqualLoc, + ParsedType DefaultArg, + bool HasTypeConstraint) { assert(S->isTemplateParamScope() && "Template type parameter not in template parameter scope!"); bool IsParameterPack = EllipsisLoc.isValid(); - TemplateTypeParmDecl *Param = TemplateTypeParmDecl::Create( - Context, Context.getTranslationUnitDecl(), KeyLoc, ParamNameLoc, Depth, - Position, ParamName, Typename, IsParameterPack); + TemplateTypeParmDecl *Param + = TemplateTypeParmDecl::Create(Context, Context.getTranslationUnitDecl(), + KeyLoc, ParamNameLoc, Depth, Position, + ParamName, Typename, IsParameterPack, + HasTypeConstraint); Param->setAccess(AS_public); if (Param->isParameterPack()) @@ -1036,6 +1039,125 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename, return Param; } +/// Convert the parser's template argument list representation into our form. +static TemplateArgumentListInfo +makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { + TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc, + TemplateId.RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(), + TemplateId.NumArgs); + S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs); + return TemplateArgs; +} + +bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc) { + ConceptDecl *CD = + cast<ConceptDecl>(TypeConstr->Template.get().getAsTemplateDecl()); + + // C++2a [temp.param]p4: + // [...] The concept designated by a type-constraint shall be a type + // concept ([temp.concept]). + if (!CD->isTypeConcept()) { + Diag(TypeConstr->TemplateNameLoc, + diag::err_type_constraint_non_type_concept); + return true; + } + + bool WereArgsSpecified = TypeConstr->LAngleLoc.isValid(); + + if (!WereArgsSpecified && + CD->getTemplateParameters()->getMinRequiredArguments() > 1) { + Diag(TypeConstr->TemplateNameLoc, + diag::err_type_constraint_missing_arguments) << CD; + return true; + } + + TemplateArgumentListInfo TemplateArgs; + if (TypeConstr->LAngleLoc.isValid()) { + TemplateArgs = + makeTemplateArgumentListInfo(*this, *TypeConstr); + } + return AttachTypeConstraint( + TypeConstr->SS.isSet() ? TypeConstr->SS.getWithLocInContext(Context) : + NestedNameSpecifierLoc(), + DeclarationNameInfo(DeclarationName(TypeConstr->Name), + TypeConstr->TemplateNameLoc), CD, + TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, + ConstrainedParameter, EllipsisLoc); +} + +/// Attach a type-constraint to a template parameter. +/// \returns true if an error occured. This can happen if the +/// immediately-declared constraint could not be formed (e.g. incorrect number +/// of arguments for the named concept). +bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, + DeclarationNameInfo NameInfo, + ConceptDecl *NamedConcept, + const TemplateArgumentListInfo *TemplateArgs, + TemplateTypeParmDecl *ConstrainedParameter, + SourceLocation EllipsisLoc) { + // C++2a [temp.param]p4: + // [...] If Q is of the form C<A1, ..., An>, then let E' be + // C<T, A1, ..., An>. Otherwise, let E' be C<T>. [...] + const ASTTemplateArgumentListInfo *ArgsAsWritten = + TemplateArgs ? ASTTemplateArgumentListInfo::Create(Context, + *TemplateArgs) : nullptr; + + QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0); + TemplateArgumentListInfo ConstraintArgs; + ConstraintArgs.addArgument( + TemplateArgumentLoc( + TemplateArgument(ParamAsArgument), + TemplateArgumentLocInfo( + Context.getTrivialTypeSourceInfo(ParamAsArgument, + ConstrainedParameter->getLocation())))); + if (TemplateArgs) { + ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc()); + ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc()); + for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments()) + ConstraintArgs.addArgument(ArgLoc); + } + + // C++2a [temp.param]p4: + // [...] This constraint-expression E is called the immediately-declared + // constraint of T. [...] + CXXScopeSpec SS; + SS.Adopt(NS); + ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS, + /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept, + NamedConcept, &ConstraintArgs); + if (ImmediatelyDeclaredConstraint.isInvalid()) + return true; + + if (ConstrainedParameter->isParameterPack()) { + // C++2a [temp.param]p4: + // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). + // + // We have the following case: + // + // template<typename T> concept C1 = true; + // template<C1... T> struct s1; + // + // The constraint: (C1<T> && ...) + ImmediatelyDeclaredConstraint = + BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), + ImmediatelyDeclaredConstraint.get(), BO_LAnd, + EllipsisLoc, /*RHS=*/nullptr, + /*RParenLoc=*/SourceLocation(), + /*NumExpansions=*/None).get(); + if (ImmediatelyDeclaredConstraint.isInvalid()) + return true; + } + + ConstrainedParameter->setTypeConstraint(NS, NameInfo, + /*FoundDecl=*/NamedConcept, + NamedConcept, ArgsAsWritten, + ImmediatelyDeclaredConstraint.get()); + return false; +} + /// Check that the type of a non-type template parameter is /// well-formed. /// @@ -1120,11 +1242,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, // Check that we have valid decl-specifiers specified. auto CheckValidDeclSpecifiers = [this, &D] { // C++ [temp.param] - // p1 + // p1 // template-parameter: // ... // parameter-declaration - // p2 + // p2 // ... A storage class shall not be specified in a template-parameter // declaration. // [dcl.typedef]p1: @@ -1868,7 +1990,23 @@ private: SemaRef.Context, DC, TTP->getBeginLoc(), TTP->getLocation(), /*Depth*/ 0, Depth1IndexAdjustment + TTP->getIndex(), TTP->getIdentifier(), TTP->wasDeclaredWithTypename(), - TTP->isParameterPack()); + TTP->isParameterPack(), TTP->hasTypeConstraint(), + TTP->isExpandedParameterPack() ? + llvm::Optional<unsigned>(TTP->getNumExpansionParameters()) : None); + if (const auto *TC = TTP->getTypeConstraint()) { + TemplateArgumentListInfo TransformedArgs; + const auto *ArgsAsWritten = TC->getTemplateArgsAsWritten(); + if (SemaRef.Subst(ArgsAsWritten->getTemplateArgs(), + ArgsAsWritten->NumTemplateArgs, TransformedArgs, + Args)) + SemaRef.AttachTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), &TransformedArgs, NewTTP, + NewTTP->isParameterPack() + ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc() + : SourceLocation()); + } if (TTP->hasDefaultArgument()) { TypeSourceInfo *InstantiatedDefaultArg = SemaRef.SubstType(TTP->getDefaultArgumentInfo(), Args, @@ -1894,7 +2032,7 @@ private: // Ask the template instantiator to do the heavy lifting for us, then adjust // the index of the parameter once it's done. auto *NewParam = - cast_or_null<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args)); + cast<TemplateParmDecl>(SemaRef.SubstDecl(OldParam, DC, Args)); assert(NewParam->getDepth() == 0 && "unexpected template param depth"); NewParam->setPosition(NewParam->getPosition() + Depth1IndexAdjustment); return NewParam; @@ -2177,6 +2315,17 @@ static bool DiagnoseUnexpandedParameterPacks(Sema &S, TemplateParameterList *Params = TTP->getTemplateParameters(); for (unsigned I = 0, N = Params->size(); I != N; ++I) { NamedDecl *P = Params->getParam(I); + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(P)) { + if (!TTP->isParameterPack()) + if (const TypeConstraint *TC = TTP->getTypeConstraint()) + if (TC->hasExplicitTemplateArgs()) + for (auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments()) + if (S.DiagnoseUnexpandedParameterPack(ArgLoc, + Sema::UPPC_TypeConstraint)) + return true; + continue; + } + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) { if (!NTTP->isParameterPack() && S.DiagnoseUnexpandedParameterPack(NTTP->getLocation(), @@ -2549,6 +2698,9 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { /// list. static bool DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) { + if (!Params->size()) + return false; + DependencyChecker Checker(Params, /*IgnoreNonTypeDependent*/false); Checker.TraverseType(T); return Checker.Match; @@ -3210,8 +3362,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template || isa<FunctionTemplateDecl>(Template) || - isa<VarTemplateDecl>(Template) || - isa<ConceptDecl>(Template)) { + isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) { // We might have a substituted template template parameter pack. If so, // build a template specialization type for it. if (Name.getAsSubstTemplateTemplateParmPack()) @@ -3227,7 +3378,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(Template, TemplateLoc, TemplateArgs, - false, Converted)) + false, Converted, + /*UpdateArgsWithConversion=*/true)) return QualType(); QualType CanonType; @@ -3235,6 +3387,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, bool InstantiationDependent = false; if (TypeAliasTemplateDecl *AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(Template)) { + // Find the canonical type for this type alias template specialization. TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl(); if (Pattern->isInvalidDecl()) @@ -3707,17 +3860,6 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params, return true; } -/// Convert the parser's template argument list representation into our form. -static TemplateArgumentListInfo -makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { - TemplateArgumentListInfo TemplateArgs(TemplateId.LAngleLoc, - TemplateId.RAngleLoc); - ASTTemplateArgsPtr TemplateArgsPtr(TemplateId.getTemplateArgs(), - TemplateId.NumArgs); - S.translateTemplateArguments(TemplateArgsPtr, TemplateArgs); - return TemplateArgs; -} - template<typename PartialSpecDecl> static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { if (Partial->getDeclContext()->isDependentContext()) @@ -3746,6 +3888,11 @@ static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { } S.Diag(Template->getLocation(), diag::note_template_decl_here); + SmallVector<const Expr *, 3> PartialAC, TemplateAC; + Template->getAssociatedConstraints(TemplateAC); + Partial->getAssociatedConstraints(PartialAC); + S.MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Partial, PartialAC, Template, + TemplateAC); } static void @@ -3872,7 +4019,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(VarTemplate, TemplateNameLoc, TemplateArgs, - false, Converted)) + false, Converted, + /*UpdateArgsWithConversion=*/true)) return true; // Find the variable template (partial) specialization declaration that @@ -3895,7 +4043,9 @@ DeclResult Sema::ActOnVarTemplateSpecialization( } if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(), - Converted)) { + Converted) && + (!Context.getLangOpts().ConceptsTS || + !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: // // -- The argument list of the specialization shall not be identical @@ -3914,8 +4064,8 @@ DeclResult Sema::ActOnVarTemplateSpecialization( VarTemplateSpecializationDecl *PrevDecl = nullptr; if (IsPartialSpecialization) - // FIXME: Template parameter list matters too - PrevDecl = VarTemplate->findPartialSpecialization(Converted, InsertPos); + PrevDecl = VarTemplate->findPartialSpecialization(Converted, TemplateParams, + InsertPos); else PrevDecl = VarTemplate->findSpecialization(Converted, InsertPos); @@ -4043,7 +4193,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, if (CheckTemplateArgumentList( Template, TemplateNameLoc, const_cast<TemplateArgumentListInfo &>(TemplateArgs), false, - Converted)) + Converted, /*UpdateArgsWithConversion=*/true)) return true; // Find the variable template specialization declaration that @@ -4221,20 +4371,20 @@ void Sema::diagnoseMissingTemplateArguments(TemplateName Name, ExprResult Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - SourceLocation ConceptNameLoc, + const DeclarationNameInfo &ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, const TemplateArgumentListInfo *TemplateArgs) { assert(NamedConcept && "A concept template id without a template?"); llvm::SmallVector<TemplateArgument, 4> Converted; - if (CheckTemplateArgumentList(NamedConcept, ConceptNameLoc, + if (CheckTemplateArgumentList(NamedConcept, ConceptNameInfo.getLoc(), const_cast<TemplateArgumentListInfo&>(*TemplateArgs), /*PartialTemplateArgs=*/false, Converted, /*UpdateArgsWithConversion=*/false)) return ExprError(); - Optional<bool> IsSatisfied; + ConstraintSatisfaction Satisfaction; bool AreArgsDependent = false; for (TemplateArgument &Arg : Converted) { if (Arg.isDependent()) { @@ -4242,25 +4392,21 @@ Sema::CheckConceptTemplateId(const CXXScopeSpec &SS, break; } } - if (!AreArgsDependent) { - InstantiatingTemplate Inst(*this, ConceptNameLoc, - InstantiatingTemplate::ConstraintsCheck{}, NamedConcept, Converted, - SourceRange(SS.isSet() ? SS.getBeginLoc() : ConceptNameLoc, - TemplateArgs->getRAngleLoc())); - MultiLevelTemplateArgumentList MLTAL; - MLTAL.addOuterTemplateArguments(Converted); - bool Satisfied; - if (CalculateConstraintSatisfaction(NamedConcept, MLTAL, - NamedConcept->getConstraintExpr(), - Satisfied)) + if (!AreArgsDependent && + CheckConstraintSatisfaction(NamedConcept, + {NamedConcept->getConstraintExpr()}, + Converted, + SourceRange(SS.isSet() ? SS.getBeginLoc() : + ConceptNameInfo.getLoc(), + TemplateArgs->getRAngleLoc()), + Satisfaction)) return ExprError(); - IsSatisfied = Satisfied; - } + return ConceptSpecializationExpr::Create(Context, SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc{}, - TemplateKWLoc, ConceptNameLoc, FoundDecl, NamedConcept, + TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, ASTTemplateArgumentListInfo::Create(Context, *TemplateArgs), Converted, - IsSatisfied); + AreArgsDependent ? nullptr : &Satisfaction); } ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, @@ -4304,8 +4450,7 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, } if (R.getAsSingle<ConceptDecl>()) { - return CheckConceptTemplateId(SS, TemplateKWLoc, - R.getLookupNameInfo().getBeginLoc(), + return CheckConceptTemplateId(SS, TemplateKWLoc, R.getLookupNameInfo(), R.getFoundDecl(), R.getAsSingle<ConceptDecl>(), TemplateArgs); } @@ -5108,7 +5253,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: - if (CheckTemplateTemplateArgument(Params, Arg)) + if (CheckTemplateTemplateArgument(TempParm, Params, Arg)) return true; Converted.push_back(Arg.getArgument()); @@ -5148,6 +5293,12 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, /// In \c A<int,int>::B, \c NTs and \c TTs have expanded pack size 2, and \c Us /// is not a pack expansion, so returns an empty Optional. static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) { + if (TemplateTypeParmDecl *TTP + = dyn_cast<TemplateTypeParmDecl>(Param)) { + if (TTP->isExpandedParameterPack()) + return TTP->getNumExpansionParameters(); + } + if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { if (NTTP->isExpandedParameterPack()) @@ -5206,7 +5357,11 @@ bool Sema::CheckTemplateArgumentList( TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs, bool PartialTemplateArgs, SmallVectorImpl<TemplateArgument> &Converted, - bool UpdateArgsWithConversions) { + bool UpdateArgsWithConversions, bool *ConstraintsNotSatisfied) { + + if (ConstraintsNotSatisfied) + *ConstraintsNotSatisfied = false; + // Make a copy of the template arguments for processing. Only make the // changes at the end when successful in matching the arguments to the // template. @@ -5268,12 +5423,16 @@ bool Sema::CheckTemplateArgumentList( bool PackExpansionIntoNonPack = NewArgs[ArgIdx].getArgument().isPackExpansion() && (!(*Param)->isTemplateParameterPack() || getExpandedPackSize(*Param)); - if (PackExpansionIntoNonPack && isa<TypeAliasTemplateDecl>(Template)) { + if (PackExpansionIntoNonPack && (isa<TypeAliasTemplateDecl>(Template) || + isa<ConceptDecl>(Template))) { // Core issue 1430: we have a pack expansion as an argument to an // alias template, and it's not part of a parameter pack. This // can't be canonicalized, so reject it now. + // As for concepts - we cannot normalize constraints where this + // situation exists. Diag(NewArgs[ArgIdx].getLocation(), - diag::err_alias_template_expansion_into_fixed_list) + diag::err_template_expansion_into_fixed_list) + << (isa<ConceptDecl>(Template) ? 1 : 0) << NewArgs[ArgIdx].getSourceRange(); Diag((*Param)->getLocation(), diag::note_template_param_here); return true; @@ -5321,7 +5480,6 @@ bool Sema::CheckTemplateArgumentList( if ((*Param)->isTemplateParameterPack() && !ArgumentPack.empty()) Converted.push_back( TemplateArgument::CreatePackCopy(Context, ArgumentPack)); - return false; } @@ -5460,6 +5618,15 @@ bool Sema::CheckTemplateArgumentList( if (UpdateArgsWithConversions) TemplateArgs = std::move(NewArgs); + if (!PartialTemplateArgs && + EnsureTemplateArgumentListConstraints( + Template, Converted, SourceRange(TemplateLoc, + TemplateArgs.getRAngleLoc()))) { + if (ConstraintsNotSatisfied) + *ConstraintsNotSatisfied = true; + return true; + } + return false; } @@ -6870,7 +7037,8 @@ static void DiagnoseTemplateParameterListArityMismatch( /// /// This routine implements the semantics of C++ [temp.arg.template]. /// It returns true if an error occurred, and false otherwise. -bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params, +bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, + TemplateParameterList *Params, TemplateArgumentLoc &Arg) { TemplateName Name = Arg.getArgument().getAsTemplateOrTemplatePattern(); TemplateDecl *Template = Name.getAsTemplateDecl(); @@ -6909,6 +7077,9 @@ bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params, // C++1z [temp.arg.template]p3: (DR 150) // A template-argument matches a template template-parameter P when P // is at least as specialized as the template-argument A. + // FIXME: We should enable RelaxedTemplateTemplateArgs by default as it is a + // defect report resolution from C++17 and shouldn't be introduced by + // concepts. if (getLangOpts().RelaxedTemplateTemplateArgs) { // Quick check for the common case: // If P contains a parameter pack, then A [...] matches P if each of A's @@ -6916,12 +7087,39 @@ bool Sema::CheckTemplateTemplateArgument(TemplateParameterList *Params, // the template-parameter-list of P. if (TemplateParameterListsAreEqual( Template->getTemplateParameters(), Params, false, - TPL_TemplateTemplateArgumentMatch, Arg.getLocation())) + TPL_TemplateTemplateArgumentMatch, Arg.getLocation()) && + // If the argument has no associated constraints, then the parameter is + // definitely at least as specialized as the argument. + // Otherwise - we need a more thorough check. + !Template->hasAssociatedConstraints()) return false; if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template, - Arg.getLocation())) + Arg.getLocation())) { + // C++2a[temp.func.order]p2 + // [...] If both deductions succeed, the partial ordering selects the + // more constrained template as described by the rules in + // [temp.constr.order]. + SmallVector<const Expr *, 3> ParamsAC, TemplateAC; + Params->getAssociatedConstraints(ParamsAC); + Template->getAssociatedConstraints(TemplateAC); + bool IsParamAtLeastAsConstrained; + if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, + IsParamAtLeastAsConstrained)) + return true; + if (!IsParamAtLeastAsConstrained) { + Diag(Arg.getLocation(), + diag::err_template_template_parameter_not_at_least_as_constrained) + << Template << Param << Arg.getSourceRange(); + Diag(Param->getLocation(), diag::note_entity_declared_at) << Param; + Diag(Template->getLocation(), diag::note_entity_declared_at) + << Template; + MaybeEmitAmbiguousAtomicConstraintsDiagnostic(Param, ParamsAC, Template, + TemplateAC); + return true; + } return false; + } // FIXME: Produce better diagnostics for deduction failures. } @@ -6965,94 +7163,73 @@ Sema::BuildExpressionFromDeclTemplateArgument(const TemplateArgument &Arg, ValueDecl *VD = Arg.getAsDecl(); - if (VD->getDeclContext()->isRecord() && - (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) || - isa<IndirectFieldDecl>(VD))) { - // If the value is a class member, we might have a pointer-to-member. - // Determine whether the non-type template template parameter is of - // pointer-to-member type. If so, we need to build an appropriate - // expression for a pointer-to-member, since a "normal" DeclRefExpr - // would refer to the member itself. - if (ParamType->isMemberPointerType()) { - QualType ClassType - = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext())); - NestedNameSpecifier *Qualifier - = NestedNameSpecifier::Create(Context, nullptr, false, - ClassType.getTypePtr()); - CXXScopeSpec SS; - SS.MakeTrivial(Context, Qualifier, Loc); - - // The actual value-ness of this is unimportant, but for - // internal consistency's sake, references to instance methods - // are r-values. - ExprValueKind VK = VK_LValue; - if (isa<CXXMethodDecl>(VD) && cast<CXXMethodDecl>(VD)->isInstance()) - VK = VK_RValue; - - ExprResult RefExpr = BuildDeclRefExpr(VD, - VD->getType().getNonReferenceType(), - VK, - Loc, - &SS); - if (RefExpr.isInvalid()) - return ExprError(); - - RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); - - // We might need to perform a trailing qualification conversion, since - // the element type on the parameter could be more qualified than the - // element type in the expression we constructed. - bool ObjCLifetimeConversion; - if (IsQualificationConversion(((Expr*) RefExpr.get())->getType(), - ParamType.getUnqualifiedType(), false, - ObjCLifetimeConversion)) - RefExpr = ImpCastExprToType(RefExpr.get(), ParamType.getUnqualifiedType(), CK_NoOp); - - assert(!RefExpr.isInvalid() && - Context.hasSameType(((Expr*) RefExpr.get())->getType(), - ParamType.getUnqualifiedType())); - return RefExpr; - } + CXXScopeSpec SS; + if (ParamType->isMemberPointerType()) { + // If this is a pointer to member, we need to use a qualified name to + // form a suitable pointer-to-member constant. + assert(VD->getDeclContext()->isRecord() && + (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD) || + isa<IndirectFieldDecl>(VD))); + QualType ClassType + = Context.getTypeDeclType(cast<RecordDecl>(VD->getDeclContext())); + NestedNameSpecifier *Qualifier + = NestedNameSpecifier::Create(Context, nullptr, false, + ClassType.getTypePtr()); + SS.MakeTrivial(Context, Qualifier, Loc); } - QualType T = VD->getType().getNonReferenceType(); + ExprResult RefExpr = BuildDeclarationNameExpr( + SS, DeclarationNameInfo(VD->getDeclName(), Loc), VD); + if (RefExpr.isInvalid()) + return ExprError(); - if (ParamType->isPointerType()) { - // When the non-type template parameter is a pointer, take the - // address of the declaration. - ExprResult RefExpr = BuildDeclRefExpr(VD, T, VK_LValue, Loc); + // For a pointer, the argument declaration is the pointee. Take its address. + QualType ElemT(RefExpr.get()->getType()->getArrayElementTypeNoTypeQual(), 0); + if (ParamType->isPointerType() && !ElemT.isNull() && + Context.hasSimilarType(ElemT, ParamType->getPointeeType())) { + // Decay an array argument if we want a pointer to its first element. + RefExpr = DefaultFunctionArrayConversion(RefExpr.get()); if (RefExpr.isInvalid()) return ExprError(); - - if (!Context.hasSameUnqualifiedType(ParamType->getPointeeType(), T) && - (T->isFunctionType() || T->isArrayType())) { - // Decay functions and arrays unless we're forming a pointer to array. - RefExpr = DefaultFunctionArrayConversion(RefExpr.get()); - if (RefExpr.isInvalid()) - return ExprError(); - - return RefExpr; - } - - // Take the address of everything else - return CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); + } else if (ParamType->isPointerType() || ParamType->isMemberPointerType()) { + // For any other pointer, take the address (or form a pointer-to-member). + RefExpr = CreateBuiltinUnaryOp(Loc, UO_AddrOf, RefExpr.get()); + if (RefExpr.isInvalid()) + return ExprError(); + } else { + assert(ParamType->isReferenceType() && + "unexpected type for decl template argument"); } - ExprValueKind VK = VK_RValue; + // At this point we should have the right value category. + assert(ParamType->isReferenceType() == RefExpr.get()->isLValue() && + "value kind mismatch for non-type template argument"); - // If the non-type template parameter has reference type, qualify the - // resulting declaration reference with the extra qualifiers on the - // type that the reference refers to. - if (const ReferenceType *TargetRef = ParamType->getAs<ReferenceType>()) { - VK = VK_LValue; - T = Context.getQualifiedType(T, - TargetRef->getPointeeType().getQualifiers()); - } else if (isa<FunctionDecl>(VD)) { - // References to functions are always lvalues. - VK = VK_LValue; + // The type of the template parameter can differ from the type of the + // argument in various ways; convert it now if necessary. + QualType DestExprType = ParamType.getNonLValueExprType(Context); + if (!Context.hasSameType(RefExpr.get()->getType(), DestExprType)) { + CastKind CK; + QualType Ignored; + if (Context.hasSimilarType(RefExpr.get()->getType(), DestExprType) || + IsFunctionConversion(RefExpr.get()->getType(), DestExprType, Ignored)) { + CK = CK_NoOp; + } else if (ParamType->isVoidPointerType() && + RefExpr.get()->getType()->isPointerType()) { + CK = CK_BitCast; + } else { + // FIXME: Pointers to members can need conversion derived-to-base or + // base-to-derived conversions. We currently don't retain enough + // information to convert properly (we need to track a cast path or + // subobject number in the template argument). + llvm_unreachable( + "unexpected conversion required for non-type template argument"); + } + RefExpr = ImpCastExprToType(RefExpr.get(), DestExprType, CK, + RefExpr.get()->getValueKind()); } - return BuildDeclRefExpr(VD, T, VK, Loc); + return RefExpr; } /// Construct a new expression that refers to the given @@ -7173,50 +7350,73 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, // template parameter and one of the non-type template parameter types // is dependent, then we must wait until template instantiation time // to actually compare the arguments. - if (Kind == Sema::TPL_TemplateTemplateArgumentMatch && - (OldNTTP->getType()->isDependentType() || - NewNTTP->getType()->isDependentType())) - return true; - - if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { - if (Complain) { - unsigned NextDiag = diag::err_template_nontype_parm_different_type; - if (TemplateArgLoc.isValid()) { - S.Diag(TemplateArgLoc, - diag::err_template_arg_template_params_mismatch); - NextDiag = diag::note_template_nontype_parm_different_type; + if (Kind != Sema::TPL_TemplateTemplateArgumentMatch || + (!OldNTTP->getType()->isDependentType() && + !NewNTTP->getType()->isDependentType())) + if (!S.Context.hasSameType(OldNTTP->getType(), NewNTTP->getType())) { + if (Complain) { + unsigned NextDiag = diag::err_template_nontype_parm_different_type; + if (TemplateArgLoc.isValid()) { + S.Diag(TemplateArgLoc, + diag::err_template_arg_template_params_mismatch); + NextDiag = diag::note_template_nontype_parm_different_type; + } + S.Diag(NewNTTP->getLocation(), NextDiag) + << NewNTTP->getType() + << (Kind != Sema::TPL_TemplateMatch); + S.Diag(OldNTTP->getLocation(), + diag::note_template_nontype_parm_prev_declaration) + << OldNTTP->getType(); } - S.Diag(NewNTTP->getLocation(), NextDiag) - << NewNTTP->getType() - << (Kind != Sema::TPL_TemplateMatch); - S.Diag(OldNTTP->getLocation(), - diag::note_template_nontype_parm_prev_declaration) - << OldNTTP->getType(); - } - return false; - } - - return true; + return false; + } } - // For template template parameters, check the template parameter types. // The template parameter lists of template template // parameters must agree. - if (TemplateTemplateParmDecl *OldTTP + else if (TemplateTemplateParmDecl *OldTTP = dyn_cast<TemplateTemplateParmDecl>(Old)) { TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New); - return S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), - OldTTP->getTemplateParameters(), - Complain, + if (!S.TemplateParameterListsAreEqual(NewTTP->getTemplateParameters(), + OldTTP->getTemplateParameters(), + Complain, (Kind == Sema::TPL_TemplateMatch ? Sema::TPL_TemplateTemplateParmMatch : Kind), - TemplateArgLoc); - } + TemplateArgLoc)) + return false; + } else if (Kind != Sema::TPL_TemplateTemplateArgumentMatch) { + const Expr *NewC = nullptr, *OldC = nullptr; + if (const auto *TC = cast<TemplateTypeParmDecl>(New)->getTypeConstraint()) + NewC = TC->getImmediatelyDeclaredConstraint(); + if (const auto *TC = cast<TemplateTypeParmDecl>(Old)->getTypeConstraint()) + OldC = TC->getImmediatelyDeclaredConstraint(); + + auto Diagnose = [&] { + S.Diag(NewC ? NewC->getBeginLoc() : New->getBeginLoc(), + diag::err_template_different_type_constraint); + S.Diag(OldC ? OldC->getBeginLoc() : Old->getBeginLoc(), + diag::note_template_prev_declaration) << /*declaration*/0; + }; - // TODO: Concepts: Match immediately-introduced-constraint for type - // constraints + if (!NewC != !OldC) { + if (Complain) + Diagnose(); + return false; + } + + if (NewC) { + llvm::FoldingSetNodeID OldCID, NewCID; + OldC->Profile(OldCID, S.Context, /*Canonical=*/true); + NewC->Profile(NewCID, S.Context, /*Canonical=*/true); + if (OldCID != NewCID) { + if (Complain) + Diagnose(); + return false; + } + } + } return true; } @@ -7243,15 +7443,6 @@ void DiagnoseTemplateParameterListArityMismatch(Sema &S, << SourceRange(Old->getTemplateLoc(), Old->getRAngleLoc()); } -static void -DiagnoseTemplateParameterListRequiresClauseMismatch(Sema &S, - TemplateParameterList *New, - TemplateParameterList *Old){ - S.Diag(New->getTemplateLoc(), diag::err_template_different_requires_clause); - S.Diag(Old->getTemplateLoc(), diag::note_template_prev_declaration) - << /*declaration*/0; -} - /// Determine whether the given template parameter lists are /// equivalent. /// @@ -7344,9 +7535,17 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, if (Kind != TPL_TemplateTemplateArgumentMatch) { const Expr *NewRC = New->getRequiresClause(); const Expr *OldRC = Old->getRequiresClause(); + + auto Diagnose = [&] { + Diag(NewRC ? NewRC->getBeginLoc() : New->getTemplateLoc(), + diag::err_template_different_requires_clause); + Diag(OldRC ? OldRC->getBeginLoc() : Old->getTemplateLoc(), + diag::note_template_prev_declaration) << /*declaration*/0; + }; + if (!NewRC != !OldRC) { if (Complain) - DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old); + Diagnose(); return false; } @@ -7356,7 +7555,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, NewRC->Profile(NewRCID, Context, /*Canonical=*/true); if (OldRCID != NewRCID) { if (Complain) - DiagnoseTemplateParameterListRequiresClauseMismatch(*this, New, Old); + Diagnose(); return false; } } @@ -7382,7 +7581,8 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) { // C++ [temp]p4: // A template [...] shall not have C linkage. DeclContext *Ctx = S->getEntity(); - if (Ctx && Ctx->isExternCContext()) { + assert(Ctx && "Unknown context"); + if (Ctx->isExternCContext()) { Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage) << TemplateParams->getSourceRange(); if (const LinkageSpecDecl *LSD = Ctx->getExternCContext()) @@ -7794,7 +7994,8 @@ DeclResult Sema::ActOnClassTemplateSpecialization( // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, - TemplateArgs, false, Converted)) + TemplateArgs, false, Converted, + /*UpdateArgsWithConversion=*/true)) return true; // Find the class template (partial) specialization declaration that @@ -7820,8 +8021,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization( ClassTemplateSpecializationDecl *PrevDecl = nullptr; if (isPartialSpecialization) - // FIXME: Template parameter list matters, too - PrevDecl = ClassTemplate->findPartialSpecialization(Converted, InsertPos); + PrevDecl = ClassTemplate->findPartialSpecialization(Converted, + TemplateParams, + InsertPos); else PrevDecl = ClassTemplate->findSpecialization(Converted, InsertPos); @@ -7845,7 +8047,9 @@ DeclResult Sema::ActOnClassTemplateSpecialization( Converted); if (Context.hasSameType(CanonType, - ClassTemplate->getInjectedClassNameSpecialization())) { + ClassTemplate->getInjectedClassNameSpecialization()) && + (!Context.getLangOpts().ConceptsTS || + !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: // // -- The argument list of the specialization shall not be identical @@ -9040,7 +9244,8 @@ DeclResult Sema::ActOnExplicitInstantiation( // template. SmallVector<TemplateArgument, 4> Converted; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, - TemplateArgs, false, Converted)) + TemplateArgs, false, Converted, + /*UpdateArgsWithConversion=*/true)) return true; // Find the class template specialization declaration that diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 64ef819e30d4..1b9f1b2144d1 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -24,6 +24,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" @@ -642,6 +643,10 @@ static TemplateParameter makeTemplateParameter(Decl *D) { /// If \p Param is an expanded parameter pack, get the number of expansions. static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) { + if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) + if (TTP->isExpandedParameterPack()) + return TTP->getNumExpansionParameters(); + if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) if (NTTP->isExpandedParameterPack()) return NTTP->getNumExpansionTypes(); @@ -859,34 +864,31 @@ public: /// Finish template argument deduction for a set of argument packs, /// producing the argument packs and checking for consistency with prior /// deductions. - Sema::TemplateDeductionResult - finish(bool TreatNoDeductionsAsNonDeduced = true) { + Sema::TemplateDeductionResult finish() { // Build argument packs for each of the parameter packs expanded by this // pack expansion. for (auto &Pack : Packs) { // Put back the old value for this pack. Deduced[Pack.Index] = Pack.Saved; - // If we are deducing the size of this pack even if we didn't deduce any - // values for it, then make sure we build a pack of the right size. - // FIXME: Should we always deduce the size, even if the pack appears in - // a non-deduced context? - if (!TreatNoDeductionsAsNonDeduced) - Pack.New.resize(PackElements); + // Always make sure the size of this pack is correct, even if we didn't + // deduce any values for it. + // + // FIXME: This isn't required by the normative wording, but substitution + // and post-substitution checking will always fail if the arity of any + // pack is not equal to the number of elements we processed. (Either that + // or something else has gone *very* wrong.) We're permitted to skip any + // hard errors from those follow-on steps by the intent (but not the + // wording) of C++ [temp.inst]p8: + // + // If the function selected by overload resolution can be determined + // without instantiating a class template definition, it is unspecified + // whether that instantiation actually takes place + Pack.New.resize(PackElements); // Build or find a new value for this pack. DeducedTemplateArgument NewPack; - if (PackElements && Pack.New.empty()) { - if (Pack.DeferredDeduction.isNull()) { - // We were not able to deduce anything for this parameter pack - // (because it only appeared in non-deduced contexts), so just - // restore the saved argument pack. - continue; - } - - NewPack = Pack.DeferredDeduction; - Pack.DeferredDeduction = TemplateArgument(); - } else if (Pack.New.empty()) { + if (Pack.New.empty()) { // If we deduced an empty argument pack, create it now. NewPack = DeducedTemplateArgument(TemplateArgument::getEmptyPack()); } else { @@ -2501,6 +2503,30 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, llvm_unreachable("Invalid TemplateArgument Kind!"); } +TemplateArgumentLoc +Sema::getIdentityTemplateArgumentLoc(Decl *TemplateParm, + SourceLocation Location) { + if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParm)) + return getTrivialTemplateArgumentLoc( + TemplateArgument( + Context.getTemplateTypeParmType(TTP->getDepth(), TTP->getIndex(), + TTP->isParameterPack(), TTP)), + QualType(), Location.isValid() ? Location : TTP->getLocation()); + else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParm)) + return getTrivialTemplateArgumentLoc(TemplateArgument(TemplateName(TTP)), + QualType(), + Location.isValid() ? Location : + TTP->getLocation()); + auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParm); + CXXScopeSpec SS; + DeclarationNameInfo Info(NTTP->getDeclName(), + Location.isValid() ? Location : NTTP->getLocation()); + Expr *E = BuildDeclarationNameExpr(SS, Info, NTTP).get(); + return getTrivialTemplateArgumentLoc(TemplateArgument(E), NTTP->getType(), + Location.isValid() ? Location : + NTTP->getLocation()); +} + /// Convert the given deduced template argument and add it to the set of /// fully-converted template arguments. static bool @@ -2611,8 +2637,8 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( // be deduced to an empty sequence of template arguments. // FIXME: Where did the word "trailing" come from? if (Deduced[I].isNull() && Param->isTemplateParameterPack()) { - if (auto Result = PackDeductionScope(S, TemplateParams, Deduced, Info, I) - .finish(/*TreatNoDeductionsAsNonDeduced*/false)) + if (auto Result = + PackDeductionScope(S, TemplateParams, Deduced, Info, I).finish()) return Result; } @@ -2709,6 +2735,23 @@ struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> { static constexpr bool value = true; }; +template<typename TemplateDeclT> +static Sema::TemplateDeductionResult +CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template, + ArrayRef<TemplateArgument> DeducedArgs, + TemplateDeductionInfo& Info) { + llvm::SmallVector<const Expr *, 3> AssociatedConstraints; + Template->getAssociatedConstraints(AssociatedConstraints); + if (S.CheckConstraintSatisfaction(Template, AssociatedConstraints, + DeducedArgs, Info.getLocation(), + Info.AssociatedConstraintsSatisfaction) || + !Info.AssociatedConstraintsSatisfaction.IsSatisfied) { + Info.reset(TemplateArgumentList::CreateCopy(S.Context, DeducedArgs)); + return Sema::TDK_ConstraintsNotSatisfied; + } + return Sema::TDK_Success; +} + /// Complete template argument deduction for a partial specialization. template <typename T> static typename std::enable_if<IsPartialSpecialization<T>::value, @@ -2767,10 +2810,14 @@ FinishTemplateArgumentDeduction( return Sema::TDK_SubstitutionFailure; } + bool ConstraintsNotSatisfied; SmallVector<TemplateArgument, 4> ConvertedInstArgs; if (S.CheckTemplateArgumentList(Template, Partial->getLocation(), InstArgs, - false, ConvertedInstArgs)) - return Sema::TDK_SubstitutionFailure; + false, ConvertedInstArgs, + /*UpdateArgsWithConversions=*/true, + &ConstraintsNotSatisfied)) + return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied : + Sema::TDK_SubstitutionFailure; TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { @@ -2786,6 +2833,9 @@ FinishTemplateArgumentDeduction( if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; + if (auto Result = CheckDeducedArgumentConstraints(S, Partial, Builder, Info)) + return Result; + return Sema::TDK_Success; } @@ -2828,10 +2878,13 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; + if (auto Result = CheckDeducedArgumentConstraints(S, Template, Builder, + Info)) + return Result; + return Sema::TDK_Success; } - /// Perform template argument deduction to determine whether /// the given template arguments match the given class template /// partial specialization per C++ [temp.class.spec.match]. @@ -3385,6 +3438,23 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( return TDK_SubstitutionFailure; } + // C++2a [temp.deduct]p5 + // [...] When all template arguments have been deduced [...] all uses of + // template parameters [...] are replaced with the corresponding deduced + // or default argument values. + // [...] If the function template has associated constraints + // ([temp.constr.decl]), those constraints are checked for satisfaction + // ([temp.constr.constr]). If the constraints are not satisfied, type + // deduction fails. + if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(), + Specialization, Builder, Info.AssociatedConstraintsSatisfaction)) + return TDK_MiscellaneousDeductionFailure; + + if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) { + Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); + return TDK_ConstraintsNotSatisfied; + } + if (OriginalCallArgs) { // C++ [temp.deduct.call]p4: // In general, the deduction process attempts to find template argument @@ -3505,7 +3575,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, DeclAccessPair DAP; if (FunctionDecl *Viable = - S.resolveAddressOfOnlyViableOverloadCandidate(Arg, DAP)) + S.resolveAddressOfSingleOverloadCandidate(Arg, DAP)) return GetTypeOfFunction(S, R, Viable); return {}; @@ -4429,7 +4499,8 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, /*.IsPack = */ (bool)Type.getAs<PackExpansionTypeLoc>()}; if (!DependentDeductionDepth && - (Type.getType()->isDependentType() || Init->isTypeDependent())) { + (Type.getType()->isDependentType() || Init->isTypeDependent() || + Init->containsUnexpandedParameterPack())) { Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); return DAR_Succeeded; @@ -4475,11 +4546,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, // Build template<class TemplParam> void Func(FuncParam); TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create( - Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false); + Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false, + false); QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0); NamedDecl *TemplParamPtr = TemplParam; FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt( - Loc, Loc, TemplParamPtr, Loc, nullptr); + Context, Loc, Loc, TemplParamPtr, Loc, nullptr); QualType FuncParam = SubstituteDeducedTypeTransform(*this, TemplArg, /*UseTypeSugar*/false) @@ -4905,6 +4977,21 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, unsigned NumCallArguments2) { + + auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * { + llvm::SmallVector<const Expr *, 3> AC1, AC2; + FT1->getAssociatedConstraints(AC1); + FT2->getAssociatedConstraints(AC2); + bool AtLeastAsConstrained1, AtLeastAsConstrained2; + if (IsAtLeastAsConstrained(FT1, AC1, FT2, AC2, AtLeastAsConstrained1)) + return nullptr; + if (IsAtLeastAsConstrained(FT2, AC2, FT1, AC1, AtLeastAsConstrained2)) + return nullptr; + if (AtLeastAsConstrained1 == AtLeastAsConstrained2) + return nullptr; + return AtLeastAsConstrained1 ? FT1 : FT2; + }; + bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, NumCallArguments1); bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, @@ -4914,7 +5001,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, return Better1 ? FT1 : FT2; if (!Better1 && !Better2) // Neither is better than the other - return nullptr; + return JudgeByConstraints(); // FIXME: This mimics what GCC implements, but doesn't match up with the // proposed resolution for core issue 692. This area needs to be sorted out, @@ -4924,7 +5011,7 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, if (Variadic1 != Variadic2) return Variadic1? FT2 : FT1; - return nullptr; + return JudgeByConstraints(); } /// Determine if the two templates are equivalent. @@ -5119,8 +5206,21 @@ Sema::getMoreSpecializedPartialSpecialization( bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); - if (Better1 == Better2) - return nullptr; + if (!Better1 && !Better2) + return nullptr; + if (Better1 && Better2) { + llvm::SmallVector<const Expr *, 3> AC1, AC2; + PS1->getAssociatedConstraints(AC1); + PS2->getAssociatedConstraints(AC2); + bool AtLeastAsConstrained1, AtLeastAsConstrained2; + if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1)) + return nullptr; + if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2)) + return nullptr; + if (AtLeastAsConstrained1 == AtLeastAsConstrained2) + return nullptr; + return AtLeastAsConstrained1 ? PS1 : PS2; + } return Better1 ? PS1 : PS2; } @@ -5132,11 +5232,22 @@ bool Sema::isMoreSpecializedThanPrimary( QualType PartialT = Spec->getInjectedSpecializationType(); if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) return false; - if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) { - Info.clearSFINAEDiagnostic(); + if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) + return true; + Info.clearSFINAEDiagnostic(); + llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC; + Primary->getAssociatedConstraints(PrimaryAC); + Spec->getAssociatedConstraints(SpecAC); + bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec; + if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC, + AtLeastAsConstrainedSpec)) return false; - } - return true; + if (!AtLeastAsConstrainedSpec) + return false; + if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC, + AtLeastAsConstrainedPrimary)) + return false; + return !AtLeastAsConstrainedPrimary; } VarTemplatePartialSpecializationDecl * @@ -5159,8 +5270,21 @@ Sema::getMoreSpecializedPartialSpecialization( bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); - if (Better1 == Better2) + if (!Better1 && !Better2) return nullptr; + if (Better1 && Better2) { + llvm::SmallVector<const Expr *, 3> AC1, AC2; + PS1->getAssociatedConstraints(AC1); + PS2->getAssociatedConstraints(AC2); + bool AtLeastAsConstrained1, AtLeastAsConstrained2; + if (IsAtLeastAsConstrained(PS1, AC1, PS2, AC2, AtLeastAsConstrained1)) + return nullptr; + if (IsAtLeastAsConstrained(PS2, AC2, PS1, AC1, AtLeastAsConstrained2)) + return nullptr; + if (AtLeastAsConstrained1 == AtLeastAsConstrained2) + return nullptr; + return AtLeastAsConstrained1 ? PS1 : PS2; + } return Better1 ? PS1 : PS2; } @@ -5180,13 +5304,25 @@ bool Sema::isMoreSpecializedThanPrimary( CanonTemplate, PrimaryArgs); QualType PartialT = Context.getTemplateSpecializationType( CanonTemplate, Spec->getTemplateArgs().asArray()); + if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) return false; - if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) { - Info.clearSFINAEDiagnostic(); + if (!isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) + return true; + Info.clearSFINAEDiagnostic(); + llvm::SmallVector<const Expr *, 3> PrimaryAC, SpecAC; + Primary->getAssociatedConstraints(PrimaryAC); + Spec->getAssociatedConstraints(SpecAC); + bool AtLeastAsConstrainedPrimary, AtLeastAsConstrainedSpec; + if (IsAtLeastAsConstrained(Spec, SpecAC, Primary, PrimaryAC, + AtLeastAsConstrainedSpec)) + return false; + if (!AtLeastAsConstrainedSpec) return false; - } - return true; + if (IsAtLeastAsConstrained(Primary, PrimaryAC, Spec, SpecAC, + AtLeastAsConstrainedPrimary)) + return false; + return !AtLeastAsConstrainedPrimary; } bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( @@ -5220,7 +5356,8 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( SFINAETrap Trap(*this); Context.getInjectedTemplateArgs(P, PArgs); - TemplateArgumentListInfo PArgList(P->getLAngleLoc(), P->getRAngleLoc()); + TemplateArgumentListInfo PArgList(P->getLAngleLoc(), + P->getRAngleLoc()); for (unsigned I = 0, N = P->size(); I != N; ++I) { // Unwrap packs that getInjectedTemplateArgs wrapped around pack // expansions, to form an "as written" argument list. @@ -5252,6 +5389,41 @@ bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( return isAtLeastAsSpecializedAs(*this, PType, AType, AArg, Info); } +namespace { +struct MarkUsedTemplateParameterVisitor : + RecursiveASTVisitor<MarkUsedTemplateParameterVisitor> { + llvm::SmallBitVector &Used; + unsigned Depth; + + MarkUsedTemplateParameterVisitor(llvm::SmallBitVector &Used, + unsigned Depth) + : Used(Used), Depth(Depth) { } + + bool VisitTemplateTypeParmType(TemplateTypeParmType *T) { + if (T->getDepth() == Depth) + Used[T->getIndex()] = true; + return true; + } + + bool TraverseTemplateName(TemplateName Template) { + if (auto *TTP = + dyn_cast<TemplateTemplateParmDecl>(Template.getAsTemplateDecl())) + if (TTP->getDepth() == Depth) + Used[TTP->getIndex()] = true; + RecursiveASTVisitor<MarkUsedTemplateParameterVisitor>:: + TraverseTemplateName(Template); + return true; + } + + bool VisitDeclRefExpr(DeclRefExpr *E) { + if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(E->getDecl())) + if (NTTP->getDepth() == Depth) + Used[NTTP->getIndex()] = true; + return true; + } +}; +} + /// Mark the template parameters that are used by the given /// expression. static void @@ -5260,6 +5432,12 @@ MarkUsedTemplateParameters(ASTContext &Ctx, bool OnlyDeduced, unsigned Depth, llvm::SmallBitVector &Used) { + if (!OnlyDeduced) { + MarkUsedTemplateParameterVisitor(Used, Depth) + .TraverseStmt(const_cast<Expr *>(E)); + return; + } + // We can deduce from a pack expansion. if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E)) E = Expansion->getPattern(); @@ -5278,8 +5456,6 @@ MarkUsedTemplateParameters(ASTContext &Ctx, break; } - // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to - // find other occurrences of template parameters. const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E); if (!DRE) return; @@ -5659,6 +5835,20 @@ MarkUsedTemplateParameters(ASTContext &Ctx, } } +/// Mark which template parameters are used in a given expression. +/// +/// \param E the expression from which template parameters will be deduced. +/// +/// \param Used a bit vector whose elements will be set to \c true +/// to indicate when the corresponding template parameter will be +/// deduced. +void +Sema::MarkUsedTemplateParameters(const Expr *E, bool OnlyDeduced, + unsigned Depth, + llvm::SmallBitVector &Used) { + ::MarkUsedTemplateParameters(Context, E, OnlyDeduced, Depth, Used); +} + /// Mark which template parameters can be deduced from a given /// template argument list. /// diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 0daa33cfbef5..af41e231134d 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -150,7 +150,7 @@ Sema::getTemplateInstantiationArgs(NamedDecl *D, break; // If this function is a generic lambda specialization, we are done. - if (isGenericLambdaCallOperatorSpecialization(Function)) + if (isGenericLambdaCallOperatorOrStaticInvokerSpecialization(Function)) break; } else if (FunctionTemplateDecl *FunTmpl @@ -203,9 +203,12 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case DefaultTemplateArgumentChecking: case DeclaringSpecialMember: + case DeclaringImplicitEqualityComparison: case DefiningSynthesizedFunction: case ExceptionSpecEvaluation: case ConstraintSubstitution: + case ParameterMappingSubstitution: + case ConstraintNormalization: case RewritingOperatorAsSpaceship: return false; @@ -363,7 +366,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, - ConstraintsCheck, TemplateDecl *Template, + ConstraintsCheck, NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange) : InstantiatingTemplate( SemaRef, CodeSynthesisContext::ConstraintsCheck, @@ -372,13 +375,29 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, - ConstraintSubstitution, TemplateDecl *Template, + ConstraintSubstitution, NamedDecl *Template, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) : InstantiatingTemplate( SemaRef, CodeSynthesisContext::ConstraintSubstitution, PointOfInstantiation, InstantiationRange, Template, nullptr, {}, &DeductionInfo) {} +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, + ConstraintNormalization, NamedDecl *Template, + SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::ConstraintNormalization, + PointOfInstantiation, InstantiationRange, Template) {} + +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, + ParameterMappingSubstitution, NamedDecl *Template, + SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::ParameterMappingSubstitution, + PointOfInstantiation, InstantiationRange, Template) {} + void Sema::pushCodeSynthesisContext(CodeSynthesisContext Ctx) { Ctx.SavedInNonInstantiationSFINAEContext = InNonInstantiationSFINAEContext; InNonInstantiationSFINAEContext = false; @@ -671,14 +690,29 @@ void Sema::PrintInstantiationStack() { << cast<CXXRecordDecl>(Active->Entity) << Active->SpecialMember; break; + case CodeSynthesisContext::DeclaringImplicitEqualityComparison: + Diags.Report(Active->Entity->getLocation(), + diag::note_in_declaration_of_implicit_equality_comparison); + break; + case CodeSynthesisContext::DefiningSynthesizedFunction: { - // FIXME: For synthesized members other than special members, produce a note. - auto *MD = dyn_cast<CXXMethodDecl>(Active->Entity); - auto CSM = MD ? getSpecialMember(MD) : CXXInvalid; - if (CSM != CXXInvalid) { + // FIXME: For synthesized functions that are not defaulted, + // produce a note. + auto *FD = dyn_cast<FunctionDecl>(Active->Entity); + DefaultedFunctionKind DFK = + FD ? getDefaultedFunctionKind(FD) : DefaultedFunctionKind(); + if (DFK.isSpecialMember()) { + auto *MD = cast<CXXMethodDecl>(FD); Diags.Report(Active->PointOfInstantiation, diag::note_member_synthesized_at) - << CSM << Context.getTagDeclType(MD->getParent()); + << MD->isExplicitlyDefaulted() << DFK.asSpecialMember() + << Context.getTagDeclType(MD->getParent()); + } else if (DFK.isComparison()) { + Diags.Report(Active->PointOfInstantiation, + diag::note_comparison_synthesized_at) + << (int)DFK.asComparison() + << Context.getTagDeclType( + cast<CXXRecordDecl>(FD->getLexicalDeclContext())); } break; } @@ -691,29 +725,43 @@ void Sema::PrintInstantiationStack() { case CodeSynthesisContext::Memoization: break; - case CodeSynthesisContext::ConstraintsCheck: - if (auto *CD = dyn_cast<ConceptDecl>(Active->Entity)) { - SmallVector<char, 128> TemplateArgsStr; - llvm::raw_svector_ostream OS(TemplateArgsStr); - CD->printName(OS); - printTemplateArgumentList(OS, Active->template_arguments(), - getPrintingPolicy()); - Diags.Report(Active->PointOfInstantiation, - diag::note_concept_specialization_here) - << OS.str() - << Active->InstantiationRange; - break; + case CodeSynthesisContext::ConstraintsCheck: { + unsigned DiagID = 0; + if (isa<ConceptDecl>(Active->Entity)) + DiagID = diag::note_concept_specialization_here; + else if (isa<TemplateDecl>(Active->Entity)) + DiagID = diag::note_checking_constraints_for_template_id_here; + else if (isa<VarTemplatePartialSpecializationDecl>(Active->Entity)) + DiagID = diag::note_checking_constraints_for_var_spec_id_here; + else { + assert(isa<ClassTemplatePartialSpecializationDecl>(Active->Entity)); + DiagID = diag::note_checking_constraints_for_class_spec_id_here; } - // TODO: Concepts - implement this for constrained templates and partial - // specializations. - llvm_unreachable("only concept constraints are supported right now"); + SmallVector<char, 128> TemplateArgsStr; + llvm::raw_svector_ostream OS(TemplateArgsStr); + cast<NamedDecl>(Active->Entity)->printName(OS); + printTemplateArgumentList(OS, Active->template_arguments(), + getPrintingPolicy()); + Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str() + << Active->InstantiationRange; break; - + } case CodeSynthesisContext::ConstraintSubstitution: Diags.Report(Active->PointOfInstantiation, diag::note_constraint_substitution_here) << Active->InstantiationRange; break; + case CodeSynthesisContext::ConstraintNormalization: + Diags.Report(Active->PointOfInstantiation, + diag::note_constraint_normalization_here) + << cast<NamedDecl>(Active->Entity)->getName() + << Active->InstantiationRange; + break; + case CodeSynthesisContext::ParameterMappingSubstitution: + Diags.Report(Active->PointOfInstantiation, + diag::note_parameter_mapping_substitution_here) + << Active->InstantiationRange; + break; } } } @@ -738,6 +786,8 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::DefaultFunctionArgumentInstantiation: case CodeSynthesisContext::ExceptionSpecInstantiation: case CodeSynthesisContext::ConstraintsCheck: + case CodeSynthesisContext::ParameterMappingSubstitution: + case CodeSynthesisContext::ConstraintNormalization: // This is a template instantiation, so there is no SFINAE. return None; @@ -759,6 +809,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { return Active->DeductionInfo; case CodeSynthesisContext::DeclaringSpecialMember: + case CodeSynthesisContext::DeclaringImplicitEqualityComparison: case CodeSynthesisContext::DefiningSynthesizedFunction: case CodeSynthesisContext::RewritingOperatorAsSpaceship: // This happens in a context unrelated to template instantiation, so @@ -1514,8 +1565,12 @@ TemplateInstantiator::TransformFunctionTypeParam(ParmVarDecl *OldParm, int indexAdjustment, Optional<unsigned> NumExpansions, bool ExpectParameterPack) { - return SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment, - NumExpansions, ExpectParameterPack); + auto NewParm = + SemaRef.SubstParmVarDecl(OldParm, TemplateArgs, indexAdjustment, + NumExpansions, ExpectParameterPack); + if (NewParm && SemaRef.getLangOpts().OpenCL) + SemaRef.deduceOpenCLAddressSpace(NewParm); + return NewParm; } QualType @@ -2219,11 +2274,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // Finish checking fields. ActOnFields(nullptr, Instantiation->getLocation(), Instantiation, Fields, SourceLocation(), SourceLocation(), ParsedAttributesView()); - CheckCompletedCXXClass(Instantiation); + CheckCompletedCXXClass(nullptr, Instantiation); // Default arguments are parsed, if not instantiated. We can go instantiate - // default arg exprs for default constructors if necessary now. - ActOnFinishCXXNonNestedClass(Instantiation); + // default arg exprs for default constructors if necessary now. Unless we're + // parsing a class, in which case wait until that's finished. + if (ParsingClassDepth == 0) + ActOnFinishCXXNonNestedClass(); // Instantiate late parsed attributes, and attach them to their decls. // See Sema::InstantiateAttrs @@ -2900,6 +2957,17 @@ Sema::SubstStmt(Stmt *S, const MultiLevelTemplateArgumentList &TemplateArgs) { return Instantiator.TransformStmt(S); } +bool Sema::SubstTemplateArguments( + ArrayRef<TemplateArgumentLoc> Args, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateArgumentListInfo &Out) { + TemplateInstantiator Instantiator(*this, TemplateArgs, + SourceLocation(), + DeclarationName()); + return Instantiator.TransformTemplateArguments(Args.begin(), Args.end(), + Out); +} + ExprResult Sema::SubstExpr(Expr *E, const MultiLevelTemplateArgumentList &TemplateArgs) { if (!E) diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index d1ad304e62e4..64500d0a26d5 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -385,12 +385,13 @@ static void instantiateOMPDeclareVariantAttr( }; ExprResult VariantFuncRef; - if (Expr *E = Attr.getVariantFuncRef()) + if (Expr *E = Attr.getVariantFuncRef()) { + // Do not mark function as is used to prevent its emission if this is the + // only place where it is used. + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); VariantFuncRef = Subst(E); - - ExprResult Score; - if (Expr *E = Attr.getScore()) - Score = Subst(E); + } // Check function/variant ref. Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData = @@ -398,12 +399,41 @@ static void instantiateOMPDeclareVariantAttr( S.ConvertDeclToDeclGroup(New), VariantFuncRef.get(), Attr.getRange()); if (!DeclVarData) return; - // Instantiate the attribute. - Sema::OpenMPDeclareVariantCtsSelectorData Data( - Attr.getCtxSelectorSet(), Attr.getCtxSelector(), - llvm::makeMutableArrayRef(Attr.implVendors_begin(), - Attr.implVendors_size()), - Score); + SmallVector<Sema::OMPCtxSelectorData, 4> Data; + for (unsigned I = 0, E = Attr.scores_size(); I < E; ++I) { + ExprResult Score; + if (Expr *E = *std::next(Attr.scores_begin(), I)) + Score = Subst(E); + // Instantiate the attribute. + auto CtxSet = static_cast<OpenMPContextSelectorSetKind>( + *std::next(Attr.ctxSelectorSets_begin(), I)); + auto Ctx = static_cast<OpenMPContextSelectorKind>( + *std::next(Attr.ctxSelectors_begin(), I)); + switch (CtxSet) { + case OMP_CTX_SET_implementation: + switch (Ctx) { + case OMP_CTX_vendor: + Data.emplace_back(CtxSet, Ctx, Score, Attr.implVendors()); + break; + case OMP_CTX_kind: + case OMP_CTX_unknown: + llvm_unreachable("Unexpected context selector kind."); + } + break; + case OMP_CTX_SET_device: + switch (Ctx) { + case OMP_CTX_kind: + Data.emplace_back(CtxSet, Ctx, Score, Attr.deviceKinds()); + break; + case OMP_CTX_vendor: + case OMP_CTX_unknown: + llvm_unreachable("Unexpected context selector kind."); + } + break; + case OMP_CTX_SET_unknown: + llvm_unreachable("Unexpected context selector set kind."); + } + } S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first, DeclVarData.getValue().second, Attr.getRange(), Data); @@ -625,11 +655,10 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, LateAttrs->push_back(LateInstantiatedAttribute(TmplAttr, Saved, New)); } else { // Allow 'this' within late-parsed attributes. - NamedDecl *ND = dyn_cast<NamedDecl>(New); - CXXRecordDecl *ThisContext = - dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext()); + auto *ND = cast<NamedDecl>(New); + auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext()); CXXThisScopeRAII ThisScope(*this, ThisContext, Qualifiers(), - ND && ND->isCXXInstanceMember()); + ND->isCXXInstanceMember()); Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context, *this, TemplateArgs); @@ -905,6 +934,9 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, SemaRef.inferObjCARCLifetime(Var)) Var->setInvalidDecl(); + if (SemaRef.getLangOpts().OpenCL) + SemaRef.deduceOpenCLAddressSpace(Var); + // Substitute the nested name specifier, if any. if (SubstQualifier(D, Var)) return nullptr; @@ -1761,8 +1793,9 @@ static QualType adjustFunctionTypeForInstantiation(ASTContext &Context, /// 1) instantiating function templates /// 2) substituting friend declarations /// 3) substituting deduction guide declarations for nested class templates -Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, - TemplateParameterList *TemplateParams) { +Decl *TemplateDeclInstantiator::VisitFunctionDecl( + FunctionDecl *D, TemplateParameterList *TemplateParams, + RewriteKind FunctionRewriteKind) { // Check whether there is already a function template specialization for // this declaration. FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); @@ -1812,6 +1845,18 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, return nullptr; } + // FIXME: Concepts: Do not substitute into constraint expressions + Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); + if (TrailingRequiresClause) { + ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, + TemplateArgs); + if (SubstRC.isInvalid()) + return nullptr; + TrailingRequiresClause = SubstRC.get(); + if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause)) + return nullptr; + } + // If we're instantiating a local function declaration, put the result // in the enclosing namespace; otherwise we need to find the instantiated // context. @@ -1832,6 +1877,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, DeclarationNameInfo NameInfo = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); + if (FunctionRewriteKind != RewriteKind::None) + adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo); + FunctionDecl *Function; if (auto *DGuide = dyn_cast<CXXDeductionGuideDecl>(D)) { Function = CXXDeductionGuideDecl::Create( @@ -1845,7 +1893,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Function = FunctionDecl::Create( SemaRef.Context, DC, D->getInnerLocStart(), NameInfo, T, TInfo, D->getCanonicalDecl()->getStorageClass(), D->isInlineSpecified(), - D->hasWrittenPrototype(), D->getConstexprKind()); + D->hasWrittenPrototype(), D->getConstexprKind(), + TrailingRequiresClause); Function->setRangeEnd(D->getSourceRange().getEnd()); } @@ -1872,6 +1921,9 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, Params[P]->setOwningFunction(Function); Function->setParams(Params); + if (TrailingRequiresClause) + Function->setTrailingRequiresClause(TrailingRequiresClause); + if (TemplateParams) { // Our resulting instantiation is actually a function template, since we // are substituting only the outer template parameters. For example, given @@ -2049,6 +2101,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, } } + if (D->isExplicitlyDefaulted()) { + if (SubstDefaultedFunction(Function, D)) + return nullptr; + } + if (D->isDeleted()) + SemaRef.SetDeclDeleted(Function, D->getLocation()); + if (Function->isLocalExternDecl() && !Function->getPreviousDecl()) DC->makeDeclVisibleInContext(PrincipalDecl); @@ -2056,14 +2115,13 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, PrincipalDecl->isInIdentifierNamespace(Decl::IDNS_Ordinary)) PrincipalDecl->setNonMemberOperator(); - assert(!D->isDefaulted() && "only methods should be defaulted"); return Function; } Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( CXXMethodDecl *D, TemplateParameterList *TemplateParams, - Optional<const ASTTemplateArgumentListInfo *> - ClassScopeSpecializationArgs) { + Optional<const ASTTemplateArgumentListInfo *> ClassScopeSpecializationArgs, + RewriteKind FunctionRewriteKind) { FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate(); if (FunctionTemplate && !TemplateParams) { // We are creating a function template specialization from a function @@ -2125,6 +2183,18 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( return nullptr; } + // FIXME: Concepts: Do not substitute into constraint expressions + Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); + if (TrailingRequiresClause) { + ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, + TemplateArgs); + if (SubstRC.isInvalid()) + return nullptr; + TrailingRequiresClause = SubstRC.get(); + if (!SemaRef.CheckConstraintExpression(TrailingRequiresClause)) + return nullptr; + } + DeclContext *DC = Owner; if (isFriend) { if (QualifierLoc) { @@ -2142,34 +2212,42 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( if (!DC) return nullptr; } + DeclarationNameInfo NameInfo + = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); + + if (FunctionRewriteKind != RewriteKind::None) + adjustForRewrite(FunctionRewriteKind, D, T, TInfo, NameInfo); + // Build the instantiated method declaration. CXXRecordDecl *Record = cast<CXXRecordDecl>(DC); CXXMethodDecl *Method = nullptr; SourceLocation StartLoc = D->getInnerLocStart(); - DeclarationNameInfo NameInfo - = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { Method = CXXConstructorDecl::Create( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, InstantiatedExplicitSpecifier, Constructor->isInlineSpecified(), false, - Constructor->getConstexprKind()); + Constructor->getConstexprKind(), InheritedConstructor(), + TrailingRequiresClause); Method->setRangeEnd(Constructor->getEndLoc()); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, - Destructor->isInlineSpecified(), false, Destructor->getConstexprKind()); + Destructor->isInlineSpecified(), false, Destructor->getConstexprKind(), + TrailingRequiresClause); Method->setRangeEnd(Destructor->getEndLoc()); } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { Method = CXXConversionDecl::Create( SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, Conversion->isInlineSpecified(), InstantiatedExplicitSpecifier, - Conversion->getConstexprKind(), Conversion->getEndLoc()); + Conversion->getConstexprKind(), Conversion->getEndLoc(), + TrailingRequiresClause); } else { StorageClass SC = D->isStatic() ? SC_Static : SC_None; Method = CXXMethodDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, SC, D->isInlineSpecified(), - D->getConstexprKind(), D->getEndLoc()); + D->getConstexprKind(), D->getEndLoc(), + TrailingRequiresClause); } if (D->isInlined()) @@ -2325,8 +2403,10 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( SemaRef.CheckOverrideControl(Method); // If a function is defined as defaulted or deleted, mark it as such now. - if (D->isExplicitlyDefaulted()) - SemaRef.SetDeclDefaulted(Method, Method->getLocation()); + if (D->isExplicitlyDefaulted()) { + if (SubstDefaultedFunction(Method, D)) + return nullptr; + } if (D->isDeletedAsWritten()) SemaRef.SetDeclDeleted(Method, Method->getLocation()); @@ -2399,13 +2479,68 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( // TODO: don't always clone when decls are refcounted. assert(D->getTypeForDecl()->isTemplateTypeParmType()); + Optional<unsigned> NumExpanded; + + if (const TypeConstraint *TC = D->getTypeConstraint()) { + if (D->isPackExpansion() && !D->isExpandedParameterPack()) { + assert(TC->getTemplateArgsAsWritten() && + "type parameter can only be an expansion when explicit arguments " + "are specified"); + // The template type parameter pack's type is a pack expansion of types. + // Determine whether we need to expand this parameter pack into separate + // types. + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + for (auto &ArgLoc : TC->getTemplateArgsAsWritten()->arguments()) + SemaRef.collectUnexpandedParameterPacks(ArgLoc, Unexpanded); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + if (SemaRef.CheckParameterPacksForExpansion( + cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc(), + SourceRange(TC->getConceptNameLoc(), + TC->hasExplicitTemplateArgs() ? + TC->getTemplateArgsAsWritten()->getRAngleLoc() : + TC->getConceptNameInfo().getEndLoc()), + Unexpanded, TemplateArgs, Expand, RetainExpansion, NumExpanded)) + return nullptr; + } + } + TemplateTypeParmDecl *Inst = TemplateTypeParmDecl::Create( SemaRef.Context, Owner, D->getBeginLoc(), D->getLocation(), D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getIndex(), - D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack()); + D->getIdentifier(), D->wasDeclaredWithTypename(), D->isParameterPack(), + D->hasTypeConstraint(), NumExpanded); + Inst->setAccess(AS_public); Inst->setImplicit(D->isImplicit()); + if (auto *TC = D->getTypeConstraint()) { + // TODO: Concepts: do not instantiate the constraint (delayed constraint + // substitution) + const ASTTemplateArgumentListInfo *TemplArgInfo + = TC->getTemplateArgsAsWritten(); + TemplateArgumentListInfo InstArgs; + if (TemplArgInfo) { + InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); + InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); + if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(), + TemplArgInfo->NumTemplateArgs, + InstArgs, TemplateArgs)) + return nullptr; + } + if (SemaRef.AttachTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), &InstArgs, Inst, + D->isParameterPack() + ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc() + : SourceLocation())) + return nullptr; + } if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { TypeSourceInfo *InstantiatedDefaultArg = SemaRef.SubstType(D->getDefaultArgumentInfo(), TemplateArgs, @@ -3040,7 +3175,9 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( } if (SubstReductionType.isNull()) return nullptr; - bool IsCorrect = !SubstReductionType.isNull(); + Expr *Combiner = D->getCombiner(); + Expr *Init = D->getInitializer(); + bool IsCorrect = true; // Create instantiated copy. std::pair<QualType, SourceLocation> ReductionTypes[] = { std::make_pair(SubstReductionType, D->getLocation())}; @@ -3055,23 +3192,10 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( PrevDeclInScope); auto *NewDRD = cast<OMPDeclareReductionDecl>(DRD.get().getSingleDecl()); SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDRD); - if (!RequiresInstantiation) { - if (Expr *Combiner = D->getCombiner()) { - NewDRD->setCombinerData(D->getCombinerIn(), D->getCombinerOut()); - NewDRD->setCombiner(Combiner); - if (Expr *Init = D->getInitializer()) { - NewDRD->setInitializerData(D->getInitOrig(), D->getInitPriv()); - NewDRD->setInitializer(Init, D->getInitializerKind()); - } - } - (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd( - /*S=*/nullptr, DRD, IsCorrect && !D->isInvalidDecl()); - return NewDRD; - } Expr *SubstCombiner = nullptr; Expr *SubstInitializer = nullptr; // Combiners instantiation sequence. - if (D->getCombiner()) { + if (Combiner) { SemaRef.ActOnOpenMPDeclareReductionCombinerStart( /*S=*/nullptr, NewDRD); SemaRef.CurrentInstantiationScope->InstantiatedLocal( @@ -3083,41 +3207,41 @@ Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner); Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, Qualifiers(), ThisContext); - SubstCombiner = SemaRef.SubstExpr(D->getCombiner(), TemplateArgs).get(); + SubstCombiner = SemaRef.SubstExpr(Combiner, TemplateArgs).get(); SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner); - // Initializers instantiation sequence. - if (D->getInitializer()) { - VarDecl *OmpPrivParm = - SemaRef.ActOnOpenMPDeclareReductionInitializerStart( - /*S=*/nullptr, NewDRD); - SemaRef.CurrentInstantiationScope->InstantiatedLocal( - cast<DeclRefExpr>(D->getInitOrig())->getDecl(), - cast<DeclRefExpr>(NewDRD->getInitOrig())->getDecl()); - SemaRef.CurrentInstantiationScope->InstantiatedLocal( - cast<DeclRefExpr>(D->getInitPriv())->getDecl(), - cast<DeclRefExpr>(NewDRD->getInitPriv())->getDecl()); - if (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit) { - SubstInitializer = - SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get(); - } else { - IsCorrect = IsCorrect && OmpPrivParm->hasInit(); - } - SemaRef.ActOnOpenMPDeclareReductionInitializerEnd( - NewDRD, SubstInitializer, OmpPrivParm); + } + // Initializers instantiation sequence. + if (Init) { + VarDecl *OmpPrivParm = SemaRef.ActOnOpenMPDeclareReductionInitializerStart( + /*S=*/nullptr, NewDRD); + SemaRef.CurrentInstantiationScope->InstantiatedLocal( + cast<DeclRefExpr>(D->getInitOrig())->getDecl(), + cast<DeclRefExpr>(NewDRD->getInitOrig())->getDecl()); + SemaRef.CurrentInstantiationScope->InstantiatedLocal( + cast<DeclRefExpr>(D->getInitPriv())->getDecl(), + cast<DeclRefExpr>(NewDRD->getInitPriv())->getDecl()); + if (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit) { + SubstInitializer = SemaRef.SubstExpr(Init, TemplateArgs).get(); + } else { + auto *OldPrivParm = + cast<VarDecl>(cast<DeclRefExpr>(D->getInitPriv())->getDecl()); + IsCorrect = IsCorrect && OldPrivParm->hasInit(); + if (IsCorrect) + SemaRef.InstantiateVariableInitializer(OmpPrivParm, OldPrivParm, + TemplateArgs); } - IsCorrect = - IsCorrect && SubstCombiner && - (!D->getInitializer() || - (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit && - SubstInitializer) || - (D->getInitializerKind() != OMPDeclareReductionDecl::CallInit && - !SubstInitializer && !SubstInitializer)); - } else { - IsCorrect = false; + SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD, SubstInitializer, + OmpPrivParm); } + IsCorrect = IsCorrect && SubstCombiner && + (!Init || + (D->getInitializerKind() == OMPDeclareReductionDecl::CallInit && + SubstInitializer) || + (D->getInitializerKind() != OMPDeclareReductionDecl::CallInit && + !SubstInitializer)); - (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(/*S=*/nullptr, DRD, - IsCorrect); + (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd( + /*S=*/nullptr, DRD, IsCorrect && !D->isInvalidDecl()); return NewDRD; } @@ -3163,7 +3287,8 @@ TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) { } else { // Instantiate the mapper variable. DeclarationNameInfo DirName; - SemaRef.StartOpenMPDSABlock(OMPD_declare_mapper, DirName, /*S=*/nullptr, + SemaRef.StartOpenMPDSABlock(llvm::omp::OMPD_declare_mapper, DirName, + /*S=*/nullptr, (*D->clauselist_begin())->getBeginLoc()); SemaRef.ActOnOpenMPDeclareMapperDirectiveVarDecl( NewDMD, /*S=*/nullptr, SubstMapperTy, D->getLocation(), VN); @@ -3275,7 +3400,8 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( D->getLocation(), InstTemplateArgs, false, - Converted)) + Converted, + /*UpdateArgsWithConversion=*/true)) return nullptr; // Figure out where to insert this class template explicit specialization @@ -3396,7 +3522,8 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( // Check that the template argument list is well-formed for this template. SmallVector<TemplateArgument, 4> Converted; if (SemaRef.CheckTemplateArgumentList(InstVarTemplate, D->getLocation(), - VarTemplateArgsInfo, false, Converted)) + VarTemplateArgsInfo, false, Converted, + /*UpdateArgsWithConversion=*/true)) return nullptr; // Check whether we've already seen a declaration of this specialization. @@ -3490,6 +3617,73 @@ Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner, return SubstD; } +void TemplateDeclInstantiator::adjustForRewrite(RewriteKind RK, + FunctionDecl *Orig, QualType &T, + TypeSourceInfo *&TInfo, + DeclarationNameInfo &NameInfo) { + assert(RK == RewriteKind::RewriteSpaceshipAsEqualEqual); + + // C++2a [class.compare.default]p3: + // the return type is replaced with bool + auto *FPT = T->castAs<FunctionProtoType>(); + T = SemaRef.Context.getFunctionType( + SemaRef.Context.BoolTy, FPT->getParamTypes(), FPT->getExtProtoInfo()); + + // Update the return type in the source info too. The most straightforward + // way is to create new TypeSourceInfo for the new type. Use the location of + // the '= default' as the location of the new type. + // + // FIXME: Set the correct return type when we initially transform the type, + // rather than delaying it to now. + TypeSourceInfo *NewTInfo = + SemaRef.Context.getTrivialTypeSourceInfo(T, Orig->getEndLoc()); + auto OldLoc = TInfo->getTypeLoc().getAsAdjusted<FunctionProtoTypeLoc>(); + assert(OldLoc && "type of function is not a function type?"); + auto NewLoc = NewTInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>(); + for (unsigned I = 0, N = OldLoc.getNumParams(); I != N; ++I) + NewLoc.setParam(I, OldLoc.getParam(I)); + TInfo = NewTInfo; + + // and the declarator-id is replaced with operator== + NameInfo.setName( + SemaRef.Context.DeclarationNames.getCXXOperatorName(OO_EqualEqual)); +} + +FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD, + FunctionDecl *Spaceship) { + if (Spaceship->isInvalidDecl()) + return nullptr; + + // C++2a [class.compare.default]p3: + // an == operator function is declared implicitly [...] with the same + // access and function-definition and in the same class scope as the + // three-way comparison operator function + MultiLevelTemplateArgumentList NoTemplateArgs; + TemplateDeclInstantiator Instantiator(*this, RD, NoTemplateArgs); + Decl *R; + if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) { + R = Instantiator.VisitCXXMethodDecl( + MD, nullptr, None, + TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual); + } else { + assert(Spaceship->getFriendObjectKind() && + "defaulted spaceship is neither a member nor a friend"); + + R = Instantiator.VisitFunctionDecl( + Spaceship, nullptr, + TemplateDeclInstantiator::RewriteKind::RewriteSpaceshipAsEqualEqual); + if (!R) + return nullptr; + + FriendDecl *FD = + FriendDecl::Create(Context, RD, Spaceship->getLocation(), + cast<NamedDecl>(R), Spaceship->getBeginLoc()); + FD->setAccess(AS_public); + RD->addDecl(FD); + } + return cast_or_null<FunctionDecl>(R); +} + /// Instantiates a nested template parameter list in the current /// instantiation context. /// @@ -3598,7 +3792,8 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // in the member template's set of class template partial specializations. void *InsertPos = nullptr; ClassTemplateSpecializationDecl *PrevDecl - = ClassTemplate->findPartialSpecialization(Converted, InsertPos); + = ClassTemplate->findPartialSpecialization(Converted, InstParams, + InsertPos); // Build the canonical type that describes the converted template // arguments of the class template partial specialization. @@ -3722,7 +3917,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( // in the member template's set of variable template partial specializations. void *InsertPos = nullptr; VarTemplateSpecializationDecl *PrevDecl = - VarTemplate->findPartialSpecialization(Converted, InsertPos); + VarTemplate->findPartialSpecialization(Converted, InstParams, InsertPos); // Build the canonical type that describes the converted template // arguments of the variable template partial specialization. @@ -4009,6 +4204,48 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, TemplateArgs); } +bool Sema::CheckInstantiatedFunctionTemplateConstraints( + SourceLocation PointOfInstantiation, FunctionDecl *Decl, + ArrayRef<TemplateArgument> TemplateArgs, + ConstraintSatisfaction &Satisfaction) { + // In most cases we're not going to have constraints, so check for that first. + FunctionTemplateDecl *Template = Decl->getPrimaryTemplate(); + // Note - code synthesis context for the constraints check is created + // inside CheckConstraintsSatisfaction. + SmallVector<const Expr *, 3> TemplateAC; + Template->getAssociatedConstraints(TemplateAC); + if (TemplateAC.empty()) { + Satisfaction.IsSatisfied = true; + return false; + } + + // Enter the scope of this instantiation. We don't use + // PushDeclContext because we don't have a scope. + Sema::ContextRAII savedContext(*this, Decl); + LocalInstantiationScope Scope(*this); + + MultiLevelTemplateArgumentList MLTAL = + getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); + + // If this is not an explicit specialization - we need to get the instantiated + // version of the template arguments and add them to scope for the + // substitution. + if (Decl->isTemplateInstantiation()) { + InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(), + InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(), + MLTAL.getInnermost(), SourceRange()); + if (Inst.isInvalid()) + return true; + if (addInstantiatedParametersToScope(*this, Decl, + Decl->getTemplateInstantiationPattern(), + Scope, MLTAL)) + return true; + } + + return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs, + PointOfInstantiation, Satisfaction); +} + /// Initializes the common fields of an instantiation function /// declaration (New) from the corresponding fields of its template (Tmpl). /// @@ -4016,9 +4253,6 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, bool TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl) { - if (Tmpl->isDeleted()) - New->setDeletedAsWritten(); - New->setImplicit(Tmpl->isImplicit()); // Forward the mangling number from the template to the instantiated decl. @@ -4119,6 +4353,34 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, return false; } +bool TemplateDeclInstantiator::SubstDefaultedFunction(FunctionDecl *New, + FunctionDecl *Tmpl) { + // Transfer across any unqualified lookups. + if (auto *DFI = Tmpl->getDefaultedFunctionInfo()) { + SmallVector<DeclAccessPair, 32> Lookups; + Lookups.reserve(DFI->getUnqualifiedLookups().size()); + bool AnyChanged = false; + for (DeclAccessPair DA : DFI->getUnqualifiedLookups()) { + NamedDecl *D = SemaRef.FindInstantiatedDecl(New->getLocation(), + DA.getDecl(), TemplateArgs); + if (!D) + return true; + AnyChanged |= (D != DA.getDecl()); + Lookups.push_back(DeclAccessPair::make(D, DA.getAccess())); + } + + // It's unlikely that substitution will change any declarations. Don't + // store an unnecessary copy in that case. + New->setDefaultedFunctionInfo( + AnyChanged ? FunctionDecl::DefaultedFunctionInfo::Create( + SemaRef.Context, Lookups) + : DFI); + } + + SemaRef.SetDeclDefaulted(New, Tmpl->getLocation()); + return false; +} + /// Instantiate (or find existing instantiation of) a function template with a /// given set of template arguments. /// diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index 975d6620c06f..d947d6d282be 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -937,6 +937,10 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { } } + if (Expr *TRC = D.getTrailingRequiresClause()) + if (TRC->containsUnexpandedParameterPack()) + return true; + return false; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index fccdb2bc2e2c..3884fdae8fe7 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1976,6 +1976,19 @@ bool Sema::CheckQualifiedFunctionForTypeId(QualType T, SourceLocation Loc) { return true; } +// Helper to deduce addr space of a pointee type in OpenCL mode. +static QualType deduceOpenCLPointeeAddrSpace(Sema &S, QualType PointeeType) { + if (!PointeeType->isUndeducedAutoType() && !PointeeType->isDependentType() && + !PointeeType->isSamplerT() && + !PointeeType.hasAddressSpace()) + PointeeType = S.getASTContext().getAddrSpaceQualType( + PointeeType, + S.getLangOpts().OpenCLCPlusPlus || S.getLangOpts().OpenCLVersion == 200 + ? LangAS::opencl_generic + : LangAS::opencl_private); + return PointeeType; +} + /// Build a pointer type. /// /// \param T The type to which we'll be building a pointer. @@ -2012,6 +2025,9 @@ QualType Sema::BuildPointerType(QualType T, if (getLangOpts().ObjCAutoRefCount) T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ false); + if (getLangOpts().OpenCL) + T = deduceOpenCLPointeeAddrSpace(*this, T); + // Build the pointer type. return Context.getPointerType(T); } @@ -2072,6 +2088,9 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, if (getLangOpts().ObjCAutoRefCount) T = inferARCLifetimeForPointee(*this, T, Loc, /*reference*/ true); + if (getLangOpts().OpenCL) + T = deduceOpenCLPointeeAddrSpace(*this, T); + // Handle restrict on references. if (LValueRef) return Context.getLValueReferenceType(T, SpelledAsLValue); @@ -2655,6 +2674,9 @@ QualType Sema::BuildBlockPointerType(QualType T, if (checkQualifiedFunction(*this, T, Loc, QFK_BlockPointer)) return QualType(); + if (getLangOpts().OpenCL) + T = deduceOpenCLPointeeAddrSpace(*this, T); + return Context.getBlockPointerType(T); } @@ -2994,7 +3016,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(), /*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(), TemplateParameterDepth, AutoParameterPosition, - /*Identifier*/ nullptr, false, IsParameterPack); + /*Identifier*/ nullptr, false, IsParameterPack, + /*HasTypeConstraint=*/false); CorrespondingTemplateParam->setImplicit(); LSI->TemplateParams.push_back(CorrespondingTemplateParam); // Replace the 'auto' in the function parameter with this invented @@ -3139,7 +3162,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, T = SemaRef.Context.IntTy; D.setInvalidType(true); - } else if (!HaveTrailing && + } else if (Auto && !HaveTrailing && D.getContext() != DeclaratorContext::LambdaExprContext) { // If there was a trailing return type, we already got // warn_cxx98_compat_trailing_return_type in the parser. @@ -4788,6 +4811,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, FunctionProtoType::ExtProtoInfo EPI; EPI.ExtInfo = EI; EPI.Variadic = FTI.isVariadic; + EPI.EllipsisLoc = FTI.getEllipsisLoc(); EPI.HasTrailingReturn = FTI.hasTrailingReturnType(); EPI.TypeQuals.addCVRUQualifiers( FTI.MethodQualifiers ? FTI.MethodQualifiers->getTypeQualifiers() @@ -4927,7 +4951,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, .getScopeRep() ->getKind() == NestedNameSpecifier::TypeSpec) || state.getDeclarator().getContext() == - DeclaratorContext::MemberContext; + DeclaratorContext::MemberContext || + state.getDeclarator().getContext() == + DeclaratorContext::LambdaExprContext; }; if (state.getSema().getLangOpts().OpenCLCPlusPlus && IsClassMember()) { @@ -4946,7 +4972,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // If a class member function's address space is not set, set it to // __generic. LangAS AS = - (ASIdx == LangAS::Default ? LangAS::opencl_generic : ASIdx); + (ASIdx == LangAS::Default ? S.getDefaultCXXMethodAddrSpace() + : ASIdx); EPI.TypeQuals.addAddressSpace(AS); } T = Context.getFunctionType(T, ParamTys, EPI); @@ -6325,7 +6352,8 @@ namespace { Pointer, BlockPointer, Reference, - MemberPointer + MemberPointer, + MacroQualified, }; QualType Original; @@ -6356,6 +6384,9 @@ namespace { } else if (isa<AttributedType>(Ty)) { T = cast<AttributedType>(Ty)->getEquivalentType(); Stack.push_back(Attributed); + } else if (isa<MacroQualifiedType>(Ty)) { + T = cast<MacroQualifiedType>(Ty)->getUnderlyingType(); + Stack.push_back(MacroQualified); } else { const Type *DTy = Ty->getUnqualifiedDesugaredType(); if (Ty == DTy) { @@ -6412,6 +6443,9 @@ namespace { return C.getParenType(New); } + case MacroQualified: + return wrap(C, cast<MacroQualifiedType>(Old)->getUnderlyingType(), I); + case Pointer: { QualType New = wrap(C, cast<PointerType>(Old)->getPointeeType(), I); return C.getPointerType(New); @@ -6464,35 +6498,36 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, break; } + llvm::SmallSet<attr::Kind, 2> Attrs; attr::Kind NewAttrKind = A->getKind(); QualType Desugared = Type; const AttributedType *AT = dyn_cast<AttributedType>(Type); while (AT) { - attr::Kind CurAttrKind = AT->getAttrKind(); - - // You cannot specify duplicate type attributes, so if the attribute has - // already been applied, flag it. - if (NewAttrKind == CurAttrKind) { - S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr; - return true; - } + Attrs.insert(AT->getAttrKind()); + Desugared = AT->getModifiedType(); + AT = dyn_cast<AttributedType>(Desugared); + } - // You cannot have both __sptr and __uptr on the same type, nor can you - // have __ptr32 and __ptr64. - if ((CurAttrKind == attr::Ptr32 && NewAttrKind == attr::Ptr64) || - (CurAttrKind == attr::Ptr64 && NewAttrKind == attr::Ptr32)) { - S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) - << "'__ptr32'" << "'__ptr64'"; - return true; - } else if ((CurAttrKind == attr::SPtr && NewAttrKind == attr::UPtr) || - (CurAttrKind == attr::UPtr && NewAttrKind == attr::SPtr)) { - S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) - << "'__sptr'" << "'__uptr'"; - return true; - } + // You cannot specify duplicate type attributes, so if the attribute has + // already been applied, flag it. + if (Attrs.count(NewAttrKind)) { + S.Diag(PAttr.getLoc(), diag::warn_duplicate_attribute_exact) << PAttr; + return true; + } + Attrs.insert(NewAttrKind); - Desugared = AT->getEquivalentType(); - AT = dyn_cast<AttributedType>(Desugared); + // You cannot have both __sptr and __uptr on the same type, nor can you + // have __ptr32 and __ptr64. + if (Attrs.count(attr::Ptr32) && Attrs.count(attr::Ptr64)) { + S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) + << "'__ptr32'" + << "'__ptr64'"; + return true; + } else if (Attrs.count(attr::SPtr) && Attrs.count(attr::UPtr)) { + S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) + << "'__sptr'" + << "'__uptr'"; + return true; } // Pointer type qualifiers can only operate on pointer types, but not @@ -6510,7 +6545,26 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, return true; } - Type = State.getAttributedType(A, Type, Type); + // Add address space to type based on its attributes. + LangAS ASIdx = LangAS::Default; + uint64_t PtrWidth = S.Context.getTargetInfo().getPointerWidth(0); + if (PtrWidth == 32) { + if (Attrs.count(attr::Ptr64)) + ASIdx = LangAS::ptr64; + else if (Attrs.count(attr::UPtr)) + ASIdx = LangAS::ptr32_uptr; + } else if (PtrWidth == 64 && Attrs.count(attr::Ptr32)) { + if (Attrs.count(attr::UPtr)) + ASIdx = LangAS::ptr32_uptr; + else + ASIdx = LangAS::ptr32_sptr; + } + + QualType Pointee = Type->getPointeeType(); + if (ASIdx != LangAS::Default) + Pointee = S.Context.getAddrSpaceQualType( + S.Context.removeAddrSpaceQualType(Pointee), ASIdx); + Type = State.getAttributedType(A, Type, S.Context.getPointerType(Pointee)); return false; } @@ -7215,6 +7269,7 @@ static bool isPermittedNeonBaseType(QualType &Ty, // Signed poly is mathematically wrong, but has been baked into some ABIs by // now. bool IsPolyUnsigned = Triple.getArch() == llvm::Triple::aarch64 || + Triple.getArch() == llvm::Triple::aarch64_32 || Triple.getArch() == llvm::Triple::aarch64_be; if (VecKind == VectorType::NeonPolyVector) { if (IsPolyUnsigned) { @@ -7232,10 +7287,8 @@ static bool isPermittedNeonBaseType(QualType &Ty, // Non-polynomial vector types: the usual suspects are allowed, as well as // float64_t on AArch64. - bool Is64Bit = Triple.getArch() == llvm::Triple::aarch64 || - Triple.getArch() == llvm::Triple::aarch64_be; - - if (Is64Bit && BTy->getKind() == BuiltinType::Double) + if ((Triple.isArch64Bit() || Triple.getArch() == llvm::Triple::aarch64_32) && + BTy->getKind() == BuiltinType::Double) return true; return BTy->getKind() == BuiltinType::SChar || @@ -7261,8 +7314,10 @@ static bool isPermittedNeonBaseType(QualType &Ty, /// match one of the standard Neon vector types. static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, Sema &S, VectorType::VectorKind VecKind) { - // Target must have NEON - if (!S.Context.getTargetInfo().hasFeature("neon")) { + // Target must have NEON (or MVE, whose vectors are similar enough + // not to need a separate attribute) + if (!S.Context.getTargetInfo().hasFeature("neon") && + !S.Context.getTargetInfo().hasFeature("mve")) { S.Diag(Attr.getLoc(), diag::err_attribute_unsupported) << Attr; Attr.setInvalid(); return; @@ -7361,137 +7416,6 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr, } } -static void deduceOpenCLImplicitAddrSpace(TypeProcessingState &State, - QualType &T, TypeAttrLocation TAL) { - Declarator &D = State.getDeclarator(); - - // Handle the cases where address space should not be deduced. - // - // The pointee type of a pointer type is always deduced since a pointer always - // points to some memory location which should has an address space. - // - // There are situations that at the point of certain declarations, the address - // space may be unknown and better to be left as default. For example, when - // defining a typedef or struct type, they are not associated with any - // specific address space. Later on, they may be used with any address space - // to declare a variable. - // - // The return value of a function is r-value, therefore should not have - // address space. - // - // The void type does not occupy memory, therefore should not have address - // space, except when it is used as a pointee type. - // - // Since LLVM assumes function type is in default address space, it should not - // have address space. - auto ChunkIndex = State.getCurrentChunkIndex(); - bool IsPointee = - ChunkIndex > 0 && - (D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Pointer || - D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Reference || - D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::BlockPointer); - // For pointers/references to arrays the next chunk is always an array - // followed by any number of parentheses. - if (!IsPointee && ChunkIndex > 1) { - auto AdjustedCI = ChunkIndex - 1; - if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Array) - AdjustedCI--; - // Skip over all parentheses. - while (AdjustedCI > 0 && - D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Paren) - AdjustedCI--; - if (D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Pointer || - D.getTypeObject(AdjustedCI).Kind == DeclaratorChunk::Reference) - IsPointee = true; - } - bool IsFuncReturnType = - ChunkIndex > 0 && - D.getTypeObject(ChunkIndex - 1).Kind == DeclaratorChunk::Function; - bool IsFuncType = - ChunkIndex < D.getNumTypeObjects() && - D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function; - if ( // Do not deduce addr space for function return type and function type, - // otherwise it will fail some sema check. - IsFuncReturnType || IsFuncType || - // Do not deduce addr space for member types of struct, except the pointee - // type of a pointer member type or static data members. - (D.getContext() == DeclaratorContext::MemberContext && - (!IsPointee && - D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_static)) || - // Do not deduce addr space of non-pointee in type alias because it - // doesn't define any object. - (D.getContext() == DeclaratorContext::AliasDeclContext && !IsPointee) || - // Do not deduce addr space for types used to define a typedef and the - // typedef itself, except the pointee type of a pointer type which is used - // to define the typedef. - (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef && - !IsPointee) || - // Do not deduce addr space of the void type, e.g. in f(void), otherwise - // it will fail some sema check. - (T->isVoidType() && !IsPointee) || - // Do not deduce addr spaces for dependent types because they might end - // up instantiating to a type with an explicit address space qualifier. - // Except for pointer or reference types because the addr space in - // template argument can only belong to a pointee. - (T->isDependentType() && !T->isPointerType() && !T->isReferenceType()) || - // Do not deduce addr space of decltype because it will be taken from - // its argument. - T->isDecltypeType() || - // OpenCL spec v2.0 s6.9.b: - // The sampler type cannot be used with the __local and __global address - // space qualifiers. - // OpenCL spec v2.0 s6.13.14: - // Samplers can also be declared as global constants in the program - // source using the following syntax. - // const sampler_t <sampler name> = <value> - // In codegen, file-scope sampler type variable has special handing and - // does not rely on address space qualifier. On the other hand, deducing - // address space of const sampler file-scope variable as global address - // space causes spurious diagnostic about __global address space - // qualifier, therefore do not deduce address space of file-scope sampler - // type variable. - (D.getContext() == DeclaratorContext::FileContext && T->isSamplerT())) - return; - - LangAS ImpAddr = LangAS::Default; - // Put OpenCL automatic variable in private address space. - // OpenCL v1.2 s6.5: - // The default address space name for arguments to a function in a - // program, or local variables of a function is __private. All function - // arguments shall be in the __private address space. - if (State.getSema().getLangOpts().OpenCLVersion <= 120 && - !State.getSema().getLangOpts().OpenCLCPlusPlus) { - ImpAddr = LangAS::opencl_private; - } else { - // If address space is not set, OpenCL 2.0 defines non private default - // address spaces for some cases: - // OpenCL 2.0, section 6.5: - // The address space for a variable at program scope or a static variable - // inside a function can either be __global or __constant, but defaults to - // __global if not specified. - // (...) - // Pointers that are declared without pointing to a named address space - // point to the generic address space. - if (IsPointee) { - ImpAddr = LangAS::opencl_generic; - } else { - if (D.getContext() == DeclaratorContext::TemplateArgContext) { - // Do not deduce address space for non-pointee type in template arg. - } else if (D.getContext() == DeclaratorContext::FileContext) { - ImpAddr = LangAS::opencl_global; - } else { - if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static || - D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_extern) { - ImpAddr = LangAS::opencl_global; - } else { - ImpAddr = LangAS::opencl_private; - } - } - } - } - T = State.getSema().Context.getAddrSpaceQualType(T, ImpAddr); -} - static void HandleLifetimeBoundAttr(TypeProcessingState &State, QualType &CurType, ParsedAttr &Attr) { @@ -7504,6 +7428,16 @@ static void HandleLifetimeBoundAttr(TypeProcessingState &State, } } +static bool isAddressSpaceKind(const ParsedAttr &attr) { + auto attrKind = attr.getKind(); + + return attrKind == ParsedAttr::AT_AddressSpace || + attrKind == ParsedAttr::AT_OpenCLPrivateAddressSpace || + attrKind == ParsedAttr::AT_OpenCLGlobalAddressSpace || + attrKind == ParsedAttr::AT_OpenCLLocalAddressSpace || + attrKind == ParsedAttr::AT_OpenCLConstantAddressSpace || + attrKind == ParsedAttr::AT_OpenCLGenericAddressSpace; +} static void processTypeAttrs(TypeProcessingState &state, QualType &type, TypeAttrLocation TAL, @@ -7542,11 +7476,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, if (!IsTypeAttr) continue; } - } else if (TAL != TAL_DeclChunk && - attr.getKind() != ParsedAttr::AT_AddressSpace) { + } else if (TAL != TAL_DeclChunk && !isAddressSpaceKind(attr)) { // Otherwise, only consider type processing for a C++11 attribute if // it's actually been applied to a type. - // We also allow C++11 address_space attributes to pass through. + // We also allow C++11 address_space and + // OpenCL language address space attributes to pass through. continue; } } @@ -7701,6 +7635,18 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, else if (!handleFunctionTypeAttr(state, attr, type)) distributeFunctionTypeAttr(state, attr, type); break; + case ParsedAttr::AT_AcquireHandle: { + if (!type->isFunctionType()) + return; + StringRef HandleType; + if (!state.getSema().checkStringLiteralArgumentAttr(attr, 0, HandleType)) + return; + type = state.getAttributedType( + AcquireHandleAttr::Create(state.getSema().Context, HandleType, attr), + type, type); + attr.setUsedAsTypeAttr(); + break; + } } // Handle attributes that are defined in a macro. We do not want this to be @@ -7721,8 +7667,6 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, if (!state.getSema().getLangOpts().OpenCL || type.getAddressSpace() != LangAS::Default) return; - - deduceOpenCLImplicitAddrSpace(state, type, TAL); } void Sema::completeExprArrayBound(Expr *E) { @@ -7944,33 +7888,31 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { RD = RD->getMostRecentNonInjectedDecl(); if (!RD->hasAttr<MSInheritanceAttr>()) { - MSInheritanceAttr::Spelling IM; - + MSInheritanceModel IM; + bool BestCase = false; switch (S.MSPointerToMemberRepresentationMethod) { case LangOptions::PPTMK_BestCase: + BestCase = true; IM = RD->calculateInheritanceModel(); break; case LangOptions::PPTMK_FullGeneralitySingleInheritance: - IM = MSInheritanceAttr::Keyword_single_inheritance; + IM = MSInheritanceModel::Single; break; case LangOptions::PPTMK_FullGeneralityMultipleInheritance: - IM = MSInheritanceAttr::Keyword_multiple_inheritance; + IM = MSInheritanceModel::Multiple; break; case LangOptions::PPTMK_FullGeneralityVirtualInheritance: - IM = MSInheritanceAttr::Keyword_unspecified_inheritance; + IM = MSInheritanceModel::Unspecified; break; } - SourceRange Loc = - S.ImplicitMSInheritanceAttrLoc.isValid() - ? S.ImplicitMSInheritanceAttrLoc - : RD->getSourceRange(); - RD->addAttr(MSInheritanceAttr::CreateImplicit( - S.getASTContext(), - /*BestCase=*/S.MSPointerToMemberRepresentationMethod == - LangOptions::PPTMK_BestCase, - Loc, AttributeCommonInfo::AS_Microsoft, IM)); - S.Consumer.AssignInheritanceModel(RD); + SourceRange Loc = S.ImplicitMSInheritanceAttrLoc.isValid() + ? S.ImplicitMSInheritanceAttrLoc + : RD->getSourceRange(); + RD->addAttr(MSInheritanceAttr::CreateImplicit( + S.getASTContext(), BestCase, Loc, AttributeCommonInfo::AS_Microsoft, + MSInheritanceAttr::Spelling(IM))); + S.Consumer.AssignInheritanceModel(RD); } } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 4b3a6708717c..3b827fbc950b 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -22,6 +22,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" @@ -37,6 +38,8 @@ #include "llvm/Support/ErrorHandling.h" #include <algorithm> +using namespace llvm::omp; + namespace clang { using namespace sema; @@ -1613,7 +1616,7 @@ public: /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. - OMPClause *RebuildOMPProcBindClause(OpenMPProcBindClauseKind Kind, + OMPClause *RebuildOMPProcBindClause(ProcBindKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -1675,11 +1678,14 @@ public: /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause *RebuildOMPLastprivateClause(ArrayRef<Expr *> VarList, + OpenMPLastprivateModifier LPKind, + SourceLocation LPKindLoc, + SourceLocation ColonLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { - return getSema().ActOnOpenMPLastprivateClause(VarList, StartLoc, LParenLoc, - EndLoc); + return getSema().ActOnOpenMPLastprivateClause( + VarList, LPKind, LPKindLoc, ColonLoc, StartLoc, LParenLoc, EndLoc); } /// Build a new OpenMP 'shared' clause. @@ -1984,6 +1990,33 @@ public: return getSema().ActOnOpenMPIsDevicePtrClause(VarList, Locs); } + /// Build a new OpenMP 'defaultmap' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPDefaultmapClause(OpenMPDefaultmapClauseModifier M, + OpenMPDefaultmapClauseKind Kind, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation MLoc, + SourceLocation KindLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPDefaultmapClause(M, Kind, StartLoc, LParenLoc, + MLoc, KindLoc, EndLoc); + } + + /// Build a new OpenMP 'nontemporal' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPNontemporalClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + /// Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -3031,13 +3064,13 @@ public: /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildConceptSpecializationExpr(NestedNameSpecifierLoc NNS, - SourceLocation TemplateKWLoc, SourceLocation ConceptNameLoc, + SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, ConceptDecl *NamedConcept, TemplateArgumentListInfo *TALI) { CXXScopeSpec SS; SS.Adopt(NNS); ExprResult Result = getSema().CheckConceptTemplateId(SS, TemplateKWLoc, - ConceptNameLoc, + ConceptNameInfo, FoundDecl, NamedConcept, TALI); if (Result.isInvalid()) @@ -3455,7 +3488,7 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init, Init = AIL->getCommonExpr(); if (MaterializeTemporaryExpr *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) - Init = MTE->GetTemporaryExpr(); + Init = MTE->getSubExpr(); while (CXXBindTemporaryExpr *Binder = dyn_cast<CXXBindTemporaryExpr>(Init)) Init = Binder->getSubExpr(); @@ -4564,14 +4597,6 @@ QualType TreeTransform<Derived>::TransformDecayedType(TypeLocBuilder &TLB, return Result; } -/// Helper to deduce addr space of a pointee type in OpenCL mode. -/// If the type is updated it will be overwritten in PointeeType param. -static void deduceOpenCLPointeeAddrSpace(Sema &SemaRef, QualType &PointeeType) { - if (PointeeType.getAddressSpace() == LangAS::Default) - PointeeType = SemaRef.Context.getAddrSpaceQualType(PointeeType, - LangAS::opencl_generic); -} - template<typename Derived> QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, PointerTypeLoc TL) { @@ -4580,9 +4605,6 @@ QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB, if (PointeeType.isNull()) return QualType(); - if (SemaRef.getLangOpts().OpenCL) - deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType); - QualType Result = TL.getType(); if (PointeeType->getAs<ObjCObjectType>()) { // A dependent pointer type 'T *' has is being transformed such @@ -4621,9 +4643,6 @@ TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB, if (PointeeType.isNull()) return QualType(); - if (SemaRef.getLangOpts().OpenCL) - deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType); - QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || PointeeType != TL.getPointeeLoc().getType()) { @@ -4653,9 +4672,6 @@ TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB, if (PointeeType.isNull()) return QualType(); - if (SemaRef.getLangOpts().OpenCL) - deduceOpenCLPointeeAddrSpace(SemaRef, PointeeType); - QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || PointeeType != T->getPointeeTypeAsWritten()) { @@ -7190,8 +7206,12 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { // that may fail. ScopeInfo->setNeedsCoroutineSuspends(false); - // The new CoroutinePromise object needs to be built and put into the current - // FunctionScopeInfo before any transformations or rebuilding occurs. + // We re-build the coroutine promise object (and the coroutine parameters its + // type and constructor depend on) based on the types used in our current + // function. We must do so, and set it on the current FunctionScopeInfo, + // before attempting to transform the other parts of the coroutine body + // statement, such as the implicit suspend statements (because those + // statements reference the FunctionScopeInfo::CoroutinePromise). if (!SemaRef.buildCoroutineParameterMoves(FD->getLocation())) return StmtError(); auto *Promise = SemaRef.buildCoroutinePromise(FD->getLocation()); @@ -7200,8 +7220,9 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { getDerived().transformedLocalDecl(S->getPromiseDecl(), {Promise}); ScopeInfo->CoroutinePromise = Promise; - // Transform the implicit coroutine statements we built during the initial - // parse. + // Transform the implicit coroutine statements constructed using dependent + // types during the previous parse: initial and final suspensions, the return + // object, and others. We also transform the coroutine function's body. StmtResult InitSuspend = getDerived().TransformStmt(S->getInitSuspendStmt()); if (InitSuspend.isInvalid()) return StmtError(); @@ -7228,17 +7249,13 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { return StmtError(); Builder.ReturnValue = Res.get(); + // If during the previous parse the coroutine still had a dependent promise + // statement, we may need to build some implicit coroutine statements + // (such as exception and fallthrough handlers) for the first time. if (S->hasDependentPromiseType()) { - // PR41909: We may find a generic coroutine lambda definition within a - // template function that is being instantiated. In this case, the lambda - // will have a dependent promise type, until it is used in an expression - // that creates an instantiation with a non-dependent promise type. We - // should not assert or build coroutine dependent statements for such a - // generic lambda. - auto *MD = dyn_cast_or_null<CXXMethodDecl>(FD); - if (!MD || !MD->getParent()->isGenericLambda()) { - assert(!Promise->getType()->isDependentType() && - "the promise type must no longer be dependent"); + // We can only build these statements, however, if the current promise type + // is not dependent. + if (!Promise->getType()->isDependentType()) { assert(!S->getFallthroughHandler() && !S->getExceptionHandler() && !S->getReturnStmtOnAllocFailure() && !S->getDeallocate() && "these nodes should not have been built yet"); @@ -8046,6 +8063,17 @@ StmtResult TreeTransform<Derived>::TransformOMPParallelForSimdDirective( } template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPParallelMasterDirective( + OMPParallelMasterDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel_master, DirName, + nullptr, D->getBeginLoc()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> StmtResult TreeTransform<Derived>::TransformOMPParallelSectionsDirective( OMPParallelSectionsDirective *D) { DeclarationNameInfo DirName; @@ -8310,6 +8338,18 @@ StmtResult TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopDirective( } template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPParallelMasterTaskLoopSimdDirective( + OMPParallelMasterTaskLoopSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock( + OMPD_parallel_master_taskloop_simd, DirName, nullptr, D->getBeginLoc()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> StmtResult TreeTransform<Derived>::TransformOMPDistributeDirective( OMPDistributeDirective *D) { DeclarationNameInfo DirName; @@ -8745,7 +8785,8 @@ TreeTransform<Derived>::TransformOMPLastprivateClause(OMPLastprivateClause *C) { Vars.push_back(EVar.get()); } return getDerived().RebuildOMPLastprivateClause( - Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + Vars, C->getKind(), C->getKindLoc(), C->getColonLoc(), C->getBeginLoc(), + C->getLParenLoc(), C->getEndLoc()); } template <typename Derived> @@ -9173,7 +9214,15 @@ OMPClause *TreeTransform<Derived>::TransformOMPDistScheduleClause( template <typename Derived> OMPClause * TreeTransform<Derived>::TransformOMPDefaultmapClause(OMPDefaultmapClause *C) { - return C; + // Rebuild Defaultmap Clause since we need to invoke the checking of + // defaultmap(none:variable-category) after template initialization. + return getDerived().RebuildOMPDefaultmapClause(C->getDefaultmapModifier(), + C->getDefaultmapKind(), + C->getBeginLoc(), + C->getLParenLoc(), + C->getDefaultmapModifierLoc(), + C->getDefaultmapKindLoc(), + C->getEndLoc()); } template <typename Derived> @@ -9234,6 +9283,21 @@ TreeTransform<Derived>::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { return getDerived().RebuildOMPIsDevicePtrClause(Vars, Locs); } +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPNontemporalClause(OMPNontemporalClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPNontemporalClause( + Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// @@ -9368,7 +9432,7 @@ TreeTransform<Derived>::TransformGenericSelectionExpr(GenericSelectionExpr *E) { SmallVector<Expr *, 4> AssocExprs; SmallVector<TypeSourceInfo *, 4> AssocTypes; - for (const GenericSelectionExpr::Association &Assoc : E->associations()) { + for (const GenericSelectionExpr::Association Assoc : E->associations()) { TypeSourceInfo *TSI = Assoc.getTypeSourceInfo(); if (TSI) { TypeSourceInfo *AssocType = getDerived().TransformType(TSI); @@ -11111,7 +11175,7 @@ TreeTransform<Derived>::TransformConceptSpecializationExpr( return getDerived().RebuildConceptSpecializationExpr( E->getNestedNameSpecifierLoc(), E->getTemplateKWLoc(), - E->getConceptNameLoc(), E->getFoundDecl(), E->getNamedConcept(), + E->getConceptNameInfo(), E->getFoundDecl(), E->getNamedConcept(), &TransArgs); } @@ -11488,6 +11552,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { NewCallOpType); } + // Transform the trailing requires clause + ExprResult NewTrailingRequiresClause; + if (Expr *TRC = E->getCallOperator()->getTrailingRequiresClause()) + // FIXME: Concepts: Substitution into requires clause should only happen + // when checking satisfaction. + NewTrailingRequiresClause = getDerived().TransformExpr(TRC); + // Create the local class that will describe the lambda. CXXRecordDecl *OldClass = E->getLambdaClass(); CXXRecordDecl *Class @@ -11508,7 +11579,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { Class, E->getIntroducerRange(), NewCallOpTSI, E->getCallOperator()->getEndLoc(), NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(), - E->getCallOperator()->getConstexprKind()); + E->getCallOperator()->getConstexprKind(), + NewTrailingRequiresClause.get()); LSI->CallOperator = NewCallOperator; @@ -12145,7 +12217,7 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformMaterializeTemporaryExpr( MaterializeTemporaryExpr *E) { - return getDerived().TransformExpr(E->GetTemporaryExpr()); + return getDerived().TransformExpr(E->getSubExpr()); } template<typename Derived> diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index dd06e0582ac5..cdb5b17022c2 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -401,6 +401,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::Decomposition: case Decl::Binding: case Decl::Concept: + case Decl::LifetimeExtendedTemporary: return false; // These indirectly derive from Redeclarable<T> but are not actually diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 2d3884ebe021..19e7ebe03a1f 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -10,9 +10,11 @@ // //===----------------------------------------------------------------------===// -#include "clang/Serialization/ASTReader.h" +#include "clang/Basic/OpenMPKinds.h" +#include "clang/Serialization/ASTRecordReader.h" #include "ASTCommon.h" #include "ASTReaderInternals.h" +#include "clang/AST/AbstractTypeReader.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" @@ -29,6 +31,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExternalASTSource.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/ODRHash.h" #include "clang/AST/RawCommentList.h" #include "clang/AST/TemplateBase.h" @@ -76,7 +79,7 @@ #include "clang/Serialization/ContinuousRangeMap.h" #include "clang/Serialization/GlobalModuleIndex.h" #include "clang/Serialization/InMemoryModuleCache.h" -#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFile.h" #include "clang/Serialization/ModuleFileExtension.h" #include "clang/Serialization/ModuleManager.h" #include "clang/Serialization/PCHContainerOperations.h" @@ -1239,12 +1242,12 @@ void ASTReader::Error(StringRef Msg) const { } } -void ASTReader::Error(unsigned DiagID, - StringRef Arg1, StringRef Arg2) const { +void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2, + StringRef Arg3) const { if (Diags.isDiagnosticInFlight()) - Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2); + Diags.SetDelayedDiagnostic(DiagID, Arg1, Arg2, Arg3); else - Diag(DiagID) << Arg1 << Arg2; + Diag(DiagID) << Arg1 << Arg2 << Arg3; } void ASTReader::Error(unsigned DiagID, StringRef Arg1, StringRef Arg2, @@ -2561,7 +2564,6 @@ ASTReader::ReadControlBlock(ModuleFile &F, const ModuleFile *ImportedBy, unsigned ClientLoadCapabilities) { BitstreamCursor &Stream = F.Stream; - ASTReadResult Result = Success; if (llvm::Error Err = Stream.EnterSubBlock(CONTROL_BLOCK_ID)) { Error(std::move(Err)); @@ -2652,7 +2654,7 @@ ASTReader::ReadControlBlock(ModuleFile &F, } } - return Result; + return Success; } case llvm::BitstreamEntry::SubBlock: @@ -2682,9 +2684,10 @@ ASTReader::ReadControlBlock(ModuleFile &F, bool AllowCompatibleConfigurationMismatch = F.Kind == MK_ExplicitModule || F.Kind == MK_PrebuiltModule; - Result = ReadOptionsBlock(Stream, ClientLoadCapabilities, - AllowCompatibleConfigurationMismatch, - *Listener, SuggestedPredefines); + ASTReadResult Result = + ReadOptionsBlock(Stream, ClientLoadCapabilities, + AllowCompatibleConfigurationMismatch, *Listener, + SuggestedPredefines); if (Result == Failure) { Error("malformed block record in AST file"); return Result; @@ -3221,7 +3224,8 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { case MODULAR_CODEGEN_DECLS: // FIXME: Skip reading this record if our ASTConsumer doesn't care about // them (ie: if we're not codegenerating this module). - if (F.Kind == MK_MainFile) + if (F.Kind == MK_MainFile || + getContext().getLangOpts().BuildingPCHWithObjectFile) for (unsigned I = 0, N = Record.size(); I != N; ++I) EagerlyDeserializedDecls.push_back(getGlobalDeclID(F, Record[I])); break; @@ -3408,8 +3412,10 @@ ASTReader::ReadASTBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { break; case SOURCE_MANAGER_LINE_TABLE: - if (ParseLineTable(F, Record)) + if (ParseLineTable(F, Record)) { + Error("malformed SOURCE_MANAGER_LINE_TABLE in AST file"); return Failure; + } break; case SOURCE_LOCATION_PRELOADS: { @@ -4174,6 +4180,20 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, PreviousGeneration = incrementGeneration(*ContextObj); unsigned NumModules = ModuleMgr.size(); + auto removeModulesAndReturn = [&](ASTReadResult ReadResult) { + assert(ReadResult && "expected to return error"); + ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, + PP.getLangOpts().Modules + ? &PP.getHeaderSearchInfo().getModuleMap() + : nullptr); + + // If we find that any modules are unusable, the global index is going + // to be out-of-date. Just remove it. + GlobalIndex.reset(); + ModuleMgr.setGlobalIndex(nullptr); + return ReadResult; + }; + SmallVector<ImportedModule, 4> Loaded; switch (ASTReadResult ReadResult = ReadASTCore(FileName, Type, ImportLoc, @@ -4184,42 +4204,33 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, case OutOfDate: case VersionMismatch: case ConfigurationMismatch: - case HadErrors: { - llvm::SmallPtrSet<ModuleFile *, 4> LoadedSet; - for (const ImportedModule &IM : Loaded) - LoadedSet.insert(IM.Mod); - - ModuleMgr.removeModules(ModuleMgr.begin() + NumModules, LoadedSet, - PP.getLangOpts().Modules - ? &PP.getHeaderSearchInfo().getModuleMap() - : nullptr); - - // If we find that any modules are unusable, the global index is going - // to be out-of-date. Just remove it. - GlobalIndex.reset(); - ModuleMgr.setGlobalIndex(nullptr); - return ReadResult; - } + case HadErrors: + return removeModulesAndReturn(ReadResult); case Success: break; } // Here comes stuff that we only do once the entire chain is loaded. - // Load the AST blocks of all of the modules that we loaded. - for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(), - MEnd = Loaded.end(); - M != MEnd; ++M) { - ModuleFile &F = *M->Mod; + // Load the AST blocks of all of the modules that we loaded. We can still + // hit errors parsing the ASTs at this point. + for (ImportedModule &M : Loaded) { + ModuleFile &F = *M.Mod; // Read the AST block. if (ASTReadResult Result = ReadASTBlock(F, ClientLoadCapabilities)) - return Result; + return removeModulesAndReturn(Result); + + // The AST block should always have a definition for the main module. + if (F.isModule() && !F.DidReadTopLevelSubmodule) { + Error(diag::err_module_file_missing_top_level_submodule, F.FileName); + return removeModulesAndReturn(Failure); + } // Read the extension blocks. while (!SkipCursorToBlock(F.Stream, EXTENSION_BLOCK_ID)) { if (ASTReadResult Result = ReadExtensionBlock(F)) - return Result; + return removeModulesAndReturn(Result); } // Once read, set the ModuleFile bit base offset and update the size in @@ -4227,6 +4238,11 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, F.GlobalBitOffset = TotalModulesSizeInBits; TotalModulesSizeInBits += F.SizeInBits; GlobalBitOffsetsMap.insert(std::make_pair(F.GlobalBitOffset, &F)); + } + + // Preload source locations and interesting indentifiers. + for (ImportedModule &M : Loaded) { + ModuleFile &F = *M.Mod; // Preload SLocEntries. for (unsigned I = 0, N = F.PreloadSLocEntries.size(); I != N; ++I) { @@ -4269,10 +4285,8 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, // Setup the import locations and notify the module manager that we've // committed to these module files. - for (SmallVectorImpl<ImportedModule>::iterator M = Loaded.begin(), - MEnd = Loaded.end(); - M != MEnd; ++M) { - ModuleFile &F = *M->Mod; + for (ImportedModule &M : Loaded) { + ModuleFile &F = *M.Mod; ModuleMgr.moduleFileAccepted(&F); @@ -4280,10 +4294,10 @@ ASTReader::ASTReadResult ASTReader::ReadAST(StringRef FileName, F.DirectImportLoc = ImportLoc; // FIXME: We assume that locations from PCH / preamble do not need // any translation. - if (!M->ImportedBy) - F.ImportLoc = M->ImportLoc; + if (!M.ImportedBy) + F.ImportLoc = M.ImportLoc; else - F.ImportLoc = TranslateSourceLocation(*M->ImportedBy, M->ImportLoc); + F.ImportLoc = TranslateSourceLocation(*M.ImportedBy, M.ImportLoc); } if (!PP.getLangOpts().CPlusPlus || @@ -4773,8 +4787,10 @@ ASTReader::ASTReadResult ASTReader::ReadExtensionBlock(ModuleFile &F) { switch (MaybeRecCode.get()) { case EXTENSION_METADATA: { ModuleFileExtensionMetadata Metadata; - if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) + if (parseModuleFileExtensionMetadata(Record, Blob, Metadata)) { + Error("malformed EXTENSION_METADATA in AST file"); return Failure; + } // Find a module file extension with this block name. auto Known = ModuleFileExtensions.find(Metadata.BlockName); @@ -5476,16 +5492,14 @@ ASTReader::ReadSubmoduleBlock(ModuleFile &F, unsigned ClientLoadCapabilities) { // Don't emit module relocation error if we have -fno-validate-pch if (!PP.getPreprocessorOpts().DisablePCHValidation && CurFile != F.File) { - if (!Diags.isDiagnosticInFlight()) { - Diag(diag::err_module_file_conflict) - << CurrentModule->getTopLevelModuleName() - << CurFile->getName() - << F.File->getName(); - } + Error(diag::err_module_file_conflict, + CurrentModule->getTopLevelModuleName(), CurFile->getName(), + F.File->getName()); return Failure; } } + F.DidReadTopLevelSubmodule = true; CurrentModule->setASTFile(F.File); CurrentModule->PresumedModuleMapFile = F.ModuleMapPath; } @@ -6306,6 +6320,15 @@ ASTReader::RecordLocation ASTReader::TypeCursorForIndex(unsigned Index) { return RecordLocation(M, M->TypeOffsets[Index - M->BaseTypeIndex]); } +static llvm::Optional<Type::TypeClass> getTypeClassForCode(TypeCode code) { + switch (code) { +#define TYPE_BIT_CODE(CLASS_ID, CODE_ID, CODE_VALUE) \ + case TYPE_##CODE_ID: return Type::CLASS_ID; +#include "clang/Serialization/TypeBitCodes.def" + default: return llvm::None; + } +} + /// Read and return the type with the given index.. /// /// The index is the type ID, shifted and minus the number of predefs. This @@ -6327,616 +6350,61 @@ QualType ASTReader::readTypeRecord(unsigned Index) { // Note that we are loading a type record. Deserializing AType(this); - unsigned Idx = 0; if (llvm::Error Err = DeclsCursor.JumpToBit(Loc.Offset)) { Error(std::move(Err)); return QualType(); } - RecordData Record; - Expected<unsigned> MaybeCode = DeclsCursor.ReadCode(); - if (!MaybeCode) { - Error(MaybeCode.takeError()); + Expected<unsigned> RawCode = DeclsCursor.ReadCode(); + if (!RawCode) { + Error(RawCode.takeError()); return QualType(); } - unsigned Code = MaybeCode.get(); - Expected<unsigned> MaybeTypeCode = DeclsCursor.readRecord(Code, Record); - if (!MaybeTypeCode) { - Error(MaybeTypeCode.takeError()); + ASTRecordReader Record(*this, *Loc.F); + Expected<unsigned> Code = Record.readRecord(DeclsCursor, RawCode.get()); + if (!Code) { + Error(Code.takeError()); return QualType(); } - switch ((TypeCode)MaybeTypeCode.get()) { - case TYPE_EXT_QUAL: { - if (Record.size() != 2) { - Error("Incorrect encoding of extended qualifier type"); - return QualType(); - } - QualType Base = readType(*Loc.F, Record, Idx); - Qualifiers Quals = Qualifiers::fromOpaqueValue(Record[Idx++]); - return Context.getQualifiedType(Base, Quals); - } - - case TYPE_COMPLEX: { - if (Record.size() != 1) { - Error("Incorrect encoding of complex type"); - return QualType(); - } - QualType ElemType = readType(*Loc.F, Record, Idx); - return Context.getComplexType(ElemType); - } - - case TYPE_POINTER: { - if (Record.size() != 1) { - Error("Incorrect encoding of pointer type"); - return QualType(); - } - QualType PointeeType = readType(*Loc.F, Record, Idx); - return Context.getPointerType(PointeeType); - } - - case TYPE_DECAYED: { - if (Record.size() != 1) { - Error("Incorrect encoding of decayed type"); - return QualType(); - } - QualType OriginalType = readType(*Loc.F, Record, Idx); - QualType DT = Context.getAdjustedParameterType(OriginalType); - if (!isa<DecayedType>(DT)) - Error("Decayed type does not decay"); - return DT; - } - - case TYPE_ADJUSTED: { - if (Record.size() != 2) { - Error("Incorrect encoding of adjusted type"); - return QualType(); - } - QualType OriginalTy = readType(*Loc.F, Record, Idx); - QualType AdjustedTy = readType(*Loc.F, Record, Idx); - return Context.getAdjustedType(OriginalTy, AdjustedTy); - } - - case TYPE_BLOCK_POINTER: { - if (Record.size() != 1) { - Error("Incorrect encoding of block pointer type"); - return QualType(); - } - QualType PointeeType = readType(*Loc.F, Record, Idx); - return Context.getBlockPointerType(PointeeType); - } - - case TYPE_LVALUE_REFERENCE: { - if (Record.size() != 2) { - Error("Incorrect encoding of lvalue reference type"); - return QualType(); - } - QualType PointeeType = readType(*Loc.F, Record, Idx); - return Context.getLValueReferenceType(PointeeType, Record[1]); - } - - case TYPE_RVALUE_REFERENCE: { - if (Record.size() != 1) { - Error("Incorrect encoding of rvalue reference type"); - return QualType(); - } - QualType PointeeType = readType(*Loc.F, Record, Idx); - return Context.getRValueReferenceType(PointeeType); - } - - case TYPE_MEMBER_POINTER: { - if (Record.size() != 2) { - Error("Incorrect encoding of member pointer type"); - return QualType(); - } - QualType PointeeType = readType(*Loc.F, Record, Idx); - QualType ClassType = readType(*Loc.F, Record, Idx); - if (PointeeType.isNull() || ClassType.isNull()) - return QualType(); - - return Context.getMemberPointerType(PointeeType, ClassType.getTypePtr()); - } - - case TYPE_CONSTANT_ARRAY: { - QualType ElementType = readType(*Loc.F, Record, Idx); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - unsigned Idx = 3; - llvm::APInt Size = ReadAPInt(Record, Idx); - Expr *SizeExpr = ReadExpr(*Loc.F); - return Context.getConstantArrayType(ElementType, Size, SizeExpr, - ASM, IndexTypeQuals); - } - - case TYPE_INCOMPLETE_ARRAY: { - QualType ElementType = readType(*Loc.F, Record, Idx); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - return Context.getIncompleteArrayType(ElementType, ASM, IndexTypeQuals); - } - - case TYPE_VARIABLE_ARRAY: { - QualType ElementType = readType(*Loc.F, Record, Idx); - ArrayType::ArraySizeModifier ASM = (ArrayType::ArraySizeModifier)Record[1]; - unsigned IndexTypeQuals = Record[2]; - SourceLocation LBLoc = ReadSourceLocation(*Loc.F, Record[3]); - SourceLocation RBLoc = ReadSourceLocation(*Loc.F, Record[4]); - return Context.getVariableArrayType(ElementType, ReadExpr(*Loc.F), - ASM, IndexTypeQuals, - SourceRange(LBLoc, RBLoc)); - } - - case TYPE_VECTOR: { - if (Record.size() != 3) { - Error("incorrect encoding of vector type in AST file"); - return QualType(); - } - - QualType ElementType = readType(*Loc.F, Record, Idx); - unsigned NumElements = Record[1]; - unsigned VecKind = Record[2]; - return Context.getVectorType(ElementType, NumElements, - (VectorType::VectorKind)VecKind); - } - - case TYPE_EXT_VECTOR: { - if (Record.size() != 3) { - Error("incorrect encoding of extended vector type in AST file"); - return QualType(); - } - - QualType ElementType = readType(*Loc.F, Record, Idx); - unsigned NumElements = Record[1]; - return Context.getExtVectorType(ElementType, NumElements); + if (Code.get() == TYPE_EXT_QUAL) { + QualType baseType = Record.readQualType(); + Qualifiers quals = Record.readQualifiers(); + return Context.getQualifiedType(baseType, quals); } - case TYPE_FUNCTION_NO_PROTO: { - if (Record.size() != 8) { - Error("incorrect encoding of no-proto function type"); - return QualType(); - } - QualType ResultType = readType(*Loc.F, Record, Idx); - FunctionType::ExtInfo Info(Record[1], Record[2], Record[3], - (CallingConv)Record[4], Record[5], Record[6], - Record[7]); - return Context.getFunctionNoProtoType(ResultType, Info); - } - - case TYPE_FUNCTION_PROTO: { - QualType ResultType = readType(*Loc.F, Record, Idx); - - FunctionProtoType::ExtProtoInfo EPI; - EPI.ExtInfo = FunctionType::ExtInfo(/*noreturn*/ Record[1], - /*hasregparm*/ Record[2], - /*regparm*/ Record[3], - static_cast<CallingConv>(Record[4]), - /*produces*/ Record[5], - /*nocallersavedregs*/ Record[6], - /*nocfcheck*/ Record[7]); - - unsigned Idx = 8; - - EPI.Variadic = Record[Idx++]; - EPI.HasTrailingReturn = Record[Idx++]; - EPI.TypeQuals = Qualifiers::fromOpaqueValue(Record[Idx++]); - EPI.RefQualifier = static_cast<RefQualifierKind>(Record[Idx++]); - SmallVector<QualType, 8> ExceptionStorage; - readExceptionSpec(*Loc.F, ExceptionStorage, EPI.ExceptionSpec, Record, Idx); - - unsigned NumParams = Record[Idx++]; - SmallVector<QualType, 16> ParamTypes; - for (unsigned I = 0; I != NumParams; ++I) - ParamTypes.push_back(readType(*Loc.F, Record, Idx)); - - SmallVector<FunctionProtoType::ExtParameterInfo, 4> ExtParameterInfos; - if (Idx != Record.size()) { - for (unsigned I = 0; I != NumParams; ++I) - ExtParameterInfos.push_back( - FunctionProtoType::ExtParameterInfo - ::getFromOpaqueValue(Record[Idx++])); - EPI.ExtParameterInfos = ExtParameterInfos.data(); - } - - assert(Idx == Record.size()); - - return Context.getFunctionType(ResultType, ParamTypes, EPI); - } - - case TYPE_UNRESOLVED_USING: { - unsigned Idx = 0; - return Context.getTypeDeclType( - ReadDeclAs<UnresolvedUsingTypenameDecl>(*Loc.F, Record, Idx)); - } - - case TYPE_TYPEDEF: { - if (Record.size() != 2) { - Error("incorrect encoding of typedef type"); - return QualType(); - } - unsigned Idx = 0; - TypedefNameDecl *Decl = ReadDeclAs<TypedefNameDecl>(*Loc.F, Record, Idx); - QualType Canonical = readType(*Loc.F, Record, Idx); - if (!Canonical.isNull()) - Canonical = Context.getCanonicalType(Canonical); - return Context.getTypedefType(Decl, Canonical); - } - - case TYPE_TYPEOF_EXPR: - return Context.getTypeOfExprType(ReadExpr(*Loc.F)); - - case TYPE_TYPEOF: { - if (Record.size() != 1) { - Error("incorrect encoding of typeof(type) in AST file"); - return QualType(); - } - QualType UnderlyingType = readType(*Loc.F, Record, Idx); - return Context.getTypeOfType(UnderlyingType); - } - - case TYPE_DECLTYPE: { - QualType UnderlyingType = readType(*Loc.F, Record, Idx); - return Context.getDecltypeType(ReadExpr(*Loc.F), UnderlyingType); - } - - case TYPE_UNARY_TRANSFORM: { - QualType BaseType = readType(*Loc.F, Record, Idx); - QualType UnderlyingType = readType(*Loc.F, Record, Idx); - UnaryTransformType::UTTKind UKind = (UnaryTransformType::UTTKind)Record[2]; - return Context.getUnaryTransformType(BaseType, UnderlyingType, UKind); - } - - case TYPE_AUTO: { - QualType Deduced = readType(*Loc.F, Record, Idx); - AutoTypeKeyword Keyword = (AutoTypeKeyword)Record[Idx++]; - bool IsDependent = false, IsPack = false; - if (Deduced.isNull()) { - IsDependent = Record[Idx] > 0; - IsPack = Record[Idx] > 1; - ++Idx; - } - return Context.getAutoType(Deduced, Keyword, IsDependent, IsPack); - } - - case TYPE_DEDUCED_TEMPLATE_SPECIALIZATION: { - TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); - QualType Deduced = readType(*Loc.F, Record, Idx); - bool IsDependent = Deduced.isNull() ? Record[Idx++] : false; - return Context.getDeducedTemplateSpecializationType(Name, Deduced, - IsDependent); - } - - case TYPE_RECORD: { - if (Record.size() != 2) { - Error("incorrect encoding of record type"); - return QualType(); - } - unsigned Idx = 0; - bool IsDependent = Record[Idx++]; - RecordDecl *RD = ReadDeclAs<RecordDecl>(*Loc.F, Record, Idx); - RD = cast_or_null<RecordDecl>(RD->getCanonicalDecl()); - QualType T = Context.getRecordType(RD); - const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); - return T; - } - - case TYPE_ENUM: { - if (Record.size() != 2) { - Error("incorrect encoding of enum type"); - return QualType(); - } - unsigned Idx = 0; - bool IsDependent = Record[Idx++]; - QualType T - = Context.getEnumType(ReadDeclAs<EnumDecl>(*Loc.F, Record, Idx)); - const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); - return T; - } - - case TYPE_ATTRIBUTED: { - if (Record.size() != 3) { - Error("incorrect encoding of attributed type"); - return QualType(); - } - QualType modifiedType = readType(*Loc.F, Record, Idx); - QualType equivalentType = readType(*Loc.F, Record, Idx); - AttributedType::Kind kind = static_cast<AttributedType::Kind>(Record[2]); - return Context.getAttributedType(kind, modifiedType, equivalentType); - } - - case TYPE_PAREN: { - if (Record.size() != 1) { - Error("incorrect encoding of paren type"); - return QualType(); - } - QualType InnerType = readType(*Loc.F, Record, Idx); - return Context.getParenType(InnerType); - } - - case TYPE_MACRO_QUALIFIED: { - if (Record.size() != 2) { - Error("incorrect encoding of macro defined type"); - return QualType(); - } - QualType UnderlyingTy = readType(*Loc.F, Record, Idx); - IdentifierInfo *MacroII = GetIdentifierInfo(*Loc.F, Record, Idx); - return Context.getMacroQualifiedType(UnderlyingTy, MacroII); - } - - case TYPE_PACK_EXPANSION: { - if (Record.size() != 2) { - Error("incorrect encoding of pack expansion type"); - return QualType(); - } - QualType Pattern = readType(*Loc.F, Record, Idx); - if (Pattern.isNull()) - return QualType(); - Optional<unsigned> NumExpansions; - if (Record[1]) - NumExpansions = Record[1] - 1; - return Context.getPackExpansionType(Pattern, NumExpansions); - } - - case TYPE_ELABORATED: { - unsigned Idx = 0; - ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); - QualType NamedType = readType(*Loc.F, Record, Idx); - TagDecl *OwnedTagDecl = ReadDeclAs<TagDecl>(*Loc.F, Record, Idx); - return Context.getElaboratedType(Keyword, NNS, NamedType, OwnedTagDecl); - } - - case TYPE_OBJC_INTERFACE: { - unsigned Idx = 0; - ObjCInterfaceDecl *ItfD - = ReadDeclAs<ObjCInterfaceDecl>(*Loc.F, Record, Idx); - return Context.getObjCInterfaceType(ItfD->getCanonicalDecl()); - } - - case TYPE_OBJC_TYPE_PARAM: { - unsigned Idx = 0; - ObjCTypeParamDecl *Decl - = ReadDeclAs<ObjCTypeParamDecl>(*Loc.F, Record, Idx); - unsigned NumProtos = Record[Idx++]; - SmallVector<ObjCProtocolDecl*, 4> Protos; - for (unsigned I = 0; I != NumProtos; ++I) - Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx)); - return Context.getObjCTypeParamType(Decl, Protos); - } - - case TYPE_OBJC_OBJECT: { - unsigned Idx = 0; - QualType Base = readType(*Loc.F, Record, Idx); - unsigned NumTypeArgs = Record[Idx++]; - SmallVector<QualType, 4> TypeArgs; - for (unsigned I = 0; I != NumTypeArgs; ++I) - TypeArgs.push_back(readType(*Loc.F, Record, Idx)); - unsigned NumProtos = Record[Idx++]; - SmallVector<ObjCProtocolDecl*, 4> Protos; - for (unsigned I = 0; I != NumProtos; ++I) - Protos.push_back(ReadDeclAs<ObjCProtocolDecl>(*Loc.F, Record, Idx)); - bool IsKindOf = Record[Idx++]; - return Context.getObjCObjectType(Base, TypeArgs, Protos, IsKindOf); - } - - case TYPE_OBJC_OBJECT_POINTER: { - unsigned Idx = 0; - QualType Pointee = readType(*Loc.F, Record, Idx); - return Context.getObjCObjectPointerType(Pointee); - } - - case TYPE_SUBST_TEMPLATE_TYPE_PARM: { - unsigned Idx = 0; - QualType Parm = readType(*Loc.F, Record, Idx); - QualType Replacement = readType(*Loc.F, Record, Idx); - return Context.getSubstTemplateTypeParmType( - cast<TemplateTypeParmType>(Parm), - Context.getCanonicalType(Replacement)); - } - - case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: { - unsigned Idx = 0; - QualType Parm = readType(*Loc.F, Record, Idx); - TemplateArgument ArgPack = ReadTemplateArgument(*Loc.F, Record, Idx); - return Context.getSubstTemplateTypeParmPackType( - cast<TemplateTypeParmType>(Parm), - ArgPack); - } - - case TYPE_INJECTED_CLASS_NAME: { - CXXRecordDecl *D = ReadDeclAs<CXXRecordDecl>(*Loc.F, Record, Idx); - QualType TST = readType(*Loc.F, Record, Idx); // probably derivable - // FIXME: ASTContext::getInjectedClassNameType is not currently suitable - // for AST reading, too much interdependencies. - const Type *T = nullptr; - for (auto *DI = D; DI; DI = DI->getPreviousDecl()) { - if (const Type *Existing = DI->getTypeForDecl()) { - T = Existing; - break; - } - } - if (!T) { - T = new (Context, TypeAlignment) InjectedClassNameType(D, TST); - for (auto *DI = D; DI; DI = DI->getPreviousDecl()) - DI->setTypeForDecl(T); - } - return QualType(T, 0); - } - - case TYPE_TEMPLATE_TYPE_PARM: { - unsigned Idx = 0; - unsigned Depth = Record[Idx++]; - unsigned Index = Record[Idx++]; - bool Pack = Record[Idx++]; - TemplateTypeParmDecl *D - = ReadDeclAs<TemplateTypeParmDecl>(*Loc.F, Record, Idx); - return Context.getTemplateTypeParmType(Depth, Index, Pack, D); - } - - case TYPE_DEPENDENT_NAME: { - unsigned Idx = 0; - ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); - const IdentifierInfo *Name = GetIdentifierInfo(*Loc.F, Record, Idx); - QualType Canon = readType(*Loc.F, Record, Idx); - if (!Canon.isNull()) - Canon = Context.getCanonicalType(Canon); - return Context.getDependentNameType(Keyword, NNS, Name, Canon); - } - - case TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION: { - unsigned Idx = 0; - ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(*Loc.F, Record, Idx); - const IdentifierInfo *Name = GetIdentifierInfo(*Loc.F, Record, Idx); - unsigned NumArgs = Record[Idx++]; - SmallVector<TemplateArgument, 8> Args; - Args.reserve(NumArgs); - while (NumArgs--) - Args.push_back(ReadTemplateArgument(*Loc.F, Record, Idx)); - return Context.getDependentTemplateSpecializationType(Keyword, NNS, Name, - Args); - } - - case TYPE_DEPENDENT_SIZED_ARRAY: { - unsigned Idx = 0; - - // ArrayType - QualType ElementType = readType(*Loc.F, Record, Idx); - ArrayType::ArraySizeModifier ASM - = (ArrayType::ArraySizeModifier)Record[Idx++]; - unsigned IndexTypeQuals = Record[Idx++]; - - // DependentSizedArrayType - Expr *NumElts = ReadExpr(*Loc.F); - SourceRange Brackets = ReadSourceRange(*Loc.F, Record, Idx); - - return Context.getDependentSizedArrayType(ElementType, NumElts, ASM, - IndexTypeQuals, Brackets); - } - - case TYPE_TEMPLATE_SPECIALIZATION: { - unsigned Idx = 0; - bool IsDependent = Record[Idx++]; - TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); - SmallVector<TemplateArgument, 8> Args; - ReadTemplateArgumentList(Args, *Loc.F, Record, Idx); - QualType Underlying = readType(*Loc.F, Record, Idx); - QualType T; - if (Underlying.isNull()) - T = Context.getCanonicalTemplateSpecializationType(Name, Args); - else - T = Context.getTemplateSpecializationType(Name, Args, Underlying); - const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); - return T; - } - - case TYPE_ATOMIC: { - if (Record.size() != 1) { - Error("Incorrect encoding of atomic type"); - return QualType(); - } - QualType ValueType = readType(*Loc.F, Record, Idx); - return Context.getAtomicType(ValueType); - } - - case TYPE_PIPE: { - if (Record.size() != 2) { - Error("Incorrect encoding of pipe type"); - return QualType(); - } - - // Reading the pipe element type. - QualType ElementType = readType(*Loc.F, Record, Idx); - unsigned ReadOnly = Record[1]; - return Context.getPipeType(ElementType, ReadOnly); - } - - case TYPE_DEPENDENT_SIZED_VECTOR: { - unsigned Idx = 0; - QualType ElementType = readType(*Loc.F, Record, Idx); - Expr *SizeExpr = ReadExpr(*Loc.F); - SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx); - unsigned VecKind = Record[Idx]; - - return Context.getDependentVectorType(ElementType, SizeExpr, AttrLoc, - (VectorType::VectorKind)VecKind); - } - - case TYPE_DEPENDENT_SIZED_EXT_VECTOR: { - unsigned Idx = 0; - - // DependentSizedExtVectorType - QualType ElementType = readType(*Loc.F, Record, Idx); - Expr *SizeExpr = ReadExpr(*Loc.F); - SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx); - - return Context.getDependentSizedExtVectorType(ElementType, SizeExpr, - AttrLoc); - } - - case TYPE_DEPENDENT_ADDRESS_SPACE: { - unsigned Idx = 0; - - // DependentAddressSpaceType - QualType PointeeType = readType(*Loc.F, Record, Idx); - Expr *AddrSpaceExpr = ReadExpr(*Loc.F); - SourceLocation AttrLoc = ReadSourceLocation(*Loc.F, Record, Idx); - - return Context.getDependentAddressSpaceType(PointeeType, AddrSpaceExpr, - AttrLoc); - } + auto maybeClass = getTypeClassForCode((TypeCode) Code.get()); + if (!maybeClass) { + Error("Unexpected code for type"); + return QualType(); } - llvm_unreachable("Invalid TypeCode!"); -} -void ASTReader::readExceptionSpec(ModuleFile &ModuleFile, - SmallVectorImpl<QualType> &Exceptions, - FunctionProtoType::ExceptionSpecInfo &ESI, - const RecordData &Record, unsigned &Idx) { - ExceptionSpecificationType EST = - static_cast<ExceptionSpecificationType>(Record[Idx++]); - ESI.Type = EST; - if (EST == EST_Dynamic) { - for (unsigned I = 0, N = Record[Idx++]; I != N; ++I) - Exceptions.push_back(readType(ModuleFile, Record, Idx)); - ESI.Exceptions = Exceptions; - } else if (isComputedNoexcept(EST)) { - ESI.NoexceptExpr = ReadExpr(ModuleFile); - } else if (EST == EST_Uninstantiated) { - ESI.SourceDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx); - ESI.SourceTemplate = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx); - } else if (EST == EST_Unevaluated) { - ESI.SourceDecl = ReadDeclAs<FunctionDecl>(ModuleFile, Record, Idx); - } + serialization::AbstractTypeReader<ASTRecordReader> TypeReader(Record); + return TypeReader.read(*maybeClass); } namespace clang { class TypeLocReader : public TypeLocVisitor<TypeLocReader> { - ModuleFile *F; - ASTReader *Reader; - const ASTReader::RecordData &Record; - unsigned &Idx; + ASTRecordReader &Reader; - SourceLocation ReadSourceLocation() { - return Reader->ReadSourceLocation(*F, Record, Idx); + SourceLocation readSourceLocation() { + return Reader.readSourceLocation(); } TypeSourceInfo *GetTypeSourceInfo() { - return Reader->GetTypeSourceInfo(*F, Record, Idx); + return Reader.readTypeSourceInfo(); } NestedNameSpecifierLoc ReadNestedNameSpecifierLoc() { - return Reader->ReadNestedNameSpecifierLoc(*F, Record, Idx); + return Reader.readNestedNameSpecifierLoc(); } Attr *ReadAttr() { - return Reader->ReadAttr(*F, Record, Idx); + return Reader.readAttr(); } public: - TypeLocReader(ModuleFile &F, ASTReader &Reader, - const ASTReader::RecordData &Record, unsigned &Idx) - : F(&F), Reader(&Reader), Record(Record), Idx(Idx) {} + TypeLocReader(ASTRecordReader &Reader) : Reader(Reader) {} // We want compile-time assurance that we've enumerated all of // these, so unfortunately we have to declare them first, then @@ -6957,21 +6425,21 @@ void TypeLocReader::VisitQualifiedTypeLoc(QualifiedTypeLoc TL) { } void TypeLocReader::VisitBuiltinTypeLoc(BuiltinTypeLoc TL) { - TL.setBuiltinLoc(ReadSourceLocation()); + TL.setBuiltinLoc(readSourceLocation()); if (TL.needsExtraLocalData()) { - TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Record[Idx++])); - TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Record[Idx++])); - TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Record[Idx++])); - TL.setModeAttr(Record[Idx++]); + TL.setWrittenTypeSpec(static_cast<DeclSpec::TST>(Reader.readInt())); + TL.setWrittenSignSpec(static_cast<DeclSpec::TSS>(Reader.readInt())); + TL.setWrittenWidthSpec(static_cast<DeclSpec::TSW>(Reader.readInt())); + TL.setModeAttr(Reader.readInt()); } } void TypeLocReader::VisitComplexTypeLoc(ComplexTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitPointerTypeLoc(PointerTypeLoc TL) { - TL.setStarLoc(ReadSourceLocation()); + TL.setStarLoc(readSourceLocation()); } void TypeLocReader::VisitDecayedTypeLoc(DecayedTypeLoc TL) { @@ -6983,31 +6451,31 @@ void TypeLocReader::VisitAdjustedTypeLoc(AdjustedTypeLoc TL) { } void TypeLocReader::VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) { - TL.setExpansionLoc(ReadSourceLocation()); + TL.setExpansionLoc(readSourceLocation()); } void TypeLocReader::VisitBlockPointerTypeLoc(BlockPointerTypeLoc TL) { - TL.setCaretLoc(ReadSourceLocation()); + TL.setCaretLoc(readSourceLocation()); } void TypeLocReader::VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { - TL.setAmpLoc(ReadSourceLocation()); + TL.setAmpLoc(readSourceLocation()); } void TypeLocReader::VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL) { - TL.setAmpAmpLoc(ReadSourceLocation()); + TL.setAmpAmpLoc(readSourceLocation()); } void TypeLocReader::VisitMemberPointerTypeLoc(MemberPointerTypeLoc TL) { - TL.setStarLoc(ReadSourceLocation()); + TL.setStarLoc(readSourceLocation()); TL.setClassTInfo(GetTypeSourceInfo()); } void TypeLocReader::VisitArrayTypeLoc(ArrayTypeLoc TL) { - TL.setLBracketLoc(ReadSourceLocation()); - TL.setRBracketLoc(ReadSourceLocation()); - if (Record[Idx++]) - TL.setSizeExpr(Reader->ReadExpr(*F)); + TL.setLBracketLoc(readSourceLocation()); + TL.setRBracketLoc(readSourceLocation()); + if (Reader.readBool()) + TL.setSizeExpr(Reader.readExpr()); else TL.setSizeExpr(nullptr); } @@ -7032,41 +6500,37 @@ void TypeLocReader::VisitDependentSizedArrayTypeLoc( void TypeLocReader::VisitDependentAddressSpaceTypeLoc( DependentAddressSpaceTypeLoc TL) { - TL.setAttrNameLoc(ReadSourceLocation()); - SourceRange range; - range.setBegin(ReadSourceLocation()); - range.setEnd(ReadSourceLocation()); - TL.setAttrOperandParensRange(range); - TL.setAttrExprOperand(Reader->ReadExpr(*F)); + TL.setAttrNameLoc(readSourceLocation()); + TL.setAttrOperandParensRange(Reader.readSourceRange()); + TL.setAttrExprOperand(Reader.readExpr()); } void TypeLocReader::VisitDependentSizedExtVectorTypeLoc( DependentSizedExtVectorTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitVectorTypeLoc(VectorTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitDependentVectorTypeLoc( DependentVectorTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitExtVectorTypeLoc(ExtVectorTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitFunctionTypeLoc(FunctionTypeLoc TL) { - TL.setLocalRangeBegin(ReadSourceLocation()); - TL.setLParenLoc(ReadSourceLocation()); - TL.setRParenLoc(ReadSourceLocation()); - TL.setExceptionSpecRange(SourceRange(Reader->ReadSourceLocation(*F, Record, Idx), - Reader->ReadSourceLocation(*F, Record, Idx))); - TL.setLocalRangeEnd(ReadSourceLocation()); + TL.setLocalRangeBegin(readSourceLocation()); + TL.setLParenLoc(readSourceLocation()); + TL.setRParenLoc(readSourceLocation()); + TL.setExceptionSpecRange(Reader.readSourceRange()); + TL.setLocalRangeEnd(readSourceLocation()); for (unsigned i = 0, e = TL.getNumParams(); i != e; ++i) { - TL.setParam(i, Reader->ReadDeclAs<ParmVarDecl>(*F, Record, Idx)); + TL.setParam(i, Reader.readDeclAs<ParmVarDecl>()); } } @@ -7079,52 +6543,52 @@ void TypeLocReader::VisitFunctionNoProtoTypeLoc(FunctionNoProtoTypeLoc TL) { } void TypeLocReader::VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitTypedefTypeLoc(TypedefTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { - TL.setTypeofLoc(ReadSourceLocation()); - TL.setLParenLoc(ReadSourceLocation()); - TL.setRParenLoc(ReadSourceLocation()); + TL.setTypeofLoc(readSourceLocation()); + TL.setLParenLoc(readSourceLocation()); + TL.setRParenLoc(readSourceLocation()); } void TypeLocReader::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { - TL.setTypeofLoc(ReadSourceLocation()); - TL.setLParenLoc(ReadSourceLocation()); - TL.setRParenLoc(ReadSourceLocation()); + TL.setTypeofLoc(readSourceLocation()); + TL.setLParenLoc(readSourceLocation()); + TL.setRParenLoc(readSourceLocation()); TL.setUnderlyingTInfo(GetTypeSourceInfo()); } void TypeLocReader::VisitDecltypeTypeLoc(DecltypeTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc TL) { - TL.setKWLoc(ReadSourceLocation()); - TL.setLParenLoc(ReadSourceLocation()); - TL.setRParenLoc(ReadSourceLocation()); + TL.setKWLoc(readSourceLocation()); + TL.setLParenLoc(readSourceLocation()); + TL.setRParenLoc(readSourceLocation()); TL.setUnderlyingTInfo(GetTypeSourceInfo()); } void TypeLocReader::VisitAutoTypeLoc(AutoTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitDeducedTemplateSpecializationTypeLoc( DeducedTemplateSpecializationTypeLoc TL) { - TL.setTemplateNameLoc(ReadSourceLocation()); + TL.setTemplateNameLoc(readSourceLocation()); } void TypeLocReader::VisitRecordTypeLoc(RecordTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitEnumTypeLoc(EnumTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) { @@ -7132,126 +6596,123 @@ void TypeLocReader::VisitAttributedTypeLoc(AttributedTypeLoc TL) { } void TypeLocReader::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( SubstTemplateTypeParmTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc( SubstTemplateTypeParmPackTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { - TL.setTemplateKeywordLoc(ReadSourceLocation()); - TL.setTemplateNameLoc(ReadSourceLocation()); - TL.setLAngleLoc(ReadSourceLocation()); - TL.setRAngleLoc(ReadSourceLocation()); + TL.setTemplateKeywordLoc(readSourceLocation()); + TL.setTemplateNameLoc(readSourceLocation()); + TL.setLAngleLoc(readSourceLocation()); + TL.setRAngleLoc(readSourceLocation()); for (unsigned i = 0, e = TL.getNumArgs(); i != e; ++i) TL.setArgLocInfo( i, - Reader->GetTemplateArgumentLocInfo( - *F, TL.getTypePtr()->getArg(i).getKind(), Record, Idx)); + Reader.readTemplateArgumentLocInfo( + TL.getTypePtr()->getArg(i).getKind())); } void TypeLocReader::VisitParenTypeLoc(ParenTypeLoc TL) { - TL.setLParenLoc(ReadSourceLocation()); - TL.setRParenLoc(ReadSourceLocation()); + TL.setLParenLoc(readSourceLocation()); + TL.setRParenLoc(readSourceLocation()); } void TypeLocReader::VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { - TL.setElaboratedKeywordLoc(ReadSourceLocation()); + TL.setElaboratedKeywordLoc(readSourceLocation()); TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); } void TypeLocReader::VisitInjectedClassNameTypeLoc(InjectedClassNameTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitDependentNameTypeLoc(DependentNameTypeLoc TL) { - TL.setElaboratedKeywordLoc(ReadSourceLocation()); + TL.setElaboratedKeywordLoc(readSourceLocation()); TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc( DependentTemplateSpecializationTypeLoc TL) { - TL.setElaboratedKeywordLoc(ReadSourceLocation()); + TL.setElaboratedKeywordLoc(readSourceLocation()); TL.setQualifierLoc(ReadNestedNameSpecifierLoc()); - TL.setTemplateKeywordLoc(ReadSourceLocation()); - TL.setTemplateNameLoc(ReadSourceLocation()); - TL.setLAngleLoc(ReadSourceLocation()); - TL.setRAngleLoc(ReadSourceLocation()); + TL.setTemplateKeywordLoc(readSourceLocation()); + TL.setTemplateNameLoc(readSourceLocation()); + TL.setLAngleLoc(readSourceLocation()); + TL.setRAngleLoc(readSourceLocation()); for (unsigned I = 0, E = TL.getNumArgs(); I != E; ++I) TL.setArgLocInfo( I, - Reader->GetTemplateArgumentLocInfo( - *F, TL.getTypePtr()->getArg(I).getKind(), Record, Idx)); + Reader.readTemplateArgumentLocInfo( + TL.getTypePtr()->getArg(I).getKind())); } void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { - TL.setEllipsisLoc(ReadSourceLocation()); + TL.setEllipsisLoc(readSourceLocation()); } void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { - TL.setNameLoc(ReadSourceLocation()); + TL.setNameLoc(readSourceLocation()); } void TypeLocReader::VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc TL) { if (TL.getNumProtocols()) { - TL.setProtocolLAngleLoc(ReadSourceLocation()); - TL.setProtocolRAngleLoc(ReadSourceLocation()); + TL.setProtocolLAngleLoc(readSourceLocation()); + TL.setProtocolRAngleLoc(readSourceLocation()); } for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) - TL.setProtocolLoc(i, ReadSourceLocation()); + TL.setProtocolLoc(i, readSourceLocation()); } void TypeLocReader::VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL) { - TL.setHasBaseTypeAsWritten(Record[Idx++]); - TL.setTypeArgsLAngleLoc(ReadSourceLocation()); - TL.setTypeArgsRAngleLoc(ReadSourceLocation()); + TL.setHasBaseTypeAsWritten(Reader.readBool()); + TL.setTypeArgsLAngleLoc(readSourceLocation()); + TL.setTypeArgsRAngleLoc(readSourceLocation()); for (unsigned i = 0, e = TL.getNumTypeArgs(); i != e; ++i) TL.setTypeArgTInfo(i, GetTypeSourceInfo()); - TL.setProtocolLAngleLoc(ReadSourceLocation()); - TL.setProtocolRAngleLoc(ReadSourceLocation()); + TL.setProtocolLAngleLoc(readSourceLocation()); + TL.setProtocolRAngleLoc(readSourceLocation()); for (unsigned i = 0, e = TL.getNumProtocols(); i != e; ++i) - TL.setProtocolLoc(i, ReadSourceLocation()); + TL.setProtocolLoc(i, readSourceLocation()); } void TypeLocReader::VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL) { - TL.setStarLoc(ReadSourceLocation()); + TL.setStarLoc(readSourceLocation()); } void TypeLocReader::VisitAtomicTypeLoc(AtomicTypeLoc TL) { - TL.setKWLoc(ReadSourceLocation()); - TL.setLParenLoc(ReadSourceLocation()); - TL.setRParenLoc(ReadSourceLocation()); + TL.setKWLoc(readSourceLocation()); + TL.setLParenLoc(readSourceLocation()); + TL.setRParenLoc(readSourceLocation()); } void TypeLocReader::VisitPipeTypeLoc(PipeTypeLoc TL) { - TL.setKWLoc(ReadSourceLocation()); + TL.setKWLoc(readSourceLocation()); } -void ASTReader::ReadTypeLoc(ModuleFile &F, const ASTReader::RecordData &Record, - unsigned &Idx, TypeLoc TL) { - TypeLocReader TLR(F, *this, Record, Idx); +void ASTRecordReader::readTypeLoc(TypeLoc TL) { + TypeLocReader TLR(*this); for (; !TL.isNull(); TL = TL.getNextTypeLoc()) TLR.Visit(TL); } -TypeSourceInfo * -ASTReader::GetTypeSourceInfo(ModuleFile &F, const ASTReader::RecordData &Record, - unsigned &Idx) { - QualType InfoTy = readType(F, Record, Idx); +TypeSourceInfo *ASTRecordReader::readTypeSourceInfo() { + QualType InfoTy = readType(); if (InfoTy.isNull()) return nullptr; TypeSourceInfo *TInfo = getContext().CreateTypeSourceInfo(InfoTy); - ReadTypeLoc(F, Record, Idx, TInfo->getTypeLoc()); + readTypeLoc(TInfo->getTypeLoc()); return TInfo; } @@ -7534,27 +6995,23 @@ ASTReader::getGlobalTypeID(ModuleFile &F, unsigned LocalID) const { } TemplateArgumentLocInfo -ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F, - TemplateArgument::ArgKind Kind, - const RecordData &Record, - unsigned &Index) { +ASTRecordReader::readTemplateArgumentLocInfo(TemplateArgument::ArgKind Kind) { switch (Kind) { case TemplateArgument::Expression: - return ReadExpr(F); + return readExpr(); case TemplateArgument::Type: - return GetTypeSourceInfo(F, Record, Index); + return readTypeSourceInfo(); case TemplateArgument::Template: { - NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, - Index); - SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index); + NestedNameSpecifierLoc QualifierLoc = + readNestedNameSpecifierLoc(); + SourceLocation TemplateNameLoc = readSourceLocation(); return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc, SourceLocation()); } case TemplateArgument::TemplateExpansion: { - NestedNameSpecifierLoc QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, - Index); - SourceLocation TemplateNameLoc = ReadSourceLocation(F, Record, Index); - SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Index); + NestedNameSpecifierLoc QualifierLoc = readNestedNameSpecifierLoc(); + SourceLocation TemplateNameLoc = readSourceLocation(); + SourceLocation EllipsisLoc = readSourceLocation(); return TemplateArgumentLocInfo(QualifierLoc, TemplateNameLoc, EllipsisLoc); } @@ -7569,29 +7026,24 @@ ASTReader::GetTemplateArgumentLocInfo(ModuleFile &F, llvm_unreachable("unexpected template argument loc"); } -TemplateArgumentLoc -ASTReader::ReadTemplateArgumentLoc(ModuleFile &F, - const RecordData &Record, unsigned &Index) { - TemplateArgument Arg = ReadTemplateArgument(F, Record, Index); +TemplateArgumentLoc ASTRecordReader::readTemplateArgumentLoc() { + TemplateArgument Arg = readTemplateArgument(); if (Arg.getKind() == TemplateArgument::Expression) { - if (Record[Index++]) // bool InfoHasSameExpr. + if (readBool()) // bool InfoHasSameExpr. return TemplateArgumentLoc(Arg, TemplateArgumentLocInfo(Arg.getAsExpr())); } - return TemplateArgumentLoc(Arg, GetTemplateArgumentLocInfo(F, Arg.getKind(), - Record, Index)); + return TemplateArgumentLoc(Arg, readTemplateArgumentLocInfo(Arg.getKind())); } -const ASTTemplateArgumentListInfo* -ASTReader::ReadASTTemplateArgumentListInfo(ModuleFile &F, - const RecordData &Record, - unsigned &Index) { - SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Index); - SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Index); - unsigned NumArgsAsWritten = Record[Index++]; +const ASTTemplateArgumentListInfo * +ASTRecordReader::readASTTemplateArgumentListInfo() { + SourceLocation LAngleLoc = readSourceLocation(); + SourceLocation RAngleLoc = readSourceLocation(); + unsigned NumArgsAsWritten = readInt(); TemplateArgumentListInfo TemplArgsInfo(LAngleLoc, RAngleLoc); for (unsigned i = 0; i != NumArgsAsWritten; ++i) - TemplArgsInfo.addArgument(ReadTemplateArgumentLoc(F, Record, Index)); + TemplArgsInfo.addArgument(readTemplateArgumentLoc()); return ASTTemplateArgumentListInfo::Create(getContext(), TemplArgsInfo); } @@ -7662,7 +7114,6 @@ ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) { } ReadingKindTracker ReadingKind(Read_Decl, *this); - RecordData Record; Expected<unsigned> MaybeCode = Cursor.ReadCode(); if (!MaybeCode) { Error(MaybeCode.takeError()); @@ -7670,7 +7121,8 @@ ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) { } unsigned Code = MaybeCode.get(); - Expected<unsigned> MaybeRecCode = Cursor.readRecord(Code, Record); + ASTRecordReader Record(*this, *Loc.F); + Expected<unsigned> MaybeRecCode = Record.readRecord(Cursor, Code); if (!MaybeRecCode) { Error(MaybeRecCode.takeError()); return nullptr; @@ -7680,8 +7132,7 @@ ASTReader::GetExternalCXXCtorInitializers(uint64_t Offset) { return nullptr; } - unsigned Idx = 0; - return ReadCXXCtorInitializers(*Loc.F, Record, Idx); + return Record.readCXXCtorInitializers(); } CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { @@ -7696,7 +7147,6 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { return nullptr; } ReadingKindTracker ReadingKind(Read_Decl, *this); - RecordData Record; Expected<unsigned> MaybeCode = Cursor.ReadCode(); if (!MaybeCode) { @@ -7705,7 +7155,8 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { } unsigned Code = MaybeCode.get(); - Expected<unsigned> MaybeRecCode = Cursor.readRecord(Code, Record); + ASTRecordReader Record(*this, *Loc.F); + Expected<unsigned> MaybeRecCode = Record.readRecord(Cursor, Code); if (!MaybeRecCode) { Error(MaybeCode.takeError()); return nullptr; @@ -7717,12 +7168,11 @@ CXXBaseSpecifier *ASTReader::GetExternalCXXBaseSpecifiers(uint64_t Offset) { return nullptr; } - unsigned Idx = 0; - unsigned NumBases = Record[Idx++]; + unsigned NumBases = Record.readInt(); void *Mem = Context.Allocate(sizeof(CXXBaseSpecifier) * NumBases); CXXBaseSpecifier *Bases = new (Mem) CXXBaseSpecifier [NumBases]; for (unsigned I = 0; I != NumBases; ++I) - Bases[I] = ReadCXXBaseSpecifier(*Loc.F, Record, Idx); + Bases[I] = Record.readCXXBaseSpecifier(); return Bases; } @@ -9112,72 +8562,26 @@ ASTReader::getGlobalSelectorID(ModuleFile &M, unsigned LocalID) const { return LocalID + I->second; } -DeclarationName -ASTReader::ReadDeclarationName(ModuleFile &F, - const RecordData &Record, unsigned &Idx) { - ASTContext &Context = getContext(); - DeclarationName::NameKind Kind = (DeclarationName::NameKind)Record[Idx++]; - switch (Kind) { - case DeclarationName::Identifier: - return DeclarationName(GetIdentifierInfo(F, Record, Idx)); - - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - return DeclarationName(ReadSelector(F, Record, Idx)); - - case DeclarationName::CXXConstructorName: - return Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(readType(F, Record, Idx))); - - case DeclarationName::CXXDestructorName: - return Context.DeclarationNames.getCXXDestructorName( - Context.getCanonicalType(readType(F, Record, Idx))); - - case DeclarationName::CXXDeductionGuideName: - return Context.DeclarationNames.getCXXDeductionGuideName( - ReadDeclAs<TemplateDecl>(F, Record, Idx)); - - case DeclarationName::CXXConversionFunctionName: - return Context.DeclarationNames.getCXXConversionFunctionName( - Context.getCanonicalType(readType(F, Record, Idx))); - - case DeclarationName::CXXOperatorName: - return Context.DeclarationNames.getCXXOperatorName( - (OverloadedOperatorKind)Record[Idx++]); - - case DeclarationName::CXXLiteralOperatorName: - return Context.DeclarationNames.getCXXLiteralOperatorName( - GetIdentifierInfo(F, Record, Idx)); - - case DeclarationName::CXXUsingDirective: - return DeclarationName::getUsingDirectiveName(); - } - - llvm_unreachable("Invalid NameKind!"); -} - -void ASTReader::ReadDeclarationNameLoc(ModuleFile &F, - DeclarationNameLoc &DNLoc, - DeclarationName Name, - const RecordData &Record, unsigned &Idx) { +DeclarationNameLoc +ASTRecordReader::readDeclarationNameLoc(DeclarationName Name) { + DeclarationNameLoc DNLoc; switch (Name.getNameKind()) { case DeclarationName::CXXConstructorName: case DeclarationName::CXXDestructorName: case DeclarationName::CXXConversionFunctionName: - DNLoc.NamedType.TInfo = GetTypeSourceInfo(F, Record, Idx); + DNLoc.NamedType.TInfo = readTypeSourceInfo(); break; case DeclarationName::CXXOperatorName: DNLoc.CXXOperatorName.BeginOpNameLoc - = ReadSourceLocation(F, Record, Idx).getRawEncoding(); + = readSourceLocation().getRawEncoding(); DNLoc.CXXOperatorName.EndOpNameLoc - = ReadSourceLocation(F, Record, Idx).getRawEncoding(); + = readSourceLocation().getRawEncoding(); break; case DeclarationName::CXXLiteralOperatorName: DNLoc.CXXLiteralOperatorName.OpNameLoc - = ReadSourceLocation(F, Record, Idx).getRawEncoding(); + = readSourceLocation().getRawEncoding(); break; case DeclarationName::Identifier: @@ -9188,204 +8592,78 @@ void ASTReader::ReadDeclarationNameLoc(ModuleFile &F, case DeclarationName::CXXDeductionGuideName: break; } + return DNLoc; } -void ASTReader::ReadDeclarationNameInfo(ModuleFile &F, - DeclarationNameInfo &NameInfo, - const RecordData &Record, unsigned &Idx) { - NameInfo.setName(ReadDeclarationName(F, Record, Idx)); - NameInfo.setLoc(ReadSourceLocation(F, Record, Idx)); - DeclarationNameLoc DNLoc; - ReadDeclarationNameLoc(F, DNLoc, NameInfo.getName(), Record, Idx); - NameInfo.setInfo(DNLoc); +DeclarationNameInfo ASTRecordReader::readDeclarationNameInfo() { + DeclarationNameInfo NameInfo; + NameInfo.setName(readDeclarationName()); + NameInfo.setLoc(readSourceLocation()); + NameInfo.setInfo(readDeclarationNameLoc(NameInfo.getName())); + return NameInfo; } -void ASTReader::ReadQualifierInfo(ModuleFile &F, QualifierInfo &Info, - const RecordData &Record, unsigned &Idx) { - Info.QualifierLoc = ReadNestedNameSpecifierLoc(F, Record, Idx); - unsigned NumTPLists = Record[Idx++]; +void ASTRecordReader::readQualifierInfo(QualifierInfo &Info) { + Info.QualifierLoc = readNestedNameSpecifierLoc(); + unsigned NumTPLists = readInt(); Info.NumTemplParamLists = NumTPLists; if (NumTPLists) { Info.TemplParamLists = new (getContext()) TemplateParameterList *[NumTPLists]; for (unsigned i = 0; i != NumTPLists; ++i) - Info.TemplParamLists[i] = ReadTemplateParameterList(F, Record, Idx); - } -} - -TemplateName -ASTReader::ReadTemplateName(ModuleFile &F, const RecordData &Record, - unsigned &Idx) { - ASTContext &Context = getContext(); - TemplateName::NameKind Kind = (TemplateName::NameKind)Record[Idx++]; - switch (Kind) { - case TemplateName::Template: - return TemplateName(ReadDeclAs<TemplateDecl>(F, Record, Idx)); - - case TemplateName::OverloadedTemplate: { - unsigned size = Record[Idx++]; - UnresolvedSet<8> Decls; - while (size--) - Decls.addDecl(ReadDeclAs<NamedDecl>(F, Record, Idx)); - - return Context.getOverloadedTemplateName(Decls.begin(), Decls.end()); - } - - case TemplateName::AssumedTemplate: { - DeclarationName Name = ReadDeclarationName(F, Record, Idx); - return Context.getAssumedTemplateName(Name); - } - - case TemplateName::QualifiedTemplate: { - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx); - bool hasTemplKeyword = Record[Idx++]; - TemplateDecl *Template = ReadDeclAs<TemplateDecl>(F, Record, Idx); - return Context.getQualifiedTemplateName(NNS, hasTemplKeyword, Template); - } - - case TemplateName::DependentTemplate: { - NestedNameSpecifier *NNS = ReadNestedNameSpecifier(F, Record, Idx); - if (Record[Idx++]) // isIdentifier - return Context.getDependentTemplateName(NNS, - GetIdentifierInfo(F, Record, - Idx)); - return Context.getDependentTemplateName(NNS, - (OverloadedOperatorKind)Record[Idx++]); - } - - case TemplateName::SubstTemplateTemplateParm: { - TemplateTemplateParmDecl *param - = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx); - if (!param) return TemplateName(); - TemplateName replacement = ReadTemplateName(F, Record, Idx); - return Context.getSubstTemplateTemplateParm(param, replacement); - } - - case TemplateName::SubstTemplateTemplateParmPack: { - TemplateTemplateParmDecl *Param - = ReadDeclAs<TemplateTemplateParmDecl>(F, Record, Idx); - if (!Param) - return TemplateName(); - - TemplateArgument ArgPack = ReadTemplateArgument(F, Record, Idx); - if (ArgPack.getKind() != TemplateArgument::Pack) - return TemplateName(); - - return Context.getSubstTemplateTemplateParmPack(Param, ArgPack); - } - } - - llvm_unreachable("Unhandled template name kind!"); -} - -TemplateArgument ASTReader::ReadTemplateArgument(ModuleFile &F, - const RecordData &Record, - unsigned &Idx, - bool Canonicalize) { - ASTContext &Context = getContext(); - if (Canonicalize) { - // The caller wants a canonical template argument. Sometimes the AST only - // wants template arguments in canonical form (particularly as the template - // argument lists of template specializations) so ensure we preserve that - // canonical form across serialization. - TemplateArgument Arg = ReadTemplateArgument(F, Record, Idx, false); - return Context.getCanonicalTemplateArgument(Arg); - } - - TemplateArgument::ArgKind Kind = (TemplateArgument::ArgKind)Record[Idx++]; - switch (Kind) { - case TemplateArgument::Null: - return TemplateArgument(); - case TemplateArgument::Type: - return TemplateArgument(readType(F, Record, Idx)); - case TemplateArgument::Declaration: { - ValueDecl *D = ReadDeclAs<ValueDecl>(F, Record, Idx); - return TemplateArgument(D, readType(F, Record, Idx)); - } - case TemplateArgument::NullPtr: - return TemplateArgument(readType(F, Record, Idx), /*isNullPtr*/true); - case TemplateArgument::Integral: { - llvm::APSInt Value = ReadAPSInt(Record, Idx); - QualType T = readType(F, Record, Idx); - return TemplateArgument(Context, Value, T); - } - case TemplateArgument::Template: - return TemplateArgument(ReadTemplateName(F, Record, Idx)); - case TemplateArgument::TemplateExpansion: { - TemplateName Name = ReadTemplateName(F, Record, Idx); - Optional<unsigned> NumTemplateExpansions; - if (unsigned NumExpansions = Record[Idx++]) - NumTemplateExpansions = NumExpansions - 1; - return TemplateArgument(Name, NumTemplateExpansions); + Info.TemplParamLists[i] = readTemplateParameterList(); } - case TemplateArgument::Expression: - return TemplateArgument(ReadExpr(F)); - case TemplateArgument::Pack: { - unsigned NumArgs = Record[Idx++]; - TemplateArgument *Args = new (Context) TemplateArgument[NumArgs]; - for (unsigned I = 0; I != NumArgs; ++I) - Args[I] = ReadTemplateArgument(F, Record, Idx); - return TemplateArgument(llvm::makeArrayRef(Args, NumArgs)); - } - } - - llvm_unreachable("Unhandled template argument kind!"); } TemplateParameterList * -ASTReader::ReadTemplateParameterList(ModuleFile &F, - const RecordData &Record, unsigned &Idx) { - SourceLocation TemplateLoc = ReadSourceLocation(F, Record, Idx); - SourceLocation LAngleLoc = ReadSourceLocation(F, Record, Idx); - SourceLocation RAngleLoc = ReadSourceLocation(F, Record, Idx); +ASTRecordReader::readTemplateParameterList() { + SourceLocation TemplateLoc = readSourceLocation(); + SourceLocation LAngleLoc = readSourceLocation(); + SourceLocation RAngleLoc = readSourceLocation(); - unsigned NumParams = Record[Idx++]; + unsigned NumParams = readInt(); SmallVector<NamedDecl *, 16> Params; Params.reserve(NumParams); while (NumParams--) - Params.push_back(ReadDeclAs<NamedDecl>(F, Record, Idx)); + Params.push_back(readDeclAs<NamedDecl>()); - bool HasRequiresClause = Record[Idx++]; - Expr *RequiresClause = HasRequiresClause ? ReadExpr(F) : nullptr; + bool HasRequiresClause = readBool(); + Expr *RequiresClause = HasRequiresClause ? readExpr() : nullptr; TemplateParameterList *TemplateParams = TemplateParameterList::Create( getContext(), TemplateLoc, LAngleLoc, Params, RAngleLoc, RequiresClause); return TemplateParams; } -void -ASTReader:: -ReadTemplateArgumentList(SmallVectorImpl<TemplateArgument> &TemplArgs, - ModuleFile &F, const RecordData &Record, - unsigned &Idx, bool Canonicalize) { - unsigned NumTemplateArgs = Record[Idx++]; +void ASTRecordReader::readTemplateArgumentList( + SmallVectorImpl<TemplateArgument> &TemplArgs, + bool Canonicalize) { + unsigned NumTemplateArgs = readInt(); TemplArgs.reserve(NumTemplateArgs); while (NumTemplateArgs--) - TemplArgs.push_back(ReadTemplateArgument(F, Record, Idx, Canonicalize)); + TemplArgs.push_back(readTemplateArgument(Canonicalize)); } /// Read a UnresolvedSet structure. -void ASTReader::ReadUnresolvedSet(ModuleFile &F, LazyASTUnresolvedSet &Set, - const RecordData &Record, unsigned &Idx) { - unsigned NumDecls = Record[Idx++]; +void ASTRecordReader::readUnresolvedSet(LazyASTUnresolvedSet &Set) { + unsigned NumDecls = readInt(); Set.reserve(getContext(), NumDecls); while (NumDecls--) { - DeclID ID = ReadDeclID(F, Record, Idx); - AccessSpecifier AS = (AccessSpecifier)Record[Idx++]; + DeclID ID = readDeclID(); + AccessSpecifier AS = (AccessSpecifier) readInt(); Set.addLazyDecl(getContext(), ID, AS); } } CXXBaseSpecifier -ASTReader::ReadCXXBaseSpecifier(ModuleFile &F, - const RecordData &Record, unsigned &Idx) { - bool isVirtual = static_cast<bool>(Record[Idx++]); - bool isBaseOfClass = static_cast<bool>(Record[Idx++]); - AccessSpecifier AS = static_cast<AccessSpecifier>(Record[Idx++]); - bool inheritConstructors = static_cast<bool>(Record[Idx++]); - TypeSourceInfo *TInfo = GetTypeSourceInfo(F, Record, Idx); - SourceRange Range = ReadSourceRange(F, Record, Idx); - SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Idx); +ASTRecordReader::readCXXBaseSpecifier() { + bool isVirtual = readBool(); + bool isBaseOfClass = readBool(); + AccessSpecifier AS = static_cast<AccessSpecifier>(readInt()); + bool inheritConstructors = readBool(); + TypeSourceInfo *TInfo = readTypeSourceInfo(); + SourceRange Range = readSourceRange(); + SourceLocation EllipsisLoc = readSourceLocation(); CXXBaseSpecifier Result(Range, isVirtual, isBaseOfClass, AS, TInfo, EllipsisLoc); Result.setInheritConstructors(inheritConstructors); @@ -9393,10 +8671,9 @@ ASTReader::ReadCXXBaseSpecifier(ModuleFile &F, } CXXCtorInitializer ** -ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, - unsigned &Idx) { +ASTRecordReader::readCXXCtorInitializers() { ASTContext &Context = getContext(); - unsigned NumInitializers = Record[Idx++]; + unsigned NumInitializers = readInt(); assert(NumInitializers && "wrote ctor initializers but have no inits"); auto **CtorInitializers = new (Context) CXXCtorInitializer*[NumInitializers]; for (unsigned i = 0; i != NumInitializers; ++i) { @@ -9405,30 +8682,30 @@ ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, FieldDecl *Member = nullptr; IndirectFieldDecl *IndirectMember = nullptr; - CtorInitializerType Type = (CtorInitializerType)Record[Idx++]; + CtorInitializerType Type = (CtorInitializerType) readInt(); switch (Type) { case CTOR_INITIALIZER_BASE: - TInfo = GetTypeSourceInfo(F, Record, Idx); - IsBaseVirtual = Record[Idx++]; + TInfo = readTypeSourceInfo(); + IsBaseVirtual = readBool(); break; case CTOR_INITIALIZER_DELEGATING: - TInfo = GetTypeSourceInfo(F, Record, Idx); + TInfo = readTypeSourceInfo(); break; case CTOR_INITIALIZER_MEMBER: - Member = ReadDeclAs<FieldDecl>(F, Record, Idx); + Member = readDeclAs<FieldDecl>(); break; case CTOR_INITIALIZER_INDIRECT_MEMBER: - IndirectMember = ReadDeclAs<IndirectFieldDecl>(F, Record, Idx); + IndirectMember = readDeclAs<IndirectFieldDecl>(); break; } - SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx); - Expr *Init = ReadExpr(F); - SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx); - SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx); + SourceLocation MemberOrEllipsisLoc = readSourceLocation(); + Expr *Init = readExpr(); + SourceLocation LParenLoc = readSourceLocation(); + SourceLocation RParenLoc = readSourceLocation(); CXXCtorInitializer *BOMInit; if (Type == CTOR_INITIALIZER_BASE) @@ -9447,8 +8724,8 @@ ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, CXXCtorInitializer(Context, IndirectMember, MemberOrEllipsisLoc, LParenLoc, Init, RParenLoc); - if (/*IsWritten*/Record[Idx++]) { - unsigned SourceOrder = Record[Idx++]; + if (/*IsWritten*/readBool()) { + unsigned SourceOrder = readInt(); BOMInit->setSourceOrder(SourceOrder); } @@ -9458,99 +8735,42 @@ ASTReader::ReadCXXCtorInitializers(ModuleFile &F, const RecordData &Record, return CtorInitializers; } -NestedNameSpecifier * -ASTReader::ReadNestedNameSpecifier(ModuleFile &F, - const RecordData &Record, unsigned &Idx) { - ASTContext &Context = getContext(); - unsigned N = Record[Idx++]; - NestedNameSpecifier *NNS = nullptr, *Prev = nullptr; - for (unsigned I = 0; I != N; ++I) { - NestedNameSpecifier::SpecifierKind Kind - = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; - switch (Kind) { - case NestedNameSpecifier::Identifier: { - IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx); - NNS = NestedNameSpecifier::Create(Context, Prev, II); - break; - } - - case NestedNameSpecifier::Namespace: { - NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx); - NNS = NestedNameSpecifier::Create(Context, Prev, NS); - break; - } - - case NestedNameSpecifier::NamespaceAlias: { - NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx); - NNS = NestedNameSpecifier::Create(Context, Prev, Alias); - break; - } - - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: { - const Type *T = readType(F, Record, Idx).getTypePtrOrNull(); - if (!T) - return nullptr; - - bool Template = Record[Idx++]; - NNS = NestedNameSpecifier::Create(Context, Prev, Template, T); - break; - } - - case NestedNameSpecifier::Global: - NNS = NestedNameSpecifier::GlobalSpecifier(Context); - // No associated value, and there can't be a prefix. - break; - - case NestedNameSpecifier::Super: { - CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(F, Record, Idx); - NNS = NestedNameSpecifier::SuperSpecifier(Context, RD); - break; - } - } - Prev = NNS; - } - return NNS; -} - NestedNameSpecifierLoc -ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record, - unsigned &Idx) { +ASTRecordReader::readNestedNameSpecifierLoc() { ASTContext &Context = getContext(); - unsigned N = Record[Idx++]; + unsigned N = readInt(); NestedNameSpecifierLocBuilder Builder; for (unsigned I = 0; I != N; ++I) { - NestedNameSpecifier::SpecifierKind Kind - = (NestedNameSpecifier::SpecifierKind)Record[Idx++]; + auto Kind = readNestedNameSpecifierKind(); switch (Kind) { case NestedNameSpecifier::Identifier: { - IdentifierInfo *II = GetIdentifierInfo(F, Record, Idx); - SourceRange Range = ReadSourceRange(F, Record, Idx); + IdentifierInfo *II = readIdentifier(); + SourceRange Range = readSourceRange(); Builder.Extend(Context, II, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::Namespace: { - NamespaceDecl *NS = ReadDeclAs<NamespaceDecl>(F, Record, Idx); - SourceRange Range = ReadSourceRange(F, Record, Idx); + NamespaceDecl *NS = readDeclAs<NamespaceDecl>(); + SourceRange Range = readSourceRange(); Builder.Extend(Context, NS, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::NamespaceAlias: { - NamespaceAliasDecl *Alias =ReadDeclAs<NamespaceAliasDecl>(F, Record, Idx); - SourceRange Range = ReadSourceRange(F, Record, Idx); + NamespaceAliasDecl *Alias = readDeclAs<NamespaceAliasDecl>(); + SourceRange Range = readSourceRange(); Builder.Extend(Context, Alias, Range.getBegin(), Range.getEnd()); break; } case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { - bool Template = Record[Idx++]; - TypeSourceInfo *T = GetTypeSourceInfo(F, Record, Idx); + bool Template = readBool(); + TypeSourceInfo *T = readTypeSourceInfo(); if (!T) return NestedNameSpecifierLoc(); - SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); + SourceLocation ColonColonLoc = readSourceLocation(); // FIXME: 'template' keyword location not saved anywhere, so we fake it. Builder.Extend(Context, @@ -9560,14 +8780,14 @@ ASTReader::ReadNestedNameSpecifierLoc(ModuleFile &F, const RecordData &Record, } case NestedNameSpecifier::Global: { - SourceLocation ColonColonLoc = ReadSourceLocation(F, Record, Idx); + SourceLocation ColonColonLoc = readSourceLocation(); Builder.MakeGlobal(Context, ColonColonLoc); break; } case NestedNameSpecifier::Super: { - CXXRecordDecl *RD = ReadDeclAs<CXXRecordDecl>(F, Record, Idx); - SourceRange Range = ReadSourceRange(F, Record, Idx); + CXXRecordDecl *RD = readDeclAs<CXXRecordDecl>(); + SourceRange Range = readSourceRange(); Builder.MakeSuper(Context, RD, Range.getBegin(), Range.getEnd()); break; } @@ -9598,35 +8818,38 @@ ReadFixedPointSemantics(const SmallVectorImpl<uint64_t> &Record, HasUnsignedPadding); } -APValue ASTReader::ReadAPValue(const RecordData &Record, unsigned &Idx) { - unsigned Kind = Record[Idx++]; - switch (Kind) { +static const llvm::fltSemantics & +readAPFloatSemantics(ASTRecordReader &reader) { + return llvm::APFloatBase::EnumToSemantics( + static_cast<llvm::APFloatBase::Semantics>(reader.readInt())); +} + +APValue ASTRecordReader::readAPValue() { + unsigned Kind = readInt(); + switch ((APValue::ValueKind) Kind) { case APValue::None: return APValue(); case APValue::Indeterminate: return APValue::IndeterminateValue(); case APValue::Int: - return APValue(ReadAPSInt(Record, Idx)); + return APValue(readAPSInt()); case APValue::Float: { - const llvm::fltSemantics &FloatSema = llvm::APFloatBase::EnumToSemantics( - static_cast<llvm::APFloatBase::Semantics>(Record[Idx++])); - return APValue(ReadAPFloat(Record, FloatSema, Idx)); + const llvm::fltSemantics &FloatSema = readAPFloatSemantics(*this); + return APValue(readAPFloat(FloatSema)); } case APValue::FixedPoint: { FixedPointSemantics FPSema = ReadFixedPointSemantics(Record, Idx); - return APValue(APFixedPoint(ReadAPInt(Record, Idx), FPSema)); + return APValue(APFixedPoint(readAPInt(), FPSema)); } case APValue::ComplexInt: { - llvm::APSInt First = ReadAPSInt(Record, Idx); - return APValue(std::move(First), ReadAPSInt(Record, Idx)); + llvm::APSInt First = readAPSInt(); + return APValue(std::move(First), readAPSInt()); } case APValue::ComplexFloat: { - const llvm::fltSemantics &FloatSema1 = llvm::APFloatBase::EnumToSemantics( - static_cast<llvm::APFloatBase::Semantics>(Record[Idx++])); - llvm::APFloat First = ReadAPFloat(Record, FloatSema1, Idx); - const llvm::fltSemantics &FloatSema2 = llvm::APFloatBase::EnumToSemantics( - static_cast<llvm::APFloatBase::Semantics>(Record[Idx++])); - return APValue(std::move(First), ReadAPFloat(Record, FloatSema2, Idx)); + const llvm::fltSemantics &FloatSema1 = readAPFloatSemantics(*this); + llvm::APFloat First = readAPFloat(FloatSema1); + const llvm::fltSemantics &FloatSema2 = readAPFloatSemantics(*this); + return APValue(std::move(First), readAPFloat(FloatSema2)); } case APValue::LValue: case APValue::Vector: @@ -9641,26 +8864,9 @@ APValue ASTReader::ReadAPValue(const RecordData &Record, unsigned &Idx) { llvm_unreachable("Invalid APValue::ValueKind"); } -/// Read an integral value -llvm::APInt ASTReader::ReadAPInt(const RecordData &Record, unsigned &Idx) { - unsigned BitWidth = Record[Idx++]; - unsigned NumWords = llvm::APInt::getNumWords(BitWidth); - llvm::APInt Result(BitWidth, NumWords, &Record[Idx]); - Idx += NumWords; - return Result; -} - -/// Read a signed integral value -llvm::APSInt ASTReader::ReadAPSInt(const RecordData &Record, unsigned &Idx) { - bool isUnsigned = Record[Idx++]; - return llvm::APSInt(ReadAPInt(Record, Idx), isUnsigned); -} - /// Read a floating-point value -llvm::APFloat ASTReader::ReadAPFloat(const RecordData &Record, - const llvm::fltSemantics &Sem, - unsigned &Idx) { - return llvm::APFloat(Sem, ReadAPInt(Record, Idx)); +llvm::APFloat ASTRecordReader::readAPFloat(const llvm::fltSemantics &Sem) { + return llvm::APFloat(Sem, readAPInt()); } // Read a string @@ -10888,14 +10094,22 @@ void ASTReader::diagnoseOdrViolations() { } if (IsFirstBitField && IsSecondBitField) { - ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), - FieldDifferentWidthBitField) - << FirstII << FirstField->getBitWidth()->getSourceRange(); - ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(), - FieldDifferentWidthBitField) - << SecondII << SecondField->getBitWidth()->getSourceRange(); - Diagnosed = true; - break; + unsigned FirstBitWidthHash = + ComputeODRHash(FirstField->getBitWidth()); + unsigned SecondBitWidthHash = + ComputeODRHash(SecondField->getBitWidth()); + if (FirstBitWidthHash != SecondBitWidthHash) { + ODRDiagError(FirstField->getLocation(), + FirstField->getSourceRange(), + FieldDifferentWidthBitField) + << FirstII << FirstField->getBitWidth()->getSourceRange(); + ODRDiagNote(SecondField->getLocation(), + SecondField->getSourceRange(), + FieldDifferentWidthBitField) + << SecondII << SecondField->getBitWidth()->getSourceRange(); + Diagnosed = true; + break; + } } const bool IsFirstMutable = FirstField->isMutable(); @@ -12268,6 +11482,31 @@ Expected<unsigned> ASTRecordReader::readRecord(llvm::BitstreamCursor &Cursor, //// OMPClauseReader implementation ////===----------------------------------------------------------------------===// +// This has to be in namespace clang because it's friended by all +// of the OMP clauses. +namespace clang { + +class OMPClauseReader : public OMPClauseVisitor<OMPClauseReader> { + ASTRecordReader &Record; + ASTContext &Context; + +public: + OMPClauseReader(ASTRecordReader &Record) + : Record(Record), Context(Record.getContext()) {} + +#define OPENMP_CLAUSE(Name, Class) void Visit##Class(Class *C); +#include "clang/Basic/OpenMPKinds.def" + OMPClause *readClause(); + void VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C); + void VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C); +}; + +} // end namespace clang + +OMPClause *ASTRecordReader::readOMPClause() { + return OMPClauseReader(*this).readClause(); +} + OMPClause *OMPClauseReader::readClause() { OMPClause *C = nullptr; switch (Record.readInt()) { @@ -12469,6 +11708,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_allocate: C = OMPAllocateClause::CreateEmpty(Context, Record.readInt()); break; + case OMPC_nontemporal: + C = OMPNontemporalClause::CreateEmpty(Context, Record.readInt()); + break; } assert(C && "Unknown OMPClause type"); @@ -12538,8 +11780,7 @@ void OMPClauseReader::VisitOMPDefaultClause(OMPDefaultClause *C) { } void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) { - C->setProcBindKind( - static_cast<OpenMPProcBindClauseKind>(Record.readInt())); + C->setProcBindKind(static_cast<llvm::omp::ProcBindKind>(Record.readInt())); C->setLParenLoc(Record.readSourceLocation()); C->setProcBindKindKwLoc(Record.readSourceLocation()); } @@ -12646,6 +11887,9 @@ void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { void OMPClauseReader::VisitOMPLastprivateClause(OMPLastprivateClause *C) { VisitOMPClauseWithPostUpdate(C); C->setLParenLoc(Record.readSourceLocation()); + C->setKind(Record.readEnum<OpenMPLastprivateModifier>()); + C->setKindLoc(Record.readSourceLocation()); + C->setColonLoc(Record.readSourceLocation()); unsigned NumVars = C->varlist_size(); SmallVector<Expr *, 16> Vars; Vars.reserve(NumVars); @@ -12685,8 +11929,7 @@ void OMPClauseReader::VisitOMPReductionClause(OMPReductionClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc(); - DeclarationNameInfo DNI; - Record.readDeclarationNameInfo(DNI); + DeclarationNameInfo DNI = Record.readDeclarationNameInfo(); C->setQualifierLoc(NNSL); C->setNameInfo(DNI); @@ -12719,8 +11962,7 @@ void OMPClauseReader::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc(); - DeclarationNameInfo DNI; - Record.readDeclarationNameInfo(DNI); + DeclarationNameInfo DNI = Record.readDeclarationNameInfo(); C->setQualifierLoc(NNSL); C->setNameInfo(DNI); @@ -12753,8 +11995,7 @@ void OMPClauseReader::VisitOMPInReductionClause(OMPInReductionClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setColonLoc(Record.readSourceLocation()); NestedNameSpecifierLoc NNSL = Record.readNestedNameSpecifierLoc(); - DeclarationNameInfo DNI; - Record.readDeclarationNameInfo(DNI); + DeclarationNameInfo DNI = Record.readDeclarationNameInfo(); C->setQualifierLoc(NNSL); C->setNameInfo(DNI); @@ -12918,9 +12159,7 @@ void OMPClauseReader::VisitOMPMapClause(OMPMapClause *C) { C->setMapTypeModifierLoc(I, Record.readSourceLocation()); } C->setMapperQualifierLoc(Record.readNestedNameSpecifierLoc()); - DeclarationNameInfo DNI; - Record.readDeclarationNameInfo(DNI); - C->setMapperIdInfo(DNI); + C->setMapperIdInfo(Record.readDeclarationNameInfo()); C->setMapType( static_cast<OpenMPMapClauseKind>(Record.readInt())); C->setMapLoc(Record.readSourceLocation()); @@ -13041,9 +12280,7 @@ void OMPClauseReader::VisitOMPDefaultmapClause(OMPDefaultmapClause *C) { void OMPClauseReader::VisitOMPToClause(OMPToClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setMapperQualifierLoc(Record.readNestedNameSpecifierLoc()); - DeclarationNameInfo DNI; - Record.readDeclarationNameInfo(DNI); - C->setMapperIdInfo(DNI); + C->setMapperIdInfo(Record.readDeclarationNameInfo()); auto NumVars = C->varlist_size(); auto UniqueDecls = C->getUniqueDeclarationsNum(); auto TotalLists = C->getTotalComponentListNum(); @@ -13093,9 +12330,7 @@ void OMPClauseReader::VisitOMPToClause(OMPToClause *C) { void OMPClauseReader::VisitOMPFromClause(OMPFromClause *C) { C->setLParenLoc(Record.readSourceLocation()); C->setMapperQualifierLoc(Record.readNestedNameSpecifierLoc()); - DeclarationNameInfo DNI; - Record.readDeclarationNameInfo(DNI); - C->setMapperIdInfo(DNI); + C->setMapperIdInfo(Record.readDeclarationNameInfo()); auto NumVars = C->varlist_size(); auto UniqueDecls = C->getUniqueDeclarationsNum(); auto TotalLists = C->getTotalComponentListNum(); @@ -13234,3 +12469,18 @@ void OMPClauseReader::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { } C->setComponents(Components, ListSizes); } + +void OMPClauseReader::VisitOMPNontemporalClause(OMPNontemporalClause *C) { + C->setLParenLoc(Record.readSourceLocation()); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setVarRefs(Vars); + Vars.clear(); + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Record.readSubExpr()); + C->setPrivateRefs(Vars); +} diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 9aa8c77c6231..96a7d5ae0a31 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// // -// This file implements the ASTReader::ReadDeclRecord method, which is the +// This file implements the ASTReader::readDeclRecord method, which is the // entrypoint for loading a decl. // //===----------------------------------------------------------------------===// @@ -48,9 +48,9 @@ #include "clang/Basic/Specifiers.h" #include "clang/Sema/IdentifierResolver.h" #include "clang/Serialization/ASTBitCodes.h" -#include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/ASTRecordReader.h" #include "clang/Serialization/ContinuousRangeMap.h" -#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFile.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/STLExtras.h" @@ -111,48 +111,40 @@ namespace clang { return Local ? Record.getGlobalBitOffset(Local) : 0; } - SourceLocation ReadSourceLocation() { + SourceLocation readSourceLocation() { return Record.readSourceLocation(); } - SourceRange ReadSourceRange() { + SourceRange readSourceRange() { return Record.readSourceRange(); } - TypeSourceInfo *GetTypeSourceInfo() { - return Record.getTypeSourceInfo(); + TypeSourceInfo *readTypeSourceInfo() { + return Record.readTypeSourceInfo(); } - serialization::DeclID ReadDeclID() { + serialization::DeclID readDeclID() { return Record.readDeclID(); } - std::string ReadString() { + std::string readString() { return Record.readString(); } - void ReadDeclIDList(SmallVectorImpl<DeclID> &IDs) { + void readDeclIDList(SmallVectorImpl<DeclID> &IDs) { for (unsigned I = 0, Size = Record.readInt(); I != Size; ++I) - IDs.push_back(ReadDeclID()); + IDs.push_back(readDeclID()); } - Decl *ReadDecl() { + Decl *readDecl() { return Record.readDecl(); } template<typename T> - T *ReadDeclAs() { + T *readDeclAs() { return Record.readDeclAs<T>(); } - void ReadQualifierInfo(QualifierInfo &Info) { - Record.readQualifierInfo(Info); - } - - void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc, DeclarationName Name) { - Record.readDeclarationNameLoc(DNLoc, Name); - } - serialization::SubmoduleID readSubmoduleID() { if (Record.getIdx() == Record.size()) return 0; @@ -405,6 +397,7 @@ namespace clang { void VisitBlockDecl(BlockDecl *BD); void VisitCapturedDecl(CapturedDecl *CD); void VisitEmptyDecl(EmptyDecl *D); + void VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D); std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC); @@ -423,6 +416,8 @@ namespace clang { template<typename T> void mergeMergeable(Mergeable<T> *D); + void mergeMergeable(LifetimeExtendedTemporaryDecl *D); + void mergeTemplatePattern(RedeclarableTemplateDecl *D, RedeclarableTemplateDecl *Existing, DeclID DsID, bool IsKeyDecl); @@ -506,8 +501,12 @@ uint64_t ASTDeclReader::GetCurrentCursorOffset() { } void ASTDeclReader::ReadFunctionDefinition(FunctionDecl *FD) { - if (Record.readInt()) + if (Record.readInt()) { Reader.DefinitionSource[FD] = Loc.F->Kind == ModuleKind::MK_MainFile; + if (Reader.getContext().getLangOpts().BuildingPCHWithObjectFile && + Reader.DeclIsFromPCHWithObjectFile(FD)) + Reader.DefinitionSource[FD] = true; + } if (auto *CD = dyn_cast<CXXConstructorDecl>(FD)) { CD->setNumCtorInitializers(Record.readInt()); if (CD->getNumCtorInitializers()) @@ -562,8 +561,8 @@ void ASTDeclReader::VisitDecl(Decl *D) { // example, a function parameter can be used in decltype() in trailing // return type of the function). Use the translation unit DeclContext as a // placeholder. - GlobalDeclID SemaDCIDForTemplateParmDecl = ReadDeclID(); - GlobalDeclID LexicalDCIDForTemplateParmDecl = ReadDeclID(); + GlobalDeclID SemaDCIDForTemplateParmDecl = readDeclID(); + GlobalDeclID LexicalDCIDForTemplateParmDecl = readDeclID(); if (!LexicalDCIDForTemplateParmDecl) LexicalDCIDForTemplateParmDecl = SemaDCIDForTemplateParmDecl; Reader.addPendingDeclContextInfo(D, @@ -571,8 +570,8 @@ void ASTDeclReader::VisitDecl(Decl *D) { LexicalDCIDForTemplateParmDecl); D->setDeclContext(Reader.getContext().getTranslationUnitDecl()); } else { - auto *SemaDC = ReadDeclAs<DeclContext>(); - auto *LexicalDC = ReadDeclAs<DeclContext>(); + auto *SemaDC = readDeclAs<DeclContext>(); + auto *LexicalDC = readDeclAs<DeclContext>(); if (!LexicalDC) LexicalDC = SemaDC; DeclContext *MergedSemaDC = Reader.MergedDeclContexts.lookup(SemaDC); @@ -628,22 +627,22 @@ void ASTDeclReader::VisitDecl(Decl *D) { void ASTDeclReader::VisitPragmaCommentDecl(PragmaCommentDecl *D) { VisitDecl(D); - D->setLocation(ReadSourceLocation()); + D->setLocation(readSourceLocation()); D->CommentKind = (PragmaMSCommentKind)Record.readInt(); - std::string Arg = ReadString(); + std::string Arg = readString(); memcpy(D->getTrailingObjects<char>(), Arg.data(), Arg.size()); D->getTrailingObjects<char>()[Arg.size()] = '\0'; } void ASTDeclReader::VisitPragmaDetectMismatchDecl(PragmaDetectMismatchDecl *D) { VisitDecl(D); - D->setLocation(ReadSourceLocation()); - std::string Name = ReadString(); + D->setLocation(readSourceLocation()); + std::string Name = readString(); memcpy(D->getTrailingObjects<char>(), Name.data(), Name.size()); D->getTrailingObjects<char>()[Name.size()] = '\0'; D->ValueStart = Name.size() + 1; - std::string Value = ReadString(); + std::string Value = readString(); memcpy(D->getTrailingObjects<char>() + D->ValueStart, Value.data(), Value.size()); D->getTrailingObjects<char>()[D->ValueStart + Value.size()] = '\0'; @@ -661,7 +660,7 @@ void ASTDeclReader::VisitNamedDecl(NamedDecl *ND) { void ASTDeclReader::VisitTypeDecl(TypeDecl *TD) { VisitNamedDecl(TD); - TD->setLocStart(ReadSourceLocation()); + TD->setLocStart(readSourceLocation()); // Delay type reading until after we have fully initialized the decl. DeferredTypeID = Record.getGlobalTypeID(Record.readInt()); } @@ -670,7 +669,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) { RedeclarableResult Redecl = VisitRedeclarable(TD); VisitTypeDecl(TD); - TypeSourceInfo *TInfo = GetTypeSourceInfo(); + TypeSourceInfo *TInfo = readTypeSourceInfo(); if (Record.readInt()) { // isModed QualType modedT = Record.readType(); TD->setModedTypeSourceInfo(TInfo, modedT); @@ -680,7 +679,7 @@ ASTDeclReader::VisitTypedefNameDecl(TypedefNameDecl *TD) { // linkage, if it exists. We cannot rely on our type to pull in this decl, // because it might have been merged with a type from another module and // thus might not refer to our version of the declaration. - ReadDecl(); + readDecl(); return Redecl; } @@ -691,7 +690,7 @@ void ASTDeclReader::VisitTypedefDecl(TypedefDecl *TD) { void ASTDeclReader::VisitTypeAliasDecl(TypeAliasDecl *TD) { RedeclarableResult Redecl = VisitTypedefNameDecl(TD); - if (auto *Template = ReadDeclAs<TypeAliasTemplateDecl>()) + if (auto *Template = readDeclAs<TypeAliasTemplateDecl>()) // Merged when we merge the template. TD->setDescribedAliasTemplate(Template); else @@ -709,20 +708,20 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) { TD->setEmbeddedInDeclarator(Record.readInt()); TD->setFreeStanding(Record.readInt()); TD->setCompleteDefinitionRequired(Record.readInt()); - TD->setBraceRange(ReadSourceRange()); + TD->setBraceRange(readSourceRange()); switch (Record.readInt()) { case 0: break; case 1: { // ExtInfo auto *Info = new (Reader.getContext()) TagDecl::ExtInfo(); - ReadQualifierInfo(*Info); + Record.readQualifierInfo(*Info); TD->TypedefNameDeclOrQualifier = Info; break; } case 2: // TypedefNameForAnonDecl - NamedDeclForTagDecl = ReadDeclID(); - TypedefNameForLinkage = Record.getIdentifierInfo(); + NamedDeclForTagDecl = readDeclID(); + TypedefNameForLinkage = Record.readIdentifier(); break; default: llvm_unreachable("unexpected tag info kind"); @@ -735,7 +734,7 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitTagDecl(TagDecl *TD) { void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) { VisitTagDecl(ED); - if (TypeSourceInfo *TI = GetTypeSourceInfo()) + if (TypeSourceInfo *TI = readTypeSourceInfo()) ED->setIntegerTypeSourceInfo(TI); else ED->setIntegerType(Record.readType()); @@ -776,9 +775,9 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) { } } - if (auto *InstED = ReadDeclAs<EnumDecl>()) { + if (auto *InstED = readDeclAs<EnumDecl>()) { auto TSK = (TemplateSpecializationKind)Record.readInt(); - SourceLocation POI = ReadSourceLocation(); + SourceLocation POI = readSourceLocation(); ED->setInstantiationOfMemberEnum(Reader.getContext(), InstED, TSK); ED->getMemberSpecializationInfo()->setPointOfInstantiation(POI); } @@ -823,10 +822,11 @@ void ASTDeclReader::VisitEnumConstantDecl(EnumConstantDecl *ECD) { void ASTDeclReader::VisitDeclaratorDecl(DeclaratorDecl *DD) { VisitValueDecl(DD); - DD->setInnerLocStart(ReadSourceLocation()); + DD->setInnerLocStart(readSourceLocation()); if (Record.readInt()) { // hasExtInfo auto *Info = new (Reader.getContext()) DeclaratorDecl::ExtInfo(); - ReadQualifierInfo(*Info); + Record.readQualifierInfo(*Info); + Info->TrailingRequiresClause = Record.readExpr(); DD->DeclInfo = Info; } QualType TSIType = Record.readType(); @@ -853,7 +853,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { } DeferredTypeID = 0; - ReadDeclarationNameLoc(FD->DNLoc, FD->getDeclName()); + FD->DNLoc = Record.readDeclarationNameLoc(FD->getDeclName()); FD->IdentifierNamespace = Record.readInt(); // FunctionDecl's body is handled last at ASTDeclReader::Visit, @@ -879,10 +879,24 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { FD->setLateTemplateParsed(Record.readInt()); FD->setCachedLinkage(static_cast<Linkage>(Record.readInt())); - FD->EndRangeLoc = ReadSourceLocation(); + FD->EndRangeLoc = readSourceLocation(); FD->ODRHash = Record.readInt(); FD->setHasODRHash(true); + FD->setUsesFPIntrin(Record.readInt()); + + if (FD->isDefaulted()) { + if (unsigned NumLookups = Record.readInt()) { + SmallVector<DeclAccessPair, 8> Lookups; + for (unsigned I = 0; I != NumLookups; ++I) { + NamedDecl *ND = Record.readDeclAs<NamedDecl>(); + AccessSpecifier AS = (AccessSpecifier)Record.readInt(); + Lookups.push_back(DeclAccessPair::make(ND, AS)); + } + FD->setDefaultedFunctionInfo(FunctionDecl::DefaultedFunctionInfo::Create( + Reader.getContext(), Lookups)); + } + } switch ((FunctionDecl::TemplatedKind)Record.readInt()) { case FunctionDecl::TK_NonTemplate: @@ -890,19 +904,19 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { break; case FunctionDecl::TK_FunctionTemplate: // Merged when we merge the template. - FD->setDescribedFunctionTemplate(ReadDeclAs<FunctionTemplateDecl>()); + FD->setDescribedFunctionTemplate(readDeclAs<FunctionTemplateDecl>()); break; case FunctionDecl::TK_MemberSpecialization: { - auto *InstFD = ReadDeclAs<FunctionDecl>(); + auto *InstFD = readDeclAs<FunctionDecl>(); auto TSK = (TemplateSpecializationKind)Record.readInt(); - SourceLocation POI = ReadSourceLocation(); + SourceLocation POI = readSourceLocation(); FD->setInstantiationOfMemberFunction(Reader.getContext(), InstFD, TSK); FD->getMemberSpecializationInfo()->setPointOfInstantiation(POI); mergeRedeclarable(FD, Redecl); break; } case FunctionDecl::TK_FunctionTemplateSpecialization: { - auto *Template = ReadDeclAs<FunctionTemplateDecl>(); + auto *Template = readDeclAs<FunctionTemplateDecl>(); auto TSK = (TemplateSpecializationKind)Record.readInt(); // Template arguments. @@ -919,11 +933,11 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { for (unsigned i = 0; i != NumTemplateArgLocs; ++i) TemplArgLocs.push_back(Record.readTemplateArgumentLoc()); - LAngleLoc = ReadSourceLocation(); - RAngleLoc = ReadSourceLocation(); + LAngleLoc = readSourceLocation(); + RAngleLoc = readSourceLocation(); } - SourceLocation POI = ReadSourceLocation(); + SourceLocation POI = readSourceLocation(); ASTContext &C = Reader.getContext(); TemplateArgumentList *TemplArgList @@ -934,9 +948,9 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { MemberSpecializationInfo *MSInfo = nullptr; if (Record.readInt()) { - auto *FD = ReadDeclAs<FunctionDecl>(); + auto *FD = readDeclAs<FunctionDecl>(); auto TSK = (TemplateSpecializationKind)Record.readInt(); - SourceLocation POI = ReadSourceLocation(); + SourceLocation POI = readSourceLocation(); MSInfo = new (C) MemberSpecializationInfo(FD, TSK); MSInfo->setPointOfInstantiation(POI); @@ -952,7 +966,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { if (FD->isCanonicalDecl()) { // if canonical add to template's set. // The template that contains the specializations set. It's not safe to // use getCanonicalDecl on Template since it may still be initializing. - auto *CanonTemplate = ReadDeclAs<FunctionTemplateDecl>(); + auto *CanonTemplate = readDeclAs<FunctionTemplateDecl>(); // Get the InsertPos by FindNodeOrInsertPos() instead of calling // InsertNode(FTInfo) directly to avoid the getASTContext() call in // FunctionTemplateSpecializationInfo's Profile(). @@ -979,15 +993,15 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { UnresolvedSet<8> TemplDecls; unsigned NumTemplates = Record.readInt(); while (NumTemplates--) - TemplDecls.addDecl(ReadDeclAs<NamedDecl>()); + TemplDecls.addDecl(readDeclAs<NamedDecl>()); // Templates args. TemplateArgumentListInfo TemplArgs; unsigned NumArgs = Record.readInt(); while (NumArgs--) TemplArgs.addArgument(Record.readTemplateArgumentLoc()); - TemplArgs.setLAngleLoc(ReadSourceLocation()); - TemplArgs.setRAngleLoc(ReadSourceLocation()); + TemplArgs.setLAngleLoc(readSourceLocation()); + TemplArgs.setRAngleLoc(readSourceLocation()); FD->setDependentTemplateSpecialization(Reader.getContext(), TemplDecls, TemplArgs); @@ -1002,7 +1016,7 @@ void ASTDeclReader::VisitFunctionDecl(FunctionDecl *FD) { SmallVector<ParmVarDecl *, 16> Params; Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) - Params.push_back(ReadDeclAs<ParmVarDecl>()); + Params.push_back(readDeclAs<ParmVarDecl>()); FD->setParams(Reader.getContext(), Params); } @@ -1013,12 +1027,13 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { // definitions rarely show up in headers. Reader.PendingBodies[MD] = GetCurrentCursorOffset(); HasPendingBody = true; - MD->setSelfDecl(ReadDeclAs<ImplicitParamDecl>()); - MD->setCmdDecl(ReadDeclAs<ImplicitParamDecl>()); } + MD->setSelfDecl(readDeclAs<ImplicitParamDecl>()); + MD->setCmdDecl(readDeclAs<ImplicitParamDecl>()); MD->setInstanceMethod(Record.readInt()); MD->setVariadic(Record.readInt()); MD->setPropertyAccessor(Record.readInt()); + MD->setSynthesizedAccessorStub(Record.readInt()); MD->setDefined(Record.readInt()); MD->setOverriding(Record.readInt()); MD->setHasSkippedBody(Record.readInt()); @@ -1027,26 +1042,26 @@ void ASTDeclReader::VisitObjCMethodDecl(ObjCMethodDecl *MD) { MD->setHasRedeclaration(Record.readInt()); if (MD->hasRedeclaration()) Reader.getContext().setObjCMethodRedeclaration(MD, - ReadDeclAs<ObjCMethodDecl>()); + readDeclAs<ObjCMethodDecl>()); MD->setDeclImplementation((ObjCMethodDecl::ImplementationControl)Record.readInt()); MD->setObjCDeclQualifier((Decl::ObjCDeclQualifier)Record.readInt()); MD->setRelatedResultType(Record.readInt()); MD->setReturnType(Record.readType()); - MD->setReturnTypeSourceInfo(GetTypeSourceInfo()); - MD->DeclEndLoc = ReadSourceLocation(); + MD->setReturnTypeSourceInfo(readTypeSourceInfo()); + MD->DeclEndLoc = readSourceLocation(); unsigned NumParams = Record.readInt(); SmallVector<ParmVarDecl *, 16> Params; Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) - Params.push_back(ReadDeclAs<ParmVarDecl>()); + Params.push_back(readDeclAs<ParmVarDecl>()); MD->setSelLocsKind((SelectorLocationsKind)Record.readInt()); unsigned NumStoredSelLocs = Record.readInt(); SmallVector<SourceLocation, 16> SelLocs; SelLocs.reserve(NumStoredSelLocs); for (unsigned i = 0; i != NumStoredSelLocs; ++i) - SelLocs.push_back(ReadSourceLocation()); + SelLocs.push_back(readSourceLocation()); MD->setParamsAndSelLocs(Reader.getContext(), Params, SelLocs); } @@ -1056,14 +1071,14 @@ void ASTDeclReader::VisitObjCTypeParamDecl(ObjCTypeParamDecl *D) { D->Variance = Record.readInt(); D->Index = Record.readInt(); - D->VarianceLoc = ReadSourceLocation(); - D->ColonLoc = ReadSourceLocation(); + D->VarianceLoc = readSourceLocation(); + D->ColonLoc = readSourceLocation(); } void ASTDeclReader::VisitObjCContainerDecl(ObjCContainerDecl *CD) { VisitNamedDecl(CD); - CD->setAtStartLoc(ReadSourceLocation()); - CD->setAtEndRange(ReadSourceRange()); + CD->setAtStartLoc(readSourceLocation()); + CD->setAtEndRange(readSourceRange()); } ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() { @@ -1074,15 +1089,15 @@ ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() { SmallVector<ObjCTypeParamDecl *, 4> typeParams; typeParams.reserve(numParams); for (unsigned i = 0; i != numParams; ++i) { - auto *typeParam = ReadDeclAs<ObjCTypeParamDecl>(); + auto *typeParam = readDeclAs<ObjCTypeParamDecl>(); if (!typeParam) return nullptr; typeParams.push_back(typeParam); } - SourceLocation lAngleLoc = ReadSourceLocation(); - SourceLocation rAngleLoc = ReadSourceLocation(); + SourceLocation lAngleLoc = readSourceLocation(); + SourceLocation rAngleLoc = readSourceLocation(); return ObjCTypeParamList::create(Reader.getContext(), lAngleLoc, typeParams, rAngleLoc); @@ -1091,9 +1106,9 @@ ObjCTypeParamList *ASTDeclReader::ReadObjCTypeParamList() { void ASTDeclReader::ReadObjCDefinitionData( struct ObjCInterfaceDecl::DefinitionData &Data) { // Read the superclass. - Data.SuperClassTInfo = GetTypeSourceInfo(); + Data.SuperClassTInfo = readTypeSourceInfo(); - Data.EndLoc = ReadSourceLocation(); + Data.EndLoc = readSourceLocation(); Data.HasDesignatedInitializers = Record.readInt(); // Read the directly referenced protocols and their SourceLocations. @@ -1101,11 +1116,11 @@ void ASTDeclReader::ReadObjCDefinitionData( SmallVector<ObjCProtocolDecl *, 16> Protocols; Protocols.reserve(NumProtocols); for (unsigned I = 0; I != NumProtocols; ++I) - Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>()); + Protocols.push_back(readDeclAs<ObjCProtocolDecl>()); SmallVector<SourceLocation, 16> ProtoLocs; ProtoLocs.reserve(NumProtocols); for (unsigned I = 0; I != NumProtocols; ++I) - ProtoLocs.push_back(ReadSourceLocation()); + ProtoLocs.push_back(readSourceLocation()); Data.ReferencedProtocols.set(Protocols.data(), NumProtocols, ProtoLocs.data(), Reader.getContext()); @@ -1114,7 +1129,7 @@ void ASTDeclReader::ReadObjCDefinitionData( Protocols.clear(); Protocols.reserve(NumProtocols); for (unsigned I = 0; I != NumProtocols; ++I) - Protocols.push_back(ReadDeclAs<ObjCProtocolDecl>()); + Protocols.push_back(readDeclAs<ObjCProtocolDecl>()); Data.AllReferencedProtocols.set(Protocols.data(), NumProtocols, Reader.getContext()); } @@ -1176,11 +1191,11 @@ void ASTDeclReader::ReadObjCDefinitionData( SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>()); + ProtoRefs.push_back(readDeclAs<ObjCProtocolDecl>()); SmallVector<SourceLocation, 16> ProtoLocs; ProtoLocs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoLocs.push_back(ReadSourceLocation()); + ProtoLocs.push_back(readSourceLocation()); Data.ReferencedProtocols.set(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), Reader.getContext()); } @@ -1225,26 +1240,26 @@ void ASTDeclReader::VisitObjCAtDefsFieldDecl(ObjCAtDefsFieldDecl *FD) { void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { VisitObjCContainerDecl(CD); - CD->setCategoryNameLoc(ReadSourceLocation()); - CD->setIvarLBraceLoc(ReadSourceLocation()); - CD->setIvarRBraceLoc(ReadSourceLocation()); + CD->setCategoryNameLoc(readSourceLocation()); + CD->setIvarLBraceLoc(readSourceLocation()); + CD->setIvarRBraceLoc(readSourceLocation()); // Note that this category has been deserialized. We do this before // deserializing the interface declaration, so that it will consider this /// category. Reader.CategoriesDeserialized.insert(CD); - CD->ClassInterface = ReadDeclAs<ObjCInterfaceDecl>(); + CD->ClassInterface = readDeclAs<ObjCInterfaceDecl>(); CD->TypeParamList = ReadObjCTypeParamList(); unsigned NumProtoRefs = Record.readInt(); SmallVector<ObjCProtocolDecl *, 16> ProtoRefs; ProtoRefs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoRefs.push_back(ReadDeclAs<ObjCProtocolDecl>()); + ProtoRefs.push_back(readDeclAs<ObjCProtocolDecl>()); SmallVector<SourceLocation, 16> ProtoLocs; ProtoLocs.reserve(NumProtoRefs); for (unsigned I = 0; I != NumProtoRefs; ++I) - ProtoLocs.push_back(ReadSourceLocation()); + ProtoLocs.push_back(readSourceLocation()); CD->setProtocolList(ProtoRefs.data(), NumProtoRefs, ProtoLocs.data(), Reader.getContext()); @@ -1257,15 +1272,15 @@ void ASTDeclReader::VisitObjCCategoryDecl(ObjCCategoryDecl *CD) { void ASTDeclReader::VisitObjCCompatibleAliasDecl(ObjCCompatibleAliasDecl *CAD) { VisitNamedDecl(CAD); - CAD->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>()); + CAD->setClassInterface(readDeclAs<ObjCInterfaceDecl>()); } void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { VisitNamedDecl(D); - D->setAtLoc(ReadSourceLocation()); - D->setLParenLoc(ReadSourceLocation()); + D->setAtLoc(readSourceLocation()); + D->setLParenLoc(readSourceLocation()); QualType T = Record.readType(); - TypeSourceInfo *TSI = GetTypeSourceInfo(); + TypeSourceInfo *TSI = readTypeSourceInfo(); D->setType(T, TSI); D->setPropertyAttributes( (ObjCPropertyDecl::PropertyAttributeKind)Record.readInt()); @@ -1274,32 +1289,32 @@ void ASTDeclReader::VisitObjCPropertyDecl(ObjCPropertyDecl *D) { D->setPropertyImplementation( (ObjCPropertyDecl::PropertyControl)Record.readInt()); DeclarationName GetterName = Record.readDeclarationName(); - SourceLocation GetterLoc = ReadSourceLocation(); + SourceLocation GetterLoc = readSourceLocation(); D->setGetterName(GetterName.getObjCSelector(), GetterLoc); DeclarationName SetterName = Record.readDeclarationName(); - SourceLocation SetterLoc = ReadSourceLocation(); + SourceLocation SetterLoc = readSourceLocation(); D->setSetterName(SetterName.getObjCSelector(), SetterLoc); - D->setGetterMethodDecl(ReadDeclAs<ObjCMethodDecl>()); - D->setSetterMethodDecl(ReadDeclAs<ObjCMethodDecl>()); - D->setPropertyIvarDecl(ReadDeclAs<ObjCIvarDecl>()); + D->setGetterMethodDecl(readDeclAs<ObjCMethodDecl>()); + D->setSetterMethodDecl(readDeclAs<ObjCMethodDecl>()); + D->setPropertyIvarDecl(readDeclAs<ObjCIvarDecl>()); } void ASTDeclReader::VisitObjCImplDecl(ObjCImplDecl *D) { VisitObjCContainerDecl(D); - D->setClassInterface(ReadDeclAs<ObjCInterfaceDecl>()); + D->setClassInterface(readDeclAs<ObjCInterfaceDecl>()); } void ASTDeclReader::VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D) { VisitObjCImplDecl(D); - D->CategoryNameLoc = ReadSourceLocation(); + D->CategoryNameLoc = readSourceLocation(); } void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { VisitObjCImplDecl(D); - D->setSuperClass(ReadDeclAs<ObjCInterfaceDecl>()); - D->SuperLoc = ReadSourceLocation(); - D->setIvarLBraceLoc(ReadSourceLocation()); - D->setIvarRBraceLoc(ReadSourceLocation()); + D->setSuperClass(readDeclAs<ObjCInterfaceDecl>()); + D->SuperLoc = readSourceLocation(); + D->setIvarLBraceLoc(readSourceLocation()); + D->setIvarRBraceLoc(readSourceLocation()); D->setHasNonZeroConstructors(Record.readInt()); D->setHasDestructors(Record.readInt()); D->NumIvarInitializers = Record.readInt(); @@ -1309,10 +1324,12 @@ void ASTDeclReader::VisitObjCImplementationDecl(ObjCImplementationDecl *D) { void ASTDeclReader::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { VisitDecl(D); - D->setAtLoc(ReadSourceLocation()); - D->setPropertyDecl(ReadDeclAs<ObjCPropertyDecl>()); - D->PropertyIvarDecl = ReadDeclAs<ObjCIvarDecl>(); - D->IvarLoc = ReadSourceLocation(); + D->setAtLoc(readSourceLocation()); + D->setPropertyDecl(readDeclAs<ObjCPropertyDecl>()); + D->PropertyIvarDecl = readDeclAs<ObjCIvarDecl>(); + D->IvarLoc = readSourceLocation(); + D->setGetterMethodDecl(readDeclAs<ObjCMethodDecl>()); + D->setSetterMethodDecl(readDeclAs<ObjCMethodDecl>()); D->setGetterCXXConstructor(Record.readExpr()); D->setSetterCXXAssignment(Record.readExpr()); } @@ -1332,7 +1349,7 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { FD->setBitWidth(BW); if (!FD->getDeclName()) { - if (auto *Tmpl = ReadDeclAs<FieldDecl>()) + if (auto *Tmpl = readDeclAs<FieldDecl>()) Reader.getContext().setInstantiatedFromUnnamedFieldDecl(FD, Tmpl); } mergeMergeable(FD); @@ -1340,8 +1357,8 @@ void ASTDeclReader::VisitFieldDecl(FieldDecl *FD) { void ASTDeclReader::VisitMSPropertyDecl(MSPropertyDecl *PD) { VisitDeclaratorDecl(PD); - PD->GetterId = Record.getIdentifierInfo(); - PD->SetterId = Record.getIdentifierInfo(); + PD->GetterId = Record.readIdentifier(); + PD->SetterId = Record.readIdentifier(); } void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { @@ -1352,7 +1369,7 @@ void ASTDeclReader::VisitIndirectFieldDecl(IndirectFieldDecl *FD) { FD->Chaining = new (Reader.getContext())NamedDecl*[FD->ChainingSize]; for (unsigned I = 0; I != FD->ChainingSize; ++I) - FD->Chaining[I] = ReadDeclAs<NamedDecl>(); + FD->Chaining[I] = readDeclAs<NamedDecl>(); mergeMergeable(FD); } @@ -1404,8 +1421,12 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { Reader.getContext().setBlockVarCopyInit(VD, CopyExpr, Record.readInt()); } - if (VD->getStorageDuration() == SD_Static && Record.readInt()) + if (VD->getStorageDuration() == SD_Static && Record.readInt()) { Reader.DefinitionSource[VD] = Loc.F->Kind == ModuleKind::MK_MainFile; + if (Reader.getContext().getLangOpts().BuildingPCHWithObjectFile && + Reader.DeclIsFromPCHWithObjectFile(VD)) + Reader.DefinitionSource[VD] = true; + } enum VarKind { VarNotTemplate = 0, VarTemplate, StaticDataMemberSpecialization @@ -1420,12 +1441,12 @@ ASTDeclReader::RedeclarableResult ASTDeclReader::VisitVarDeclImpl(VarDecl *VD) { break; case VarTemplate: // Merged when we merge the template. - VD->setDescribedVarTemplate(ReadDeclAs<VarTemplateDecl>()); + VD->setDescribedVarTemplate(readDeclAs<VarTemplateDecl>()); break; case StaticDataMemberSpecialization: { // HasMemberSpecializationInfo. - auto *Tmpl = ReadDeclAs<VarDecl>(); + auto *Tmpl = readDeclAs<VarDecl>(); auto TSK = (TemplateSpecializationKind)Record.readInt(); - SourceLocation POI = ReadSourceLocation(); + SourceLocation POI = readSourceLocation(); Reader.getContext().setInstantiatedFromStaticDataMember(VD, Tmpl, TSK,POI); mergeRedeclarable(VD, Redecl); break; @@ -1465,7 +1486,7 @@ void ASTDeclReader::VisitDecompositionDecl(DecompositionDecl *DD) { VisitVarDecl(DD); auto **BDs = DD->getTrailingObjects<BindingDecl *>(); for (unsigned I = 0; I != DD->NumBindings; ++I) { - BDs[I] = ReadDeclAs<BindingDecl>(); + BDs[I] = readDeclAs<BindingDecl>(); BDs[I]->setDecomposedDecl(DD); } } @@ -1478,18 +1499,18 @@ void ASTDeclReader::VisitBindingDecl(BindingDecl *BD) { void ASTDeclReader::VisitFileScopeAsmDecl(FileScopeAsmDecl *AD) { VisitDecl(AD); AD->setAsmString(cast<StringLiteral>(Record.readExpr())); - AD->setRParenLoc(ReadSourceLocation()); + AD->setRParenLoc(readSourceLocation()); } void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { VisitDecl(BD); BD->setBody(cast_or_null<CompoundStmt>(Record.readStmt())); - BD->setSignatureAsWritten(GetTypeSourceInfo()); + BD->setSignatureAsWritten(readTypeSourceInfo()); unsigned NumParams = Record.readInt(); SmallVector<ParmVarDecl *, 16> Params; Params.reserve(NumParams); for (unsigned I = 0; I != NumParams; ++I) - Params.push_back(ReadDeclAs<ParmVarDecl>()); + Params.push_back(readDeclAs<ParmVarDecl>()); BD->setParams(Params); BD->setIsVariadic(Record.readInt()); @@ -1503,7 +1524,7 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) { SmallVector<BlockDecl::Capture, 16> captures; captures.reserve(numCaptures); for (unsigned i = 0; i != numCaptures; ++i) { - auto *decl = ReadDeclAs<VarDecl>(); + auto *decl = readDeclAs<VarDecl>(); unsigned flags = Record.readInt(); bool byRef = (flags & 1); bool nested = (flags & 2); @@ -1521,35 +1542,35 @@ void ASTDeclReader::VisitCapturedDecl(CapturedDecl *CD) { // Body is set by VisitCapturedStmt. for (unsigned I = 0; I < CD->NumParams; ++I) { if (I != ContextParamPos) - CD->setParam(I, ReadDeclAs<ImplicitParamDecl>()); + CD->setParam(I, readDeclAs<ImplicitParamDecl>()); else - CD->setContextParam(I, ReadDeclAs<ImplicitParamDecl>()); + CD->setContextParam(I, readDeclAs<ImplicitParamDecl>()); } } void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) { VisitDecl(D); D->setLanguage((LinkageSpecDecl::LanguageIDs)Record.readInt()); - D->setExternLoc(ReadSourceLocation()); - D->setRBraceLoc(ReadSourceLocation()); + D->setExternLoc(readSourceLocation()); + D->setRBraceLoc(readSourceLocation()); } void ASTDeclReader::VisitExportDecl(ExportDecl *D) { VisitDecl(D); - D->RBraceLoc = ReadSourceLocation(); + D->RBraceLoc = readSourceLocation(); } void ASTDeclReader::VisitLabelDecl(LabelDecl *D) { VisitNamedDecl(D); - D->setLocStart(ReadSourceLocation()); + D->setLocStart(readSourceLocation()); } void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); VisitNamedDecl(D); D->setInline(Record.readInt()); - D->LocStart = ReadSourceLocation(); - D->RBraceLoc = ReadSourceLocation(); + D->LocStart = readSourceLocation(); + D->RBraceLoc = readSourceLocation(); // Defer loading the anonymous namespace until we've finished merging // this namespace; loading it might load a later declaration of the @@ -1557,7 +1578,7 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { // get merged before newer ones try to merge. GlobalDeclID AnonNamespace = 0; if (Redecl.getFirstID() == ThisDeclID) { - AnonNamespace = ReadDeclID(); + AnonNamespace = readDeclID(); } else { // Link this namespace back to the first declaration, which has already // been deserialized. @@ -1579,41 +1600,41 @@ void ASTDeclReader::VisitNamespaceDecl(NamespaceDecl *D) { void ASTDeclReader::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); VisitNamedDecl(D); - D->NamespaceLoc = ReadSourceLocation(); - D->IdentLoc = ReadSourceLocation(); + D->NamespaceLoc = readSourceLocation(); + D->IdentLoc = readSourceLocation(); D->QualifierLoc = Record.readNestedNameSpecifierLoc(); - D->Namespace = ReadDeclAs<NamedDecl>(); + D->Namespace = readDeclAs<NamedDecl>(); mergeRedeclarable(D, Redecl); } void ASTDeclReader::VisitUsingDecl(UsingDecl *D) { VisitNamedDecl(D); - D->setUsingLoc(ReadSourceLocation()); + D->setUsingLoc(readSourceLocation()); D->QualifierLoc = Record.readNestedNameSpecifierLoc(); - ReadDeclarationNameLoc(D->DNLoc, D->getDeclName()); - D->FirstUsingShadow.setPointer(ReadDeclAs<UsingShadowDecl>()); + D->DNLoc = Record.readDeclarationNameLoc(D->getDeclName()); + D->FirstUsingShadow.setPointer(readDeclAs<UsingShadowDecl>()); D->setTypename(Record.readInt()); - if (auto *Pattern = ReadDeclAs<NamedDecl>()) + if (auto *Pattern = readDeclAs<NamedDecl>()) Reader.getContext().setInstantiatedFromUsingDecl(D, Pattern); mergeMergeable(D); } void ASTDeclReader::VisitUsingPackDecl(UsingPackDecl *D) { VisitNamedDecl(D); - D->InstantiatedFrom = ReadDeclAs<NamedDecl>(); + D->InstantiatedFrom = readDeclAs<NamedDecl>(); auto **Expansions = D->getTrailingObjects<NamedDecl *>(); for (unsigned I = 0; I != D->NumExpansions; ++I) - Expansions[I] = ReadDeclAs<NamedDecl>(); + Expansions[I] = readDeclAs<NamedDecl>(); mergeMergeable(D); } void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) { RedeclarableResult Redecl = VisitRedeclarable(D); VisitNamedDecl(D); - D->Underlying = ReadDeclAs<NamedDecl>(); + D->Underlying = readDeclAs<NamedDecl>(); D->IdentifierNamespace = Record.readInt(); - D->UsingOrNextShadow = ReadDeclAs<NamedDecl>(); - auto *Pattern = ReadDeclAs<UsingShadowDecl>(); + D->UsingOrNextShadow = readDeclAs<NamedDecl>(); + auto *Pattern = readDeclAs<UsingShadowDecl>(); if (Pattern) Reader.getContext().setInstantiatedFromUsingShadowDecl(D, Pattern); mergeRedeclarable(D, Redecl); @@ -1622,35 +1643,35 @@ void ASTDeclReader::VisitUsingShadowDecl(UsingShadowDecl *D) { void ASTDeclReader::VisitConstructorUsingShadowDecl( ConstructorUsingShadowDecl *D) { VisitUsingShadowDecl(D); - D->NominatedBaseClassShadowDecl = ReadDeclAs<ConstructorUsingShadowDecl>(); - D->ConstructedBaseClassShadowDecl = ReadDeclAs<ConstructorUsingShadowDecl>(); + D->NominatedBaseClassShadowDecl = readDeclAs<ConstructorUsingShadowDecl>(); + D->ConstructedBaseClassShadowDecl = readDeclAs<ConstructorUsingShadowDecl>(); D->IsVirtual = Record.readInt(); } void ASTDeclReader::VisitUsingDirectiveDecl(UsingDirectiveDecl *D) { VisitNamedDecl(D); - D->UsingLoc = ReadSourceLocation(); - D->NamespaceLoc = ReadSourceLocation(); + D->UsingLoc = readSourceLocation(); + D->NamespaceLoc = readSourceLocation(); D->QualifierLoc = Record.readNestedNameSpecifierLoc(); - D->NominatedNamespace = ReadDeclAs<NamedDecl>(); - D->CommonAncestor = ReadDeclAs<DeclContext>(); + D->NominatedNamespace = readDeclAs<NamedDecl>(); + D->CommonAncestor = readDeclAs<DeclContext>(); } void ASTDeclReader::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { VisitValueDecl(D); - D->setUsingLoc(ReadSourceLocation()); + D->setUsingLoc(readSourceLocation()); D->QualifierLoc = Record.readNestedNameSpecifierLoc(); - ReadDeclarationNameLoc(D->DNLoc, D->getDeclName()); - D->EllipsisLoc = ReadSourceLocation(); + D->DNLoc = Record.readDeclarationNameLoc(D->getDeclName()); + D->EllipsisLoc = readSourceLocation(); mergeMergeable(D); } void ASTDeclReader::VisitUnresolvedUsingTypenameDecl( UnresolvedUsingTypenameDecl *D) { VisitTypeDecl(D); - D->TypenameLocation = ReadSourceLocation(); + D->TypenameLocation = readSourceLocation(); D->QualifierLoc = Record.readNestedNameSpecifierLoc(); - D->EllipsisLoc = ReadSourceLocation(); + D->EllipsisLoc = readSourceLocation(); mergeMergeable(D); } @@ -1664,8 +1685,12 @@ void ASTDeclReader::ReadCXXDefinitionData( Data.ODRHash = Record.readInt(); Data.HasODRHash = true; - if (Record.readInt()) + if (Record.readInt()) { Reader.DefinitionSource[D] = Loc.F->Kind == ModuleKind::MK_MainFile; + if (Reader.getContext().getLangOpts().BuildingPCHWithObjectFile && + Reader.DeclIsFromPCHWithObjectFile(D)) + Reader.DefinitionSource[D] = true; + } Data.NumBases = Record.readInt(); if (Data.NumBases) @@ -1679,7 +1704,7 @@ void ASTDeclReader::ReadCXXDefinitionData( if (Data.ComputedVisibleConversions) Record.readUnresolvedSet(Data.VisibleConversions); assert(Data.Definition && "Data.Definition should be already set!"); - Data.FirstFriend = ReadDeclID(); + Data.FirstFriend = readDeclID(); if (Data.IsLambda) { using Capture = LambdaCapture; @@ -1692,13 +1717,13 @@ void ASTDeclReader::ReadCXXDefinitionData( Lambda.NumExplicitCaptures = Record.readInt(); Lambda.HasKnownInternalLinkage = Record.readInt(); Lambda.ManglingNumber = Record.readInt(); - Lambda.ContextDecl = ReadDeclID(); + Lambda.ContextDecl = readDeclID(); Lambda.Captures = (Capture *)Reader.getContext().Allocate( sizeof(Capture) * Lambda.NumCaptures); Capture *ToCapture = Lambda.Captures; - Lambda.MethodTyInfo = GetTypeSourceInfo(); + Lambda.MethodTyInfo = readTypeSourceInfo(); for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { - SourceLocation Loc = ReadSourceLocation(); + SourceLocation Loc = readSourceLocation(); bool IsImplicit = Record.readInt(); auto Kind = static_cast<LambdaCaptureKind>(Record.readInt()); switch (Kind) { @@ -1709,8 +1734,8 @@ void ASTDeclReader::ReadCXXDefinitionData( break; case LCK_ByCopy: case LCK_ByRef: - auto *Var = ReadDeclAs<VarDecl>(); - SourceLocation EllipsisLoc = ReadSourceLocation(); + auto *Var = readDeclAs<VarDecl>(); + SourceLocation EllipsisLoc = readSourceLocation(); *ToCapture++ = Capture(Loc, IsImplicit, Kind, Var, EllipsisLoc); break; } @@ -1849,7 +1874,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) { break; case CXXRecTemplate: { // Merged when we merge the template. - auto *Template = ReadDeclAs<ClassTemplateDecl>(); + auto *Template = readDeclAs<ClassTemplateDecl>(); D->TemplateOrInstantiation = Template; if (!Template->getTemplatedDecl()) { // We've not actually loaded the ClassTemplateDecl yet, because we're @@ -1863,9 +1888,9 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) { break; } case CXXRecMemberSpecialization: { - auto *RD = ReadDeclAs<CXXRecordDecl>(); + auto *RD = readDeclAs<CXXRecordDecl>(); auto TSK = (TemplateSpecializationKind)Record.readInt(); - SourceLocation POI = ReadSourceLocation(); + SourceLocation POI = readSourceLocation(); MemberSpecializationInfo *MSI = new (C) MemberSpecializationInfo(RD, TSK); MSI->setPointOfInstantiation(POI); D->TemplateOrInstantiation = MSI; @@ -1884,7 +1909,7 @@ ASTDeclReader::VisitCXXRecordDeclImpl(CXXRecordDecl *D) { // Lazily load the key function to avoid deserializing every method so we can // compute it. if (WasDefinition) { - DeclID KeyFn = ReadDeclID(); + DeclID KeyFn = readDeclID(); if (KeyFn && D->isCompleteDefinition()) // FIXME: This is wrong for the ARM ABI, where some other module may have // made this function no longer be a key function. We need an update @@ -1909,7 +1934,7 @@ void ASTDeclReader::VisitCXXMethodDecl(CXXMethodDecl *D) { while (NumOverridenMethods--) { // Avoid invariant checking of CXXMethodDecl::addOverriddenMethod, // MD may be initializing. - if (auto *MD = ReadDeclAs<CXXMethodDecl>()) + if (auto *MD = readDeclAs<CXXMethodDecl>()) Reader.getContext().addOverriddenMethod(D, MD->getCanonicalDecl()); } } else { @@ -1924,8 +1949,8 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { // so we have to read it before we call VisitCXXMethodDecl. D->setExplicitSpecifier(Record.readExplicitSpec()); if (D->isInheritingConstructor()) { - auto *Shadow = ReadDeclAs<ConstructorUsingShadowDecl>(); - auto *Ctor = ReadDeclAs<CXXConstructorDecl>(); + auto *Shadow = readDeclAs<ConstructorUsingShadowDecl>(); + auto *Ctor = readDeclAs<CXXConstructorDecl>(); *D->getTrailingObjects<InheritedConstructor>() = InheritedConstructor(Shadow, Ctor); } @@ -1936,7 +1961,7 @@ void ASTDeclReader::VisitCXXConstructorDecl(CXXConstructorDecl *D) { void ASTDeclReader::VisitCXXDestructorDecl(CXXDestructorDecl *D) { VisitCXXMethodDecl(D); - if (auto *OperatorDelete = ReadDeclAs<FunctionDecl>()) { + if (auto *OperatorDelete = readDeclAs<FunctionDecl>()) { CXXDestructorDecl *Canon = D->getCanonicalDecl(); auto *ThisArg = Record.readExpr(); // FIXME: Check consistency if we have an old and new operator delete. @@ -1958,27 +1983,27 @@ void ASTDeclReader::VisitImportDecl(ImportDecl *D) { D->ImportedAndComplete.setInt(Record.readInt()); auto *StoredLocs = D->getTrailingObjects<SourceLocation>(); for (unsigned I = 0, N = Record.back(); I != N; ++I) - StoredLocs[I] = ReadSourceLocation(); + StoredLocs[I] = readSourceLocation(); Record.skipInts(1); // The number of stored source locations. } void ASTDeclReader::VisitAccessSpecDecl(AccessSpecDecl *D) { VisitDecl(D); - D->setColonLoc(ReadSourceLocation()); + D->setColonLoc(readSourceLocation()); } void ASTDeclReader::VisitFriendDecl(FriendDecl *D) { VisitDecl(D); if (Record.readInt()) // hasFriendDecl - D->Friend = ReadDeclAs<NamedDecl>(); + D->Friend = readDeclAs<NamedDecl>(); else - D->Friend = GetTypeSourceInfo(); + D->Friend = readTypeSourceInfo(); for (unsigned i = 0; i != D->NumTPLists; ++i) D->getTrailingObjects<TemplateParameterList *>()[i] = Record.readTemplateParameterList(); - D->NextFriend = ReadDeclID(); + D->NextFriend = readDeclID(); D->UnsupportedFriend = (Record.readInt() != 0); - D->FriendLoc = ReadSourceLocation(); + D->FriendLoc = readSourceLocation(); } void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) { @@ -1989,16 +2014,16 @@ void ASTDeclReader::VisitFriendTemplateDecl(FriendTemplateDecl *D) { for (unsigned i = 0; i != NumParams; ++i) D->Params[i] = Record.readTemplateParameterList(); if (Record.readInt()) // HasFriendDecl - D->Friend = ReadDeclAs<NamedDecl>(); + D->Friend = readDeclAs<NamedDecl>(); else - D->Friend = GetTypeSourceInfo(); - D->FriendLoc = ReadSourceLocation(); + D->Friend = readTypeSourceInfo(); + D->FriendLoc = readSourceLocation(); } DeclID ASTDeclReader::VisitTemplateDecl(TemplateDecl *D) { VisitNamedDecl(D); - DeclID PatternID = ReadDeclID(); + DeclID PatternID = readDeclID(); auto *TemplatedDecl = cast_or_null<NamedDecl>(Reader.GetDecl(PatternID)); TemplateParameterList *TemplateParams = Record.readTemplateParameterList(); D->init(TemplatedDecl, TemplateParams); @@ -2028,7 +2053,7 @@ ASTDeclReader::VisitRedeclarableTemplateDecl(RedeclarableTemplateDecl *D) { // If this is the first declaration of the template, fill in the information // for the 'common' pointer. if (ThisDeclID == Redecl.getFirstID()) { - if (auto *RTD = ReadDeclAs<RedeclarableTemplateDecl>()) { + if (auto *RTD = readDeclAs<RedeclarableTemplateDecl>()) { assert(RTD->getKind() == D->getKind() && "InstantiatedFromMemberTemplate kind mismatch"); D->setInstantiatedFromMemberTemplate(RTD); @@ -2057,7 +2082,7 @@ void ASTDeclReader::VisitClassTemplateDecl(ClassTemplateDecl *D) { // This ClassTemplateDecl owns a CommonPtr; read it to keep track of all of // the specializations. SmallVector<serialization::DeclID, 32> SpecIDs; - ReadDeclIDList(SpecIDs); + readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } @@ -2084,7 +2109,7 @@ void ASTDeclReader::VisitVarTemplateDecl(VarTemplateDecl *D) { // This VarTemplateDecl owns a CommonPtr; read it to keep track of all of // the specializations. SmallVector<serialization::DeclID, 32> SpecIDs; - ReadDeclIDList(SpecIDs); + readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } } @@ -2095,7 +2120,7 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl( RedeclarableResult Redecl = VisitCXXRecordDeclImpl(D); ASTContext &C = Reader.getContext(); - if (Decl *InstD = ReadDecl()) { + if (Decl *InstD = readDecl()) { if (auto *CTD = dyn_cast<ClassTemplateDecl>(InstD)) { D->SpecializedTemplate = CTD; } else { @@ -2116,12 +2141,12 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl( SmallVector<TemplateArgument, 8> TemplArgs; Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true); D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs); - D->PointOfInstantiation = ReadSourceLocation(); + D->PointOfInstantiation = readSourceLocation(); D->SpecializationKind = (TemplateSpecializationKind)Record.readInt(); bool writtenAsCanonicalDecl = Record.readInt(); if (writtenAsCanonicalDecl) { - auto *CanonPattern = ReadDeclAs<ClassTemplateDecl>(); + auto *CanonPattern = readDeclAs<ClassTemplateDecl>(); if (D->isCanonicalDecl()) { // It's kept in the folding set. // Set this as, or find, the canonical declaration for this specialization ClassTemplateSpecializationDecl *CanonSpec; @@ -2150,12 +2175,12 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl( } // Explicit info. - if (TypeSourceInfo *TyInfo = GetTypeSourceInfo()) { + if (TypeSourceInfo *TyInfo = readTypeSourceInfo()) { auto *ExplicitInfo = new (C) ClassTemplateSpecializationDecl::ExplicitSpecializationInfo; ExplicitInfo->TypeAsWritten = TyInfo; - ExplicitInfo->ExternLoc = ReadSourceLocation(); - ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(); + ExplicitInfo->ExternLoc = readSourceLocation(); + ExplicitInfo->TemplateKeywordLoc = readSourceLocation(); D->ExplicitInfo = ExplicitInfo; } @@ -2164,16 +2189,18 @@ ASTDeclReader::VisitClassTemplateSpecializationDeclImpl( void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { - RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D); - + // We need to read the template params first because redeclarable is going to + // need them for profiling TemplateParameterList *Params = Record.readTemplateParameterList(); D->TemplateParams = Params; D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); + RedeclarableResult Redecl = VisitClassTemplateSpecializationDeclImpl(D); + // These are read/set from/to the first declaration. if (ThisDeclID == Redecl.getFirstID()) { D->InstantiatedFromMember.setPointer( - ReadDeclAs<ClassTemplatePartialSpecializationDecl>()); + readDeclAs<ClassTemplatePartialSpecializationDecl>()); D->InstantiatedFromMember.setInt(Record.readInt()); } } @@ -2181,7 +2208,7 @@ void ASTDeclReader::VisitClassTemplatePartialSpecializationDecl( void ASTDeclReader::VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *D) { VisitDecl(D); - D->Specialization = ReadDeclAs<CXXMethodDecl>(); + D->Specialization = readDeclAs<CXXMethodDecl>(); if (Record.readInt()) D->TemplateArgs = Record.readASTTemplateArgumentListInfo(); } @@ -2192,7 +2219,7 @@ void ASTDeclReader::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { if (ThisDeclID == Redecl.getFirstID()) { // This FunctionTemplateDecl owns a CommonPtr; read it. SmallVector<serialization::DeclID, 32> SpecIDs; - ReadDeclIDList(SpecIDs); + readDeclIDList(SpecIDs); ASTDeclReader::AddLazySpecializations(D, SpecIDs); } } @@ -2208,7 +2235,7 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl( RedeclarableResult Redecl = VisitVarDeclImpl(D); ASTContext &C = Reader.getContext(); - if (Decl *InstD = ReadDecl()) { + if (Decl *InstD = readDecl()) { if (auto *VTD = dyn_cast<VarTemplateDecl>(InstD)) { D->SpecializedTemplate = VTD; } else { @@ -2227,25 +2254,25 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl( } // Explicit info. - if (TypeSourceInfo *TyInfo = GetTypeSourceInfo()) { + if (TypeSourceInfo *TyInfo = readTypeSourceInfo()) { auto *ExplicitInfo = new (C) VarTemplateSpecializationDecl::ExplicitSpecializationInfo; ExplicitInfo->TypeAsWritten = TyInfo; - ExplicitInfo->ExternLoc = ReadSourceLocation(); - ExplicitInfo->TemplateKeywordLoc = ReadSourceLocation(); + ExplicitInfo->ExternLoc = readSourceLocation(); + ExplicitInfo->TemplateKeywordLoc = readSourceLocation(); D->ExplicitInfo = ExplicitInfo; } SmallVector<TemplateArgument, 8> TemplArgs; Record.readTemplateArgumentList(TemplArgs, /*Canonicalize*/ true); D->TemplateArgs = TemplateArgumentList::CreateCopy(C, TemplArgs); - D->PointOfInstantiation = ReadSourceLocation(); + D->PointOfInstantiation = readSourceLocation(); D->SpecializationKind = (TemplateSpecializationKind)Record.readInt(); D->IsCompleteDefinition = Record.readInt(); bool writtenAsCanonicalDecl = Record.readInt(); if (writtenAsCanonicalDecl) { - auto *CanonPattern = ReadDeclAs<VarTemplateDecl>(); + auto *CanonPattern = readDeclAs<VarTemplateDecl>(); if (D->isCanonicalDecl()) { // It's kept in the folding set. // FIXME: If it's already present, merge it. if (auto *Partial = dyn_cast<VarTemplatePartialSpecializationDecl>(D)) { @@ -2267,16 +2294,16 @@ ASTDeclReader::VisitVarTemplateSpecializationDeclImpl( /// using Template(Partial)SpecializationDecl as input type. void ASTDeclReader::VisitVarTemplatePartialSpecializationDecl( VarTemplatePartialSpecializationDecl *D) { - RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D); - TemplateParameterList *Params = Record.readTemplateParameterList(); D->TemplateParams = Params; D->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); + RedeclarableResult Redecl = VisitVarTemplateSpecializationDeclImpl(D); + // These are read/set from/to the first declaration. if (ThisDeclID == Redecl.getFirstID()) { D->InstantiatedFromMember.setPointer( - ReadDeclAs<VarTemplatePartialSpecializationDecl>()); + readDeclAs<VarTemplatePartialSpecializationDecl>()); D->InstantiatedFromMember.setInt(Record.readInt()); } } @@ -2286,9 +2313,22 @@ void ASTDeclReader::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { D->setDeclaredWithTypename(Record.readInt()); - // TODO: Concepts: Immediately introduced constraint + if (Record.readInt()) { + NestedNameSpecifierLoc NNS = Record.readNestedNameSpecifierLoc(); + DeclarationNameInfo DN = Record.readDeclarationNameInfo(); + ConceptDecl *NamedConcept = cast<ConceptDecl>(Record.readDecl()); + const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr; + if (Record.readInt()) + ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); + Expr *ImmediatelyDeclaredConstraint = Record.readExpr(); + D->setTypeConstraint(NNS, DN, /*FoundDecl=*/nullptr, NamedConcept, + ArgsAsWritten, ImmediatelyDeclaredConstraint); + if ((D->ExpandedParameterPack = Record.readInt())) + D->NumExpanded = Record.readInt(); + } + if (Record.readInt()) - D->setDefaultArgument(GetTypeSourceInfo()); + D->setDefaultArgument(readTypeSourceInfo()); } void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { @@ -2301,7 +2341,7 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { D->getTrailingObjects<std::pair<QualType, TypeSourceInfo *>>(); for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { new (&TypesAndInfos[I].first) QualType(Record.readType()); - TypesAndInfos[I].second = GetTypeSourceInfo(); + TypesAndInfos[I].second = readTypeSourceInfo(); } } else { // Rest of NonTypeTemplateParmDecl. @@ -2339,13 +2379,24 @@ void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) { D->AssertExprAndFailed.setPointer(Record.readExpr()); D->AssertExprAndFailed.setInt(Record.readInt()); D->Message = cast_or_null<StringLiteral>(Record.readExpr()); - D->RParenLoc = ReadSourceLocation(); + D->RParenLoc = readSourceLocation(); } void ASTDeclReader::VisitEmptyDecl(EmptyDecl *D) { VisitDecl(D); } +void ASTDeclReader::VisitLifetimeExtendedTemporaryDecl( + LifetimeExtendedTemporaryDecl *D) { + VisitDecl(D); + D->ExtendingDecl = readDeclAs<ValueDecl>(); + D->ExprWithTemporary = Record.readStmt(); + if (Record.readInt()) + D->Value = new (D->getASTContext()) APValue(Record.readAPValue()); + D->ManglingNumber = Record.readInt(); + mergeMergeable(D); +} + std::pair<uint64_t, uint64_t> ASTDeclReader::VisitDeclContext(DeclContext *DC) { uint64_t LexicalOffset = ReadLocalOffset(); @@ -2356,7 +2407,7 @@ ASTDeclReader::VisitDeclContext(DeclContext *DC) { template <typename T> ASTDeclReader::RedeclarableResult ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { - DeclID FirstDeclID = ReadDeclID(); + DeclID FirstDeclID = readDeclID(); Decl *MergeWith = nullptr; bool IsKeyDecl = ThisDeclID == FirstDeclID; @@ -2382,13 +2433,13 @@ ASTDeclReader::VisitRedeclarable(Redeclarable<T> *D) { // FIXME: Provide a known merge target to the second and subsequent such // declaration. for (unsigned I = 0; I != N - 1; ++I) - MergeWith = ReadDecl(); + MergeWith = readDecl(); RedeclOffset = ReadLocalOffset(); } else { // This declaration was not the first local declaration. Read the first // local declaration now, to trigger the import of other redeclarations. - (void)ReadDecl(); + (void)readDecl(); } auto *FirstDecl = cast_or_null<T>(Reader.GetDecl(FirstDeclID)); @@ -2541,6 +2592,25 @@ static bool allowODRLikeMergeInC(NamedDecl *ND) { return false; } +/// Attempts to merge LifetimeExtendedTemporaryDecl with +/// identical class definitions from two different modules. +void ASTDeclReader::mergeMergeable(LifetimeExtendedTemporaryDecl *D) { + // If modules are not available, there is no reason to perform this merge. + if (!Reader.getContext().getLangOpts().Modules) + return; + + LifetimeExtendedTemporaryDecl *LETDecl = D; + + LifetimeExtendedTemporaryDecl *&LookupResult = + Reader.LETemporaryForMerging[std::make_pair( + LETDecl->getExtendingDecl(), LETDecl->getManglingNumber())]; + if (LookupResult) + Reader.getContext().setPrimaryMergedDecl(LETDecl, + LookupResult->getCanonicalDecl()); + else + LookupResult = LETDecl; +} + /// Attempts to merge the given declaration (D) with another declaration /// of the same entity, for the case where the entity is not actually /// redeclarable. This happens, for instance, when merging the fields of @@ -2588,9 +2658,8 @@ void ASTDeclReader::VisitOMPAllocateDecl(OMPAllocateDecl *D) { D->setVars(Vars); SmallVector<OMPClause *, 8> Clauses; Clauses.reserve(NumClauses); - OMPClauseReader ClauseReader(Record); for (unsigned I = 0; I != NumClauses; ++I) - Clauses.push_back(ClauseReader.readClause()); + Clauses.push_back(Record.readOMPClause()); D->setClauses(Clauses); } @@ -2599,15 +2668,14 @@ void ASTDeclReader::VisitOMPRequiresDecl(OMPRequiresDecl * D) { unsigned NumClauses = D->clauselist_size(); SmallVector<OMPClause *, 8> Clauses; Clauses.reserve(NumClauses); - OMPClauseReader ClauseReader(Record); for (unsigned I = 0; I != NumClauses; ++I) - Clauses.push_back(ClauseReader.readClause()); + Clauses.push_back(Record.readOMPClause()); D->setClauses(Clauses); } void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { VisitValueDecl(D); - D->setLocation(ReadSourceLocation()); + D->setLocation(readSourceLocation()); Expr *In = Record.readExpr(); Expr *Out = Record.readExpr(); D->setCombinerData(In, Out); @@ -2619,22 +2687,21 @@ void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { Expr *Init = Record.readExpr(); auto IK = static_cast<OMPDeclareReductionDecl::InitKind>(Record.readInt()); D->setInitializer(Init, IK); - D->PrevDeclInScope = ReadDeclID(); + D->PrevDeclInScope = readDeclID(); } void ASTDeclReader::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) { VisitValueDecl(D); - D->setLocation(ReadSourceLocation()); + D->setLocation(readSourceLocation()); Expr *MapperVarRefE = Record.readExpr(); D->setMapperVarRef(MapperVarRefE); D->VarName = Record.readDeclarationName(); - D->PrevDeclInScope = ReadDeclID(); + D->PrevDeclInScope = readDeclID(); unsigned NumClauses = D->clauselist_size(); SmallVector<OMPClause *, 8> Clauses; Clauses.reserve(NumClauses); - OMPClauseReader ClauseReader(Record); for (unsigned I = 0; I != NumClauses; ++I) - Clauses.push_back(ClauseReader.readClause()); + Clauses.push_back(Record.readOMPClause()); D->setClauses(Clauses); } @@ -2648,53 +2715,49 @@ void ASTDeclReader::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { namespace { class AttrReader { - ModuleFile *F; - ASTReader *Reader; - const ASTReader::RecordData &Record; - unsigned &Idx; + ASTRecordReader &Reader; public: - AttrReader(ModuleFile &F, ASTReader &Reader, - const ASTReader::RecordData &Record, unsigned &Idx) - : F(&F), Reader(&Reader), Record(Record), Idx(Idx) {} + AttrReader(ASTRecordReader &Reader) : Reader(Reader) {} - const uint64_t &readInt() { return Record[Idx++]; } + uint64_t readInt() { + return Reader.readInt(); + } SourceRange readSourceRange() { - return Reader->ReadSourceRange(*F, Record, Idx); + return Reader.readSourceRange(); } SourceLocation readSourceLocation() { - return Reader->ReadSourceLocation(*F, Record, Idx); + return Reader.readSourceLocation(); } - Expr *readExpr() { return Reader->ReadExpr(*F); } + Expr *readExpr() { return Reader.readExpr(); } std::string readString() { - return Reader->ReadString(Record, Idx); + return Reader.readString(); } - TypeSourceInfo *getTypeSourceInfo() { - return Reader->GetTypeSourceInfo(*F, Record, Idx); + TypeSourceInfo *readTypeSourceInfo() { + return Reader.readTypeSourceInfo(); } - IdentifierInfo *getIdentifierInfo() { - return Reader->GetIdentifierInfo(*F, Record, Idx); + IdentifierInfo *readIdentifier() { + return Reader.readIdentifier(); } VersionTuple readVersionTuple() { - return ASTReader::ReadVersionTuple(Record, Idx); + return Reader.readVersionTuple(); } template <typename T> T *GetLocalDeclAs(uint32_t LocalID) { - return cast_or_null<T>(Reader->GetLocalDecl(*F, LocalID)); + return Reader.GetLocalDeclAs<T>(LocalID); } }; } -Attr *ASTReader::ReadAttr(ModuleFile &M, const RecordData &Rec, - unsigned &Idx) { - AttrReader Record(M, *this, Rec, Idx); +Attr *ASTRecordReader::readAttr() { + AttrReader Record(*this); auto V = Record.readInt(); if (!V) return nullptr; @@ -2705,8 +2768,8 @@ Attr *ASTReader::ReadAttr(ModuleFile &M, const RecordData &Rec, auto Kind = static_cast<attr::Kind>(V - 1); ASTContext &Context = getContext(); - IdentifierInfo *AttrName = Record.getIdentifierInfo(); - IdentifierInfo *ScopeName = Record.getIdentifierInfo(); + IdentifierInfo *AttrName = Record.readIdentifier(); + IdentifierInfo *ScopeName = Record.readIdentifier(); SourceRange AttrRange = Record.readSourceRange(); SourceLocation ScopeLoc = Record.readSourceLocation(); unsigned ParsedKind = Record.readInt(); @@ -2724,9 +2787,9 @@ Attr *ASTReader::ReadAttr(ModuleFile &M, const RecordData &Rec, } /// Reads attributes from the current stream position. -void ASTReader::ReadAttributes(ASTRecordReader &Record, AttrVec &Attrs) { - for (unsigned I = 0, E = Record.readInt(); I != E; ++I) - Attrs.push_back(Record.readAttr()); +void ASTRecordReader::readAttributes(AttrVec &Attrs) { + for (unsigned I = 0, E = readInt(); I != E; ++I) + Attrs.push_back(readAttr()); } //===----------------------------------------------------------------------===// @@ -3621,7 +3684,7 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { Deserializing ADecl(this); auto Fail = [](const char *what, llvm::Error &&Err) { - llvm::report_fatal_error(Twine("ASTReader::ReadDeclRecord failed ") + what + + llvm::report_fatal_error(Twine("ASTReader::readDeclRecord failed ") + what + ": " + toString(std::move(Err))); }; @@ -3639,12 +3702,12 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { Expected<unsigned> MaybeDeclCode = Record.readRecord(DeclsCursor, Code); if (!MaybeDeclCode) llvm::report_fatal_error( - "ASTReader::ReadDeclRecord failed reading decl code: " + + "ASTReader::readDeclRecord failed reading decl code: " + toString(MaybeDeclCode.takeError())); switch ((DeclCode)MaybeDeclCode.get()) { case DECL_CONTEXT_LEXICAL: case DECL_CONTEXT_VISIBLE: - llvm_unreachable("Record cannot be de-serialized with ReadDeclRecord"); + llvm_unreachable("Record cannot be de-serialized with readDeclRecord"); case DECL_TYPEDEF: D = TypedefDecl::CreateDeserialized(Context, ID); break; @@ -3750,9 +3813,12 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_FUNCTION_TEMPLATE: D = FunctionTemplateDecl::CreateDeserialized(Context, ID); break; - case DECL_TEMPLATE_TYPE_PARM: - D = TemplateTypeParmDecl::CreateDeserialized(Context, ID); + case DECL_TEMPLATE_TYPE_PARM: { + bool HasTypeConstraint = Record.readInt(); + D = TemplateTypeParmDecl::CreateDeserialized(Context, ID, + HasTypeConstraint); break; + } case DECL_NON_TYPE_TEMPLATE_PARM: D = NonTypeTemplateParmDecl::CreateDeserialized(Context, ID); break; @@ -3884,6 +3950,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_EMPTY: D = EmptyDecl::CreateDeserialized(Context, ID); break; + case DECL_LIFETIME_EXTENDED_TEMPORARY: + D = LifetimeExtendedTemporaryDecl::CreateDeserialized(Context, ID); + break; case DECL_OBJC_TYPE_PARAM: D = ObjCTypeParamDecl::CreateDeserialized(Context, ID); break; @@ -4254,11 +4323,11 @@ void ASTDeclReader::UpdateDecl(Decl *D, case UPD_CXX_ADDED_TEMPLATE_SPECIALIZATION: // It will be added to the template's lazy specialization set. - PendingLazySpecializationIDs.push_back(ReadDeclID()); + PendingLazySpecializationIDs.push_back(readDeclID()); break; case UPD_CXX_ADDED_ANONYMOUS_NAMESPACE: { - auto *Anon = ReadDeclAs<NamespaceDecl>(); + auto *Anon = readDeclAs<NamespaceDecl>(); // Each module has its own anonymous namespace, which is disjoint from // any other module's anonymous namespaces, so don't attach the anonymous @@ -4354,7 +4423,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, FD->setImplicitlyInline(); }); } - FD->setInnerLocStart(ReadSourceLocation()); + FD->setInnerLocStart(readSourceLocation()); ReadFunctionDefinition(FD); assert(Record.getIdx() == Record.size() && "lazy body must be last"); break; @@ -4379,7 +4448,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, } auto TSK = (TemplateSpecializationKind)Record.readInt(); - SourceLocation POI = ReadSourceLocation(); + SourceLocation POI = readSourceLocation(); if (MemberSpecializationInfo *MSInfo = RD->getMemberSpecializationInfo()) { MSInfo->setTemplateSpecializationKind(TSK); @@ -4391,7 +4460,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, if (Record.readInt()) { auto *PartialSpec = - ReadDeclAs<ClassTemplatePartialSpecializationDecl>(); + readDeclAs<ClassTemplatePartialSpecializationDecl>(); SmallVector<TemplateArgument, 8> TemplArgs; Record.readTemplateArgumentList(TemplArgs); auto *TemplArgList = TemplateArgumentList::CreateCopy( @@ -4406,9 +4475,9 @@ void ASTDeclReader::UpdateDecl(Decl *D, } RD->setTagKind((TagTypeKind)Record.readInt()); - RD->setLocation(ReadSourceLocation()); - RD->setLocStart(ReadSourceLocation()); - RD->setBraceRange(ReadSourceRange()); + RD->setLocation(readSourceLocation()); + RD->setLocStart(readSourceLocation()); + RD->setBraceRange(readSourceRange()); if (Record.readInt()) { AttrVec Attrs; @@ -4424,7 +4493,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, case UPD_CXX_RESOLVED_DTOR_DELETE: { // Set the 'operator delete' directly to avoid emitting another update // record. - auto *Del = ReadDeclAs<FunctionDecl>(); + auto *Del = readDeclAs<FunctionDecl>(); auto *First = cast<CXXDestructorDecl>(D->getCanonicalDecl()); auto *ThisArg = Record.readExpr(); // FIXME: Check consistency if we have an old and new operator delete. @@ -4436,9 +4505,8 @@ void ASTDeclReader::UpdateDecl(Decl *D, } case UPD_CXX_RESOLVED_EXCEPTION_SPEC: { - FunctionProtoType::ExceptionSpecInfo ESI; SmallVector<QualType, 8> ExceptionStorage; - Record.readExceptionSpec(ExceptionStorage, ESI); + auto ESI = Record.readExceptionSpecInfo(ExceptionStorage); // Update this declaration's exception specification, if needed. auto *FD = cast<FunctionDecl>(D); @@ -4483,7 +4551,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, case UPD_DECL_MARKED_OPENMP_THREADPRIVATE: D->addAttr(OMPThreadPrivateDeclAttr::CreateImplicit( - Reader.getContext(), ReadSourceRange(), + Reader.getContext(), readSourceRange(), AttributeCommonInfo::AS_Pragma)); break; @@ -4491,7 +4559,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(Record.readInt()); Expr *Allocator = Record.readExpr(); - SourceRange SR = ReadSourceRange(); + SourceRange SR = readSourceRange(); D->addAttr(OMPAllocateDeclAttr::CreateImplicit( Reader.getContext(), AllocatorKind, Allocator, SR, AttributeCommonInfo::AS_Pragma)); @@ -4513,7 +4581,7 @@ void ASTDeclReader::UpdateDecl(Decl *D, OMPDeclareTargetDeclAttr::DevTypeTy DevType = static_cast<OMPDeclareTargetDeclAttr::DevTypeTy>(Record.readInt()); D->addAttr(OMPDeclareTargetDeclAttr::CreateImplicit( - Reader.getContext(), MapType, DevType, ReadSourceRange(), + Reader.getContext(), MapType, DevType, readSourceRange(), AttributeCommonInfo::AS_Pragma)); break; } diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index a275e0c30579..f558c26b5f1e 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -11,7 +11,8 @@ // //===----------------------------------------------------------------------===// -#include "clang/Serialization/ASTReader.h" +#include "clang/Serialization/ASTRecordReader.h" +#include "clang/AST/ASTConcept.h" #include "clang/AST/ASTContext.h" #include "clang/AST/AttrIterator.h" #include "clang/AST/Decl.h" @@ -66,45 +67,34 @@ using namespace serialization; namespace clang { class ASTStmtReader : public StmtVisitor<ASTStmtReader> { - friend class OMPClauseReader; - ASTRecordReader &Record; llvm::BitstreamCursor &DeclsCursor; - SourceLocation ReadSourceLocation() { + SourceLocation readSourceLocation() { return Record.readSourceLocation(); } - SourceRange ReadSourceRange() { + SourceRange readSourceRange() { return Record.readSourceRange(); } - std::string ReadString() { + std::string readString() { return Record.readString(); } - TypeSourceInfo *GetTypeSourceInfo() { - return Record.getTypeSourceInfo(); + TypeSourceInfo *readTypeSourceInfo() { + return Record.readTypeSourceInfo(); } - Decl *ReadDecl() { + Decl *readDecl() { return Record.readDecl(); } template<typename T> - T *ReadDeclAs() { + T *readDeclAs() { return Record.readDeclAs<T>(); } - void ReadDeclarationNameLoc(DeclarationNameLoc &DNLoc, - DeclarationName Name) { - Record.readDeclarationNameLoc(DNLoc, Name); - } - - void ReadDeclarationNameInfo(DeclarationNameInfo &NameInfo) { - Record.readDeclarationNameInfo(NameInfo); - } - public: ASTStmtReader(ASTRecordReader &Record, llvm::BitstreamCursor &Cursor) : Record(Record), DeclsCursor(Cursor) {} @@ -137,10 +127,10 @@ namespace clang { void ASTStmtReader::ReadTemplateKWAndArgsInfo(ASTTemplateKWAndArgsInfo &Args, TemplateArgumentLoc *ArgsLocArray, unsigned NumTemplateArgs) { - SourceLocation TemplateKWLoc = ReadSourceLocation(); + SourceLocation TemplateKWLoc = readSourceLocation(); TemplateArgumentListInfo ArgInfo; - ArgInfo.setLAngleLoc(ReadSourceLocation()); - ArgInfo.setRAngleLoc(ReadSourceLocation()); + ArgInfo.setLAngleLoc(readSourceLocation()); + ArgInfo.setRAngleLoc(readSourceLocation()); for (unsigned i = 0; i != NumTemplateArgs; ++i) ArgInfo.addArgument(Record.readTemplateArgumentLoc()); Args.initializeFrom(TemplateKWLoc, ArgInfo, ArgsLocArray); @@ -153,7 +143,7 @@ void ASTStmtReader::VisitStmt(Stmt *S) { void ASTStmtReader::VisitNullStmt(NullStmt *S) { VisitStmt(S); - S->setSemiLoc(ReadSourceLocation()); + S->setSemiLoc(readSourceLocation()); S->NullStmtBits.HasLeadingEmptyMacro = Record.readInt(); } @@ -164,15 +154,15 @@ void ASTStmtReader::VisitCompoundStmt(CompoundStmt *S) { while (NumStmts--) Stmts.push_back(Record.readSubStmt()); S->setStmts(Stmts); - S->CompoundStmtBits.LBraceLoc = ReadSourceLocation(); - S->RBraceLoc = ReadSourceLocation(); + S->CompoundStmtBits.LBraceLoc = readSourceLocation(); + S->RBraceLoc = readSourceLocation(); } void ASTStmtReader::VisitSwitchCase(SwitchCase *S) { VisitStmt(S); Record.recordSwitchCaseID(S, Record.readInt()); - S->setKeywordLoc(ReadSourceLocation()); - S->setColonLoc(ReadSourceLocation()); + S->setKeywordLoc(readSourceLocation()); + S->setColonLoc(readSourceLocation()); } void ASTStmtReader::VisitCaseStmt(CaseStmt *S) { @@ -182,7 +172,7 @@ void ASTStmtReader::VisitCaseStmt(CaseStmt *S) { S->setSubStmt(Record.readSubStmt()); if (CaseStmtIsGNURange) { S->setRHS(Record.readSubExpr()); - S->setEllipsisLoc(ReadSourceLocation()); + S->setEllipsisLoc(readSourceLocation()); } } @@ -193,11 +183,11 @@ void ASTStmtReader::VisitDefaultStmt(DefaultStmt *S) { void ASTStmtReader::VisitLabelStmt(LabelStmt *S) { VisitStmt(S); - auto *LD = ReadDeclAs<LabelDecl>(); + auto *LD = readDeclAs<LabelDecl>(); LD->setStmt(S); S->setDecl(LD); S->setSubStmt(Record.readSubStmt()); - S->setIdentLoc(ReadSourceLocation()); + S->setIdentLoc(readSourceLocation()); } void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) { @@ -213,7 +203,7 @@ void ASTStmtReader::VisitAttributedStmt(AttributedStmt *S) { assert(NumAttrs == Attrs.size()); std::copy(Attrs.begin(), Attrs.end(), S->getAttrArrayPtr()); S->SubStmt = Record.readSubStmt(); - S->AttributedStmtBits.AttrLoc = ReadSourceLocation(); + S->AttributedStmtBits.AttrLoc = readSourceLocation(); } void ASTStmtReader::VisitIfStmt(IfStmt *S) { @@ -229,13 +219,13 @@ void ASTStmtReader::VisitIfStmt(IfStmt *S) { if (HasElse) S->setElse(Record.readSubStmt()); if (HasVar) - S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>()); + S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>()); if (HasInit) S->setInit(Record.readSubStmt()); - S->setIfLoc(ReadSourceLocation()); + S->setIfLoc(readSourceLocation()); if (HasElse) - S->setElseLoc(ReadSourceLocation()); + S->setElseLoc(readSourceLocation()); } void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) { @@ -252,9 +242,9 @@ void ASTStmtReader::VisitSwitchStmt(SwitchStmt *S) { if (HasInit) S->setInit(Record.readSubStmt()); if (HasVar) - S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>()); + S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>()); - S->setSwitchLoc(ReadSourceLocation()); + S->setSwitchLoc(readSourceLocation()); SwitchCase *PrevSC = nullptr; for (auto E = Record.size(); Record.getIdx() != E; ) { @@ -276,54 +266,54 @@ void ASTStmtReader::VisitWhileStmt(WhileStmt *S) { S->setCond(Record.readSubExpr()); S->setBody(Record.readSubStmt()); if (HasVar) - S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>()); + S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>()); - S->setWhileLoc(ReadSourceLocation()); + S->setWhileLoc(readSourceLocation()); } void ASTStmtReader::VisitDoStmt(DoStmt *S) { VisitStmt(S); S->setCond(Record.readSubExpr()); S->setBody(Record.readSubStmt()); - S->setDoLoc(ReadSourceLocation()); - S->setWhileLoc(ReadSourceLocation()); - S->setRParenLoc(ReadSourceLocation()); + S->setDoLoc(readSourceLocation()); + S->setWhileLoc(readSourceLocation()); + S->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitForStmt(ForStmt *S) { VisitStmt(S); S->setInit(Record.readSubStmt()); S->setCond(Record.readSubExpr()); - S->setConditionVariable(Record.getContext(), ReadDeclAs<VarDecl>()); + S->setConditionVariable(Record.getContext(), readDeclAs<VarDecl>()); S->setInc(Record.readSubExpr()); S->setBody(Record.readSubStmt()); - S->setForLoc(ReadSourceLocation()); - S->setLParenLoc(ReadSourceLocation()); - S->setRParenLoc(ReadSourceLocation()); + S->setForLoc(readSourceLocation()); + S->setLParenLoc(readSourceLocation()); + S->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitGotoStmt(GotoStmt *S) { VisitStmt(S); - S->setLabel(ReadDeclAs<LabelDecl>()); - S->setGotoLoc(ReadSourceLocation()); - S->setLabelLoc(ReadSourceLocation()); + S->setLabel(readDeclAs<LabelDecl>()); + S->setGotoLoc(readSourceLocation()); + S->setLabelLoc(readSourceLocation()); } void ASTStmtReader::VisitIndirectGotoStmt(IndirectGotoStmt *S) { VisitStmt(S); - S->setGotoLoc(ReadSourceLocation()); - S->setStarLoc(ReadSourceLocation()); + S->setGotoLoc(readSourceLocation()); + S->setStarLoc(readSourceLocation()); S->setTarget(Record.readSubExpr()); } void ASTStmtReader::VisitContinueStmt(ContinueStmt *S) { VisitStmt(S); - S->setContinueLoc(ReadSourceLocation()); + S->setContinueLoc(readSourceLocation()); } void ASTStmtReader::VisitBreakStmt(BreakStmt *S) { VisitStmt(S); - S->setBreakLoc(ReadSourceLocation()); + S->setBreakLoc(readSourceLocation()); } void ASTStmtReader::VisitReturnStmt(ReturnStmt *S) { @@ -333,25 +323,25 @@ void ASTStmtReader::VisitReturnStmt(ReturnStmt *S) { S->setRetValue(Record.readSubExpr()); if (HasNRVOCandidate) - S->setNRVOCandidate(ReadDeclAs<VarDecl>()); + S->setNRVOCandidate(readDeclAs<VarDecl>()); - S->setReturnLoc(ReadSourceLocation()); + S->setReturnLoc(readSourceLocation()); } void ASTStmtReader::VisitDeclStmt(DeclStmt *S) { VisitStmt(S); - S->setStartLoc(ReadSourceLocation()); - S->setEndLoc(ReadSourceLocation()); + S->setStartLoc(readSourceLocation()); + S->setEndLoc(readSourceLocation()); if (Record.size() - Record.getIdx() == 1) { // Single declaration - S->setDeclGroup(DeclGroupRef(ReadDecl())); + S->setDeclGroup(DeclGroupRef(readDecl())); } else { SmallVector<Decl *, 16> Decls; int N = Record.size() - Record.getIdx(); Decls.reserve(N); for (int I = 0; I < N; ++I) - Decls.push_back(ReadDecl()); + Decls.push_back(readDecl()); S->setDeclGroup(DeclGroupRef(DeclGroup::Create(Record.getContext(), Decls.data(), Decls.size()))); @@ -363,7 +353,7 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) { S->NumOutputs = Record.readInt(); S->NumInputs = Record.readInt(); S->NumClobbers = Record.readInt(); - S->setAsmLoc(ReadSourceLocation()); + S->setAsmLoc(readSourceLocation()); S->setVolatile(Record.readInt()); S->setSimple(Record.readInt()); } @@ -371,7 +361,7 @@ void ASTStmtReader::VisitAsmStmt(AsmStmt *S) { void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) { VisitAsmStmt(S); S->NumLabels = Record.readInt(); - S->setRParenLoc(ReadSourceLocation()); + S->setRParenLoc(readSourceLocation()); S->setAsmString(cast_or_null<StringLiteral>(Record.readSubStmt())); unsigned NumOutputs = S->getNumOutputs(); @@ -384,7 +374,7 @@ void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) { SmallVector<StringLiteral*, 16> Constraints; SmallVector<Stmt*, 16> Exprs; for (unsigned I = 0, N = NumOutputs + NumInputs; I != N; ++I) { - Names.push_back(Record.getIdentifierInfo()); + Names.push_back(Record.readIdentifier()); Constraints.push_back(cast_or_null<StringLiteral>(Record.readSubStmt())); Exprs.push_back(Record.readSubStmt()); } @@ -407,10 +397,10 @@ void ASTStmtReader::VisitGCCAsmStmt(GCCAsmStmt *S) { void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) { VisitAsmStmt(S); - S->LBraceLoc = ReadSourceLocation(); - S->EndLoc = ReadSourceLocation(); + S->LBraceLoc = readSourceLocation(); + S->EndLoc = readSourceLocation(); S->NumAsmToks = Record.readInt(); - std::string AsmStr = ReadString(); + std::string AsmStr = readString(); // Read the tokens. SmallVector<Token, 16> AsmToks; @@ -428,7 +418,7 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) { ClobbersData.reserve(S->NumClobbers); Clobbers.reserve(S->NumClobbers); for (unsigned i = 0, e = S->NumClobbers; i != e; ++i) { - ClobbersData.push_back(ReadString()); + ClobbersData.push_back(readString()); Clobbers.push_back(ClobbersData.back()); } @@ -442,7 +432,7 @@ void ASTStmtReader::VisitMSAsmStmt(MSAsmStmt *S) { Constraints.reserve(NumOperands); for (unsigned i = 0; i != NumOperands; ++i) { Exprs.push_back(cast<Expr>(Record.readSubStmt())); - ConstraintsData.push_back(ReadString()); + ConstraintsData.push_back(readString()); Constraints.push_back(ConstraintsData.back()); } @@ -470,7 +460,7 @@ void ASTStmtReader::VisitCoreturnStmt(CoreturnStmt *S) { void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *E) { VisitExpr(E); - E->KeywordLoc = ReadSourceLocation(); + E->KeywordLoc = readSourceLocation(); for (auto &SubExpr: E->SubExprs) SubExpr = Record.readSubStmt(); E->OpaqueValue = cast_or_null<OpaqueValueExpr>(Record.readSubStmt()); @@ -479,7 +469,7 @@ void ASTStmtReader::VisitCoawaitExpr(CoawaitExpr *E) { void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *E) { VisitExpr(E); - E->KeywordLoc = ReadSourceLocation(); + E->KeywordLoc = readSourceLocation(); for (auto &SubExpr: E->SubExprs) SubExpr = Record.readSubStmt(); E->OpaqueValue = cast_or_null<OpaqueValueExpr>(Record.readSubStmt()); @@ -487,7 +477,7 @@ void ASTStmtReader::VisitCoyieldExpr(CoyieldExpr *E) { void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) { VisitExpr(E); - E->KeywordLoc = ReadSourceLocation(); + E->KeywordLoc = readSourceLocation(); for (auto &SubExpr: E->SubExprs) SubExpr = Record.readSubStmt(); } @@ -495,9 +485,9 @@ void ASTStmtReader::VisitDependentCoawaitExpr(DependentCoawaitExpr *E) { void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) { VisitStmt(S); Record.skipInts(1); - S->setCapturedDecl(ReadDeclAs<CapturedDecl>()); + S->setCapturedDecl(readDeclAs<CapturedDecl>()); S->setCapturedRegionKind(static_cast<CapturedRegionKind>(Record.readInt())); - S->setCapturedRecordDecl(ReadDeclAs<RecordDecl>()); + S->setCapturedRecordDecl(readDeclAs<RecordDecl>()); // Capture inits for (CapturedStmt::capture_init_iterator I = S->capture_init_begin(), @@ -511,10 +501,10 @@ void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) { // Captures for (auto &I : S->captures()) { - I.VarAndKind.setPointer(ReadDeclAs<VarDecl>()); + I.VarAndKind.setPointer(readDeclAs<VarDecl>()); I.VarAndKind.setInt( static_cast<CapturedStmt::VariableCaptureKind>(Record.readInt())); - I.Loc = ReadSourceLocation(); + I.Loc = readSourceLocation(); } } @@ -553,7 +543,7 @@ void ASTStmtReader::VisitPredefinedExpr(PredefinedExpr *E) { bool HasFunctionName = Record.readInt(); E->PredefinedExprBits.HasFunctionName = HasFunctionName; E->PredefinedExprBits.Kind = Record.readInt(); - E->setLocation(ReadSourceLocation()); + E->setLocation(readSourceLocation()); if (HasFunctionName) E->setFunctionName(cast<StringLiteral>(Record.readSubExpr())); } @@ -576,27 +566,27 @@ void ASTStmtReader::VisitDeclRefExpr(DeclRefExpr *E) { NestedNameSpecifierLoc(Record.readNestedNameSpecifierLoc()); if (E->hasFoundDecl()) - *E->getTrailingObjects<NamedDecl *>() = ReadDeclAs<NamedDecl>(); + *E->getTrailingObjects<NamedDecl *>() = readDeclAs<NamedDecl>(); if (E->hasTemplateKWAndArgsInfo()) ReadTemplateKWAndArgsInfo( *E->getTrailingObjects<ASTTemplateKWAndArgsInfo>(), E->getTrailingObjects<TemplateArgumentLoc>(), NumTemplateArgs); - E->setDecl(ReadDeclAs<ValueDecl>()); - E->setLocation(ReadSourceLocation()); - ReadDeclarationNameLoc(E->DNLoc, E->getDecl()->getDeclName()); + E->setDecl(readDeclAs<ValueDecl>()); + E->setLocation(readSourceLocation()); + E->DNLoc = Record.readDeclarationNameLoc(E->getDecl()->getDeclName()); } void ASTStmtReader::VisitIntegerLiteral(IntegerLiteral *E) { VisitExpr(E); - E->setLocation(ReadSourceLocation()); + E->setLocation(readSourceLocation()); E->setValue(Record.getContext(), Record.readAPInt()); } void ASTStmtReader::VisitFixedPointLiteral(FixedPointLiteral *E) { VisitExpr(E); - E->setLocation(ReadSourceLocation()); + E->setLocation(readSourceLocation()); E->setValue(Record.getContext(), Record.readAPInt()); } @@ -606,7 +596,7 @@ void ASTStmtReader::VisitFloatingLiteral(FloatingLiteral *E) { static_cast<llvm::APFloatBase::Semantics>(Record.readInt())); E->setExact(Record.readInt()); E->setValue(Record.getContext(), Record.readAPFloat(E->getSemantics())); - E->setLocation(ReadSourceLocation()); + E->setLocation(readSourceLocation()); } void ASTStmtReader::VisitImaginaryLiteral(ImaginaryLiteral *E) { @@ -639,7 +629,7 @@ void ASTStmtReader::VisitStringLiteral(StringLiteral *E) { // Deserialize the trailing array of SourceLocation. for (unsigned I = 0; I < NumConcatenated; ++I) - E->setStrTokenLoc(I, ReadSourceLocation()); + E->setStrTokenLoc(I, readSourceLocation()); // Deserialize the trailing array of char holding the string data. char *StrData = E->getStrDataAsChar(); @@ -650,14 +640,14 @@ void ASTStmtReader::VisitStringLiteral(StringLiteral *E) { void ASTStmtReader::VisitCharacterLiteral(CharacterLiteral *E) { VisitExpr(E); E->setValue(Record.readInt()); - E->setLocation(ReadSourceLocation()); + E->setLocation(readSourceLocation()); E->setKind(static_cast<CharacterLiteral::CharacterKind>(Record.readInt())); } void ASTStmtReader::VisitParenExpr(ParenExpr *E) { VisitExpr(E); - E->setLParen(ReadSourceLocation()); - E->setRParen(ReadSourceLocation()); + E->setLParen(readSourceLocation()); + E->setRParen(readSourceLocation()); E->setSubExpr(Record.readSubExpr()); } @@ -667,15 +657,15 @@ void ASTStmtReader::VisitParenListExpr(ParenListExpr *E) { assert((NumExprs == E->getNumExprs()) && "Wrong NumExprs!"); for (unsigned I = 0; I != NumExprs; ++I) E->getTrailingObjects<Stmt *>()[I] = Record.readSubStmt(); - E->LParenLoc = ReadSourceLocation(); - E->RParenLoc = ReadSourceLocation(); + E->LParenLoc = readSourceLocation(); + E->RParenLoc = readSourceLocation(); } void ASTStmtReader::VisitUnaryOperator(UnaryOperator *E) { VisitExpr(E); E->setSubExpr(Record.readSubExpr()); E->setOpcode((UnaryOperator::Opcode)Record.readInt()); - E->setOperatorLoc(ReadSourceLocation()); + E->setOperatorLoc(readSourceLocation()); E->setCanOverflow(Record.readInt()); } @@ -685,13 +675,13 @@ void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { Record.skipInts(1); assert(E->getNumExpressions() == Record.peekInt()); Record.skipInts(1); - E->setOperatorLoc(ReadSourceLocation()); - E->setRParenLoc(ReadSourceLocation()); - E->setTypeSourceInfo(GetTypeSourceInfo()); + E->setOperatorLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); + E->setTypeSourceInfo(readTypeSourceInfo()); for (unsigned I = 0, N = E->getNumComponents(); I != N; ++I) { auto Kind = static_cast<OffsetOfNode::Kind>(Record.readInt()); - SourceLocation Start = ReadSourceLocation(); - SourceLocation End = ReadSourceLocation(); + SourceLocation Start = readSourceLocation(); + SourceLocation End = readSourceLocation(); switch (Kind) { case OffsetOfNode::Array: E->setComponent(I, OffsetOfNode(Start, Record.readInt(), End)); @@ -699,13 +689,13 @@ void ASTStmtReader::VisitOffsetOfExpr(OffsetOfExpr *E) { case OffsetOfNode::Field: E->setComponent( - I, OffsetOfNode(Start, ReadDeclAs<FieldDecl>(), End)); + I, OffsetOfNode(Start, readDeclAs<FieldDecl>(), End)); break; case OffsetOfNode::Identifier: E->setComponent( I, - OffsetOfNode(Start, Record.getIdentifierInfo(), End)); + OffsetOfNode(Start, Record.readIdentifier(), End)); break; case OffsetOfNode::Base: { @@ -728,10 +718,10 @@ void ASTStmtReader::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E) { E->setArgument(Record.readSubExpr()); Record.skipInts(1); } else { - E->setArgument(GetTypeSourceInfo()); + E->setArgument(readTypeSourceInfo()); } - E->setOperatorLoc(ReadSourceLocation()); - E->setRParenLoc(ReadSourceLocation()); + E->setOperatorLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitConceptSpecializationExpr( @@ -740,23 +730,40 @@ void ASTStmtReader::VisitConceptSpecializationExpr( unsigned NumTemplateArgs = Record.readInt(); E->NestedNameSpec = Record.readNestedNameSpecifierLoc(); E->TemplateKWLoc = Record.readSourceLocation(); - E->ConceptNameLoc = Record.readSourceLocation(); - E->FoundDecl = ReadDeclAs<NamedDecl>(); - E->NamedConcept.setPointer(ReadDeclAs<ConceptDecl>()); - const ASTTemplateArgumentListInfo *ArgsAsWritten = - Record.readASTTemplateArgumentListInfo(); + E->ConceptName = Record.readDeclarationNameInfo(); + E->NamedConcept = readDeclAs<ConceptDecl>(); + E->ArgsAsWritten = Record.readASTTemplateArgumentListInfo(); llvm::SmallVector<TemplateArgument, 4> Args; for (unsigned I = 0; I < NumTemplateArgs; ++I) Args.push_back(Record.readTemplateArgument()); - E->setTemplateArguments(ArgsAsWritten, Args); - E->NamedConcept.setInt(Record.readInt() == 1); + E->setTemplateArguments(Args); + ConstraintSatisfaction Satisfaction; + Satisfaction.IsSatisfied = Record.readInt(); + if (!Satisfaction.IsSatisfied) { + unsigned NumDetailRecords = Record.readInt(); + for (unsigned i = 0; i != NumDetailRecords; ++i) { + Expr *ConstraintExpr = Record.readExpr(); + bool IsDiagnostic = Record.readInt(); + if (IsDiagnostic) { + SourceLocation DiagLocation = Record.readSourceLocation(); + std::string DiagMessage = Record.readString(); + Satisfaction.Details.emplace_back( + ConstraintExpr, new (Record.getContext()) + ConstraintSatisfaction::SubstitutionDiagnostic{ + DiagLocation, DiagMessage}); + } else + Satisfaction.Details.emplace_back(ConstraintExpr, Record.readExpr()); + } + } + E->Satisfaction = ASTConstraintSatisfaction::Create(Record.getContext(), + Satisfaction); } void ASTStmtReader::VisitArraySubscriptExpr(ArraySubscriptExpr *E) { VisitExpr(E); E->setLHS(Record.readSubExpr()); E->setRHS(Record.readSubExpr()); - E->setRBracketLoc(ReadSourceLocation()); + E->setRBracketLoc(readSourceLocation()); } void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { @@ -764,15 +771,15 @@ void ASTStmtReader::VisitOMPArraySectionExpr(OMPArraySectionExpr *E) { E->setBase(Record.readSubExpr()); E->setLowerBound(Record.readSubExpr()); E->setLength(Record.readSubExpr()); - E->setColonLoc(ReadSourceLocation()); - E->setRBracketLoc(ReadSourceLocation()); + E->setColonLoc(readSourceLocation()); + E->setRBracketLoc(readSourceLocation()); } void ASTStmtReader::VisitCallExpr(CallExpr *E) { VisitExpr(E); unsigned NumArgs = Record.readInt(); assert((NumArgs == E->getNumArgs()) && "Wrong NumArgs!"); - E->setRParenLoc(ReadSourceLocation()); + E->setRParenLoc(readSourceLocation()); E->setCallee(Record.readSubExpr()); for (unsigned I = 0; I != NumArgs; ++I) E->setArg(I, Record.readSubExpr()); @@ -793,7 +800,7 @@ void ASTStmtReader::VisitMemberExpr(MemberExpr *E) { E->Base = Record.readSubExpr(); E->MemberDecl = Record.readDeclAs<ValueDecl>(); - Record.readDeclarationNameLoc(E->MemberDNLoc, E->MemberDecl->getDeclName()); + E->MemberDNLoc = Record.readDeclarationNameLoc(E->MemberDecl->getDeclName()); E->MemberLoc = Record.readSourceLocation(); E->MemberExprBits.IsArrow = Record.readInt(); E->MemberExprBits.HasQualifierOrFoundDecl = HasQualifier || HasFoundDecl; @@ -830,8 +837,8 @@ void ASTStmtReader::VisitMemberExpr(MemberExpr *E) { void ASTStmtReader::VisitObjCIsaExpr(ObjCIsaExpr *E) { VisitExpr(E); E->setBase(Record.readSubExpr()); - E->setIsaMemberLoc(ReadSourceLocation()); - E->setOpLoc(ReadSourceLocation()); + E->setIsaMemberLoc(readSourceLocation()); + E->setOpLoc(readSourceLocation()); E->setArrow(Record.readInt()); } @@ -844,8 +851,8 @@ VisitObjCIndirectCopyRestoreExpr(ObjCIndirectCopyRestoreExpr *E) { void ASTStmtReader::VisitObjCBridgedCastExpr(ObjCBridgedCastExpr *E) { VisitExplicitCastExpr(E); - E->LParenLoc = ReadSourceLocation(); - E->BridgeKeywordLoc = ReadSourceLocation(); + E->LParenLoc = readSourceLocation(); + E->BridgeKeywordLoc = readSourceLocation(); E->Kind = Record.readInt(); } @@ -868,7 +875,7 @@ void ASTStmtReader::VisitBinaryOperator(BinaryOperator *E) { E->setLHS(Record.readSubExpr()); E->setRHS(Record.readSubExpr()); E->setOpcode((BinaryOperator::Opcode)Record.readInt()); - E->setOperatorLoc(ReadSourceLocation()); + E->setOperatorLoc(readSourceLocation()); E->setFPFeatures(FPOptions(Record.readInt())); } @@ -883,8 +890,8 @@ void ASTStmtReader::VisitConditionalOperator(ConditionalOperator *E) { E->SubExprs[ConditionalOperator::COND] = Record.readSubExpr(); E->SubExprs[ConditionalOperator::LHS] = Record.readSubExpr(); E->SubExprs[ConditionalOperator::RHS] = Record.readSubExpr(); - E->QuestionLoc = ReadSourceLocation(); - E->ColonLoc = ReadSourceLocation(); + E->QuestionLoc = readSourceLocation(); + E->ColonLoc = readSourceLocation(); } void @@ -895,8 +902,8 @@ ASTStmtReader::VisitBinaryConditionalOperator(BinaryConditionalOperator *E) { E->SubExprs[BinaryConditionalOperator::COND] = Record.readSubExpr(); E->SubExprs[BinaryConditionalOperator::LHS] = Record.readSubExpr(); E->SubExprs[BinaryConditionalOperator::RHS] = Record.readSubExpr(); - E->QuestionLoc = ReadSourceLocation(); - E->ColonLoc = ReadSourceLocation(); + E->QuestionLoc = readSourceLocation(); + E->ColonLoc = readSourceLocation(); } void ASTStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) { @@ -906,19 +913,19 @@ void ASTStmtReader::VisitImplicitCastExpr(ImplicitCastExpr *E) { void ASTStmtReader::VisitExplicitCastExpr(ExplicitCastExpr *E) { VisitCastExpr(E); - E->setTypeInfoAsWritten(GetTypeSourceInfo()); + E->setTypeInfoAsWritten(readTypeSourceInfo()); } void ASTStmtReader::VisitCStyleCastExpr(CStyleCastExpr *E) { VisitExplicitCastExpr(E); - E->setLParenLoc(ReadSourceLocation()); - E->setRParenLoc(ReadSourceLocation()); + E->setLParenLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { VisitExpr(E); - E->setLParenLoc(ReadSourceLocation()); - E->setTypeSourceInfo(GetTypeSourceInfo()); + E->setLParenLoc(readSourceLocation()); + E->setTypeSourceInfo(readTypeSourceInfo()); E->setInitializer(Record.readSubExpr()); E->setFileScope(Record.readInt()); } @@ -926,23 +933,23 @@ void ASTStmtReader::VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { void ASTStmtReader::VisitExtVectorElementExpr(ExtVectorElementExpr *E) { VisitExpr(E); E->setBase(Record.readSubExpr()); - E->setAccessor(Record.getIdentifierInfo()); - E->setAccessorLoc(ReadSourceLocation()); + E->setAccessor(Record.readIdentifier()); + E->setAccessorLoc(readSourceLocation()); } void ASTStmtReader::VisitInitListExpr(InitListExpr *E) { VisitExpr(E); if (auto *SyntForm = cast_or_null<InitListExpr>(Record.readSubStmt())) E->setSyntacticForm(SyntForm); - E->setLBraceLoc(ReadSourceLocation()); - E->setRBraceLoc(ReadSourceLocation()); + E->setLBraceLoc(readSourceLocation()); + E->setRBraceLoc(readSourceLocation()); bool isArrayFiller = Record.readInt(); Expr *filler = nullptr; if (isArrayFiller) { filler = Record.readSubExpr(); E->ArrayFillerOrUnionFieldInit = filler; } else - E->ArrayFillerOrUnionFieldInit = ReadDeclAs<FieldDecl>(); + E->ArrayFillerOrUnionFieldInit = readDeclAs<FieldDecl>(); E->sawArrayRangeDesignator(Record.readInt()); unsigned NumInits = Record.readInt(); E->reserveInits(Record.getContext(), NumInits); @@ -965,16 +972,16 @@ void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) { assert(NumSubExprs == E->getNumSubExprs() && "Wrong number of subexprs"); for (unsigned I = 0; I != NumSubExprs; ++I) E->setSubExpr(I, Record.readSubExpr()); - E->setEqualOrColonLoc(ReadSourceLocation()); + E->setEqualOrColonLoc(readSourceLocation()); E->setGNUSyntax(Record.readInt()); SmallVector<Designator, 4> Designators; while (Record.getIdx() < Record.size()) { switch ((DesignatorTypes)Record.readInt()) { case DESIG_FIELD_DECL: { - auto *Field = ReadDeclAs<FieldDecl>(); - SourceLocation DotLoc = ReadSourceLocation(); - SourceLocation FieldLoc = ReadSourceLocation(); + auto *Field = readDeclAs<FieldDecl>(); + SourceLocation DotLoc = readSourceLocation(); + SourceLocation FieldLoc = readSourceLocation(); Designators.push_back(Designator(Field->getIdentifier(), DotLoc, FieldLoc)); Designators.back().setField(Field); @@ -982,26 +989,26 @@ void ASTStmtReader::VisitDesignatedInitExpr(DesignatedInitExpr *E) { } case DESIG_FIELD_NAME: { - const IdentifierInfo *Name = Record.getIdentifierInfo(); - SourceLocation DotLoc = ReadSourceLocation(); - SourceLocation FieldLoc = ReadSourceLocation(); + const IdentifierInfo *Name = Record.readIdentifier(); + SourceLocation DotLoc = readSourceLocation(); + SourceLocation FieldLoc = readSourceLocation(); Designators.push_back(Designator(Name, DotLoc, FieldLoc)); break; } case DESIG_ARRAY: { unsigned Index = Record.readInt(); - SourceLocation LBracketLoc = ReadSourceLocation(); - SourceLocation RBracketLoc = ReadSourceLocation(); + SourceLocation LBracketLoc = readSourceLocation(); + SourceLocation RBracketLoc = readSourceLocation(); Designators.push_back(Designator(Index, LBracketLoc, RBracketLoc)); break; } case DESIG_ARRAY_RANGE: { unsigned Index = Record.readInt(); - SourceLocation LBracketLoc = ReadSourceLocation(); - SourceLocation EllipsisLoc = ReadSourceLocation(); - SourceLocation RBracketLoc = ReadSourceLocation(); + SourceLocation LBracketLoc = readSourceLocation(); + SourceLocation EllipsisLoc = readSourceLocation(); + SourceLocation RBracketLoc = readSourceLocation(); Designators.push_back(Designator(Index, LBracketLoc, EllipsisLoc, RBracketLoc)); break; @@ -1039,32 +1046,32 @@ void ASTStmtReader::VisitImplicitValueInitExpr(ImplicitValueInitExpr *E) { void ASTStmtReader::VisitVAArgExpr(VAArgExpr *E) { VisitExpr(E); E->setSubExpr(Record.readSubExpr()); - E->setWrittenTypeInfo(GetTypeSourceInfo()); - E->setBuiltinLoc(ReadSourceLocation()); - E->setRParenLoc(ReadSourceLocation()); + E->setWrittenTypeInfo(readTypeSourceInfo()); + E->setBuiltinLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); E->setIsMicrosoftABI(Record.readInt()); } void ASTStmtReader::VisitSourceLocExpr(SourceLocExpr *E) { VisitExpr(E); - E->ParentContext = ReadDeclAs<DeclContext>(); - E->BuiltinLoc = ReadSourceLocation(); - E->RParenLoc = ReadSourceLocation(); + E->ParentContext = readDeclAs<DeclContext>(); + E->BuiltinLoc = readSourceLocation(); + E->RParenLoc = readSourceLocation(); E->SourceLocExprBits.Kind = static_cast<SourceLocExpr::IdentKind>(Record.readInt()); } void ASTStmtReader::VisitAddrLabelExpr(AddrLabelExpr *E) { VisitExpr(E); - E->setAmpAmpLoc(ReadSourceLocation()); - E->setLabelLoc(ReadSourceLocation()); - E->setLabel(ReadDeclAs<LabelDecl>()); + E->setAmpAmpLoc(readSourceLocation()); + E->setLabelLoc(readSourceLocation()); + E->setLabel(readDeclAs<LabelDecl>()); } void ASTStmtReader::VisitStmtExpr(StmtExpr *E) { VisitExpr(E); - E->setLParenLoc(ReadSourceLocation()); - E->setRParenLoc(ReadSourceLocation()); + E->setLParenLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); E->setSubStmt(cast_or_null<CompoundStmt>(Record.readSubStmt())); } @@ -1073,14 +1080,14 @@ void ASTStmtReader::VisitChooseExpr(ChooseExpr *E) { E->setCond(Record.readSubExpr()); E->setLHS(Record.readSubExpr()); E->setRHS(Record.readSubExpr()); - E->setBuiltinLoc(ReadSourceLocation()); - E->setRParenLoc(ReadSourceLocation()); + E->setBuiltinLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); E->setIsConditionTrue(Record.readInt()); } void ASTStmtReader::VisitGNUNullExpr(GNUNullExpr *E) { VisitExpr(E); - E->setTokenLocation(ReadSourceLocation()); + E->setTokenLocation(readSourceLocation()); } void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { @@ -1090,21 +1097,21 @@ void ASTStmtReader::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { while (NumExprs--) Exprs.push_back(Record.readSubExpr()); E->setExprs(Record.getContext(), Exprs); - E->setBuiltinLoc(ReadSourceLocation()); - E->setRParenLoc(ReadSourceLocation()); + E->setBuiltinLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitConvertVectorExpr(ConvertVectorExpr *E) { VisitExpr(E); - E->BuiltinLoc = ReadSourceLocation(); - E->RParenLoc = ReadSourceLocation(); - E->TInfo = GetTypeSourceInfo(); + E->BuiltinLoc = readSourceLocation(); + E->RParenLoc = readSourceLocation(); + E->TInfo = readTypeSourceInfo(); E->SrcExpr = Record.readSubExpr(); } void ASTStmtReader::VisitBlockExpr(BlockExpr *E) { VisitExpr(E); - E->setBlockDecl(ReadDeclAs<BlockDecl>()); + E->setBlockDecl(readDeclAs<BlockDecl>()); } void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) { @@ -1113,9 +1120,9 @@ void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) { unsigned NumAssocs = Record.readInt(); assert(NumAssocs == E->getNumAssocs() && "Wrong NumAssocs!"); E->ResultIndex = Record.readInt(); - E->GenericSelectionExprBits.GenericLoc = ReadSourceLocation(); - E->DefaultLoc = ReadSourceLocation(); - E->RParenLoc = ReadSourceLocation(); + E->GenericSelectionExprBits.GenericLoc = readSourceLocation(); + E->DefaultLoc = readSourceLocation(); + E->RParenLoc = readSourceLocation(); Stmt **Stmts = E->getTrailingObjects<Stmt *>(); // Add 1 to account for the controlling expression which is the first @@ -1126,7 +1133,7 @@ void ASTStmtReader::VisitGenericSelectionExpr(GenericSelectionExpr *E) { TypeSourceInfo **TSIs = E->getTrailingObjects<TypeSourceInfo *>(); for (unsigned I = 0, N = NumAssocs; I < N; ++I) - TSIs[I] = GetTypeSourceInfo(); + TSIs[I] = readTypeSourceInfo(); } void ASTStmtReader::VisitPseudoObjectExpr(PseudoObjectExpr *E) { @@ -1151,8 +1158,8 @@ void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) { E->NumSubExprs = AtomicExpr::getNumSubExprs(E->Op); for (unsigned I = 0; I != E->NumSubExprs; ++I) E->SubExprs[I] = Record.readSubExpr(); - E->BuiltinLoc = ReadSourceLocation(); - E->RParenLoc = ReadSourceLocation(); + E->BuiltinLoc = readSourceLocation(); + E->RParenLoc = readSourceLocation(); } //===----------------------------------------------------------------------===// @@ -1161,15 +1168,15 @@ void ASTStmtReader::VisitAtomicExpr(AtomicExpr *E) { void ASTStmtReader::VisitObjCStringLiteral(ObjCStringLiteral *E) { VisitExpr(E); E->setString(cast<StringLiteral>(Record.readSubStmt())); - E->setAtLoc(ReadSourceLocation()); + E->setAtLoc(readSourceLocation()); } void ASTStmtReader::VisitObjCBoxedExpr(ObjCBoxedExpr *E) { VisitExpr(E); // could be one of several IntegerLiteral, FloatLiteral, etc. E->SubExpr = Record.readSubStmt(); - E->BoxingMethod = ReadDeclAs<ObjCMethodDecl>(); - E->Range = ReadSourceRange(); + E->BoxingMethod = readDeclAs<ObjCMethodDecl>(); + E->Range = readSourceRange(); } void ASTStmtReader::VisitObjCArrayLiteral(ObjCArrayLiteral *E) { @@ -1179,8 +1186,8 @@ void ASTStmtReader::VisitObjCArrayLiteral(ObjCArrayLiteral *E) { Expr **Elements = E->getElements(); for (unsigned I = 0, N = NumElements; I != N; ++I) Elements[I] = Record.readSubExpr(); - E->ArrayWithObjectsMethod = ReadDeclAs<ObjCMethodDecl>(); - E->Range = ReadSourceRange(); + E->ArrayWithObjectsMethod = readDeclAs<ObjCMethodDecl>(); + E->Range = readSourceRange(); } void ASTStmtReader::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { @@ -1197,41 +1204,41 @@ void ASTStmtReader::VisitObjCDictionaryLiteral(ObjCDictionaryLiteral *E) { KeyValues[I].Key = Record.readSubExpr(); KeyValues[I].Value = Record.readSubExpr(); if (HasPackExpansions) { - Expansions[I].EllipsisLoc = ReadSourceLocation(); + Expansions[I].EllipsisLoc = readSourceLocation(); Expansions[I].NumExpansionsPlusOne = Record.readInt(); } } - E->DictWithObjectsMethod = ReadDeclAs<ObjCMethodDecl>(); - E->Range = ReadSourceRange(); + E->DictWithObjectsMethod = readDeclAs<ObjCMethodDecl>(); + E->Range = readSourceRange(); } void ASTStmtReader::VisitObjCEncodeExpr(ObjCEncodeExpr *E) { VisitExpr(E); - E->setEncodedTypeSourceInfo(GetTypeSourceInfo()); - E->setAtLoc(ReadSourceLocation()); - E->setRParenLoc(ReadSourceLocation()); + E->setEncodedTypeSourceInfo(readTypeSourceInfo()); + E->setAtLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitObjCSelectorExpr(ObjCSelectorExpr *E) { VisitExpr(E); E->setSelector(Record.readSelector()); - E->setAtLoc(ReadSourceLocation()); - E->setRParenLoc(ReadSourceLocation()); + E->setAtLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitObjCProtocolExpr(ObjCProtocolExpr *E) { VisitExpr(E); - E->setProtocol(ReadDeclAs<ObjCProtocolDecl>()); - E->setAtLoc(ReadSourceLocation()); - E->ProtoLoc = ReadSourceLocation(); - E->setRParenLoc(ReadSourceLocation()); + E->setProtocol(readDeclAs<ObjCProtocolDecl>()); + E->setAtLoc(readSourceLocation()); + E->ProtoLoc = readSourceLocation(); + E->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { VisitExpr(E); - E->setDecl(ReadDeclAs<ObjCIvarDecl>()); - E->setLocation(ReadSourceLocation()); - E->setOpLoc(ReadSourceLocation()); + E->setDecl(readDeclAs<ObjCIvarDecl>()); + E->setLocation(readSourceLocation()); + E->setOpLoc(readSourceLocation()); E->setBase(Record.readSubExpr()); E->setIsArrow(Record.readInt()); E->setIsFreeIvar(Record.readInt()); @@ -1242,14 +1249,14 @@ void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { unsigned MethodRefFlags = Record.readInt(); bool Implicit = Record.readInt() != 0; if (Implicit) { - auto *Getter = ReadDeclAs<ObjCMethodDecl>(); - auto *Setter = ReadDeclAs<ObjCMethodDecl>(); + auto *Getter = readDeclAs<ObjCMethodDecl>(); + auto *Setter = readDeclAs<ObjCMethodDecl>(); E->setImplicitProperty(Getter, Setter, MethodRefFlags); } else { - E->setExplicitProperty(ReadDeclAs<ObjCPropertyDecl>(), MethodRefFlags); + E->setExplicitProperty(readDeclAs<ObjCPropertyDecl>(), MethodRefFlags); } - E->setLocation(ReadSourceLocation()); - E->setReceiverLocation(ReadSourceLocation()); + E->setLocation(readSourceLocation()); + E->setReceiverLocation(readSourceLocation()); switch (Record.readInt()) { case 0: E->setBase(Record.readSubExpr()); @@ -1258,18 +1265,18 @@ void ASTStmtReader::VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { E->setSuperReceiver(Record.readType()); break; case 2: - E->setClassReceiver(ReadDeclAs<ObjCInterfaceDecl>()); + E->setClassReceiver(readDeclAs<ObjCInterfaceDecl>()); break; } } void ASTStmtReader::VisitObjCSubscriptRefExpr(ObjCSubscriptRefExpr *E) { VisitExpr(E); - E->setRBracket(ReadSourceLocation()); + E->setRBracket(readSourceLocation()); E->setBaseExpr(Record.readSubExpr()); E->setKeyExpr(Record.readSubExpr()); - E->GetAtIndexMethodDecl = ReadDeclAs<ObjCMethodDecl>(); - E->SetAtIndexMethodDecl = ReadDeclAs<ObjCMethodDecl>(); + E->GetAtIndexMethodDecl = readDeclAs<ObjCMethodDecl>(); + E->SetAtIndexMethodDecl = readDeclAs<ObjCMethodDecl>(); } void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) { @@ -1287,13 +1294,13 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) { break; case ObjCMessageExpr::Class: - E->setClassReceiver(GetTypeSourceInfo()); + E->setClassReceiver(readTypeSourceInfo()); break; case ObjCMessageExpr::SuperClass: case ObjCMessageExpr::SuperInstance: { QualType T = Record.readType(); - SourceLocation SuperLoc = ReadSourceLocation(); + SourceLocation SuperLoc = readSourceLocation(); E->setSuper(SuperLoc, T, Kind == ObjCMessageExpr::SuperInstance); break; } @@ -1302,19 +1309,19 @@ void ASTStmtReader::VisitObjCMessageExpr(ObjCMessageExpr *E) { assert(Kind == E->getReceiverKind()); if (Record.readInt()) - E->setMethodDecl(ReadDeclAs<ObjCMethodDecl>()); + E->setMethodDecl(readDeclAs<ObjCMethodDecl>()); else E->setSelector(Record.readSelector()); - E->LBracLoc = ReadSourceLocation(); - E->RBracLoc = ReadSourceLocation(); + E->LBracLoc = readSourceLocation(); + E->RBracLoc = readSourceLocation(); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) E->setArg(I, Record.readSubExpr()); SourceLocation *Locs = E->getStoredSelLocs(); for (unsigned I = 0; I != NumStoredSelLocs; ++I) - Locs[I] = ReadSourceLocation(); + Locs[I] = readSourceLocation(); } void ASTStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { @@ -1322,28 +1329,28 @@ void ASTStmtReader::VisitObjCForCollectionStmt(ObjCForCollectionStmt *S) { S->setElement(Record.readSubStmt()); S->setCollection(Record.readSubExpr()); S->setBody(Record.readSubStmt()); - S->setForLoc(ReadSourceLocation()); - S->setRParenLoc(ReadSourceLocation()); + S->setForLoc(readSourceLocation()); + S->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitObjCAtCatchStmt(ObjCAtCatchStmt *S) { VisitStmt(S); S->setCatchBody(Record.readSubStmt()); - S->setCatchParamDecl(ReadDeclAs<VarDecl>()); - S->setAtCatchLoc(ReadSourceLocation()); - S->setRParenLoc(ReadSourceLocation()); + S->setCatchParamDecl(readDeclAs<VarDecl>()); + S->setAtCatchLoc(readSourceLocation()); + S->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S) { VisitStmt(S); S->setFinallyBody(Record.readSubStmt()); - S->setAtFinallyLoc(ReadSourceLocation()); + S->setAtFinallyLoc(readSourceLocation()); } void ASTStmtReader::VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S) { VisitStmt(S); // FIXME: no test coverage. S->setSubStmt(Record.readSubStmt()); - S->setAtLoc(ReadSourceLocation()); + S->setAtLoc(readSourceLocation()); } void ASTStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { @@ -1357,26 +1364,26 @@ void ASTStmtReader::VisitObjCAtTryStmt(ObjCAtTryStmt *S) { if (HasFinally) S->setFinallyStmt(Record.readSubStmt()); - S->setAtTryLoc(ReadSourceLocation()); + S->setAtTryLoc(readSourceLocation()); } void ASTStmtReader::VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S) { VisitStmt(S); // FIXME: no test coverage. S->setSynchExpr(Record.readSubStmt()); S->setSynchBody(Record.readSubStmt()); - S->setAtSynchronizedLoc(ReadSourceLocation()); + S->setAtSynchronizedLoc(readSourceLocation()); } void ASTStmtReader::VisitObjCAtThrowStmt(ObjCAtThrowStmt *S) { VisitStmt(S); // FIXME: no test coverage. S->setThrowExpr(Record.readSubStmt()); - S->setThrowLoc(ReadSourceLocation()); + S->setThrowLoc(readSourceLocation()); } void ASTStmtReader::VisitObjCBoolLiteralExpr(ObjCBoolLiteralExpr *E) { VisitExpr(E); E->setValue(Record.readInt()); - E->setLocation(ReadSourceLocation()); + E->setLocation(readSourceLocation()); } void ASTStmtReader::VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) { @@ -1393,8 +1400,8 @@ void ASTStmtReader::VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) void ASTStmtReader::VisitCXXCatchStmt(CXXCatchStmt *S) { VisitStmt(S); - S->CatchLoc = ReadSourceLocation(); - S->ExceptionDecl = ReadDeclAs<VarDecl>(); + S->CatchLoc = readSourceLocation(); + S->ExceptionDecl = readDeclAs<VarDecl>(); S->HandlerBlock = Record.readSubStmt(); } @@ -1402,7 +1409,7 @@ void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) { VisitStmt(S); assert(Record.peekInt() == S->getNumHandlers() && "NumStmtFields is wrong ?"); Record.skipInts(1); - S->TryLoc = ReadSourceLocation(); + S->TryLoc = readSourceLocation(); S->getStmts()[0] = Record.readSubStmt(); for (unsigned i = 0, e = S->getNumHandlers(); i != e; ++i) S->getStmts()[i + 1] = Record.readSubStmt(); @@ -1410,10 +1417,10 @@ void ASTStmtReader::VisitCXXTryStmt(CXXTryStmt *S) { void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) { VisitStmt(S); - S->ForLoc = ReadSourceLocation(); - S->CoawaitLoc = ReadSourceLocation(); - S->ColonLoc = ReadSourceLocation(); - S->RParenLoc = ReadSourceLocation(); + S->ForLoc = readSourceLocation(); + S->CoawaitLoc = readSourceLocation(); + S->ColonLoc = readSourceLocation(); + S->RParenLoc = readSourceLocation(); S->setInit(Record.readSubStmt()); S->setRangeStmt(Record.readSubStmt()); S->setBeginStmt(Record.readSubStmt()); @@ -1426,10 +1433,10 @@ void ASTStmtReader::VisitCXXForRangeStmt(CXXForRangeStmt *S) { void ASTStmtReader::VisitMSDependentExistsStmt(MSDependentExistsStmt *S) { VisitStmt(S); - S->KeywordLoc = ReadSourceLocation(); + S->KeywordLoc = readSourceLocation(); S->IsIfExists = Record.readInt(); S->QualifierLoc = Record.readNestedNameSpecifierLoc(); - ReadDeclarationNameInfo(S->NameInfo); + S->NameInfo = Record.readDeclarationNameInfo(); S->SubStmt = Record.readSubStmt(); } @@ -1459,9 +1466,9 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { E->CXXConstructExprBits.StdInitListInitialization = Record.readInt(); E->CXXConstructExprBits.ZeroInitialization = Record.readInt(); E->CXXConstructExprBits.ConstructionKind = Record.readInt(); - E->CXXConstructExprBits.Loc = ReadSourceLocation(); - E->Constructor = ReadDeclAs<CXXConstructorDecl>(); - E->ParenOrBraceRange = ReadSourceRange(); + E->CXXConstructExprBits.Loc = readSourceLocation(); + E->Constructor = readDeclAs<CXXConstructorDecl>(); + E->ParenOrBraceRange = readSourceRange(); for (unsigned I = 0; I != NumArgs; ++I) E->setArg(I, Record.readSubExpr()); @@ -1469,27 +1476,27 @@ void ASTStmtReader::VisitCXXConstructExpr(CXXConstructExpr *E) { void ASTStmtReader::VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E) { VisitExpr(E); - E->Constructor = ReadDeclAs<CXXConstructorDecl>(); - E->Loc = ReadSourceLocation(); + E->Constructor = readDeclAs<CXXConstructorDecl>(); + E->Loc = readSourceLocation(); E->ConstructsVirtualBase = Record.readInt(); E->InheritedFromVirtualBase = Record.readInt(); } void ASTStmtReader::VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E) { VisitCXXConstructExpr(E); - E->TSI = GetTypeSourceInfo(); + E->TSI = readTypeSourceInfo(); } void ASTStmtReader::VisitLambdaExpr(LambdaExpr *E) { VisitExpr(E); unsigned NumCaptures = Record.readInt(); assert(NumCaptures == E->NumCaptures);(void)NumCaptures; - E->IntroducerRange = ReadSourceRange(); + E->IntroducerRange = readSourceRange(); E->CaptureDefault = static_cast<LambdaCaptureDefault>(Record.readInt()); - E->CaptureDefaultLoc = ReadSourceLocation(); + E->CaptureDefaultLoc = readSourceLocation(); E->ExplicitParams = Record.readInt(); E->ExplicitResultType = Record.readInt(); - E->ClosingBrace = ReadSourceLocation(); + E->ClosingBrace = readSourceLocation(); // Read capture initializers. for (LambdaExpr::capture_init_iterator C = E->capture_init_begin(), @@ -1506,10 +1513,10 @@ ASTStmtReader::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { void ASTStmtReader::VisitCXXNamedCastExpr(CXXNamedCastExpr *E) { VisitExplicitCastExpr(E); - SourceRange R = ReadSourceRange(); + SourceRange R = readSourceRange(); E->Loc = R.getBegin(); E->RParenLoc = R.getEnd(); - R = ReadSourceRange(); + R = readSourceRange(); E->AngleBrackets = R; } @@ -1531,38 +1538,38 @@ void ASTStmtReader::VisitCXXConstCastExpr(CXXConstCastExpr *E) { void ASTStmtReader::VisitCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { VisitExplicitCastExpr(E); - E->setLParenLoc(ReadSourceLocation()); - E->setRParenLoc(ReadSourceLocation()); + E->setLParenLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitBuiltinBitCastExpr(BuiltinBitCastExpr *E) { VisitExplicitCastExpr(E); - E->KWLoc = ReadSourceLocation(); - E->RParenLoc = ReadSourceLocation(); + E->KWLoc = readSourceLocation(); + E->RParenLoc = readSourceLocation(); } void ASTStmtReader::VisitUserDefinedLiteral(UserDefinedLiteral *E) { VisitCallExpr(E); - E->UDSuffixLoc = ReadSourceLocation(); + E->UDSuffixLoc = readSourceLocation(); } void ASTStmtReader::VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E) { VisitExpr(E); E->setValue(Record.readInt()); - E->setLocation(ReadSourceLocation()); + E->setLocation(readSourceLocation()); } void ASTStmtReader::VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E) { VisitExpr(E); - E->setLocation(ReadSourceLocation()); + E->setLocation(readSourceLocation()); } void ASTStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) { VisitExpr(E); - E->setSourceRange(ReadSourceRange()); + E->setSourceRange(readSourceRange()); if (E->isTypeOperand()) { // typeid(int) E->setTypeOperandSourceInfo( - GetTypeSourceInfo()); + readTypeSourceInfo()); return; } @@ -1572,29 +1579,29 @@ void ASTStmtReader::VisitCXXTypeidExpr(CXXTypeidExpr *E) { void ASTStmtReader::VisitCXXThisExpr(CXXThisExpr *E) { VisitExpr(E); - E->setLocation(ReadSourceLocation()); + E->setLocation(readSourceLocation()); E->setImplicit(Record.readInt()); } void ASTStmtReader::VisitCXXThrowExpr(CXXThrowExpr *E) { VisitExpr(E); - E->CXXThrowExprBits.ThrowLoc = ReadSourceLocation(); + E->CXXThrowExprBits.ThrowLoc = readSourceLocation(); E->Operand = Record.readSubExpr(); E->CXXThrowExprBits.IsThrownVariableInScope = Record.readInt(); } void ASTStmtReader::VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { VisitExpr(E); - E->Param = ReadDeclAs<ParmVarDecl>(); - E->UsedContext = ReadDeclAs<DeclContext>(); - E->CXXDefaultArgExprBits.Loc = ReadSourceLocation(); + E->Param = readDeclAs<ParmVarDecl>(); + E->UsedContext = readDeclAs<DeclContext>(); + E->CXXDefaultArgExprBits.Loc = readSourceLocation(); } void ASTStmtReader::VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E) { VisitExpr(E); - E->Field = ReadDeclAs<FieldDecl>(); - E->UsedContext = ReadDeclAs<DeclContext>(); - E->CXXDefaultInitExprBits.Loc = ReadSourceLocation(); + E->Field = readDeclAs<FieldDecl>(); + E->UsedContext = readDeclAs<DeclContext>(); + E->CXXDefaultInitExprBits.Loc = readSourceLocation(); } void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { @@ -1605,8 +1612,8 @@ void ASTStmtReader::VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { void ASTStmtReader::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { VisitExpr(E); - E->TypeInfo = GetTypeSourceInfo(); - E->CXXScalarValueInitExprBits.RParenLoc = ReadSourceLocation(); + E->TypeInfo = readTypeSourceInfo(); + E->CXXScalarValueInitExprBits.RParenLoc = readSourceLocation(); } void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) { @@ -1631,13 +1638,13 @@ void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) { (void)HasInit; (void)NumPlacementArgs; - E->setOperatorNew(ReadDeclAs<FunctionDecl>()); - E->setOperatorDelete(ReadDeclAs<FunctionDecl>()); - E->AllocatedTypeInfo = GetTypeSourceInfo(); + E->setOperatorNew(readDeclAs<FunctionDecl>()); + E->setOperatorDelete(readDeclAs<FunctionDecl>()); + E->AllocatedTypeInfo = readTypeSourceInfo(); if (IsParenTypeId) - E->getTrailingObjects<SourceRange>()[0] = ReadSourceRange(); - E->Range = ReadSourceRange(); - E->DirectInitRange = ReadSourceRange(); + E->getTrailingObjects<SourceRange>()[0] = readSourceRange(); + E->Range = readSourceRange(); + E->DirectInitRange = readSourceRange(); // Install all the subexpressions. for (CXXNewExpr::raw_arg_iterator I = E->raw_arg_begin(), @@ -1652,9 +1659,9 @@ void ASTStmtReader::VisitCXXDeleteExpr(CXXDeleteExpr *E) { E->CXXDeleteExprBits.ArrayForm = Record.readInt(); E->CXXDeleteExprBits.ArrayFormAsWritten = Record.readInt(); E->CXXDeleteExprBits.UsualArrayDeleteWantsSize = Record.readInt(); - E->OperatorDelete = ReadDeclAs<FunctionDecl>(); + E->OperatorDelete = readDeclAs<FunctionDecl>(); E->Argument = Record.readSubExpr(); - E->CXXDeleteExprBits.Loc = ReadSourceLocation(); + E->CXXDeleteExprBits.Loc = readSourceLocation(); } void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { @@ -1662,17 +1669,17 @@ void ASTStmtReader::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { E->Base = Record.readSubExpr(); E->IsArrow = Record.readInt(); - E->OperatorLoc = ReadSourceLocation(); + E->OperatorLoc = readSourceLocation(); E->QualifierLoc = Record.readNestedNameSpecifierLoc(); - E->ScopeType = GetTypeSourceInfo(); - E->ColonColonLoc = ReadSourceLocation(); - E->TildeLoc = ReadSourceLocation(); + E->ScopeType = readTypeSourceInfo(); + E->ColonColonLoc = readSourceLocation(); + E->TildeLoc = readSourceLocation(); - IdentifierInfo *II = Record.getIdentifierInfo(); + IdentifierInfo *II = Record.readIdentifier(); if (II) - E->setDestroyedType(II, ReadSourceLocation()); + E->setDestroyedType(II, readSourceLocation()); else - E->setDestroyedType(GetTypeSourceInfo()); + E->setDestroyedType(readTypeSourceInfo()); } void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) { @@ -1682,7 +1689,7 @@ void ASTStmtReader::VisitExprWithCleanups(ExprWithCleanups *E) { assert(NumObjects == E->getNumObjects()); for (unsigned i = 0; i != NumObjects; ++i) E->getTrailingObjects<BlockDecl *>()[i] = - ReadDeclAs<BlockDecl>(); + readDeclAs<BlockDecl>(); E->ExprWithCleanupsBits.CleanupsHaveSideEffects = Record.readInt(); E->SubExpr = Record.readSubExpr(); @@ -1711,15 +1718,15 @@ void ASTStmtReader::VisitCXXDependentScopeMemberExpr( "Wrong NumTemplateArgs!"); E->CXXDependentScopeMemberExprBits.IsArrow = Record.readInt(); - E->CXXDependentScopeMemberExprBits.OperatorLoc = ReadSourceLocation(); + E->CXXDependentScopeMemberExprBits.OperatorLoc = readSourceLocation(); E->BaseType = Record.readType(); E->QualifierLoc = Record.readNestedNameSpecifierLoc(); E->Base = Record.readSubExpr(); if (HasFirstQualifierFoundInScope) - *E->getTrailingObjects<NamedDecl *>() = ReadDeclAs<NamedDecl>(); + *E->getTrailingObjects<NamedDecl *>() = readDeclAs<NamedDecl>(); - ReadDeclarationNameInfo(E->MemberNameInfo); + E->MemberNameInfo = Record.readDeclarationNameInfo(); } void @@ -1733,7 +1740,7 @@ ASTStmtReader::VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { /*NumTemplateArgs=*/Record.readInt()); E->QualifierLoc = Record.readNestedNameSpecifierLoc(); - ReadDeclarationNameInfo(E->NameInfo); + E->NameInfo = Record.readDeclarationNameInfo(); } void @@ -1744,9 +1751,9 @@ ASTStmtReader::VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E) { Record.skipInts(1); for (unsigned I = 0, N = E->arg_size(); I != N; ++I) E->setArg(I, Record.readSubExpr()); - E->TSI = GetTypeSourceInfo(); - E->setLParenLoc(ReadSourceLocation()); - E->setRParenLoc(ReadSourceLocation()); + E->TSI = readTypeSourceInfo(); + E->setLParenLoc(readSourceLocation()); + E->setRParenLoc(readSourceLocation()); } void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) { @@ -1769,7 +1776,7 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) { UnresolvedSet<8> Decls; for (unsigned I = 0; I != NumResults; ++I) { - auto *D = ReadDeclAs<NamedDecl>(); + auto *D = readDeclAs<NamedDecl>(); auto AS = (AccessSpecifier)Record.readInt(); Decls.addDecl(D, AS); } @@ -1780,7 +1787,7 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) { Results[I] = (Iter + I).getPair(); } - ReadDeclarationNameInfo(E->NameInfo); + E->NameInfo = Record.readDeclarationNameInfo(); E->QualifierLoc = Record.readNestedNameSpecifierLoc(); } @@ -1790,14 +1797,14 @@ void ASTStmtReader::VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E) { E->UnresolvedMemberExprBits.HasUnresolvedUsing = Record.readInt(); E->Base = Record.readSubExpr(); E->BaseType = Record.readType(); - E->OperatorLoc = ReadSourceLocation(); + E->OperatorLoc = readSourceLocation(); } void ASTStmtReader::VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E) { VisitOverloadExpr(E); E->UnresolvedLookupExprBits.RequiresADL = Record.readInt(); E->UnresolvedLookupExprBits.Overloaded = Record.readInt(); - E->NamingClass = ReadDeclAs<CXXRecordDecl>(); + E->NamingClass = readDeclAs<CXXRecordDecl>(); } void ASTStmtReader::VisitTypeTraitExpr(TypeTraitExpr *E) { @@ -1805,23 +1812,23 @@ void ASTStmtReader::VisitTypeTraitExpr(TypeTraitExpr *E) { E->TypeTraitExprBits.NumArgs = Record.readInt(); E->TypeTraitExprBits.Kind = Record.readInt(); E->TypeTraitExprBits.Value = Record.readInt(); - SourceRange Range = ReadSourceRange(); + SourceRange Range = readSourceRange(); E->Loc = Range.getBegin(); E->RParenLoc = Range.getEnd(); auto **Args = E->getTrailingObjects<TypeSourceInfo *>(); for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I) - Args[I] = GetTypeSourceInfo(); + Args[I] = readTypeSourceInfo(); } void ASTStmtReader::VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E) { VisitExpr(E); E->ATT = (ArrayTypeTrait)Record.readInt(); E->Value = (unsigned int)Record.readInt(); - SourceRange Range = ReadSourceRange(); + SourceRange Range = readSourceRange(); E->Loc = Range.getBegin(); E->RParen = Range.getEnd(); - E->QueriedType = GetTypeSourceInfo(); + E->QueriedType = readTypeSourceInfo(); E->Dimension = Record.readSubExpr(); } @@ -1829,7 +1836,7 @@ void ASTStmtReader::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { VisitExpr(E); E->ET = (ExpressionTrait)Record.readInt(); E->Value = (bool)Record.readInt(); - SourceRange Range = ReadSourceRange(); + SourceRange Range = readSourceRange(); E->QueriedExpression = Record.readSubExpr(); E->Loc = Range.getBegin(); E->RParen = Range.getEnd(); @@ -1838,13 +1845,13 @@ void ASTStmtReader::VisitExpressionTraitExpr(ExpressionTraitExpr *E) { void ASTStmtReader::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) { VisitExpr(E); E->CXXNoexceptExprBits.Value = Record.readInt(); - E->Range = ReadSourceRange(); + E->Range = readSourceRange(); E->Operand = Record.readSubExpr(); } void ASTStmtReader::VisitPackExpansionExpr(PackExpansionExpr *E) { VisitExpr(E); - E->EllipsisLoc = ReadSourceLocation(); + E->EllipsisLoc = readSourceLocation(); E->NumExpansions = Record.readInt(); E->Pattern = Record.readSubExpr(); } @@ -1852,9 +1859,9 @@ void ASTStmtReader::VisitPackExpansionExpr(PackExpansionExpr *E) { void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) { VisitExpr(E); unsigned NumPartialArgs = Record.readInt(); - E->OperatorLoc = ReadSourceLocation(); - E->PackLoc = ReadSourceLocation(); - E->RParenLoc = ReadSourceLocation(); + E->OperatorLoc = readSourceLocation(); + E->PackLoc = readSourceLocation(); + E->RParenLoc = readSourceLocation(); E->Pack = Record.readDeclAs<NamedDecl>(); if (E->isPartiallySubstituted()) { assert(E->Length == NumPartialArgs); @@ -1870,47 +1877,48 @@ void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) { void ASTStmtReader::VisitSubstNonTypeTemplateParmExpr( SubstNonTypeTemplateParmExpr *E) { VisitExpr(E); - E->Param = ReadDeclAs<NonTypeTemplateParmDecl>(); - E->SubstNonTypeTemplateParmExprBits.NameLoc = ReadSourceLocation(); + E->Param = readDeclAs<NonTypeTemplateParmDecl>(); + E->SubstNonTypeTemplateParmExprBits.NameLoc = readSourceLocation(); E->Replacement = Record.readSubExpr(); } void ASTStmtReader::VisitSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E) { VisitExpr(E); - E->Param = ReadDeclAs<NonTypeTemplateParmDecl>(); + E->Param = readDeclAs<NonTypeTemplateParmDecl>(); TemplateArgument ArgPack = Record.readTemplateArgument(); if (ArgPack.getKind() != TemplateArgument::Pack) return; E->Arguments = ArgPack.pack_begin(); E->NumArguments = ArgPack.pack_size(); - E->NameLoc = ReadSourceLocation(); + E->NameLoc = readSourceLocation(); } void ASTStmtReader::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { VisitExpr(E); E->NumParameters = Record.readInt(); - E->ParamPack = ReadDeclAs<ParmVarDecl>(); - E->NameLoc = ReadSourceLocation(); + E->ParamPack = readDeclAs<ParmVarDecl>(); + E->NameLoc = readSourceLocation(); auto **Parms = E->getTrailingObjects<VarDecl *>(); for (unsigned i = 0, n = E->NumParameters; i != n; ++i) - Parms[i] = ReadDeclAs<VarDecl>(); + Parms[i] = readDeclAs<VarDecl>(); } void ASTStmtReader::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { VisitExpr(E); - E->State = Record.readSubExpr(); - auto *VD = ReadDeclAs<ValueDecl>(); - unsigned ManglingNumber = Record.readInt(); - E->setExtendingDecl(VD, ManglingNumber); + bool HasMaterialzedDecl = Record.readInt(); + if (HasMaterialzedDecl) + E->State = cast<LifetimeExtendedTemporaryDecl>(Record.readDecl()); + else + E->State = Record.readSubExpr(); } void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) { VisitExpr(E); - E->LParenLoc = ReadSourceLocation(); - E->EllipsisLoc = ReadSourceLocation(); - E->RParenLoc = ReadSourceLocation(); + E->LParenLoc = readSourceLocation(); + E->EllipsisLoc = readSourceLocation(); + E->RParenLoc = readSourceLocation(); E->NumExpansions = Record.readInt(); E->SubExprs[0] = Record.readSubExpr(); E->SubExprs[1] = Record.readSubExpr(); @@ -1920,7 +1928,7 @@ void ASTStmtReader::VisitCXXFoldExpr(CXXFoldExpr *E) { void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) { VisitExpr(E); E->SourceExpr = Record.readSubExpr(); - E->OpaqueValueExprBits.Loc = ReadSourceLocation(); + E->OpaqueValueExprBits.Loc = readSourceLocation(); E->setIsUnique(Record.readInt()); } @@ -1936,25 +1944,25 @@ void ASTStmtReader::VisitMSPropertyRefExpr(MSPropertyRefExpr *E) { E->IsArrow = (Record.readInt() != 0); E->BaseExpr = Record.readSubExpr(); E->QualifierLoc = Record.readNestedNameSpecifierLoc(); - E->MemberLoc = ReadSourceLocation(); - E->TheDecl = ReadDeclAs<MSPropertyDecl>(); + E->MemberLoc = readSourceLocation(); + E->TheDecl = readDeclAs<MSPropertyDecl>(); } void ASTStmtReader::VisitMSPropertySubscriptExpr(MSPropertySubscriptExpr *E) { VisitExpr(E); E->setBase(Record.readSubExpr()); E->setIdx(Record.readSubExpr()); - E->setRBracketLoc(ReadSourceLocation()); + E->setRBracketLoc(readSourceLocation()); } void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) { VisitExpr(E); - E->setSourceRange(ReadSourceRange()); - std::string UuidStr = ReadString(); + E->setSourceRange(readSourceRange()); + std::string UuidStr = readString(); E->setUuidStr(StringRef(UuidStr).copy(Record.getContext())); if (E->isTypeOperand()) { // __uuidof(ComType) E->setTypeOperandSourceInfo( - GetTypeSourceInfo()); + readTypeSourceInfo()); return; } @@ -1964,26 +1972,26 @@ void ASTStmtReader::VisitCXXUuidofExpr(CXXUuidofExpr *E) { void ASTStmtReader::VisitSEHLeaveStmt(SEHLeaveStmt *S) { VisitStmt(S); - S->setLeaveLoc(ReadSourceLocation()); + S->setLeaveLoc(readSourceLocation()); } void ASTStmtReader::VisitSEHExceptStmt(SEHExceptStmt *S) { VisitStmt(S); - S->Loc = ReadSourceLocation(); + S->Loc = readSourceLocation(); S->Children[SEHExceptStmt::FILTER_EXPR] = Record.readSubStmt(); S->Children[SEHExceptStmt::BLOCK] = Record.readSubStmt(); } void ASTStmtReader::VisitSEHFinallyStmt(SEHFinallyStmt *S) { VisitStmt(S); - S->Loc = ReadSourceLocation(); + S->Loc = readSourceLocation(); S->Block = Record.readSubStmt(); } void ASTStmtReader::VisitSEHTryStmt(SEHTryStmt *S) { VisitStmt(S); S->IsCXXTry = Record.readInt(); - S->TryLoc = ReadSourceLocation(); + S->TryLoc = readSourceLocation(); S->Children[SEHTryStmt::TRY] = Record.readSubStmt(); S->Children[SEHTryStmt::HANDLER] = Record.readSubStmt(); } @@ -2002,8 +2010,8 @@ void ASTStmtReader::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) { //===----------------------------------------------------------------------===// void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) { VisitExpr(E); - E->BuiltinLoc = ReadSourceLocation(); - E->RParenLoc = ReadSourceLocation(); + E->BuiltinLoc = readSourceLocation(); + E->RParenLoc = readSourceLocation(); E->SrcExpr = Record.readSubExpr(); } @@ -2012,12 +2020,11 @@ void ASTStmtReader::VisitAsTypeExpr(AsTypeExpr *E) { //===----------------------------------------------------------------------===// void ASTStmtReader::VisitOMPExecutableDirective(OMPExecutableDirective *E) { - E->setLocStart(ReadSourceLocation()); - E->setLocEnd(ReadSourceLocation()); - OMPClauseReader ClauseReader(Record); + E->setLocStart(readSourceLocation()); + E->setLocEnd(readSourceLocation()); SmallVector<OMPClause *, 5> Clauses; for (unsigned i = 0; i < E->getNumClauses(); ++i) - Clauses.push_back(ClauseReader.readClause()); + Clauses.push_back(Record.readOMPClause()); E->setClauses(Clauses); if (E->hasAssociatedStmt()) E->setAssociatedStmt(Record.readSubStmt()); @@ -2151,7 +2158,7 @@ void ASTStmtReader::VisitOMPCriticalDirective(OMPCriticalDirective *D) { // The NumClauses field was read in ReadStmtFromStream. Record.skipInts(1); VisitOMPExecutableDirective(D); - ReadDeclarationNameInfo(D->DirName); + D->DirName = Record.readDeclarationNameInfo(); } void ASTStmtReader::VisitOMPParallelForDirective(OMPParallelForDirective *D) { @@ -2164,6 +2171,14 @@ void ASTStmtReader::VisitOMPParallelForSimdDirective( VisitOMPLoopDirective(D); } +void ASTStmtReader::VisitOMPParallelMasterDirective( + OMPParallelMasterDirective *D) { + VisitStmt(D); + // The NumClauses field was read in ReadStmtFromStream. + Record.skipInts(1); + VisitOMPExecutableDirective(D); +} + void ASTStmtReader::VisitOMPParallelSectionsDirective( OMPParallelSectionsDirective *D) { VisitStmt(D); @@ -2316,6 +2331,11 @@ void ASTStmtReader::VisitOMPParallelMasterTaskLoopDirective( VisitOMPLoopDirective(D); } +void ASTStmtReader::VisitOMPParallelMasterTaskLoopSimdDirective( + OMPParallelMasterTaskLoopSimdDirective *D) { + VisitOMPLoopDirective(D); +} + void ASTStmtReader::VisitOMPDistributeDirective(OMPDistributeDirective *D) { VisitOMPLoopDirective(D); } @@ -2997,6 +3017,11 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; } + case STMT_OMP_PARALLEL_MASTER_DIRECTIVE: + S = OMPParallelMasterDirective::CreateEmpty( + Context, Record[ASTStmtReader::NumStmtFields], Empty); + break; + case STMT_OMP_PARALLEL_SECTIONS_DIRECTIVE: S = OMPParallelSectionsDirective::CreateEmpty( Context, Record[ASTStmtReader::NumStmtFields], Empty); @@ -3131,6 +3156,14 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) { break; } + case STMT_OMP_PARALLEL_MASTER_TASKLOOP_SIMD_DIRECTIVE: { + unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; + unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; + S = OMPParallelMasterTaskLoopSimdDirective::CreateEmpty( + Context, NumClauses, CollapsedNum, Empty); + break; + } + case STMT_OMP_DISTRIBUTE_DIRECTIVE: { unsigned NumClauses = Record[ASTStmtReader::NumStmtFields]; unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields + 1]; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 28affedbbb30..6eba48a1abe9 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -10,10 +10,12 @@ // //===----------------------------------------------------------------------===// -#include "clang/Serialization/ASTWriter.h" +#include "clang/AST/OpenMPClause.h" +#include "clang/Serialization/ASTRecordWriter.h" #include "ASTCommon.h" #include "ASTReaderInternals.h" #include "MultiOnDiskHashTable.h" +#include "clang/AST/AbstractTypeWriter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTUnresolvedSet.h" #include "clang/AST/Attr.h" @@ -65,7 +67,7 @@ #include "clang/Sema/Weak.h" #include "clang/Serialization/ASTReader.h" #include "clang/Serialization/InMemoryModuleCache.h" -#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFile.h" #include "clang/Serialization/ModuleFileExtension.h" #include "clang/Serialization/SerializationDiagnostic.h" #include "llvm/ADT/APFloat.h" @@ -132,457 +134,43 @@ static StringRef bytes(const SmallVectorImpl<T> &v) { // Type serialization //===----------------------------------------------------------------------===// -namespace clang { - - class ASTTypeWriter { - ASTWriter &Writer; - ASTRecordWriter Record; - - /// Type code that corresponds to the record generated. - TypeCode Code = static_cast<TypeCode>(0); - - /// Abbreviation to use for the record, if any. - unsigned AbbrevToUse = 0; - - public: - ASTTypeWriter(ASTWriter &Writer, ASTWriter::RecordDataImpl &Record) - : Writer(Writer), Record(Writer, Record) {} - - uint64_t Emit() { - return Record.Emit(Code, AbbrevToUse); - } - - void Visit(QualType T) { - if (T.hasLocalNonFastQualifiers()) { - Qualifiers Qs = T.getLocalQualifiers(); - Record.AddTypeRef(T.getLocalUnqualifiedType()); - Record.push_back(Qs.getAsOpaqueValue()); - Code = TYPE_EXT_QUAL; - AbbrevToUse = Writer.TypeExtQualAbbrev; - } else { - switch (T->getTypeClass()) { - // For all of the concrete, non-dependent types, call the - // appropriate visitor function. -#define TYPE(Class, Base) \ - case Type::Class: Visit##Class##Type(cast<Class##Type>(T)); break; -#define ABSTRACT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.inc" - } - } - } - - void VisitArrayType(const ArrayType *T); - void VisitFunctionType(const FunctionType *T); - void VisitTagType(const TagType *T); - -#define TYPE(Class, Base) void Visit##Class##Type(const Class##Type *T); -#define ABSTRACT_TYPE(Class, Base) -#include "clang/AST/TypeNodes.inc" - }; - -} // namespace clang - -void ASTTypeWriter::VisitBuiltinType(const BuiltinType *T) { - llvm_unreachable("Built-in types are never serialized"); -} - -void ASTTypeWriter::VisitComplexType(const ComplexType *T) { - Record.AddTypeRef(T->getElementType()); - Code = TYPE_COMPLEX; -} - -void ASTTypeWriter::VisitPointerType(const PointerType *T) { - Record.AddTypeRef(T->getPointeeType()); - Code = TYPE_POINTER; -} - -void ASTTypeWriter::VisitDecayedType(const DecayedType *T) { - Record.AddTypeRef(T->getOriginalType()); - Code = TYPE_DECAYED; -} - -void ASTTypeWriter::VisitAdjustedType(const AdjustedType *T) { - Record.AddTypeRef(T->getOriginalType()); - Record.AddTypeRef(T->getAdjustedType()); - Code = TYPE_ADJUSTED; -} - -void ASTTypeWriter::VisitBlockPointerType(const BlockPointerType *T) { - Record.AddTypeRef(T->getPointeeType()); - Code = TYPE_BLOCK_POINTER; -} - -void ASTTypeWriter::VisitLValueReferenceType(const LValueReferenceType *T) { - Record.AddTypeRef(T->getPointeeTypeAsWritten()); - Record.push_back(T->isSpelledAsLValue()); - Code = TYPE_LVALUE_REFERENCE; -} - -void ASTTypeWriter::VisitRValueReferenceType(const RValueReferenceType *T) { - Record.AddTypeRef(T->getPointeeTypeAsWritten()); - Code = TYPE_RVALUE_REFERENCE; -} - -void ASTTypeWriter::VisitMemberPointerType(const MemberPointerType *T) { - Record.AddTypeRef(T->getPointeeType()); - Record.AddTypeRef(QualType(T->getClass(), 0)); - Code = TYPE_MEMBER_POINTER; -} - -void ASTTypeWriter::VisitArrayType(const ArrayType *T) { - Record.AddTypeRef(T->getElementType()); - Record.push_back(T->getSizeModifier()); // FIXME: stable values - Record.push_back(T->getIndexTypeCVRQualifiers()); // FIXME: stable values -} - -void ASTTypeWriter::VisitConstantArrayType(const ConstantArrayType *T) { - VisitArrayType(T); - Record.AddAPInt(T->getSize()); - Record.AddStmt(const_cast<Expr*>(T->getSizeExpr())); - Code = TYPE_CONSTANT_ARRAY; -} - -void ASTTypeWriter::VisitIncompleteArrayType(const IncompleteArrayType *T) { - VisitArrayType(T); - Code = TYPE_INCOMPLETE_ARRAY; -} - -void ASTTypeWriter::VisitVariableArrayType(const VariableArrayType *T) { - VisitArrayType(T); - Record.AddSourceLocation(T->getLBracketLoc()); - Record.AddSourceLocation(T->getRBracketLoc()); - Record.AddStmt(T->getSizeExpr()); - Code = TYPE_VARIABLE_ARRAY; -} - -void ASTTypeWriter::VisitVectorType(const VectorType *T) { - Record.AddTypeRef(T->getElementType()); - Record.push_back(T->getNumElements()); - Record.push_back(T->getVectorKind()); - Code = TYPE_VECTOR; -} - -void ASTTypeWriter::VisitExtVectorType(const ExtVectorType *T) { - VisitVectorType(T); - Code = TYPE_EXT_VECTOR; -} - -void ASTTypeWriter::VisitFunctionType(const FunctionType *T) { - Record.AddTypeRef(T->getReturnType()); - FunctionType::ExtInfo C = T->getExtInfo(); - Record.push_back(C.getNoReturn()); - Record.push_back(C.getHasRegParm()); - Record.push_back(C.getRegParm()); - // FIXME: need to stabilize encoding of calling convention... - Record.push_back(C.getCC()); - Record.push_back(C.getProducesResult()); - Record.push_back(C.getNoCallerSavedRegs()); - Record.push_back(C.getNoCfCheck()); - - if (C.getHasRegParm() || C.getRegParm() || C.getProducesResult()) - AbbrevToUse = 0; -} - -void ASTTypeWriter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { - VisitFunctionType(T); - Code = TYPE_FUNCTION_NO_PROTO; -} - -static void addExceptionSpec(const FunctionProtoType *T, - ASTRecordWriter &Record) { - Record.push_back(T->getExceptionSpecType()); - if (T->getExceptionSpecType() == EST_Dynamic) { - Record.push_back(T->getNumExceptions()); - for (unsigned I = 0, N = T->getNumExceptions(); I != N; ++I) - Record.AddTypeRef(T->getExceptionType(I)); - } else if (isComputedNoexcept(T->getExceptionSpecType())) { - Record.AddStmt(T->getNoexceptExpr()); - } else if (T->getExceptionSpecType() == EST_Uninstantiated) { - Record.AddDeclRef(T->getExceptionSpecDecl()); - Record.AddDeclRef(T->getExceptionSpecTemplate()); - } else if (T->getExceptionSpecType() == EST_Unevaluated) { - Record.AddDeclRef(T->getExceptionSpecDecl()); +static TypeCode getTypeCodeForTypeClass(Type::TypeClass id) { + switch (id) { +#define TYPE_BIT_CODE(CLASS_ID, CODE_ID, CODE_VALUE) \ + case Type::CLASS_ID: return TYPE_##CODE_ID; +#include "clang/Serialization/TypeBitCodes.def" + case Type::Builtin: + llvm_unreachable("shouldn't be serializing a builtin type this way"); } + llvm_unreachable("bad type kind"); } -void ASTTypeWriter::VisitFunctionProtoType(const FunctionProtoType *T) { - VisitFunctionType(T); - - Record.push_back(T->isVariadic()); - Record.push_back(T->hasTrailingReturn()); - Record.push_back(T->getMethodQuals().getAsOpaqueValue()); - Record.push_back(static_cast<unsigned>(T->getRefQualifier())); - addExceptionSpec(T, Record); - - Record.push_back(T->getNumParams()); - for (unsigned I = 0, N = T->getNumParams(); I != N; ++I) - Record.AddTypeRef(T->getParamType(I)); - - if (T->hasExtParameterInfos()) { - for (unsigned I = 0, N = T->getNumParams(); I != N; ++I) - Record.push_back(T->getExtParameterInfo(I).getOpaqueValue()); - } - - if (T->isVariadic() || T->hasTrailingReturn() || T->getMethodQuals() || - T->getRefQualifier() || T->getExceptionSpecType() != EST_None || - T->hasExtParameterInfos()) - AbbrevToUse = 0; - - Code = TYPE_FUNCTION_PROTO; -} - -void ASTTypeWriter::VisitUnresolvedUsingType(const UnresolvedUsingType *T) { - Record.AddDeclRef(T->getDecl()); - Code = TYPE_UNRESOLVED_USING; -} - -void ASTTypeWriter::VisitTypedefType(const TypedefType *T) { - Record.AddDeclRef(T->getDecl()); - assert(!T->isCanonicalUnqualified() && "Invalid typedef ?"); - Record.AddTypeRef(T->getCanonicalTypeInternal()); - Code = TYPE_TYPEDEF; -} - -void ASTTypeWriter::VisitTypeOfExprType(const TypeOfExprType *T) { - Record.AddStmt(T->getUnderlyingExpr()); - Code = TYPE_TYPEOF_EXPR; -} - -void ASTTypeWriter::VisitTypeOfType(const TypeOfType *T) { - Record.AddTypeRef(T->getUnderlyingType()); - Code = TYPE_TYPEOF; -} - -void ASTTypeWriter::VisitDecltypeType(const DecltypeType *T) { - Record.AddTypeRef(T->getUnderlyingType()); - Record.AddStmt(T->getUnderlyingExpr()); - Code = TYPE_DECLTYPE; -} - -void ASTTypeWriter::VisitUnaryTransformType(const UnaryTransformType *T) { - Record.AddTypeRef(T->getBaseType()); - Record.AddTypeRef(T->getUnderlyingType()); - Record.push_back(T->getUTTKind()); - Code = TYPE_UNARY_TRANSFORM; -} - -void ASTTypeWriter::VisitAutoType(const AutoType *T) { - Record.AddTypeRef(T->getDeducedType()); - Record.push_back((unsigned)T->getKeyword()); - if (T->getDeducedType().isNull()) - Record.push_back(T->containsUnexpandedParameterPack() ? 2 : - T->isDependentType() ? 1 : 0); - Code = TYPE_AUTO; -} - -void ASTTypeWriter::VisitDeducedTemplateSpecializationType( - const DeducedTemplateSpecializationType *T) { - Record.AddTemplateName(T->getTemplateName()); - Record.AddTypeRef(T->getDeducedType()); - if (T->getDeducedType().isNull()) - Record.push_back(T->isDependentType()); - Code = TYPE_DEDUCED_TEMPLATE_SPECIALIZATION; -} - -void ASTTypeWriter::VisitTagType(const TagType *T) { - Record.push_back(T->isDependentType()); - Record.AddDeclRef(T->getDecl()->getCanonicalDecl()); - assert(!T->isBeingDefined() && - "Cannot serialize in the middle of a type definition"); -} - -void ASTTypeWriter::VisitRecordType(const RecordType *T) { - VisitTagType(T); - Code = TYPE_RECORD; -} - -void ASTTypeWriter::VisitEnumType(const EnumType *T) { - VisitTagType(T); - Code = TYPE_ENUM; -} - -void ASTTypeWriter::VisitAttributedType(const AttributedType *T) { - Record.AddTypeRef(T->getModifiedType()); - Record.AddTypeRef(T->getEquivalentType()); - Record.push_back(T->getAttrKind()); - Code = TYPE_ATTRIBUTED; -} - -void -ASTTypeWriter::VisitSubstTemplateTypeParmType( - const SubstTemplateTypeParmType *T) { - Record.AddTypeRef(QualType(T->getReplacedParameter(), 0)); - Record.AddTypeRef(T->getReplacementType()); - Code = TYPE_SUBST_TEMPLATE_TYPE_PARM; -} - -void -ASTTypeWriter::VisitSubstTemplateTypeParmPackType( - const SubstTemplateTypeParmPackType *T) { - Record.AddTypeRef(QualType(T->getReplacedParameter(), 0)); - Record.AddTemplateArgument(T->getArgumentPack()); - Code = TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK; -} - -void -ASTTypeWriter::VisitTemplateSpecializationType( - const TemplateSpecializationType *T) { - Record.push_back(T->isDependentType()); - Record.AddTemplateName(T->getTemplateName()); - Record.push_back(T->getNumArgs()); - for (const auto &ArgI : *T) - Record.AddTemplateArgument(ArgI); - Record.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() - : T->isCanonicalUnqualified() - ? QualType() - : T->getCanonicalTypeInternal()); - Code = TYPE_TEMPLATE_SPECIALIZATION; -} - -void -ASTTypeWriter::VisitDependentSizedArrayType(const DependentSizedArrayType *T) { - VisitArrayType(T); - Record.AddStmt(T->getSizeExpr()); - Record.AddSourceRange(T->getBracketsRange()); - Code = TYPE_DEPENDENT_SIZED_ARRAY; -} - -void -ASTTypeWriter::VisitDependentSizedExtVectorType( - const DependentSizedExtVectorType *T) { - Record.AddTypeRef(T->getElementType()); - Record.AddStmt(T->getSizeExpr()); - Record.AddSourceLocation(T->getAttributeLoc()); - Code = TYPE_DEPENDENT_SIZED_EXT_VECTOR; -} - -void ASTTypeWriter::VisitDependentVectorType(const DependentVectorType *T) { - Record.AddTypeRef(T->getElementType()); - Record.AddStmt(const_cast<Expr*>(T->getSizeExpr())); - Record.AddSourceLocation(T->getAttributeLoc()); - Record.push_back(T->getVectorKind()); - Code = TYPE_DEPENDENT_SIZED_VECTOR; -} - -void -ASTTypeWriter::VisitDependentAddressSpaceType( - const DependentAddressSpaceType *T) { - Record.AddTypeRef(T->getPointeeType()); - Record.AddStmt(T->getAddrSpaceExpr()); - Record.AddSourceLocation(T->getAttributeLoc()); - Code = TYPE_DEPENDENT_ADDRESS_SPACE; -} - -void -ASTTypeWriter::VisitTemplateTypeParmType(const TemplateTypeParmType *T) { - Record.push_back(T->getDepth()); - Record.push_back(T->getIndex()); - Record.push_back(T->isParameterPack()); - Record.AddDeclRef(T->getDecl()); - Code = TYPE_TEMPLATE_TYPE_PARM; -} - -void -ASTTypeWriter::VisitDependentNameType(const DependentNameType *T) { - Record.push_back(T->getKeyword()); - Record.AddNestedNameSpecifier(T->getQualifier()); - Record.AddIdentifierRef(T->getIdentifier()); - Record.AddTypeRef( - T->isCanonicalUnqualified() ? QualType() : T->getCanonicalTypeInternal()); - Code = TYPE_DEPENDENT_NAME; -} - -void -ASTTypeWriter::VisitDependentTemplateSpecializationType( - const DependentTemplateSpecializationType *T) { - Record.push_back(T->getKeyword()); - Record.AddNestedNameSpecifier(T->getQualifier()); - Record.AddIdentifierRef(T->getIdentifier()); - Record.push_back(T->getNumArgs()); - for (const auto &I : *T) - Record.AddTemplateArgument(I); - Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION; -} - -void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) { - Record.AddTypeRef(T->getPattern()); - if (Optional<unsigned> NumExpansions = T->getNumExpansions()) - Record.push_back(*NumExpansions + 1); - else - Record.push_back(0); - Code = TYPE_PACK_EXPANSION; -} - -void ASTTypeWriter::VisitParenType(const ParenType *T) { - Record.AddTypeRef(T->getInnerType()); - Code = TYPE_PAREN; -} - -void ASTTypeWriter::VisitMacroQualifiedType(const MacroQualifiedType *T) { - Record.AddTypeRef(T->getUnderlyingType()); - Record.AddIdentifierRef(T->getMacroIdentifier()); - Code = TYPE_MACRO_QUALIFIED; -} - -void ASTTypeWriter::VisitElaboratedType(const ElaboratedType *T) { - Record.push_back(T->getKeyword()); - Record.AddNestedNameSpecifier(T->getQualifier()); - Record.AddTypeRef(T->getNamedType()); - Record.AddDeclRef(T->getOwnedTagDecl()); - Code = TYPE_ELABORATED; -} - -void ASTTypeWriter::VisitInjectedClassNameType(const InjectedClassNameType *T) { - Record.AddDeclRef(T->getDecl()->getCanonicalDecl()); - Record.AddTypeRef(T->getInjectedSpecializationType()); - Code = TYPE_INJECTED_CLASS_NAME; -} - -void ASTTypeWriter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { - Record.AddDeclRef(T->getDecl()->getCanonicalDecl()); - Code = TYPE_OBJC_INTERFACE; -} - -void ASTTypeWriter::VisitObjCTypeParamType(const ObjCTypeParamType *T) { - Record.AddDeclRef(T->getDecl()); - Record.push_back(T->getNumProtocols()); - for (const auto *I : T->quals()) - Record.AddDeclRef(I); - Code = TYPE_OBJC_TYPE_PARAM; -} - -void ASTTypeWriter::VisitObjCObjectType(const ObjCObjectType *T) { - Record.AddTypeRef(T->getBaseType()); - Record.push_back(T->getTypeArgsAsWritten().size()); - for (auto TypeArg : T->getTypeArgsAsWritten()) - Record.AddTypeRef(TypeArg); - Record.push_back(T->getNumProtocols()); - for (const auto *I : T->quals()) - Record.AddDeclRef(I); - Record.push_back(T->isKindOfTypeAsWritten()); - Code = TYPE_OBJC_OBJECT; -} +namespace { -void -ASTTypeWriter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { - Record.AddTypeRef(T->getPointeeType()); - Code = TYPE_OBJC_OBJECT_POINTER; -} +class ASTTypeWriter { + ASTWriter &Writer; + ASTWriter::RecordData Record; + ASTRecordWriter BasicWriter; -void -ASTTypeWriter::VisitAtomicType(const AtomicType *T) { - Record.AddTypeRef(T->getValueType()); - Code = TYPE_ATOMIC; -} +public: + ASTTypeWriter(ASTWriter &Writer) + : Writer(Writer), BasicWriter(Writer, Record) {} -void -ASTTypeWriter::VisitPipeType(const PipeType *T) { - Record.AddTypeRef(T->getElementType()); - Record.push_back(T->isReadOnly()); - Code = TYPE_PIPE; -} + uint64_t write(QualType T) { + if (T.hasLocalNonFastQualifiers()) { + Qualifiers Qs = T.getLocalQualifiers(); + BasicWriter.writeQualType(T.getLocalUnqualifiedType()); + BasicWriter.writeQualifiers(Qs); + return BasicWriter.Emit(TYPE_EXT_QUAL, Writer.getTypeExtQualAbbrev()); + } -namespace { + const Type *typePtr = T.getTypePtr(); + serialization::AbstractTypeWriter<ASTRecordWriter> atw(BasicWriter); + atw.write(typePtr); + return BasicWriter.Emit(getTypeCodeForTypeClass(typePtr->getTypeClass()), + /*abbrev*/ 0); + } +}; class TypeLocWriter : public TypeLocVisitor<TypeLocWriter> { ASTRecordWriter &Record; @@ -3198,12 +2786,8 @@ void ASTWriter::WriteType(QualType T) { assert(Idx.getIndex() >= FirstTypeID && "Re-writing a type from a prior AST"); - RecordData Record; - // Emit the type's representation. - ASTTypeWriter W(*this, Record); - W.Visit(T); - uint64_t Offset = W.Emit(); + uint64_t Offset = ASTTypeWriter(*this).write(T); // Record the offset for this type. unsigned Index = Idx.getIndex() - FirstTypeID; @@ -5364,11 +4948,12 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { Record.AddStmt(cast<CXXDestructorDecl>(D)->getOperatorDeleteThisArg()); break; - case UPD_CXX_RESOLVED_EXCEPTION_SPEC: - addExceptionSpec( - cast<FunctionDecl>(D)->getType()->castAs<FunctionProtoType>(), - Record); + case UPD_CXX_RESOLVED_EXCEPTION_SPEC: { + auto prototype = + cast<FunctionDecl>(D)->getType()->castAs<FunctionProtoType>(); + Record.writeExceptionSpecInfo(prototype->getExceptionSpecInfo()); break; + } case UPD_CXX_DEDUCED_RETURN_TYPE: Record.push_back(GetOrCreateTypeID(Update.getType())); @@ -5434,17 +5019,6 @@ void ASTWriter::AddSourceRange(SourceRange Range, RecordDataImpl &Record) { AddSourceLocation(Range.getEnd(), Record); } -void ASTRecordWriter::AddAPInt(const llvm::APInt &Value) { - Record->push_back(Value.getBitWidth()); - const uint64_t *Words = Value.getRawData(); - Record->append(Words, Words + Value.getNumWords()); -} - -void ASTRecordWriter::AddAPSInt(const llvm::APSInt &Value) { - Record->push_back(Value.isUnsigned()); - AddAPInt(Value); -} - void ASTRecordWriter::AddAPFloat(const llvm::APFloat &Value) { AddAPInt(Value.bitcastToAPInt()); } @@ -5762,44 +5336,6 @@ void ASTWriter::associateDeclWithFile(const Decl *D, DeclID ID) { Decls.insert(I, LocDecl); } -void ASTRecordWriter::AddDeclarationName(DeclarationName Name) { - // FIXME: Emit a stable enum for NameKind. 0 = Identifier etc. - Record->push_back(Name.getNameKind()); - switch (Name.getNameKind()) { - case DeclarationName::Identifier: - AddIdentifierRef(Name.getAsIdentifierInfo()); - break; - - case DeclarationName::ObjCZeroArgSelector: - case DeclarationName::ObjCOneArgSelector: - case DeclarationName::ObjCMultiArgSelector: - AddSelectorRef(Name.getObjCSelector()); - break; - - case DeclarationName::CXXConstructorName: - case DeclarationName::CXXDestructorName: - case DeclarationName::CXXConversionFunctionName: - AddTypeRef(Name.getCXXNameType()); - break; - - case DeclarationName::CXXDeductionGuideName: - AddDeclRef(Name.getCXXDeductionGuideTemplate()); - break; - - case DeclarationName::CXXOperatorName: - Record->push_back(Name.getCXXOverloadedOperator()); - break; - - case DeclarationName::CXXLiteralOperatorName: - AddIdentifierRef(Name.getCXXLiteralIdentifier()); - break; - - case DeclarationName::CXXUsingDirective: - // No extra data to emit - break; - } -} - unsigned ASTWriter::getAnonymousDeclarationNumber(const NamedDecl *D) { assert(needsAnonymousDeclarationNumber(D) && "expected an anonymous declaration"); @@ -5866,52 +5402,6 @@ void ASTRecordWriter::AddQualifierInfo(const QualifierInfo &Info) { AddTemplateParameterList(Info.TemplParamLists[i]); } -void ASTRecordWriter::AddNestedNameSpecifier(NestedNameSpecifier *NNS) { - // Nested name specifiers usually aren't too long. I think that 8 would - // typically accommodate the vast majority. - SmallVector<NestedNameSpecifier *, 8> NestedNames; - - // Push each of the NNS's onto a stack for serialization in reverse order. - while (NNS) { - NestedNames.push_back(NNS); - NNS = NNS->getPrefix(); - } - - Record->push_back(NestedNames.size()); - while(!NestedNames.empty()) { - NNS = NestedNames.pop_back_val(); - NestedNameSpecifier::SpecifierKind Kind = NNS->getKind(); - Record->push_back(Kind); - switch (Kind) { - case NestedNameSpecifier::Identifier: - AddIdentifierRef(NNS->getAsIdentifier()); - break; - - case NestedNameSpecifier::Namespace: - AddDeclRef(NNS->getAsNamespace()); - break; - - case NestedNameSpecifier::NamespaceAlias: - AddDeclRef(NNS->getAsNamespaceAlias()); - break; - - case NestedNameSpecifier::TypeSpec: - case NestedNameSpecifier::TypeSpecWithTemplate: - AddTypeRef(QualType(NNS->getAsType(), 0)); - Record->push_back(Kind == NestedNameSpecifier::TypeSpecWithTemplate); - break; - - case NestedNameSpecifier::Global: - // Don't need to write an associated value. - break; - - case NestedNameSpecifier::Super: - AddDeclRef(NNS->getAsRecordDecl()); - break; - } - } -} - void ASTRecordWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { // Nested name specifiers usually aren't too long. I think that 8 would // typically accommodate the vast majority. @@ -5966,105 +5456,6 @@ void ASTRecordWriter::AddNestedNameSpecifierLoc(NestedNameSpecifierLoc NNS) { } } -void ASTRecordWriter::AddTemplateName(TemplateName Name) { - TemplateName::NameKind Kind = Name.getKind(); - Record->push_back(Kind); - switch (Kind) { - case TemplateName::Template: - AddDeclRef(Name.getAsTemplateDecl()); - break; - - case TemplateName::OverloadedTemplate: { - OverloadedTemplateStorage *OvT = Name.getAsOverloadedTemplate(); - Record->push_back(OvT->size()); - for (const auto &I : *OvT) - AddDeclRef(I); - break; - } - - case TemplateName::AssumedTemplate: { - AssumedTemplateStorage *ADLT = Name.getAsAssumedTemplateName(); - AddDeclarationName(ADLT->getDeclName()); - break; - } - - case TemplateName::QualifiedTemplate: { - QualifiedTemplateName *QualT = Name.getAsQualifiedTemplateName(); - AddNestedNameSpecifier(QualT->getQualifier()); - Record->push_back(QualT->hasTemplateKeyword()); - AddDeclRef(QualT->getTemplateDecl()); - break; - } - - case TemplateName::DependentTemplate: { - DependentTemplateName *DepT = Name.getAsDependentTemplateName(); - AddNestedNameSpecifier(DepT->getQualifier()); - Record->push_back(DepT->isIdentifier()); - if (DepT->isIdentifier()) - AddIdentifierRef(DepT->getIdentifier()); - else - Record->push_back(DepT->getOperator()); - break; - } - - case TemplateName::SubstTemplateTemplateParm: { - SubstTemplateTemplateParmStorage *subst - = Name.getAsSubstTemplateTemplateParm(); - AddDeclRef(subst->getParameter()); - AddTemplateName(subst->getReplacement()); - break; - } - - case TemplateName::SubstTemplateTemplateParmPack: { - SubstTemplateTemplateParmPackStorage *SubstPack - = Name.getAsSubstTemplateTemplateParmPack(); - AddDeclRef(SubstPack->getParameterPack()); - AddTemplateArgument(SubstPack->getArgumentPack()); - break; - } - } -} - -void ASTRecordWriter::AddTemplateArgument(const TemplateArgument &Arg) { - Record->push_back(Arg.getKind()); - switch (Arg.getKind()) { - case TemplateArgument::Null: - break; - case TemplateArgument::Type: - AddTypeRef(Arg.getAsType()); - break; - case TemplateArgument::Declaration: - AddDeclRef(Arg.getAsDecl()); - AddTypeRef(Arg.getParamTypeForDecl()); - break; - case TemplateArgument::NullPtr: - AddTypeRef(Arg.getNullPtrType()); - break; - case TemplateArgument::Integral: - AddAPSInt(Arg.getAsIntegral()); - AddTypeRef(Arg.getIntegralType()); - break; - case TemplateArgument::Template: - AddTemplateName(Arg.getAsTemplateOrTemplatePattern()); - break; - case TemplateArgument::TemplateExpansion: - AddTemplateName(Arg.getAsTemplateOrTemplatePattern()); - if (Optional<unsigned> NumExpansions = Arg.getNumTemplateExpansions()) - Record->push_back(*NumExpansions + 1); - else - Record->push_back(0); - break; - case TemplateArgument::Expression: - AddStmt(Arg.getAsExpr()); - break; - case TemplateArgument::Pack: - Record->push_back(Arg.pack_size()); - for (const auto &P : Arg.pack_elements()) - AddTemplateArgument(P); - break; - } -} - void ASTRecordWriter::AddTemplateParameterList( const TemplateParameterList *TemplateParams) { assert(TemplateParams && "No TemplateParams!"); @@ -6192,8 +5583,8 @@ void ASTRecordWriter::AddCXXDefinitionData(const CXXRecordDecl *D) { // getODRHash will compute the ODRHash if it has not been previously computed. Record->push_back(D->getODRHash()); - bool ModulesDebugInfo = Writer->Context->getLangOpts().ModulesDebugInfo && - Writer->WritingModule && !D->isDependentType(); + bool ModulesDebugInfo = + Writer->Context->getLangOpts().ModulesDebugInfo && !D->isDependentType(); Record->push_back(ModulesDebugInfo); if (ModulesDebugInfo) Writer->ModularCodegenDecls.push_back(Writer->GetDeclRef(D)); @@ -6614,6 +6005,26 @@ void ASTWriter::AddedCXXTemplateSpecialization(const FunctionTemplateDecl *TD, //// OMPClause Serialization ////===----------------------------------------------------------------------===// +namespace { + +class OMPClauseWriter : public OMPClauseVisitor<OMPClauseWriter> { + ASTRecordWriter &Record; + +public: + OMPClauseWriter(ASTRecordWriter &Record) : Record(Record) {} +#define OPENMP_CLAUSE(Name, Class) void Visit##Class(Class *S); +#include "clang/Basic/OpenMPKinds.def" + void writeClause(OMPClause *C); + void VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C); + void VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C); +}; + +} + +void ASTRecordWriter::writeOMPClause(OMPClause *C) { + OMPClauseWriter(*this).writeClause(C); +} + void OMPClauseWriter::writeClause(OMPClause *C) { Record.push_back(C->getClauseKind()); Visit(C); @@ -6622,7 +6033,7 @@ void OMPClauseWriter::writeClause(OMPClause *C) { } void OMPClauseWriter::VisitOMPClauseWithPreInit(OMPClauseWithPreInit *C) { - Record.push_back(C->getCaptureRegion()); + Record.push_back(uint64_t(C->getCaptureRegion())); Record.AddStmt(C->getPreInitStmt()); } @@ -6633,7 +6044,7 @@ void OMPClauseWriter::VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *C) { void OMPClauseWriter::VisitOMPIfClause(OMPIfClause *C) { VisitOMPClauseWithPreInit(C); - Record.push_back(C->getNameModifier()); + Record.push_back(uint64_t(C->getNameModifier())); Record.AddSourceLocation(C->getNameModifierLoc()); Record.AddSourceLocation(C->getColonLoc()); Record.AddStmt(C->getCondition()); @@ -6679,7 +6090,7 @@ void OMPClauseWriter::VisitOMPDefaultClause(OMPDefaultClause *C) { } void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) { - Record.push_back(C->getProcBindKind()); + Record.push_back(unsigned(C->getProcBindKind())); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getProcBindKindKwLoc()); } @@ -6759,6 +6170,9 @@ void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) { Record.push_back(C->varlist_size()); VisitOMPClauseWithPostUpdate(C); Record.AddSourceLocation(C->getLParenLoc()); + Record.writeEnum(C->getKind()); + Record.AddSourceLocation(C->getKindLoc()); + Record.AddSourceLocation(C->getColonLoc()); for (auto *VE : C->varlists()) Record.AddStmt(VE); for (auto *E : C->private_copies()) @@ -7127,3 +6541,12 @@ void OMPClauseWriter::VisitOMPAtomicDefaultMemOrderClause( Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getAtomicDefaultMemOrderKindKwLoc()); } + +void OMPClauseWriter::VisitOMPNontemporalClause(OMPNontemporalClause *C) { + Record.push_back(C->varlist_size()); + Record.AddSourceLocation(C->getLParenLoc()); + for (auto *VE : C->varlists()) + Record.AddStmt(VE); + for (auto *E : C->private_refs()) + Record.AddStmt(E); +} diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 039b57f88e73..b2a8c118d401 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "ASTCommon.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclContextInternals.h" #include "clang/AST/DeclTemplate.h" @@ -20,7 +21,7 @@ #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/SourceManager.h" #include "clang/Serialization/ASTReader.h" -#include "clang/Serialization/ASTWriter.h" +#include "clang/Serialization/ASTRecordWriter.h" #include "llvm/Bitstream/BitstreamWriter.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -124,6 +125,7 @@ namespace clang { void VisitBlockDecl(BlockDecl *D); void VisitCapturedDecl(CapturedDecl *D); void VisitEmptyDecl(EmptyDecl *D); + void VisitLifetimeExtendedTemporaryDecl(LifetimeExtendedTemporaryDecl *D); void VisitDeclContext(DeclContext *DC); template <typename T> void VisitRedeclarable(Redeclarable<T> *D); @@ -521,8 +523,11 @@ void ASTDeclWriter::VisitDeclaratorDecl(DeclaratorDecl *D) { VisitValueDecl(D); Record.AddSourceLocation(D->getInnerLocStart()); Record.push_back(D->hasExtInfo()); - if (D->hasExtInfo()) - Record.AddQualifierInfo(*D->getExtInfo()); + if (D->hasExtInfo()) { + DeclaratorDecl::ExtInfo *Info = D->getExtInfo(); + Record.AddQualifierInfo(*Info); + Record.AddStmt(Info->TrailingRequiresClause); + } // The location information is deferred until the end of the record. Record.AddTypeRef(D->getTypeSourceInfo() ? D->getTypeSourceInfo()->getType() : QualType()); @@ -558,6 +563,19 @@ void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { Record.AddSourceLocation(D->getEndLoc()); Record.push_back(D->getODRHash()); + Record.push_back(D->usesFPIntrin()); + + if (D->isDefaulted()) { + if (auto *FDI = D->getDefaultedFunctionInfo()) { + Record.push_back(FDI->getUnqualifiedLookups().size()); + for (DeclAccessPair P : FDI->getUnqualifiedLookups()) { + Record.AddDeclRef(P.getDecl()); + Record.push_back(P.getAccess()); + } + } else { + Record.push_back(0); + } + } Record.push_back(D->getTemplatedKind()); switch (D->getTemplatedKind()) { @@ -662,17 +680,17 @@ void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { VisitNamedDecl(D); // FIXME: convert to LazyStmtPtr? // Unlike C/C++, method bodies will never be in header files. - bool HasBodyStuff = D->getBody() != nullptr || - D->getSelfDecl() != nullptr || D->getCmdDecl() != nullptr; + bool HasBodyStuff = D->getBody() != nullptr; Record.push_back(HasBodyStuff); if (HasBodyStuff) { Record.AddStmt(D->getBody()); - Record.AddDeclRef(D->getSelfDecl()); - Record.AddDeclRef(D->getCmdDecl()); } + Record.AddDeclRef(D->getSelfDecl()); + Record.AddDeclRef(D->getCmdDecl()); Record.push_back(D->isInstanceMethod()); Record.push_back(D->isVariadic()); Record.push_back(D->isPropertyAccessor()); + Record.push_back(D->isSynthesizedAccessorStub()); Record.push_back(D->isDefined()); Record.push_back(D->isOverriding()); Record.push_back(D->hasSkippedBody()); @@ -884,6 +902,8 @@ void ASTDeclWriter::VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D) { Record.AddDeclRef(D->getPropertyDecl()); Record.AddDeclRef(D->getPropertyIvarDecl()); Record.AddSourceLocation(D->getPropertyIvarDeclLoc()); + Record.AddDeclRef(D->getGetterMethodDecl()); + Record.AddDeclRef(D->getSetterMethodDecl()); Record.AddStmt(D->getGetterCXXConstructor()); Record.AddStmt(D->getSetterCXXAssignment()); Code = serialization::DECL_OBJC_PROPERTY_IMPL; @@ -982,7 +1002,7 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { } if (D->hasAttr<BlocksAttr>() && D->getType()->getAsCXXRecordDecl()) { - ASTContext::BlockVarCopyInit Init = Writer.Context->getBlockVarCopyInit(D); + BlockVarCopyInit Init = Writer.Context->getBlockVarCopyInit(D); Record.AddStmt(Init.getCopyExpr()); if (Init.getCopyExpr()) Record.push_back(Init.canThrow()); @@ -990,15 +1010,16 @@ void ASTDeclWriter::VisitVarDecl(VarDecl *D) { if (D->getStorageDuration() == SD_Static) { bool ModulesCodegen = false; - if (Writer.WritingModule && - !D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() && + if (!D->getDescribedVarTemplate() && !D->getMemberSpecializationInfo() && !isa<VarTemplateSpecializationDecl>(D)) { // 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 variables are // still emitted in module users.) ModulesCodegen = - (Writer.WritingModule->Kind == Module::ModuleInterfaceUnit && + (((Writer.WritingModule && + Writer.WritingModule->Kind == Module::ModuleInterfaceUnit) || + Writer.Context->getLangOpts().BuildingPCHWithObjectFile) && Writer.Context->GetGVALinkageForVariable(D) == GVA_StrongExternal); } Record.push_back(ModulesCodegen); @@ -1131,6 +1152,17 @@ void ASTDeclWriter::VisitEmptyDecl(EmptyDecl *D) { Code = serialization::DECL_EMPTY; } +void ASTDeclWriter::VisitLifetimeExtendedTemporaryDecl( + LifetimeExtendedTemporaryDecl *D) { + VisitDecl(D); + Record.AddDeclRef(D->getExtendingDecl()); + Record.AddStmt(D->getTemporaryExpr()); + Record.push_back(static_cast<bool>(D->getValue())); + if (D->getValue()) + Record.AddAPValue(*D->getValue()); + Record.push_back(D->getManglingNumber()); + Code = serialization::DECL_LIFETIME_EXTENDED_TEMPORARY; +} void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) { VisitDecl(D); Record.AddStmt(D->getBody()); @@ -1511,11 +1543,11 @@ void ASTDeclWriter::VisitClassTemplateSpecializationDecl( void ASTDeclWriter::VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { - VisitClassTemplateSpecializationDecl(D); - Record.AddTemplateParameterList(D->getTemplateParameters()); Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten()); + VisitClassTemplateSpecializationDecl(D); + // These are read/set from/to the first declaration. if (D->getPreviousDecl() == nullptr) { Record.AddDeclRef(D->getInstantiatedFromMember()); @@ -1571,11 +1603,11 @@ void ASTDeclWriter::VisitVarTemplateSpecializationDecl( void ASTDeclWriter::VisitVarTemplatePartialSpecializationDecl( VarTemplatePartialSpecializationDecl *D) { - VisitVarTemplateSpecializationDecl(D); - Record.AddTemplateParameterList(D->getTemplateParameters()); Record.AddASTTemplateArgumentListInfo(D->getTemplateArgsAsWritten()); + VisitVarTemplateSpecializationDecl(D); + // These are read/set from/to the first declaration. if (D->getPreviousDecl() == nullptr) { Record.AddDeclRef(D->getInstantiatedFromMember()); @@ -1605,10 +1637,26 @@ void ASTDeclWriter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { } void ASTDeclWriter::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + Record.push_back(D->hasTypeConstraint()); VisitTypeDecl(D); Record.push_back(D->wasDeclaredWithTypename()); - // TODO: Concepts - constrained parameters. + + const TypeConstraint *TC = D->getTypeConstraint(); + Record.push_back(TC != nullptr); + if (TC) { + Record.AddNestedNameSpecifierLoc(TC->getNestedNameSpecifierLoc()); + Record.AddDeclarationNameInfo(TC->getConceptNameInfo()); + Record.AddDeclRef(TC->getNamedConcept()); + Record.push_back(TC->getTemplateArgsAsWritten() != nullptr); + if (TC->getTemplateArgsAsWritten()) + Record.AddASTTemplateArgumentListInfo(TC->getTemplateArgsAsWritten()); + Record.AddStmt(TC->getImmediatelyDeclaredConstraint()); + Record.push_back(D->isExpandedParameterPack()); + if (D->isExpandedParameterPack()) + Record.push_back(D->getNumExpansionParameters()); + } + bool OwnsDefaultArg = D->hasDefaultArgument() && !D->defaultArgumentWasInherited(); Record.push_back(OwnsDefaultArg); @@ -1638,7 +1686,6 @@ void ASTDeclWriter::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { Code = serialization::DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK; } else { - // TODO: Concepts - constrained parameters. // Rest of NonTypeTemplateParmDecl. Record.push_back(D->isParameterPack()); bool OwnsDefaultArg = D->hasDefaultArgument() && @@ -1668,7 +1715,6 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { Record.AddTemplateParameterList(D->getExpansionTemplateParameters(I)); Code = serialization::DECL_EXPANDED_TEMPLATE_TEMPLATE_PARM_PACK; } else { - // TODO: Concepts - constrained parameters. // Rest of TemplateTemplateParmDecl. Record.push_back(D->isParameterPack()); bool OwnsDefaultArg = D->hasDefaultArgument() && @@ -1790,18 +1836,16 @@ void ASTDeclWriter::VisitOMPAllocateDecl(OMPAllocateDecl *D) { VisitDecl(D); for (auto *I : D->varlists()) Record.AddStmt(I); - OMPClauseWriter ClauseWriter(Record); for (OMPClause *C : D->clauselists()) - ClauseWriter.writeClause(C); + Record.writeOMPClause(C); Code = serialization::DECL_OMP_ALLOCATE; } void ASTDeclWriter::VisitOMPRequiresDecl(OMPRequiresDecl *D) { Record.push_back(D->clauselist_size()); VisitDecl(D); - OMPClauseWriter ClauseWriter(Record); for (OMPClause *C : D->clauselists()) - ClauseWriter.writeClause(C); + Record.writeOMPClause(C); Code = serialization::DECL_OMP_REQUIRES; } @@ -1826,9 +1870,8 @@ void ASTDeclWriter::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) { Record.AddStmt(D->getMapperVarRef()); Record.AddDeclarationName(D->getVarName()); Record.AddDeclRef(D->getPrevDeclInScope()); - OMPClauseWriter ClauseWriter(Record); for (OMPClause *C : D->clauselists()) - ClauseWriter.writeClause(C); + Record.writeOMPClause(C); Code = serialization::DECL_OMP_DECLARE_MAPPER; } @@ -2397,9 +2440,11 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) { assert(FD->doesThisDeclarationHaveABody()); bool ModulesCodegen = false; - if (Writer->WritingModule && !FD->isDependentContext()) { + if (!FD->isDependentContext()) { Optional<GVALinkage> Linkage; - if (Writer->WritingModule->Kind == Module::ModuleInterfaceUnit) { + if ((Writer->WritingModule && + Writer->WritingModule->Kind == Module::ModuleInterfaceUnit) || + Writer->Context->getLangOpts().BuildingPCHWithObjectFile) { // 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 @@ -2409,11 +2454,12 @@ void ASTRecordWriter::AddFunctionDefinition(const FunctionDecl *FD) { } if (Writer->Context->getLangOpts().ModulesCodegen) { // Under -fmodules-codegen, codegen is performed for all non-internal, - // non-always_inline functions. + // non-always_inline functions, unless they are available elsewhere. if (!FD->hasAttr<AlwaysInlineAttr>()) { if (!Linkage) Linkage = Writer->Context->GetGVALinkageForFunction(FD); - ModulesCodegen = *Linkage != GVA_Internal; + ModulesCodegen = + *Linkage != GVA_Internal && *Linkage != GVA_AvailableExternally; } } } diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index c39d4d39bcdf..9231f3b2b9ba 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -11,7 +11,7 @@ /// //===----------------------------------------------------------------------===// -#include "clang/Serialization/ASTWriter.h" +#include "clang/Serialization/ASTRecordWriter.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -395,13 +395,30 @@ void ASTStmtWriter::VisitConceptSpecializationExpr( Record.push_back(TemplateArgs.size()); Record.AddNestedNameSpecifierLoc(E->getNestedNameSpecifierLoc()); Record.AddSourceLocation(E->getTemplateKWLoc()); - Record.AddSourceLocation(E->getConceptNameLoc()); - Record.AddDeclRef(E->getFoundDecl()); + Record.AddDeclarationNameInfo(E->getConceptNameInfo()); Record.AddDeclRef(E->getNamedConcept()); Record.AddASTTemplateArgumentListInfo(E->getTemplateArgsAsWritten()); for (const TemplateArgument &Arg : TemplateArgs) Record.AddTemplateArgument(Arg); - Record.push_back(E->isSatisfied()); + const ASTConstraintSatisfaction &Satisfaction = E->getSatisfaction(); + Record.push_back(Satisfaction.IsSatisfied); + if (!Satisfaction.IsSatisfied) { + Record.push_back(Satisfaction.NumRecords); + for (const auto &DetailRecord : Satisfaction) { + Record.AddStmt(const_cast<Expr *>(DetailRecord.first)); + auto *E = DetailRecord.second.dyn_cast<Expr *>(); + Record.push_back(E == nullptr); + if (E) + Record.AddStmt(E); + else { + auto *Diag = DetailRecord.second.get<std::pair<SourceLocation, + StringRef> *>(); + Record.AddSourceLocation(Diag->first); + Record.AddString(Diag->second); + } + } + } + Code = serialization::EXPR_CONCEPT_SPECIALIZATION; } @@ -1835,9 +1852,11 @@ void ASTStmtWriter::VisitFunctionParmPackExpr(FunctionParmPackExpr *E) { void ASTStmtWriter::VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E) { VisitExpr(E); - Record.AddStmt(E->getTemporary()); - Record.AddDeclRef(E->getExtendingDecl()); - Record.push_back(E->getManglingNumber()); + Record.push_back(static_cast<bool>(E->getLifetimeExtendedTemporaryDecl())); + if (E->getLifetimeExtendedTemporaryDecl()) + Record.AddDeclRef(E->getLifetimeExtendedTemporaryDecl()); + else + Record.AddStmt(E->getSubExpr()); Code = serialization::EXPR_MATERIALIZE_TEMPORARY; } @@ -1958,9 +1977,8 @@ void ASTStmtWriter::VisitSEHLeaveStmt(SEHLeaveStmt *S) { void ASTStmtWriter::VisitOMPExecutableDirective(OMPExecutableDirective *E) { Record.AddSourceLocation(E->getBeginLoc()); Record.AddSourceLocation(E->getEndLoc()); - OMPClauseWriter ClauseWriter(Record); for (unsigned i = 0; i < E->getNumClauses(); ++i) { - ClauseWriter.writeClause(E->getClause(i)); + Record.writeOMPClause(E->getClause(i)); } if (E->hasAssociatedStmt()) Record.AddStmt(E->getAssociatedStmt()); @@ -2101,6 +2119,14 @@ void ASTStmtWriter::VisitOMPParallelForSimdDirective( Code = serialization::STMT_OMP_PARALLEL_FOR_SIMD_DIRECTIVE; } +void ASTStmtWriter::VisitOMPParallelMasterDirective( + OMPParallelMasterDirective *D) { + VisitStmt(D); + Record.push_back(D->getNumClauses()); + VisitOMPExecutableDirective(D); + Code = serialization::STMT_OMP_PARALLEL_MASTER_DIRECTIVE; +} + void ASTStmtWriter::VisitOMPParallelSectionsDirective( OMPParallelSectionsDirective *D) { VisitStmt(D); @@ -2227,7 +2253,7 @@ void ASTStmtWriter::VisitOMPCancellationPointDirective( OMPCancellationPointDirective *D) { VisitStmt(D); VisitOMPExecutableDirective(D); - Record.push_back(D->getCancelRegion()); + Record.push_back(uint64_t(D->getCancelRegion())); Code = serialization::STMT_OMP_CANCELLATION_POINT_DIRECTIVE; } @@ -2235,7 +2261,7 @@ void ASTStmtWriter::VisitOMPCancelDirective(OMPCancelDirective *D) { VisitStmt(D); Record.push_back(D->getNumClauses()); VisitOMPExecutableDirective(D); - Record.push_back(D->getCancelRegion()); + Record.push_back(uint64_t(D->getCancelRegion())); Code = serialization::STMT_OMP_CANCEL_DIRECTIVE; } @@ -2267,6 +2293,12 @@ void ASTStmtWriter::VisitOMPParallelMasterTaskLoopDirective( Code = serialization::STMT_OMP_PARALLEL_MASTER_TASKLOOP_DIRECTIVE; } +void ASTStmtWriter::VisitOMPParallelMasterTaskLoopSimdDirective( + OMPParallelMasterTaskLoopSimdDirective *D) { + VisitOMPLoopDirective(D); + Code = serialization::STMT_OMP_PARALLEL_MASTER_TASKLOOP_SIMD_DIRECTIVE; +} + void ASTStmtWriter::VisitOMPDistributeDirective(OMPDistributeDirective *D) { VisitOMPLoopDirective(D); Code = serialization::STMT_OMP_DISTRIBUTE_DIRECTIVE; diff --git a/clang/lib/Serialization/GlobalModuleIndex.cpp b/clang/lib/Serialization/GlobalModuleIndex.cpp index 54ab17681ee9..462d29c2a0f1 100644 --- a/clang/lib/Serialization/GlobalModuleIndex.cpp +++ b/clang/lib/Serialization/GlobalModuleIndex.cpp @@ -10,12 +10,12 @@ // //===----------------------------------------------------------------------===// +#include "clang/Serialization/GlobalModuleIndex.h" #include "ASTReaderInternals.h" #include "clang/Basic/FileManager.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Serialization/ASTBitCodes.h" -#include "clang/Serialization/GlobalModuleIndex.h" -#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFile.h" #include "clang/Serialization/PCHContainerOperations.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" @@ -125,16 +125,17 @@ typedef llvm::OnDiskIterableChainedHashTable<IdentifierIndexReaderTrait> } -GlobalModuleIndex::GlobalModuleIndex(std::unique_ptr<llvm::MemoryBuffer> Buffer, - llvm::BitstreamCursor Cursor) - : Buffer(std::move(Buffer)), IdentifierIndex(), NumIdentifierLookups(), +GlobalModuleIndex::GlobalModuleIndex( + std::unique_ptr<llvm::MemoryBuffer> IndexBuffer, + llvm::BitstreamCursor Cursor) + : Buffer(std::move(IndexBuffer)), IdentifierIndex(), NumIdentifierLookups(), NumIdentifierLookupHits() { - auto Fail = [&Buffer](llvm::Error &&Err) { + auto Fail = [&](llvm::Error &&Err) { report_fatal_error("Module index '" + Buffer->getBufferIdentifier() + "' failed: " + toString(std::move(Err))); }; - llvm::TimeTraceScope TimeScope("Module LoadIndex", StringRef("")); + llvm::TimeTraceScope TimeScope("Module LoadIndex"); // Read the global index. bool InGlobalIndexBlock = false; bool Done = false; @@ -770,7 +771,7 @@ bool GlobalModuleIndexBuilder::writeIndex(llvm::BitstreamWriter &Stream) { } using namespace llvm; - llvm::TimeTraceScope TimeScope("Module WriteIndex", StringRef("")); + llvm::TimeTraceScope TimeScope("Module WriteIndex"); // Emit the file header. Stream.Emit((unsigned)'B', 8); diff --git a/clang/lib/Serialization/Module.cpp b/clang/lib/Serialization/ModuleFile.cpp index 2b6c9211beaf..db896fd36115 100644 --- a/clang/lib/Serialization/Module.cpp +++ b/clang/lib/Serialization/ModuleFile.cpp @@ -1,4 +1,4 @@ -//===- Module.cpp - Module description ------------------------------------===// +//===- ModuleFile.cpp - Module description --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// // -// This file implements the Module class, which describes a module that has -// been loaded from an AST file. +// This file implements the ModuleFile class, which describes a module that +// has been loaded from an AST file. // //===----------------------------------------------------------------------===// -#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFile.h" #include "ASTReaderInternals.h" #include "clang/Serialization/ContinuousRangeMap.h" #include "llvm/ADT/StringRef.h" diff --git a/clang/lib/Serialization/ModuleManager.cpp b/clang/lib/Serialization/ModuleManager.cpp index 4b9f20fca4f8..daef502cdcb5 100644 --- a/clang/lib/Serialization/ModuleManager.cpp +++ b/clang/lib/Serialization/ModuleManager.cpp @@ -18,7 +18,7 @@ #include "clang/Lex/ModuleMap.h" #include "clang/Serialization/GlobalModuleIndex.h" #include "clang/Serialization/InMemoryModuleCache.h" -#include "clang/Serialization/Module.h" +#include "clang/Serialization/ModuleFile.h" #include "clang/Serialization/PCHContainerOperations.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" @@ -219,10 +219,7 @@ ModuleManager::addModule(StringRef FileName, ModuleKind Type, return NewlyLoaded; } -void ModuleManager::removeModules( - ModuleIterator First, - llvm::SmallPtrSetImpl<ModuleFile *> &LoadedSuccessfully, - ModuleMap *modMap) { +void ModuleManager::removeModules(ModuleIterator First, ModuleMap *modMap) { auto Last = end(); if (First == Last) return; diff --git a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp index d0def6918932..2ef50a727ece 100644 --- a/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/AnalysisOrderChecker.cpp @@ -40,6 +40,7 @@ class AnalysisOrderChecker check::EndFunction, check::NewAllocator, check::Bind, + check::PointerEscape, check::RegionChanges, check::LiveSymbols> { @@ -165,6 +166,15 @@ public: llvm::errs() << "RegionChanges\n"; return State; } + + ProgramStateRef checkPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind) const { + if (isCallbackEnabled(State, "PointerEscape")) + llvm::errs() << "PointerEscape\n"; + return State; + } }; } // end anonymous namespace diff --git a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 503c451670b8..21c4bbc60264 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -28,6 +28,7 @@ using namespace clang; using namespace ento; namespace { +enum class ConcatFnKind { none = 0, strcat = 1, strlcat = 2 }; class CStringChecker : public Checker< eval::Call, check::PreStmt<DeclStmt>, check::LiveSymbols, @@ -129,11 +130,8 @@ public: void evalStrncpy(CheckerContext &C, const CallExpr *CE) const; void evalStpcpy(CheckerContext &C, const CallExpr *CE) const; void evalStrlcpy(CheckerContext &C, const CallExpr *CE) const; - void evalStrcpyCommon(CheckerContext &C, - const CallExpr *CE, - bool returnEnd, - bool isBounded, - bool isAppending, + void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool ReturnEnd, + bool IsBounded, ConcatFnKind appendK, bool returnPtr = true) const; void evalStrcat(CheckerContext &C, const CallExpr *CE) const; @@ -146,8 +144,8 @@ public: void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const; void evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, - bool isBounded = false, - bool ignoreCase = false) const; + bool IsBounded = false, + bool IgnoreCase = false) const; void evalStrsep(CheckerContext &C, const CallExpr *CE) const; @@ -292,9 +290,9 @@ ProgramStateRef CStringChecker::checkNonNull(CheckerContext &C, SmallString<80> buf; llvm::raw_svector_ostream OS(buf); assert(CurrentFunctionDescription); - OS << "Null pointer argument in call to " << CurrentFunctionDescription - << ' ' << IdxOfArg << llvm::getOrdinalSuffix(IdxOfArg) - << " parameter"; + OS << "Null pointer passed as " << IdxOfArg + << llvm::getOrdinalSuffix(IdxOfArg) << " argument to " + << CurrentFunctionDescription; emitNullArgBug(C, stateNull, S, OS.str()); } @@ -1008,12 +1006,9 @@ ProgramStateRef CStringChecker::InvalidateBuffer(CheckerContext &C, bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, const MemRegion *MR) { - const TypedValueRegion *TVR = dyn_cast<TypedValueRegion>(MR); - switch (MR->getKind()) { case MemRegion::FunctionCodeRegionKind: { - const NamedDecl *FD = cast<FunctionCodeRegion>(MR)->getDecl(); - if (FD) + if (const auto *FD = cast<FunctionCodeRegion>(MR)->getDecl()) os << "the address of the function '" << *FD << '\''; else os << "the address of a function"; @@ -1027,16 +1022,20 @@ bool CStringChecker::SummarizeRegion(raw_ostream &os, ASTContext &Ctx, return true; case MemRegion::CXXThisRegionKind: case MemRegion::CXXTempObjectRegionKind: - os << "a C++ temp object of type " << TVR->getValueType().getAsString(); + os << "a C++ temp object of type " + << cast<TypedValueRegion>(MR)->getValueType().getAsString(); return true; case MemRegion::VarRegionKind: - os << "a variable of type" << TVR->getValueType().getAsString(); + os << "a variable of type" + << cast<TypedValueRegion>(MR)->getValueType().getAsString(); return true; case MemRegion::FieldRegionKind: - os << "a field of type " << TVR->getValueType().getAsString(); + os << "a field of type " + << cast<TypedValueRegion>(MR)->getValueType().getAsString(); return true; case MemRegion::ObjCIvarRegionKind: - os << "an instance variable of type " << TVR->getValueType().getAsString(); + os << "an instance variable of type " + << cast<TypedValueRegion>(MR)->getValueType().getAsString(); return true; default: return false; @@ -1315,9 +1314,9 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { ProgramStateRef StSameBuf, StNotSameBuf; std::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf); - // If the two arguments might be the same buffer, we know the result is 0, + // If the two arguments are the same buffer, we know the result is 0, // and we only need to check one size. - if (StSameBuf) { + if (StSameBuf && !StNotSameBuf) { state = StSameBuf; state = CheckBufferAccess(C, state, Size, Left); if (state) { @@ -1325,20 +1324,19 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) const { svalBuilder.makeZeroVal(CE->getType())); C.addTransition(state); } + return; } - // If the two arguments might be different buffers, we have to check the - // size of both of them. - if (StNotSameBuf) { - state = StNotSameBuf; - state = CheckBufferAccess(C, state, Size, Left, Right); - if (state) { - // The return value is the comparison result, which we don't know. - SVal CmpV = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, - C.blockCount()); - state = state->BindExpr(CE, LCtx, CmpV); - C.addTransition(state); - } + // If the two arguments might be different buffers, we have to check + // the size of both of them. + assert(StNotSameBuf); + state = CheckBufferAccess(C, state, Size, Left, Right); + if (state) { + // The return value is the comparison result, which we don't know. + SVal CmpV = + svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); + state = state->BindExpr(CE, LCtx, CmpV); + C.addTransition(state); } } } @@ -1477,69 +1475,71 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE, void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const { // char *strcpy(char *restrict dst, const char *restrict src); evalStrcpyCommon(C, CE, - /* returnEnd = */ false, - /* isBounded = */ false, - /* isAppending = */ false); + /* ReturnEnd = */ false, + /* IsBounded = */ false, + /* appendK = */ ConcatFnKind::none); } void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const { // char *strncpy(char *restrict dst, const char *restrict src, size_t n); evalStrcpyCommon(C, CE, - /* returnEnd = */ false, - /* isBounded = */ true, - /* isAppending = */ false); + /* ReturnEnd = */ false, + /* IsBounded = */ true, + /* appendK = */ ConcatFnKind::none); } void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const { // char *stpcpy(char *restrict dst, const char *restrict src); evalStrcpyCommon(C, CE, - /* returnEnd = */ true, - /* isBounded = */ false, - /* isAppending = */ false); + /* ReturnEnd = */ true, + /* IsBounded = */ false, + /* appendK = */ ConcatFnKind::none); } void CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const { - // char *strlcpy(char *dst, const char *src, size_t n); + // size_t strlcpy(char *dest, const char *src, size_t size); evalStrcpyCommon(C, CE, - /* returnEnd = */ true, - /* isBounded = */ true, - /* isAppending = */ false, + /* ReturnEnd = */ true, + /* IsBounded = */ true, + /* appendK = */ ConcatFnKind::none, /* returnPtr = */ false); } void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const { - //char *strcat(char *restrict s1, const char *restrict s2); + // char *strcat(char *restrict s1, const char *restrict s2); evalStrcpyCommon(C, CE, - /* returnEnd = */ false, - /* isBounded = */ false, - /* isAppending = */ true); + /* ReturnEnd = */ false, + /* IsBounded = */ false, + /* appendK = */ ConcatFnKind::strcat); } void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const { //char *strncat(char *restrict s1, const char *restrict s2, size_t n); evalStrcpyCommon(C, CE, - /* returnEnd = */ false, - /* isBounded = */ true, - /* isAppending = */ true); + /* ReturnEnd = */ false, + /* IsBounded = */ true, + /* appendK = */ ConcatFnKind::strcat); } void CStringChecker::evalStrlcat(CheckerContext &C, const CallExpr *CE) const { - // FIXME: strlcat() uses a different rule for bound checking, i.e. 'n' means - // a different thing as compared to strncat(). This currently causes - // false positives in the alpha string bound checker. - - //char *strlcat(char *s1, const char *s2, size_t n); + // size_t strlcat(char *dst, const char *src, size_t size); + // It will append at most size - strlen(dst) - 1 bytes, + // NULL-terminating the result. evalStrcpyCommon(C, CE, - /* returnEnd = */ false, - /* isBounded = */ true, - /* isAppending = */ true, + /* ReturnEnd = */ false, + /* IsBounded = */ true, + /* appendK = */ ConcatFnKind::strlcat, /* returnPtr = */ false); } void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, - bool returnEnd, bool isBounded, - bool isAppending, bool returnPtr) const { - CurrentFunctionDescription = "string copy function"; + bool ReturnEnd, bool IsBounded, + ConcatFnKind appendK, + bool returnPtr) const { + if (appendK == ConcatFnKind::none) + CurrentFunctionDescription = "string copy function"; + else + CurrentFunctionDescription = "string concatenation function"; ProgramStateRef state = C.getState(); const LocationContext *LCtx = C.getLocationContext(); @@ -1560,6 +1560,11 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // Get the string length of the source. SVal strLength = getCStringLength(C, state, srcExpr, srcVal); + Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); + + // Get the string length of the destination buffer. + SVal dstStrLength = getCStringLength(C, state, Dst, DstVal); + Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>(); // If the source isn't a valid C string, give up. if (strLength.isUndef()) @@ -1576,13 +1581,14 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, SVal maxLastElementIndex = UnknownVal(); const char *boundWarning = nullptr; - state = CheckOverlap(C, state, isBounded ? CE->getArg(2) : CE->getArg(1), Dst, srcExpr); + state = CheckOverlap(C, state, IsBounded ? CE->getArg(2) : CE->getArg(1), Dst, + srcExpr); if (!state) return; // If the function is strncpy, strncat, etc... it is bounded. - if (isBounded) { + if (IsBounded) { // Get the max number of characters to copy. const Expr *lenExpr = CE->getArg(2); SVal lenVal = state->getSVal(lenExpr, LCtx); @@ -1590,57 +1596,100 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // Protect against misdeclared strncpy(). lenVal = svalBuilder.evalCast(lenVal, sizeTy, lenExpr->getType()); - Optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>(); Optional<NonLoc> lenValNL = lenVal.getAs<NonLoc>(); // If we know both values, we might be able to figure out how much // we're copying. if (strLengthNL && lenValNL) { - ProgramStateRef stateSourceTooLong, stateSourceNotTooLong; + switch (appendK) { + case ConcatFnKind::none: + case ConcatFnKind::strcat: { + ProgramStateRef stateSourceTooLong, stateSourceNotTooLong; + // Check if the max number to copy is less than the length of the src. + // If the bound is equal to the source length, strncpy won't null- + // terminate the result! + std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume( + svalBuilder + .evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy) + .castAs<DefinedOrUnknownSVal>()); - // Check if the max number to copy is less than the length of the src. - // If the bound is equal to the source length, strncpy won't null- - // terminate the result! - std::tie(stateSourceTooLong, stateSourceNotTooLong) = state->assume( - svalBuilder.evalBinOpNN(state, BO_GE, *strLengthNL, *lenValNL, cmpTy) - .castAs<DefinedOrUnknownSVal>()); + if (stateSourceTooLong && !stateSourceNotTooLong) { + // Max number to copy is less than the length of the src, so the + // actual strLength copied is the max number arg. + state = stateSourceTooLong; + amountCopied = lenVal; + + } else if (!stateSourceTooLong && stateSourceNotTooLong) { + // The source buffer entirely fits in the bound. + state = stateSourceNotTooLong; + amountCopied = strLength; + } + break; + } + case ConcatFnKind::strlcat: + if (!dstStrLengthNL) + return; - if (stateSourceTooLong && !stateSourceNotTooLong) { - // Max number to copy is less than the length of the src, so the actual - // strLength copied is the max number arg. - state = stateSourceTooLong; - amountCopied = lenVal; + // amountCopied = min (size - dstLen - 1 , srcLen) + SVal freeSpace = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, + *dstStrLengthNL, sizeTy); + if (!freeSpace.getAs<NonLoc>()) + return; + freeSpace = + svalBuilder.evalBinOp(state, BO_Sub, freeSpace, + svalBuilder.makeIntVal(1, sizeTy), sizeTy); + Optional<NonLoc> freeSpaceNL = freeSpace.getAs<NonLoc>(); - } else if (!stateSourceTooLong && stateSourceNotTooLong) { - // The source buffer entirely fits in the bound. - state = stateSourceNotTooLong; - amountCopied = strLength; + // While unlikely, it is possible that the subtraction is + // too complex to compute, let's check whether it succeeded. + if (!freeSpaceNL) + return; + SVal hasEnoughSpace = svalBuilder.evalBinOpNN( + state, BO_LE, *strLengthNL, *freeSpaceNL, cmpTy); + + ProgramStateRef TrueState, FalseState; + std::tie(TrueState, FalseState) = + state->assume(hasEnoughSpace.castAs<DefinedOrUnknownSVal>()); + + // srcStrLength <= size - dstStrLength -1 + if (TrueState && !FalseState) { + amountCopied = strLength; + } + + // srcStrLength > size - dstStrLength -1 + if (!TrueState && FalseState) { + amountCopied = freeSpace; + } + + if (TrueState && FalseState) + amountCopied = UnknownVal(); + break; } } - // We still want to know if the bound is known to be too large. if (lenValNL) { - if (isAppending) { + switch (appendK) { + case ConcatFnKind::strcat: // For strncat, the check is strlen(dst) + lenVal < sizeof(dst) // Get the string length of the destination. If the destination is // memory that can't have a string length, we shouldn't be copying // into it anyway. - SVal dstStrLength = getCStringLength(C, state, Dst, DstVal); if (dstStrLength.isUndef()) return; - if (Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>()) { - maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Add, - *lenValNL, - *dstStrLengthNL, - sizeTy); + if (dstStrLengthNL) { + maxLastElementIndex = svalBuilder.evalBinOpNN( + state, BO_Add, *lenValNL, *dstStrLengthNL, sizeTy); + boundWarning = "Size argument is greater than the free space in the " "destination buffer"; } - - } else { - // For strncpy, this is just checking that lenVal <= sizeof(dst) + break; + case ConcatFnKind::none: + case ConcatFnKind::strlcat: + // For strncpy and strlcat, this is just checking + // that lenVal <= sizeof(dst). // (Yes, strncpy and strncat differ in how they treat termination. // strncat ALWAYS terminates, but strncpy doesn't.) @@ -1649,14 +1698,22 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // as the last element accessed, so n == 0 is problematic. ProgramStateRef StateZeroSize, StateNonZeroSize; std::tie(StateZeroSize, StateNonZeroSize) = - assumeZero(C, state, *lenValNL, sizeTy); + assumeZero(C, state, *lenValNL, sizeTy); // If the size is known to be zero, we're done. if (StateZeroSize && !StateNonZeroSize) { if (returnPtr) { StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal); } else { - StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, *lenValNL); + if (appendK == ConcatFnKind::none) { + // strlcpy returns strlen(src) + StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, strLength); + } else { + // strlcat returns strlen(src) + strlen(dst) + SVal retSize = svalBuilder.evalBinOp( + state, BO_Add, strLength, dstStrLength, sizeTy); + StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, retSize); + } } C.addTransition(StateZeroSize); return; @@ -1666,50 +1723,13 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // We don't record the non-zero assumption here because we can't // be sure. We won't warn on a possible zero. NonLoc one = svalBuilder.makeIntVal(1, sizeTy).castAs<NonLoc>(); - maxLastElementIndex = svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, - one, sizeTy); + maxLastElementIndex = + svalBuilder.evalBinOpNN(state, BO_Sub, *lenValNL, one, sizeTy); boundWarning = "Size argument is greater than the length of the " "destination buffer"; + break; } } - - // If we couldn't pin down the copy length, at least bound it. - // FIXME: We should actually run this code path for append as well, but - // right now it creates problems with constraints (since we can end up - // trying to pass constraints from symbol to symbol). - if (amountCopied.isUnknown() && !isAppending) { - // Try to get a "hypothetical" string length symbol, which we can later - // set as a real value if that turns out to be the case. - amountCopied = getCStringLength(C, state, lenExpr, srcVal, true); - assert(!amountCopied.isUndef()); - - if (Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>()) { - if (lenValNL) { - // amountCopied <= lenVal - SVal copiedLessThanBound = svalBuilder.evalBinOpNN(state, BO_LE, - *amountCopiedNL, - *lenValNL, - cmpTy); - state = state->assume( - copiedLessThanBound.castAs<DefinedOrUnknownSVal>(), true); - if (!state) - return; - } - - if (strLengthNL) { - // amountCopied <= strlen(source) - SVal copiedLessThanSrc = svalBuilder.evalBinOpNN(state, BO_LE, - *amountCopiedNL, - *strLengthNL, - cmpTy); - state = state->assume( - copiedLessThanSrc.castAs<DefinedOrUnknownSVal>(), true); - if (!state) - return; - } - } - } - } else { // The function isn't bounded. The amount copied should match the length // of the source buffer. @@ -1722,28 +1742,37 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, // buffer. (It may not actually be the strlen if the destination buffer // is not terminated.) SVal finalStrLength = UnknownVal(); + SVal strlRetVal = UnknownVal(); + + if (appendK == ConcatFnKind::none && !returnPtr) { + // strlcpy returns the sizeof(src) + strlRetVal = strLength; + } // If this is an appending function (strcat, strncat...) then set the // string length to strlen(src) + strlen(dst) since the buffer will // ultimately contain both. - if (isAppending) { + if (appendK != ConcatFnKind::none) { // Get the string length of the destination. If the destination is memory // that can't have a string length, we shouldn't be copying into it anyway. - SVal dstStrLength = getCStringLength(C, state, Dst, DstVal); if (dstStrLength.isUndef()) return; - Optional<NonLoc> srcStrLengthNL = amountCopied.getAs<NonLoc>(); - Optional<NonLoc> dstStrLengthNL = dstStrLength.getAs<NonLoc>(); + if (appendK == ConcatFnKind::strlcat && dstStrLengthNL && strLengthNL) { + strlRetVal = svalBuilder.evalBinOpNN(state, BO_Add, *strLengthNL, + *dstStrLengthNL, sizeTy); + } + + Optional<NonLoc> amountCopiedNL = amountCopied.getAs<NonLoc>(); // If we know both string lengths, we might know the final string length. - if (srcStrLengthNL && dstStrLengthNL) { + if (amountCopiedNL && dstStrLengthNL) { // Make sure the two lengths together don't overflow a size_t. - state = checkAdditionOverflow(C, state, *srcStrLengthNL, *dstStrLengthNL); + state = checkAdditionOverflow(C, state, *amountCopiedNL, *dstStrLengthNL); if (!state) return; - finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *srcStrLengthNL, + finalStrLength = svalBuilder.evalBinOpNN(state, BO_Add, *amountCopiedNL, *dstStrLengthNL, sizeTy); } @@ -1756,19 +1785,19 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, assert(!finalStrLength.isUndef()); if (Optional<NonLoc> finalStrLengthNL = finalStrLength.getAs<NonLoc>()) { - if (srcStrLengthNL) { + if (amountCopiedNL && appendK == ConcatFnKind::none) { + // we overwrite dst string with the src // finalStrLength >= srcStrLength - SVal sourceInResult = svalBuilder.evalBinOpNN(state, BO_GE, - *finalStrLengthNL, - *srcStrLengthNL, - cmpTy); + SVal sourceInResult = svalBuilder.evalBinOpNN( + state, BO_GE, *finalStrLengthNL, *amountCopiedNL, cmpTy); state = state->assume(sourceInResult.castAs<DefinedOrUnknownSVal>(), true); if (!state) return; } - if (dstStrLengthNL) { + if (dstStrLengthNL && appendK != ConcatFnKind::none) { + // we extend the dst string with the src // finalStrLength >= dstStrLength SVal destInResult = svalBuilder.evalBinOpNN(state, BO_GE, *finalStrLengthNL, @@ -1793,9 +1822,13 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, if (returnPtr) { // The final result of the function will either be a pointer past the last // copied element, or a pointer to the start of the destination buffer. - Result = (returnEnd ? UnknownVal() : DstVal); + Result = (ReturnEnd ? UnknownVal() : DstVal); } else { - Result = finalStrLength; + if (appendK == ConcatFnKind::strlcat || appendK == ConcatFnKind::none) + //strlcpy, strlcat + Result = strlRetVal; + else + Result = finalStrLength; } assert(state); @@ -1834,7 +1867,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, } // If this is a stpcpy-style copy, the last element is the return value. - if (returnPtr && returnEnd) + if (returnPtr && ReturnEnd) Result = lastElement; } @@ -1854,7 +1887,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, nullptr); // Set the C string length of the destination, if we know it. - if (isBounded && !isAppending) { + if (IsBounded && (appendK == ConcatFnKind::none)) { // strncpy is annoying in that it doesn't guarantee to null-terminate // the result string. If the original string didn't fit entirely inside // the bound (including the null-terminator), we don't know how long the @@ -1870,7 +1903,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, if (returnPtr) { // If this is a stpcpy-style copy, but we were unable to check for a buffer // overflow, we still need a result. Conjure a return value. - if (returnEnd && Result.isUnknown()) { + if (ReturnEnd && Result.isUnknown()) { Result = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()); } } @@ -1881,28 +1914,28 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const { //int strcmp(const char *s1, const char *s2); - evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ false); + evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ false); } void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const { //int strncmp(const char *s1, const char *s2, size_t n); - evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ false); + evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ false); } void CStringChecker::evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const { //int strcasecmp(const char *s1, const char *s2); - evalStrcmpCommon(C, CE, /* isBounded = */ false, /* ignoreCase = */ true); + evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ true); } void CStringChecker::evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const { //int strncasecmp(const char *s1, const char *s2, size_t n); - evalStrcmpCommon(C, CE, /* isBounded = */ true, /* ignoreCase = */ true); + evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ true); } void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, - bool isBounded, bool ignoreCase) const { + bool IsBounded, bool IgnoreCase) const { CurrentFunctionDescription = "string comparison function"; ProgramStateRef state = C.getState(); const LocationContext *LCtx = C.getLocationContext(); @@ -1972,7 +2005,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, StringRef s1StrRef = s1StrLiteral->getString(); StringRef s2StrRef = s2StrLiteral->getString(); - if (isBounded) { + if (IsBounded) { // Get the max number of characters to compare. const Expr *lenExpr = CE->getArg(2); SVal lenVal = state->getSVal(lenExpr, LCtx); @@ -2000,7 +2033,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE, s2StrRef = s2StrRef.substr(0, s2Term); // Use StringRef's comparison methods to compute the actual result. - int compareRes = ignoreCase ? s1StrRef.compare_lower(s2StrRef) + int compareRes = IgnoreCase ? s1StrRef.compare_lower(s2StrRef) : s1StrRef.compare(s2StrRef); // The strcmp function returns an integer greater than, equal to, or less @@ -2180,7 +2213,7 @@ void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const { SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy); ProgramStateRef State = C.getState(); - + // See if the size argument is zero. SVal SizeVal = C.getSVal(Size); QualType SizeTy = Size->getType(); diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp new file mode 100644 index 000000000000..48fee4a0ffb7 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/CheckPlacementNew.cpp @@ -0,0 +1,121 @@ +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "llvm/Support/FormatVariadic.h" + +using namespace clang; +using namespace ento; + +namespace { +class PlacementNewChecker : public Checker<check::PreStmt<CXXNewExpr>> { +public: + void checkPreStmt(const CXXNewExpr *NE, CheckerContext &C) const; + +private: + // Returns the size of the target in a placement new expression. + // E.g. in "new (&s) long" it returns the size of `long`. + SVal getExtentSizeOfNewTarget(const CXXNewExpr *NE, ProgramStateRef State, + CheckerContext &C) const; + // Returns the size of the place in a placement new expression. + // E.g. in "new (&s) long" it returns the size of `s`. + SVal getExtentSizeOfPlace(const Expr *NE, ProgramStateRef State, + CheckerContext &C) const; + BugType BT{this, "Insufficient storage for placement new", + categories::MemoryError}; +}; +} // namespace + +SVal PlacementNewChecker::getExtentSizeOfPlace(const Expr *Place, + ProgramStateRef State, + CheckerContext &C) const { + const MemRegion *MRegion = C.getSVal(Place).getAsRegion(); + if (!MRegion) + return UnknownVal(); + RegionOffset Offset = MRegion->getAsOffset(); + if (Offset.hasSymbolicOffset()) + return UnknownVal(); + const MemRegion *BaseRegion = MRegion->getBaseRegion(); + if (!BaseRegion) + return UnknownVal(); + + SValBuilder &SvalBuilder = C.getSValBuilder(); + NonLoc OffsetInBytes = SvalBuilder.makeArrayIndex( + Offset.getOffset() / C.getASTContext().getCharWidth()); + DefinedOrUnknownSVal ExtentInBytes = + BaseRegion->castAs<SubRegion>()->getExtent(SvalBuilder); + + return SvalBuilder.evalBinOp(State, BinaryOperator::Opcode::BO_Sub, + ExtentInBytes, OffsetInBytes, + SvalBuilder.getArrayIndexType()); +} + +SVal PlacementNewChecker::getExtentSizeOfNewTarget(const CXXNewExpr *NE, + ProgramStateRef State, + CheckerContext &C) const { + SValBuilder &SvalBuilder = C.getSValBuilder(); + QualType ElementType = NE->getAllocatedType(); + ASTContext &AstContext = C.getASTContext(); + CharUnits TypeSize = AstContext.getTypeSizeInChars(ElementType); + if (NE->isArray()) { + const Expr *SizeExpr = *NE->getArraySize(); + SVal ElementCount = C.getSVal(SizeExpr); + if (auto ElementCountNL = ElementCount.getAs<NonLoc>()) { + // size in Bytes = ElementCountNL * TypeSize + return SvalBuilder.evalBinOp( + State, BO_Mul, *ElementCountNL, + SvalBuilder.makeArrayIndex(TypeSize.getQuantity()), + SvalBuilder.getArrayIndexType()); + } + } else { + // Create a concrete int whose size in bits and signedness is equal to + // ArrayIndexType. + llvm::APInt I(AstContext.getTypeSizeInChars(SvalBuilder.getArrayIndexType()) + .getQuantity() * + C.getASTContext().getCharWidth(), + TypeSize.getQuantity()); + return SvalBuilder.makeArrayIndex(I.getZExtValue()); + } + return UnknownVal(); +} + +void PlacementNewChecker::checkPreStmt(const CXXNewExpr *NE, + CheckerContext &C) const { + // Check only the default placement new. + if (!NE->getOperatorNew()->isReservedGlobalPlacementOperator()) + return; + if (NE->getNumPlacementArgs() == 0) + return; + + ProgramStateRef State = C.getState(); + SVal SizeOfTarget = getExtentSizeOfNewTarget(NE, State, C); + const Expr *Place = NE->getPlacementArg(0); + SVal SizeOfPlace = getExtentSizeOfPlace(Place, State, C); + const auto SizeOfTargetCI = SizeOfTarget.getAs<nonloc::ConcreteInt>(); + if (!SizeOfTargetCI) + return; + const auto SizeOfPlaceCI = SizeOfPlace.getAs<nonloc::ConcreteInt>(); + if (!SizeOfPlaceCI) + return; + + if (SizeOfPlaceCI->getValue() < SizeOfTargetCI->getValue()) { + if (ExplodedNode *N = C.generateErrorNode(State)) { + std::string Msg = + llvm::formatv("Storage provided to placement new is only {0} bytes, " + "whereas the allocated type requires {1} bytes", + SizeOfPlaceCI->getValue(), SizeOfTargetCI->getValue()); + + auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N); + bugreporter::trackExpressionValue(N, Place, *R); + C.emitReport(std::move(R)); + return; + } + } +} + +void ento::registerPlacementNewChecker(CheckerManager &mgr) { + mgr.registerChecker<PlacementNewChecker>(); +} + +bool ento::shouldRegisterPlacementNewChecker(const LangOptions &LO) { + return true; +} diff --git a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp index 260a2896e78c..d9ffa562c0aa 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/CheckSecuritySyntaxOnly.cpp @@ -49,6 +49,7 @@ struct ChecksFilter { DefaultBool check_vfork; DefaultBool check_FloatLoopCounter; DefaultBool check_UncheckedReturn; + DefaultBool check_decodeValueOfObjCType; CheckerNameRef checkName_bcmp; CheckerNameRef checkName_bcopy; @@ -63,6 +64,7 @@ struct ChecksFilter { CheckerNameRef checkName_vfork; CheckerNameRef checkName_FloatLoopCounter; CheckerNameRef checkName_UncheckedReturn; + CheckerNameRef checkName_decodeValueOfObjCType; }; class WalkAST : public StmtVisitor<WalkAST> { @@ -83,6 +85,7 @@ public: // Statement visitor methods. void VisitCallExpr(CallExpr *CE); + void VisitObjCMessageExpr(ObjCMessageExpr *CE); void VisitForStmt(ForStmt *S); void VisitCompoundStmt (CompoundStmt *S); void VisitStmt(Stmt *S) { VisitChildren(S); } @@ -93,6 +96,7 @@ public: bool checkCall_strCommon(const CallExpr *CE, const FunctionDecl *FD); typedef void (WalkAST::*FnCheck)(const CallExpr *, const FunctionDecl *); + typedef void (WalkAST::*MsgCheck)(const ObjCMessageExpr *); // Checker-specific methods. void checkLoopConditionForFloat(const ForStmt *FS); @@ -110,6 +114,7 @@ public: void checkCall_rand(const CallExpr *CE, const FunctionDecl *FD); void checkCall_random(const CallExpr *CE, const FunctionDecl *FD); void checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD); + void checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME); void checkUncheckedReturnValue(CallExpr *CE); }; } // end anonymous namespace @@ -182,6 +187,20 @@ void WalkAST::VisitCallExpr(CallExpr *CE) { VisitChildren(CE); } +void WalkAST::VisitObjCMessageExpr(ObjCMessageExpr *ME) { + MsgCheck evalFunction = + llvm::StringSwitch<MsgCheck>(ME->getSelector().getAsString()) + .Case("decodeValueOfObjCType:at:", + &WalkAST::checkMsg_decodeValueOfObjCType) + .Default(nullptr); + + if (evalFunction) + (this->*evalFunction)(ME); + + // Recurse and check children. + VisitChildren(ME); +} + void WalkAST::VisitCompoundStmt(CompoundStmt *S) { for (Stmt *Child : S->children()) if (Child) { @@ -924,6 +943,54 @@ void WalkAST::checkCall_vfork(const CallExpr *CE, const FunctionDecl *FD) { } //===----------------------------------------------------------------------===// +// Check: '-decodeValueOfObjCType:at:' should not be used. +// It is deprecated in favor of '-decodeValueOfObjCType:at:size:' due to +// likelihood of buffer overflows. +//===----------------------------------------------------------------------===// + +void WalkAST::checkMsg_decodeValueOfObjCType(const ObjCMessageExpr *ME) { + if (!filter.check_decodeValueOfObjCType) + return; + + // Check availability of the secure alternative: + // iOS 11+, macOS 10.13+, tvOS 11+, and watchOS 4.0+ + // FIXME: We probably shouldn't register the check if it's not available. + const TargetInfo &TI = AC->getASTContext().getTargetInfo(); + const llvm::Triple &T = TI.getTriple(); + const VersionTuple &VT = TI.getPlatformMinVersion(); + switch (T.getOS()) { + case llvm::Triple::IOS: + if (VT < VersionTuple(11, 0)) + return; + break; + case llvm::Triple::MacOSX: + if (VT < VersionTuple(10, 13)) + return; + break; + case llvm::Triple::WatchOS: + if (VT < VersionTuple(4, 0)) + return; + break; + case llvm::Triple::TvOS: + if (VT < VersionTuple(11, 0)) + return; + break; + default: + return; + } + + PathDiagnosticLocation MELoc = + PathDiagnosticLocation::createBegin(ME, BR.getSourceManager(), AC); + BR.EmitBasicReport( + AC->getDecl(), filter.checkName_decodeValueOfObjCType, + "Potential buffer overflow in '-decodeValueOfObjCType:at:'", "Security", + "Deprecated method '-decodeValueOfObjCType:at:' is insecure " + "as it can lead to potential buffer overflows. Use the safer " + "'-decodeValueOfObjCType:at:size:' method.", + MELoc, ME->getSourceRange()); +} + +//===----------------------------------------------------------------------===// // Check: Should check whether privileges are dropped successfully. // Originally: <rdar://problem/6337132> //===----------------------------------------------------------------------===// @@ -1035,3 +1102,4 @@ REGISTER_CHECKER(vfork) REGISTER_CHECKER(FloatLoopCounter) REGISTER_CHECKER(UncheckedReturn) REGISTER_CHECKER(DeprecatedOrUnsafeBufferHandling) +REGISTER_CHECKER(decodeValueOfObjCType) diff --git a/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp new file mode 100644 index 000000000000..4717fef96341 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/DebugIteratorModeling.cpp @@ -0,0 +1,196 @@ +//===-- DebugIteratorModeling.cpp ---------------------------------*- C++ -*--// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines a checker for debugging iterator modeling. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" + +#include "Iterator.h" + +using namespace clang; +using namespace ento; +using namespace iterator; + +namespace { + +class DebugIteratorModeling + : public Checker<eval::Call> { + + std::unique_ptr<BugType> DebugMsgBugType; + + template <typename Getter> + void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C, + Getter get) const; + void analyzerContainerBegin(const CallExpr *CE, CheckerContext &C) const; + void analyzerContainerEnd(const CallExpr *CE, CheckerContext &C) const; + template <typename Getter> + void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C, + Getter get, SVal Default) const; + void analyzerIteratorPosition(const CallExpr *CE, CheckerContext &C) const; + void analyzerIteratorContainer(const CallExpr *CE, CheckerContext &C) const; + void analyzerIteratorValidity(const CallExpr *CE, CheckerContext &C) const; + ExplodedNode *reportDebugMsg(llvm::StringRef Msg, CheckerContext &C) const; + + typedef void (DebugIteratorModeling::*FnCheck)(const CallExpr *, + CheckerContext &) const; + + CallDescriptionMap<FnCheck> Callbacks = { + {{0, "clang_analyzer_container_begin", 1}, + &DebugIteratorModeling::analyzerContainerBegin}, + {{0, "clang_analyzer_container_end", 1}, + &DebugIteratorModeling::analyzerContainerEnd}, + {{0, "clang_analyzer_iterator_position", 1}, + &DebugIteratorModeling::analyzerIteratorPosition}, + {{0, "clang_analyzer_iterator_container", 1}, + &DebugIteratorModeling::analyzerIteratorContainer}, + {{0, "clang_analyzer_iterator_validity", 1}, + &DebugIteratorModeling::analyzerIteratorValidity}, + }; + +public: + DebugIteratorModeling(); + + bool evalCall(const CallEvent &Call, CheckerContext &C) const; +}; + +} //namespace + +DebugIteratorModeling::DebugIteratorModeling() { + DebugMsgBugType.reset( + new BugType(this, "Checking analyzer assumptions", "debug", + /*SuppressOnSink=*/true)); +} + +bool DebugIteratorModeling::evalCall(const CallEvent &Call, + CheckerContext &C) const { + const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); + if (!CE) + return false; + + const FnCheck *Handler = Callbacks.lookup(Call); + if (!Handler) + return false; + + (this->**Handler)(CE, C); + return true; +} + +template <typename Getter> +void DebugIteratorModeling::analyzerContainerDataField(const CallExpr *CE, + CheckerContext &C, + Getter get) const { + if (CE->getNumArgs() == 0) { + reportDebugMsg("Missing container argument", C); + return; + } + + auto State = C.getState(); + const MemRegion *Cont = C.getSVal(CE->getArg(0)).getAsRegion(); + if (Cont) { + const auto *Data = getContainerData(State, Cont); + if (Data) { + SymbolRef Field = get(Data); + if (Field) { + State = State->BindExpr(CE, C.getLocationContext(), + nonloc::SymbolVal(Field)); + C.addTransition(State); + return; + } + } + } + + auto &BVF = C.getSValBuilder().getBasicValueFactory(); + State = State->BindExpr(CE, C.getLocationContext(), + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); +} + +void DebugIteratorModeling::analyzerContainerBegin(const CallExpr *CE, + CheckerContext &C) const { + analyzerContainerDataField(CE, C, [](const ContainerData *D) { + return D->getBegin(); + }); +} + +void DebugIteratorModeling::analyzerContainerEnd(const CallExpr *CE, + CheckerContext &C) const { + analyzerContainerDataField(CE, C, [](const ContainerData *D) { + return D->getEnd(); + }); +} + +template <typename Getter> +void DebugIteratorModeling::analyzerIteratorDataField(const CallExpr *CE, + CheckerContext &C, + Getter get, + SVal Default) const { + if (CE->getNumArgs() == 0) { + reportDebugMsg("Missing iterator argument", C); + return; + } + + auto State = C.getState(); + SVal V = C.getSVal(CE->getArg(0)); + const auto *Pos = getIteratorPosition(State, V); + if (Pos) { + State = State->BindExpr(CE, C.getLocationContext(), get(Pos)); + } else { + State = State->BindExpr(CE, C.getLocationContext(), Default); + } + C.addTransition(State); +} + +void DebugIteratorModeling::analyzerIteratorPosition(const CallExpr *CE, + CheckerContext &C) const { + auto &BVF = C.getSValBuilder().getBasicValueFactory(); + analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) { + return nonloc::SymbolVal(P->getOffset()); + }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); +} + +void DebugIteratorModeling::analyzerIteratorContainer(const CallExpr *CE, + CheckerContext &C) const { + auto &BVF = C.getSValBuilder().getBasicValueFactory(); + analyzerIteratorDataField(CE, C, [](const IteratorPosition *P) { + return loc::MemRegionVal(P->getContainer()); + }, loc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); +} + +void DebugIteratorModeling::analyzerIteratorValidity(const CallExpr *CE, + CheckerContext &C) const { + auto &BVF = C.getSValBuilder().getBasicValueFactory(); + analyzerIteratorDataField(CE, C, [&BVF](const IteratorPosition *P) { + return + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get((P->isValid())))); + }, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0)))); +} + +ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg, + CheckerContext &C) const { + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + return nullptr; + + auto &BR = C.getBugReporter(); + BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType, + Msg, N)); + return N; +} + +void ento::registerDebugIteratorModeling(CheckerManager &mgr) { + mgr.registerChecker<DebugIteratorModeling>(); +} + +bool ento::shouldRegisterDebugIteratorModeling(const LangOptions &LO) { + return true; +} diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index e3de0b4f4a7f..46100cd1dace 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp @@ -107,7 +107,7 @@ static const Expr *getDereferenceExpr(const Stmt *S, bool IsBind=false){ static bool suppressReport(const Expr *E) { // Do not report dereferences on memory in non-default address spaces. - return E->getType().getQualifiers().hasAddressSpace(); + return E->getType().hasAddressSpace(); } static bool isDeclRefExprToReference(const Expr *E) { diff --git a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp index 0058f3d3881f..0c46447e1985 100644 --- a/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/DirectIvarAssignment.cpp @@ -144,6 +144,8 @@ void DirectIvarAssignment::checkASTDecl(const ObjCImplementationDecl *D, continue; const Stmt *Body = M->getBody(); + if (M->isSynthesizedAccessorStub()) + continue; assert(Body); MethodCrawler MC(IvarToPropMap, M->getCanonicalDecl(), InterD, BR, this, diff --git a/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp new file mode 100644 index 000000000000..3c04983df443 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp @@ -0,0 +1,557 @@ +//=== FuchsiaHandleChecker.cpp - Find handle leaks/double closes -*- C++ -*--=// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This checker checks if the handle of Fuchsia is properly used according to +// following rules. +// - If a handle is acquired, it should be released before execution +// ends. +// - If a handle is released, it should not be released again. +// - If a handle is released, it should not be used for other purposes +// such as I/O. +// +// In this checker, each tracked handle is associated with a state. When the +// handle variable is passed to different function calls or syscalls, its state +// changes. The state changes can be generally represented by following ASCII +// Art: +// +// +// +-+---------v-+ +------------+ +// acquire_func succeeded | | Escape | | +// +-----------------> Allocated +---------> Escaped <--+ +// | | | | | | +// | +-----+------++ +------------+ | +// | | | | +// | release_func | +--+ | +// | | | handle +--------+ | +// | | | dies | | | +// | +----v-----+ +---------> Leaked | | +// | | | |(REPORT)| | +// +----------+--+ | Released | Escape +--------+ | +// | | | +---------------------------+ +// | Not tracked <--+ +----+---+-+ +// | | | | | As argument by value +// +------+------+ | release_func | +------+ in function call +// | | | | or by reference in +// | | | | use_func call +// +---------+ +----v-----+ | +-----------+ +// acquire_func failed | Double | +-----> Use after | +// | released | | released | +// | (REPORT) | | (REPORT) | +// +----------+ +-----------+ +// +// acquire_func represents the functions or syscalls that may acquire a handle. +// release_func represents the functions or syscalls that may release a handle. +// use_func represents the functions or syscall that requires an open handle. +// +// If a tracked handle dies in "Released" or "Not Tracked" state, we assume it +// is properly used. Otherwise a bug and will be reported. +// +// Note that, the analyzer does not always know for sure if a function failed +// or succeeded. In those cases we use the state MaybeAllocated. +// Thus, the diagramm above captures the intent, not implementation details. +// +// Due to the fact that the number of handle related syscalls in Fuchsia +// is large, we adopt the annotation attributes to descript syscalls' +// operations(acquire/release/use) on handles instead of hardcoding +// everything in the checker. +// +// We use following annotation attributes for handle related syscalls or +// functions: +// 1. __attribute__((acquire_handle("Fuchsia"))) |handle will be acquired +// 2. __attribute__((release_handle("Fuchsia"))) |handle will be released +// 3. __attribute__((use_handle("Fuchsia"))) |handle will not transit to +// escaped state, it also needs to be open. +// +// For example, an annotated syscall: +// zx_status_t zx_channel_create( +// uint32_t options, +// zx_handle_t* out0 __attribute__((acquire_handle("Fuchsia"))) , +// zx_handle_t* out1 __attribute__((acquire_handle("Fuchsia")))); +// denotes a syscall which will acquire two handles and save them to 'out0' and +// 'out1' when succeeded. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/CheckerManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" + +using namespace clang; +using namespace ento; + +namespace { + +static const StringRef HandleTypeName = "zx_handle_t"; +static const StringRef ErrorTypeName = "zx_status_t"; + +class HandleState { +private: + enum class Kind { MaybeAllocated, Allocated, Released, Escaped } K; + SymbolRef ErrorSym; + HandleState(Kind K, SymbolRef ErrorSym) : K(K), ErrorSym(ErrorSym) {} + +public: + bool operator==(const HandleState &Other) const { + return K == Other.K && ErrorSym == Other.ErrorSym; + } + bool isAllocated() const { return K == Kind::Allocated; } + bool maybeAllocated() const { return K == Kind::MaybeAllocated; } + bool isReleased() const { return K == Kind::Released; } + bool isEscaped() const { return K == Kind::Escaped; } + + static HandleState getMaybeAllocated(SymbolRef ErrorSym) { + return HandleState(Kind::MaybeAllocated, ErrorSym); + } + static HandleState getAllocated(ProgramStateRef State, HandleState S) { + assert(S.maybeAllocated()); + assert(State->getConstraintManager() + .isNull(State, S.getErrorSym()) + .isConstrained()); + return HandleState(Kind::Allocated, nullptr); + } + static HandleState getReleased() { + return HandleState(Kind::Released, nullptr); + } + static HandleState getEscaped() { + return HandleState(Kind::Escaped, nullptr); + } + + SymbolRef getErrorSym() const { return ErrorSym; } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddInteger(static_cast<int>(K)); + ID.AddPointer(ErrorSym); + } + + LLVM_DUMP_METHOD void dump(raw_ostream &OS) const { + switch (K) { +#define CASE(ID) \ + case ID: \ + OS << #ID; \ + break; + CASE(Kind::MaybeAllocated) + CASE(Kind::Allocated) + CASE(Kind::Released) + CASE(Kind::Escaped) + } + } + + LLVM_DUMP_METHOD void dump() const { dump(llvm::errs()); } +}; + +template <typename Attr> static bool hasFuchsiaAttr(const Decl *D) { + return D->hasAttr<Attr>() && D->getAttr<Attr>()->getHandleType() == "Fuchsia"; +} + +class FuchsiaHandleChecker + : public Checker<check::PostCall, check::PreCall, check::DeadSymbols, + check::PointerEscape, eval::Assume> { + BugType LeakBugType{this, "Fuchsia handle leak", "Fuchsia Handle Error", + /*SuppressOnSink=*/true}; + BugType DoubleReleaseBugType{this, "Fuchsia handle double release", + "Fuchsia Handle Error"}; + BugType UseAfterReleaseBugType{this, "Fuchsia handle use after release", + "Fuchsia Handle Error"}; + +public: + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + void checkPostCall(const CallEvent &Call, CheckerContext &C) const; + void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; + ProgramStateRef evalAssume(ProgramStateRef State, SVal Cond, + bool Assumption) const; + ProgramStateRef checkPointerEscape(ProgramStateRef State, + const InvalidatedSymbols &Escaped, + const CallEvent *Call, + PointerEscapeKind Kind) const; + + ExplodedNode *reportLeaks(ArrayRef<SymbolRef> LeakedHandles, + CheckerContext &C, ExplodedNode *Pred) const; + + void reportDoubleRelease(SymbolRef HandleSym, const SourceRange &Range, + CheckerContext &C) const; + + void reportUseAfterFree(SymbolRef HandleSym, const SourceRange &Range, + CheckerContext &C) const; + + void reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, CheckerContext &C, + const SourceRange *Range, const BugType &Type, + StringRef Msg) const; + + void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, + const char *Sep) const override; +}; +} // end anonymous namespace + +REGISTER_MAP_WITH_PROGRAMSTATE(HStateMap, SymbolRef, HandleState) + +static const ExplodedNode *getAcquireSite(const ExplodedNode *N, SymbolRef Sym, + CheckerContext &Ctx) { + ProgramStateRef State = N->getState(); + // When bug type is handle leak, exploded node N does not have state info for + // leaking handle. Get the predecessor of N instead. + if (!State->get<HStateMap>(Sym)) + N = N->getFirstPred(); + + const ExplodedNode *Pred = N; + while (N) { + State = N->getState(); + if (!State->get<HStateMap>(Sym)) { + const HandleState *HState = Pred->getState()->get<HStateMap>(Sym); + if (HState && (HState->isAllocated() || HState->maybeAllocated())) + return N; + } + Pred = N; + N = N->getFirstPred(); + } + return nullptr; +} + +/// Returns the symbols extracted from the argument or null if it cannot be +/// found. +static SymbolRef getFuchsiaHandleSymbol(QualType QT, SVal Arg, + ProgramStateRef State) { + int PtrToHandleLevel = 0; + while (QT->isAnyPointerType() || QT->isReferenceType()) { + ++PtrToHandleLevel; + QT = QT->getPointeeType(); + } + if (const auto *HandleType = QT->getAs<TypedefType>()) { + if (HandleType->getDecl()->getName() != HandleTypeName) + return nullptr; + if (PtrToHandleLevel > 1) { + // Not supported yet. + return nullptr; + } + + if (PtrToHandleLevel == 0) { + return Arg.getAsSymbol(); + } else { + assert(PtrToHandleLevel == 1); + if (Optional<Loc> ArgLoc = Arg.getAs<Loc>()) + return State->getSVal(*ArgLoc).getAsSymbol(); + } + } + return nullptr; +} + +void FuchsiaHandleChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); + if (!FuncDecl) { + // Unknown call, escape by value handles. They are not covered by + // PointerEscape callback. + for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) { + if (SymbolRef Handle = Call.getArgSVal(Arg).getAsSymbol()) + State = State->set<HStateMap>(Handle, HandleState::getEscaped()); + } + C.addTransition(State); + return; + } + + for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) { + if (Arg >= FuncDecl->getNumParams()) + break; + const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); + SymbolRef Handle = + getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State); + if (!Handle) + continue; + + // Handled in checkPostCall. + if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD) || + hasFuchsiaAttr<AcquireHandleAttr>(PVD)) + continue; + + const HandleState *HState = State->get<HStateMap>(Handle); + if (!HState || HState->isEscaped()) + continue; + + if (hasFuchsiaAttr<UseHandleAttr>(PVD) || PVD->getType()->isIntegerType()) { + if (HState->isReleased()) { + reportUseAfterFree(Handle, Call.getArgSourceRange(Arg), C); + return; + } + } + if (!hasFuchsiaAttr<UseHandleAttr>(PVD) && + PVD->getType()->isIntegerType()) { + // Working around integer by-value escapes. + State = State->set<HStateMap>(Handle, HandleState::getEscaped()); + } + } + C.addTransition(State); +} + +void FuchsiaHandleChecker::checkPostCall(const CallEvent &Call, + CheckerContext &C) const { + const FunctionDecl *FuncDecl = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); + if (!FuncDecl) + return; + + ProgramStateRef State = C.getState(); + + std::vector<std::function<std::string(BugReport & BR)>> Notes; + SymbolRef ResultSymbol = nullptr; + if (const auto *TypeDefTy = FuncDecl->getReturnType()->getAs<TypedefType>()) + if (TypeDefTy->getDecl()->getName() == ErrorTypeName) + ResultSymbol = Call.getReturnValue().getAsSymbol(); + + // Function returns an open handle. + if (hasFuchsiaAttr<AcquireHandleAttr>(FuncDecl)) { + SymbolRef RetSym = Call.getReturnValue().getAsSymbol(); + State = + State->set<HStateMap>(RetSym, HandleState::getMaybeAllocated(nullptr)); + } + + for (unsigned Arg = 0; Arg < Call.getNumArgs(); ++Arg) { + if (Arg >= FuncDecl->getNumParams()) + break; + const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); + SymbolRef Handle = + getFuchsiaHandleSymbol(PVD->getType(), Call.getArgSVal(Arg), State); + if (!Handle) + continue; + + const HandleState *HState = State->get<HStateMap>(Handle); + if (HState && HState->isEscaped()) + continue; + if (hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) { + if (HState && HState->isReleased()) { + reportDoubleRelease(Handle, Call.getArgSourceRange(Arg), C); + return; + } else { + Notes.push_back([Handle](BugReport &BR) { + auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR); + if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) { + return "Handle released here."; + } else + return ""; + }); + State = State->set<HStateMap>(Handle, HandleState::getReleased()); + } + } else if (hasFuchsiaAttr<AcquireHandleAttr>(PVD)) { + Notes.push_back([Handle](BugReport &BR) { + auto *PathBR = static_cast<PathSensitiveBugReport *>(&BR); + if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) { + return "Handle allocated here."; + } else + return ""; + }); + State = State->set<HStateMap>( + Handle, HandleState::getMaybeAllocated(ResultSymbol)); + } + } + const NoteTag *T = nullptr; + if (!Notes.empty()) { + T = C.getNoteTag( + [this, Notes{std::move(Notes)}](BugReport &BR) -> std::string { + if (&BR.getBugType() != &UseAfterReleaseBugType && + &BR.getBugType() != &LeakBugType && + &BR.getBugType() != &DoubleReleaseBugType) + return ""; + for (auto &Note : Notes) { + std::string Text = Note(BR); + if (!Text.empty()) + return Text; + } + return ""; + }); + } + C.addTransition(State, T); +} + +void FuchsiaHandleChecker::checkDeadSymbols(SymbolReaper &SymReaper, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); + SmallVector<SymbolRef, 2> LeakedSyms; + HStateMapTy TrackedHandles = State->get<HStateMap>(); + for (auto &CurItem : TrackedHandles) { + if (!SymReaper.isDead(CurItem.first)) + continue; + if (CurItem.second.isAllocated() || CurItem.second.maybeAllocated()) + LeakedSyms.push_back(CurItem.first); + State = State->remove<HStateMap>(CurItem.first); + } + + ExplodedNode *N = C.getPredecessor(); + if (!LeakedSyms.empty()) + N = reportLeaks(LeakedSyms, C, N); + + C.addTransition(State, N); +} + +// Acquiring a handle is not always successful. In Fuchsia most functions +// return a status code that determines the status of the handle. +// When we split the path based on this status code we know that on one +// path we do have the handle and on the other path the acquire failed. +// This method helps avoiding false positive leak warnings on paths where +// the function failed. +// Moreover, when a handle is known to be zero (the invalid handle), +// we no longer can follow the symbol on the path, becaue the constant +// zero will be used instead of the symbol. We also do not need to release +// an invalid handle, so we remove the corresponding symbol from the state. +ProgramStateRef FuchsiaHandleChecker::evalAssume(ProgramStateRef State, + SVal Cond, + bool Assumption) const { + // TODO: add notes about successes/fails for APIs. + ConstraintManager &Cmr = State->getConstraintManager(); + HStateMapTy TrackedHandles = State->get<HStateMap>(); + for (auto &CurItem : TrackedHandles) { + ConditionTruthVal HandleVal = Cmr.isNull(State, CurItem.first); + if (HandleVal.isConstrainedTrue()) { + // The handle is invalid. We can no longer follow the symbol on this path. + State = State->remove<HStateMap>(CurItem.first); + } + SymbolRef ErrorSym = CurItem.second.getErrorSym(); + if (!ErrorSym) + continue; + ConditionTruthVal ErrorVal = Cmr.isNull(State, ErrorSym); + if (ErrorVal.isConstrainedTrue()) { + // Allocation succeeded. + if (CurItem.second.maybeAllocated()) + State = State->set<HStateMap>( + CurItem.first, HandleState::getAllocated(State, CurItem.second)); + } else if (ErrorVal.isConstrainedFalse()) { + // Allocation failed. + if (CurItem.second.maybeAllocated()) + State = State->remove<HStateMap>(CurItem.first); + } + } + return State; +} + +ProgramStateRef FuchsiaHandleChecker::checkPointerEscape( + ProgramStateRef State, const InvalidatedSymbols &Escaped, + const CallEvent *Call, PointerEscapeKind Kind) const { + const FunctionDecl *FuncDecl = + Call ? dyn_cast_or_null<FunctionDecl>(Call->getDecl()) : nullptr; + + llvm::DenseSet<SymbolRef> UnEscaped; + // Not all calls should escape our symbols. + if (FuncDecl && + (Kind == PSK_DirectEscapeOnCall || Kind == PSK_IndirectEscapeOnCall || + Kind == PSK_EscapeOutParameters)) { + for (unsigned Arg = 0; Arg < Call->getNumArgs(); ++Arg) { + if (Arg >= FuncDecl->getNumParams()) + break; + const ParmVarDecl *PVD = FuncDecl->getParamDecl(Arg); + SymbolRef Handle = + getFuchsiaHandleSymbol(PVD->getType(), Call->getArgSVal(Arg), State); + if (!Handle) + continue; + if (hasFuchsiaAttr<UseHandleAttr>(PVD) || + hasFuchsiaAttr<ReleaseHandleAttr>(PVD)) + UnEscaped.insert(Handle); + } + } + + // For out params, we have to deal with derived symbols. See + // MacOSKeychainAPIChecker for details. + for (auto I : State->get<HStateMap>()) { + if (Escaped.count(I.first) && !UnEscaped.count(I.first)) + State = State->set<HStateMap>(I.first, HandleState::getEscaped()); + if (const auto *SD = dyn_cast<SymbolDerived>(I.first)) { + auto ParentSym = SD->getParentSymbol(); + if (Escaped.count(ParentSym)) + State = State->set<HStateMap>(I.first, HandleState::getEscaped()); + } + } + + return State; +} + +ExplodedNode * +FuchsiaHandleChecker::reportLeaks(ArrayRef<SymbolRef> LeakedHandles, + CheckerContext &C, ExplodedNode *Pred) const { + ExplodedNode *ErrNode = C.generateNonFatalErrorNode(C.getState(), Pred); + for (SymbolRef LeakedHandle : LeakedHandles) { + reportBug(LeakedHandle, ErrNode, C, nullptr, LeakBugType, + "Potential leak of handle"); + } + return ErrNode; +} + +void FuchsiaHandleChecker::reportDoubleRelease(SymbolRef HandleSym, + const SourceRange &Range, + CheckerContext &C) const { + ExplodedNode *ErrNode = C.generateErrorNode(C.getState()); + reportBug(HandleSym, ErrNode, C, &Range, DoubleReleaseBugType, + "Releasing a previously released handle"); +} + +void FuchsiaHandleChecker::reportUseAfterFree(SymbolRef HandleSym, + const SourceRange &Range, + CheckerContext &C) const { + ExplodedNode *ErrNode = C.generateErrorNode(C.getState()); + reportBug(HandleSym, ErrNode, C, &Range, UseAfterReleaseBugType, + "Using a previously released handle"); +} + +void FuchsiaHandleChecker::reportBug(SymbolRef Sym, ExplodedNode *ErrorNode, + CheckerContext &C, + const SourceRange *Range, + const BugType &Type, StringRef Msg) const { + if (!ErrorNode) + return; + + std::unique_ptr<PathSensitiveBugReport> R; + if (Type.isSuppressOnSink()) { + const ExplodedNode *AcquireNode = getAcquireSite(ErrorNode, Sym, C); + if (AcquireNode) { + PathDiagnosticLocation LocUsedForUniqueing = + PathDiagnosticLocation::createBegin( + AcquireNode->getStmtForDiagnostics(), C.getSourceManager(), + AcquireNode->getLocationContext()); + + R = std::make_unique<PathSensitiveBugReport>( + Type, Msg, ErrorNode, LocUsedForUniqueing, + AcquireNode->getLocationContext()->getDecl()); + } + } + if (!R) + R = std::make_unique<PathSensitiveBugReport>(Type, Msg, ErrorNode); + if (Range) + R->addRange(*Range); + R->markInteresting(Sym); + C.emitReport(std::move(R)); +} + +void ento::registerFuchsiaHandleChecker(CheckerManager &mgr) { + mgr.registerChecker<FuchsiaHandleChecker>(); +} + +bool ento::shouldRegisterFuchsiaHandleChecker(const LangOptions &LO) { + return true; +} + +void FuchsiaHandleChecker::printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const { + + HStateMapTy StateMap = State->get<HStateMap>(); + + if (!StateMap.isEmpty()) { + Out << Sep << "FuchsiaHandleChecker :" << NL; + for (HStateMapTy::iterator I = StateMap.begin(), E = StateMap.end(); I != E; + ++I) { + I.getKey()->dumpToStream(Out); + Out << " : "; + I.getData().dump(Out); + Out << NL; + } + } +} diff --git a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp index d442b26b3959..302d5bb1bea8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/GenericTaintChecker.cpp @@ -24,9 +24,10 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" -#include "llvm/ADT/StringMap.h" #include "llvm/Support/YAMLTraits.h" +#include <algorithm> #include <limits> +#include <unordered_map> #include <utility> using namespace clang; @@ -56,10 +57,11 @@ public: /// Used to parse the configuration file. struct TaintConfiguration { - using NameArgsPair = std::pair<std::string, ArgVector>; + using NameScopeArgs = std::tuple<std::string, std::string, ArgVector>; struct Propagation { std::string Name; + std::string Scope; ArgVector SrcArgs; SignedArgVector DstArgs; VariadicType VarType; @@ -67,8 +69,8 @@ public: }; std::vector<Propagation> Propagations; - std::vector<NameArgsPair> Filters; - std::vector<NameArgsPair> Sinks; + std::vector<NameScopeArgs> Filters; + std::vector<NameScopeArgs> Sinks; TaintConfiguration() = default; TaintConfiguration(const TaintConfiguration &) = default; @@ -97,14 +99,52 @@ private: BT.reset(new BugType(this, "Use of Untrusted Data", "Untrusted Data")); } + struct FunctionData { + FunctionData() = delete; + FunctionData(const FunctionData &) = default; + FunctionData(FunctionData &&) = default; + FunctionData &operator=(const FunctionData &) = delete; + FunctionData &operator=(FunctionData &&) = delete; + + static Optional<FunctionData> create(const CallExpr *CE, + const CheckerContext &C) { + const FunctionDecl *FDecl = C.getCalleeDecl(CE); + if (!FDecl || (FDecl->getKind() != Decl::Function && + FDecl->getKind() != Decl::CXXMethod)) + return None; + + StringRef Name = C.getCalleeName(FDecl); + std::string FullName = FDecl->getQualifiedNameAsString(); + if (Name.empty() || FullName.empty()) + return None; + + return FunctionData{FDecl, Name, FullName}; + } + + bool isInScope(StringRef Scope) const { + return StringRef(FullName).startswith(Scope); + } + + const FunctionDecl *const FDecl; + const StringRef Name; + const std::string FullName; + }; + /// Catch taint related bugs. Check if tainted data is passed to a - /// system call etc. - bool checkPre(const CallExpr *CE, CheckerContext &C) const; + /// system call etc. Returns true on matching. + bool checkPre(const CallExpr *CE, const FunctionData &FData, + CheckerContext &C) const; - /// Add taint sources on a pre-visit. - void addSourcesPre(const CallExpr *CE, CheckerContext &C) const; + /// Add taint sources on a pre-visit. Returns true on matching. + bool addSourcesPre(const CallExpr *CE, const FunctionData &FData, + CheckerContext &C) const; - /// Propagate taint generated at pre-visit. + /// Mark filter's arguments not tainted on a pre-visit. Returns true on + /// matching. + bool addFiltersPre(const CallExpr *CE, const FunctionData &FData, + CheckerContext &C) const; + + /// Propagate taint generated at pre-visit. Returns true on matching. bool propagateFromPre(const CallExpr *CE, CheckerContext &C) const; /// Check if the region the expression evaluates to is the standard input, @@ -142,7 +182,7 @@ private: /// Check if tainted data is used as a custom sink's parameter. static constexpr llvm::StringLiteral MsgCustomSink = "Untrusted data is passed to a user-defined sink"; - bool checkCustomSinks(const CallExpr *CE, StringRef Name, + bool checkCustomSinks(const CallExpr *CE, const FunctionData &FData, CheckerContext &C) const; /// Generate a report if the expression is tainted or points to tainted data. @@ -150,8 +190,17 @@ private: CheckerContext &C) const; struct TaintPropagationRule; - using NameRuleMap = llvm::StringMap<TaintPropagationRule>; - using NameArgMap = llvm::StringMap<ArgVector>; + template <typename T> + using ConfigDataMap = + std::unordered_multimap<std::string, std::pair<std::string, T>>; + using NameRuleMap = ConfigDataMap<TaintPropagationRule>; + using NameArgMap = ConfigDataMap<ArgVector>; + + /// Find a function with the given name and scope. Returns the first match + /// or the end of the map. + template <typename T> + static auto findFunctionInConfig(const ConfigDataMap<T> &Map, + const FunctionData &FData); /// A struct used to specify taint propagation rules for a function. /// @@ -193,8 +242,7 @@ private: /// Get the propagation rule for a given function. static TaintPropagationRule getTaintPropagationRule(const NameRuleMap &CustomPropagations, - const FunctionDecl *FDecl, StringRef Name, - CheckerContext &C); + const FunctionData &FData, CheckerContext &C); void addSrcArg(unsigned A) { SrcArgs.push_back(A); } void addDstArg(unsigned A) { DstArgs.push_back(A); } @@ -229,14 +277,15 @@ private: CheckerContext &C); }; - /// Defines a map between the propagation function's name and - /// TaintPropagationRule. + /// Defines a map between the propagation function's name, scope + /// and TaintPropagationRule. NameRuleMap CustomPropagations; - /// Defines a map between the filter function's name and filtering args. + /// Defines a map between the filter function's name, scope and filtering + /// args. NameArgMap CustomFilters; - /// Defines a map between the sink function's name and sinking args. + /// Defines a map between the sink function's name, scope and sinking args. NameArgMap CustomSinks; }; @@ -253,7 +302,7 @@ constexpr llvm::StringLiteral GenericTaintChecker::MsgCustomSink; using TaintConfig = GenericTaintChecker::TaintConfiguration; LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::Propagation) -LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameArgsPair) +LLVM_YAML_IS_SEQUENCE_VECTOR(TaintConfig::NameScopeArgs) namespace llvm { namespace yaml { @@ -268,6 +317,7 @@ template <> struct MappingTraits<TaintConfig> { template <> struct MappingTraits<TaintConfig::Propagation> { static void mapping(IO &IO, TaintConfig::Propagation &Propagation) { IO.mapRequired("Name", Propagation.Name); + IO.mapOptional("Scope", Propagation.Scope); IO.mapOptional("SrcArgs", Propagation.SrcArgs); IO.mapOptional("DstArgs", Propagation.DstArgs); IO.mapOptional("VariadicType", Propagation.VarType, @@ -285,10 +335,11 @@ template <> struct ScalarEnumerationTraits<GenericTaintChecker::VariadicType> { } }; -template <> struct MappingTraits<TaintConfig::NameArgsPair> { - static void mapping(IO &IO, TaintConfig::NameArgsPair &NameArg) { - IO.mapRequired("Name", NameArg.first); - IO.mapRequired("Args", NameArg.second); +template <> struct MappingTraits<TaintConfig::NameScopeArgs> { + static void mapping(IO &IO, TaintConfig::NameScopeArgs &NSA) { + IO.mapRequired("Name", std::get<0>(NSA)); + IO.mapOptional("Scope", std::get<1>(NSA)); + IO.mapRequired("Args", std::get<2>(NSA)); } }; } // namespace yaml @@ -321,31 +372,51 @@ void GenericTaintChecker::parseConfiguration(CheckerManager &Mgr, const std::string &Option, TaintConfiguration &&Config) { for (auto &P : Config.Propagations) { - GenericTaintChecker::CustomPropagations.try_emplace( - P.Name, std::move(P.SrcArgs), - convertToArgVector(Mgr, Option, P.DstArgs), P.VarType, P.VarIndex); + GenericTaintChecker::CustomPropagations.emplace( + P.Name, + std::make_pair(P.Scope, TaintPropagationRule{ + std::move(P.SrcArgs), + convertToArgVector(Mgr, Option, P.DstArgs), + P.VarType, P.VarIndex})); } for (auto &F : Config.Filters) { - GenericTaintChecker::CustomFilters.try_emplace(F.first, - std::move(F.second)); + GenericTaintChecker::CustomFilters.emplace( + std::get<0>(F), + std::make_pair(std::move(std::get<1>(F)), std::move(std::get<2>(F)))); } for (auto &S : Config.Sinks) { - GenericTaintChecker::CustomSinks.try_emplace(S.first, std::move(S.second)); + GenericTaintChecker::CustomSinks.emplace( + std::get<0>(S), + std::make_pair(std::move(std::get<1>(S)), std::move(std::get<2>(S)))); } } +template <typename T> +auto GenericTaintChecker::findFunctionInConfig(const ConfigDataMap<T> &Map, + const FunctionData &FData) { + auto Range = Map.equal_range(FData.Name); + auto It = + std::find_if(Range.first, Range.second, [&FData](const auto &Entry) { + const auto &Value = Entry.second; + StringRef Scope = Value.first; + return Scope.empty() || FData.isInScope(Scope); + }); + return It != Range.second ? It : Map.end(); +} + GenericTaintChecker::TaintPropagationRule GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( - const NameRuleMap &CustomPropagations, const FunctionDecl *FDecl, - StringRef Name, CheckerContext &C) { + const NameRuleMap &CustomPropagations, const FunctionData &FData, + CheckerContext &C) { // TODO: Currently, we might lose precision here: we always mark a return // value as tainted even if it's just a pointer, pointing to tainted data. // Check for exact name match for functions without builtin substitutes. + // Use qualified name, because these are C functions without namespace. TaintPropagationRule Rule = - llvm::StringSwitch<TaintPropagationRule>(Name) + llvm::StringSwitch<TaintPropagationRule>(FData.FullName) // Source functions // TODO: Add support for vfscanf & family. .Case("fdopen", TaintPropagationRule({}, {ReturnValueIndex})) @@ -390,6 +461,7 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( // Check if it's one of the memory setting/copying functions. // This check is specialized but faster then calling isCLibraryFunction. + const FunctionDecl *FDecl = FData.FDecl; unsigned BId = 0; if ((BId = FDecl->getMemoryFunctionKind())) switch (BId) { @@ -433,23 +505,32 @@ GenericTaintChecker::TaintPropagationRule::getTaintPropagationRule( // or smart memory copy: // - memccpy - copying until hitting a special character. - auto It = CustomPropagations.find(Name); - if (It != CustomPropagations.end()) - return It->getValue(); + auto It = findFunctionInConfig(CustomPropagations, FData); + if (It != CustomPropagations.end()) { + const auto &Value = It->second; + return Value.second; + } return TaintPropagationRule(); } void GenericTaintChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const { + Optional<FunctionData> FData = FunctionData::create(CE, C); + if (!FData) + return; + // Check for taintedness related errors first: system call, uncontrolled // format string, tainted buffer size. - if (checkPre(CE, C)) + if (checkPre(CE, *FData, C)) return; // Marks the function's arguments and/or return value tainted if it present in // the list. - addSourcesPre(CE, C); + if (addSourcesPre(CE, *FData, C)) + return; + + addFiltersPre(CE, *FData, C); } void GenericTaintChecker::checkPostStmt(const CallExpr *CE, @@ -464,31 +545,47 @@ void GenericTaintChecker::printState(raw_ostream &Out, ProgramStateRef State, printTaint(State, Out, NL, Sep); } -void GenericTaintChecker::addSourcesPre(const CallExpr *CE, +bool GenericTaintChecker::addSourcesPre(const CallExpr *CE, + const FunctionData &FData, CheckerContext &C) const { - ProgramStateRef State = nullptr; - const FunctionDecl *FDecl = C.getCalleeDecl(CE); - if (!FDecl || FDecl->getKind() != Decl::Function) - return; - - StringRef Name = C.getCalleeName(FDecl); - if (Name.empty()) - return; - // First, try generating a propagation rule for this function. TaintPropagationRule Rule = TaintPropagationRule::getTaintPropagationRule( - this->CustomPropagations, FDecl, Name, C); + this->CustomPropagations, FData, C); if (!Rule.isNull()) { - State = Rule.process(CE, C); - if (!State) - return; - C.addTransition(State); - return; + ProgramStateRef State = Rule.process(CE, C); + if (State) { + C.addTransition(State); + return true; + } } + return false; +} - if (!State) - return; - C.addTransition(State); +bool GenericTaintChecker::addFiltersPre(const CallExpr *CE, + const FunctionData &FData, + CheckerContext &C) const { + auto It = findFunctionInConfig(CustomFilters, FData); + if (It == CustomFilters.end()) + return false; + + ProgramStateRef State = C.getState(); + const auto &Value = It->second; + const ArgVector &Args = Value.second; + for (unsigned ArgNum : Args) { + if (ArgNum >= CE->getNumArgs()) + continue; + + const Expr *Arg = CE->getArg(ArgNum); + Optional<SVal> V = getPointedToSVal(C, Arg); + if (V) + State = removeTaint(State, *V); + } + + if (State != C.getState()) { + C.addTransition(State); + return true; + } + return false; } bool GenericTaintChecker::propagateFromPre(const CallExpr *CE, @@ -530,26 +627,19 @@ bool GenericTaintChecker::propagateFromPre(const CallExpr *CE, } bool GenericTaintChecker::checkPre(const CallExpr *CE, + const FunctionData &FData, CheckerContext &C) const { if (checkUncontrolledFormatString(CE, C)) return true; - const FunctionDecl *FDecl = C.getCalleeDecl(CE); - if (!FDecl || FDecl->getKind() != Decl::Function) - return false; - - StringRef Name = C.getCalleeName(FDecl); - if (Name.empty()) - return false; - - if (checkSystemCall(CE, Name, C)) + if (checkSystemCall(CE, FData.Name, C)) return true; - if (checkTaintedBufferSize(CE, FDecl, C)) + if (checkTaintedBufferSize(CE, FData.FDecl, C)) return true; - if (checkCustomSinks(CE, Name, C)) + if (checkCustomSinks(CE, FData, C)) return true; return false; @@ -568,7 +658,7 @@ Optional<SVal> GenericTaintChecker::getPointedToSVal(CheckerContext &C, QualType ArgTy = Arg->getType().getCanonicalType(); if (!ArgTy->isPointerType()) - return None; + return State->getSVal(*AddrLoc); QualType ValTy = ArgTy->getPointeeType(); @@ -821,13 +911,15 @@ bool GenericTaintChecker::checkTaintedBufferSize(const CallExpr *CE, generateReportIfTainted(CE->getArg(ArgNum), MsgTaintedBufferSize, C); } -bool GenericTaintChecker::checkCustomSinks(const CallExpr *CE, StringRef Name, +bool GenericTaintChecker::checkCustomSinks(const CallExpr *CE, + const FunctionData &FData, CheckerContext &C) const { - auto It = CustomSinks.find(Name); + auto It = findFunctionInConfig(CustomSinks, FData); if (It == CustomSinks.end()) return false; - const GenericTaintChecker::ArgVector &Args = It->getValue(); + const auto &Value = It->second; + const GenericTaintChecker::ArgVector &Args = Value.second; for (unsigned ArgNum : Args) { if (ArgNum >= CE->getNumArgs()) continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp index b0d101c88517..dd89c53478e8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp @@ -62,7 +62,7 @@ public: // lookup by region. bool isSymbolTracked(ProgramStateRef State, SymbolRef Sym) { RawPtrMapTy Map = State->get<RawPtrMap>(); - for (const auto Entry : Map) { + for (const auto &Entry : Map) { if (Entry.second.contains(Sym)) return true; } @@ -236,7 +236,7 @@ void InnerPointerChecker::checkDeadSymbols(SymbolReaper &SymReaper, ProgramStateRef State = C.getState(); PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>(); RawPtrMapTy RPM = State->get<RawPtrMap>(); - for (const auto Entry : RPM) { + for (const auto &Entry : RPM) { if (!SymReaper.isLiveRegion(Entry.first)) { // Due to incomplete destructor support, some dead regions might // remain in the program state map. Clean them up. @@ -266,7 +266,7 @@ std::unique_ptr<BugReporterVisitor> getInnerPointerBRVisitor(SymbolRef Sym) { const MemRegion *getContainerObjRegion(ProgramStateRef State, SymbolRef Sym) { RawPtrMapTy Map = State->get<RawPtrMap>(); - for (const auto Entry : Map) { + for (const auto &Entry : Map) { if (Entry.second.contains(Sym)) { return Entry.first; } diff --git a/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp new file mode 100644 index 000000000000..d1a9a7df071d --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/InvalidatedIteratorChecker.cpp @@ -0,0 +1,95 @@ +//===-- InvalidatedIteratorChecker.cpp ----------------------------*- C++ -*--// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines a checker for access of invalidated iterators. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" + + +#include "Iterator.h" + +using namespace clang; +using namespace ento; +using namespace iterator; + +namespace { + +class InvalidatedIteratorChecker + : public Checker<check::PreCall> { + + std::unique_ptr<BugType> InvalidatedBugType; + + void verifyAccess(CheckerContext &C, const SVal &Val) const; + void reportBug(const StringRef &Message, const SVal &Val, + CheckerContext &C, ExplodedNode *ErrNode) const; +public: + InvalidatedIteratorChecker(); + + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + +}; + +} //namespace + +InvalidatedIteratorChecker::InvalidatedIteratorChecker() { + InvalidatedBugType.reset( + new BugType(this, "Iterator invalidated", "Misuse of STL APIs")); +} + +void InvalidatedIteratorChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + // Check for access of invalidated position + const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); + if (!Func) + return; + + if (Func->isOverloadedOperator() && + isAccessOperator(Func->getOverloadedOperator())) { + // Check for any kind of access of invalidated iterator positions + if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { + verifyAccess(C, InstCall->getCXXThisVal()); + } else { + verifyAccess(C, Call.getArgSVal(0)); + } + } +} + +void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const { + auto State = C.getState(); + const auto *Pos = getIteratorPosition(State, Val); + if (Pos && !Pos->isValid()) { + auto *N = C.generateErrorNode(State); + if (!N) { + return; + } + reportBug("Invalidated iterator accessed.", Val, C, N); + } +} + +void InvalidatedIteratorChecker::reportBug(const StringRef &Message, + const SVal &Val, CheckerContext &C, + ExplodedNode *ErrNode) const { + auto R = std::make_unique<PathSensitiveBugReport>(*InvalidatedBugType, + Message, ErrNode); + R->markInteresting(Val); + C.emitReport(std::move(R)); +} + +void ento::registerInvalidatedIteratorChecker(CheckerManager &mgr) { + mgr.registerChecker<InvalidatedIteratorChecker>(); +} + +bool ento::shouldRegisterInvalidatedIteratorChecker(const LangOptions &LO) { + return true; +} diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp new file mode 100644 index 000000000000..6bca5515724c --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.cpp @@ -0,0 +1,227 @@ +//=== Iterator.cpp - Common functions for iterator checkers. -------*- C++ -*-// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines common functions to be used by the itertor checkers . +// +//===----------------------------------------------------------------------===// + +#include "Iterator.h" + +namespace clang { +namespace ento { +namespace iterator { + +bool isIteratorType(const QualType &Type) { + if (Type->isPointerType()) + return true; + + const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl(); + return isIterator(CRD); +} + +bool isIterator(const CXXRecordDecl *CRD) { + if (!CRD) + return false; + + const auto Name = CRD->getName(); + if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") || + Name.endswith_lower("it"))) + return false; + + bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false, + HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false; + for (const auto *Method : CRD->methods()) { + if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) { + if (Ctor->isCopyConstructor()) { + HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public; + } + continue; + } + if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) { + HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public; + continue; + } + if (Method->isCopyAssignmentOperator()) { + HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public; + continue; + } + if (!Method->isOverloadedOperator()) + continue; + const auto OPK = Method->getOverloadedOperator(); + if (OPK == OO_PlusPlus) { + HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0); + HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1); + continue; + } + if (OPK == OO_Star) { + HasDerefOp = (Method->getNumParams() == 0); + continue; + } + } + + return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp && + HasPostIncrOp && HasDerefOp; +} + +bool isComparisonOperator(OverloadedOperatorKind OK) { + return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less || + OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual; +} + +bool isInsertCall(const FunctionDecl *Func) { + const auto *IdInfo = Func->getIdentifier(); + if (!IdInfo) + return false; + if (Func->getNumParams() < 2 || Func->getNumParams() > 3) + return false; + if (!isIteratorType(Func->getParamDecl(0)->getType())) + return false; + return IdInfo->getName() == "insert"; +} + +bool isEmplaceCall(const FunctionDecl *Func) { + const auto *IdInfo = Func->getIdentifier(); + if (!IdInfo) + return false; + if (Func->getNumParams() < 2) + return false; + if (!isIteratorType(Func->getParamDecl(0)->getType())) + return false; + return IdInfo->getName() == "emplace"; +} + +bool isEraseCall(const FunctionDecl *Func) { + const auto *IdInfo = Func->getIdentifier(); + if (!IdInfo) + return false; + if (Func->getNumParams() < 1 || Func->getNumParams() > 2) + return false; + if (!isIteratorType(Func->getParamDecl(0)->getType())) + return false; + if (Func->getNumParams() == 2 && + !isIteratorType(Func->getParamDecl(1)->getType())) + return false; + return IdInfo->getName() == "erase"; +} + +bool isEraseAfterCall(const FunctionDecl *Func) { + const auto *IdInfo = Func->getIdentifier(); + if (!IdInfo) + return false; + if (Func->getNumParams() < 1 || Func->getNumParams() > 2) + return false; + if (!isIteratorType(Func->getParamDecl(0)->getType())) + return false; + if (Func->getNumParams() == 2 && + !isIteratorType(Func->getParamDecl(1)->getType())) + return false; + return IdInfo->getName() == "erase_after"; +} + +bool isAccessOperator(OverloadedOperatorKind OK) { + return isDereferenceOperator(OK) || isIncrementOperator(OK) || + isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK); +} + +bool isDereferenceOperator(OverloadedOperatorKind OK) { + return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar || + OK == OO_Subscript; +} + +bool isIncrementOperator(OverloadedOperatorKind OK) { + return OK == OO_PlusPlus; +} + +bool isDecrementOperator(OverloadedOperatorKind OK) { + return OK == OO_MinusMinus; +} + +bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) { + return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus || + OK == OO_MinusEqual; +} + +const ContainerData *getContainerData(ProgramStateRef State, + const MemRegion *Cont) { + return State->get<ContainerMap>(Cont); +} + +const IteratorPosition *getIteratorPosition(ProgramStateRef State, + const SVal &Val) { + if (auto Reg = Val.getAsRegion()) { + Reg = Reg->getMostDerivedObjectRegion(); + return State->get<IteratorRegionMap>(Reg); + } else if (const auto Sym = Val.getAsSymbol()) { + return State->get<IteratorSymbolMap>(Sym); + } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) { + return State->get<IteratorRegionMap>(LCVal->getRegion()); + } + return nullptr; +} + +ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val, + const IteratorPosition &Pos) { + if (auto Reg = Val.getAsRegion()) { + Reg = Reg->getMostDerivedObjectRegion(); + return State->set<IteratorRegionMap>(Reg, Pos); + } else if (const auto Sym = Val.getAsSymbol()) { + return State->set<IteratorSymbolMap>(Sym, Pos); + } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) { + return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos); + } + return nullptr; +} + +ProgramStateRef advancePosition(ProgramStateRef State, const SVal &Iter, + OverloadedOperatorKind Op, + const SVal &Distance) { + const auto *Pos = getIteratorPosition(State, Iter); + if (!Pos) + return nullptr; + + auto &SymMgr = State->getStateManager().getSymbolManager(); + auto &SVB = State->getStateManager().getSValBuilder(); + + assert ((Op == OO_Plus || Op == OO_PlusEqual || + Op == OO_Minus || Op == OO_MinusEqual) && + "Advance operator must be one of +, -, += and -=."); + auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub; + if (const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) { + // For concrete integers we can calculate the new position + const auto NewPos = + Pos->setTo(SVB.evalBinOp(State, BinOp, + nonloc::SymbolVal(Pos->getOffset()), + *IntDist, SymMgr.getType(Pos->getOffset())) + .getAsSymbol()); + return setIteratorPosition(State, Iter, NewPos); + } + + return nullptr; +} + +bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, + BinaryOperator::Opcode Opc) { + return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc); +} + +bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2, + BinaryOperator::Opcode Opc) { + auto &SVB = State->getStateManager().getSValBuilder(); + + const auto comparison = + SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType()); + + assert(comparison.getAs<DefinedSVal>() && + "Symbol comparison must be a `DefinedSVal`"); + + return !State->assume(comparison.castAs<DefinedSVal>(), false); +} + +} // namespace iterator +} // namespace ento +} // namespace clang diff --git a/clang/lib/StaticAnalyzer/Checkers/Iterator.h b/clang/lib/StaticAnalyzer/Checkers/Iterator.h new file mode 100644 index 000000000000..c10d86691693 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/Iterator.h @@ -0,0 +1,175 @@ +//=== Iterator.h - Common functions for iterator checkers. ---------*- C++ -*-// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines common functions to be used by the itertor checkers . +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ITERATOR_H +#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_ITERATOR_H + +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h" + +namespace clang { +namespace ento { +namespace iterator { + +// Abstract position of an iterator. This helps to handle all three kinds +// of operators in a common way by using a symbolic position. +struct IteratorPosition { +private: + + // Container the iterator belongs to + const MemRegion *Cont; + + // Whether iterator is valid + const bool Valid; + + // Abstract offset + const SymbolRef Offset; + + IteratorPosition(const MemRegion *C, bool V, SymbolRef Of) + : Cont(C), Valid(V), Offset(Of) {} + +public: + const MemRegion *getContainer() const { return Cont; } + bool isValid() const { return Valid; } + SymbolRef getOffset() const { return Offset; } + + IteratorPosition invalidate() const { + return IteratorPosition(Cont, false, Offset); + } + + static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) { + return IteratorPosition(C, true, Of); + } + + IteratorPosition setTo(SymbolRef NewOf) const { + return IteratorPosition(Cont, Valid, NewOf); + } + + IteratorPosition reAssign(const MemRegion *NewCont) const { + return IteratorPosition(NewCont, Valid, Offset); + } + + bool operator==(const IteratorPosition &X) const { + return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset; + } + + bool operator!=(const IteratorPosition &X) const { + return Cont != X.Cont || Valid != X.Valid || Offset != X.Offset; + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.AddPointer(Cont); + ID.AddInteger(Valid); + ID.Add(Offset); + } +}; + +// Structure to record the symbolic begin and end position of a container +struct ContainerData { +private: + const SymbolRef Begin, End; + + ContainerData(SymbolRef B, SymbolRef E) : Begin(B), End(E) {} + +public: + static ContainerData fromBegin(SymbolRef B) { + return ContainerData(B, nullptr); + } + + static ContainerData fromEnd(SymbolRef E) { + return ContainerData(nullptr, E); + } + + SymbolRef getBegin() const { return Begin; } + SymbolRef getEnd() const { return End; } + + ContainerData newBegin(SymbolRef B) const { return ContainerData(B, End); } + + ContainerData newEnd(SymbolRef E) const { return ContainerData(Begin, E); } + + bool operator==(const ContainerData &X) const { + return Begin == X.Begin && End == X.End; + } + + bool operator!=(const ContainerData &X) const { + return Begin != X.Begin || End != X.End; + } + + void Profile(llvm::FoldingSetNodeID &ID) const { + ID.Add(Begin); + ID.Add(End); + } +}; + +class IteratorSymbolMap {}; +class IteratorRegionMap {}; +class ContainerMap {}; + +using IteratorSymbolMapTy = CLANG_ENTO_PROGRAMSTATE_MAP(SymbolRef, IteratorPosition); +using IteratorRegionMapTy = CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, IteratorPosition); +using ContainerMapTy = CLANG_ENTO_PROGRAMSTATE_MAP(const MemRegion *, ContainerData); + +} // namespace iterator + +template<> +struct ProgramStateTrait<iterator::IteratorSymbolMap> + : public ProgramStatePartialTrait<iterator::IteratorSymbolMapTy> { + static void *GDMIndex() { static int Index; return &Index; } +}; + +template<> +struct ProgramStateTrait<iterator::IteratorRegionMap> + : public ProgramStatePartialTrait<iterator::IteratorRegionMapTy> { + static void *GDMIndex() { static int Index; return &Index; } +}; + +template<> +struct ProgramStateTrait<iterator::ContainerMap> + : public ProgramStatePartialTrait<iterator::ContainerMapTy> { + static void *GDMIndex() { static int Index; return &Index; } +}; + +namespace iterator { + +bool isIteratorType(const QualType &Type); +bool isIterator(const CXXRecordDecl *CRD); +bool isComparisonOperator(OverloadedOperatorKind OK); +bool isInsertCall(const FunctionDecl *Func); +bool isEraseCall(const FunctionDecl *Func); +bool isEraseAfterCall(const FunctionDecl *Func); +bool isEmplaceCall(const FunctionDecl *Func); +bool isAccessOperator(OverloadedOperatorKind OK); +bool isDereferenceOperator(OverloadedOperatorKind OK); +bool isIncrementOperator(OverloadedOperatorKind OK); +bool isDecrementOperator(OverloadedOperatorKind OK); +bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK); +const ContainerData *getContainerData(ProgramStateRef State, + const MemRegion *Cont); +const IteratorPosition *getIteratorPosition(ProgramStateRef State, + const SVal &Val); +ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val, + const IteratorPosition &Pos); +ProgramStateRef advancePosition(ProgramStateRef State, + const SVal &Iter, + OverloadedOperatorKind Op, + const SVal &Distance); +bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, + BinaryOperator::Opcode Opc); +bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2, + BinaryOperator::Opcode Opc); + +} // namespace iterator +} // namespace ento +} // namespace clang + +#endif diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp index 97ace68569ef..eb962a2ffd9e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/IteratorChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorModeling.cpp @@ -1,4 +1,4 @@ -//===-- IteratorChecker.cpp ---------------------------------------*- C++ -*--// +//===-- IteratorModeling.cpp --------------------------------------*- C++ -*--// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -73,127 +73,33 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" +#include "Iterator.h" + #include <utility> using namespace clang; using namespace ento; +using namespace iterator; namespace { -// Abstract position of an iterator. This helps to handle all three kinds -// of operators in a common way by using a symbolic position. -struct IteratorPosition { -private: - - // Container the iterator belongs to - const MemRegion *Cont; - - // Whether iterator is valid - const bool Valid; - - // Abstract offset - const SymbolRef Offset; - - IteratorPosition(const MemRegion *C, bool V, SymbolRef Of) - : Cont(C), Valid(V), Offset(Of) {} - -public: - const MemRegion *getContainer() const { return Cont; } - bool isValid() const { return Valid; } - SymbolRef getOffset() const { return Offset; } - - IteratorPosition invalidate() const { - return IteratorPosition(Cont, false, Offset); - } - - static IteratorPosition getPosition(const MemRegion *C, SymbolRef Of) { - return IteratorPosition(C, true, Of); - } - - IteratorPosition setTo(SymbolRef NewOf) const { - return IteratorPosition(Cont, Valid, NewOf); - } - - IteratorPosition reAssign(const MemRegion *NewCont) const { - return IteratorPosition(NewCont, Valid, Offset); - } - - bool operator==(const IteratorPosition &X) const { - return Cont == X.Cont && Valid == X.Valid && Offset == X.Offset; - } - - bool operator!=(const IteratorPosition &X) const { - return Cont != X.Cont || Valid != X.Valid || Offset != X.Offset; - } - - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.AddPointer(Cont); - ID.AddInteger(Valid); - ID.Add(Offset); - } -}; - -// Structure to record the symbolic begin and end position of a container -struct ContainerData { -private: - const SymbolRef Begin, End; - - ContainerData(SymbolRef B, SymbolRef E) : Begin(B), End(E) {} - -public: - static ContainerData fromBegin(SymbolRef B) { - return ContainerData(B, nullptr); - } - - static ContainerData fromEnd(SymbolRef E) { - return ContainerData(nullptr, E); - } - - SymbolRef getBegin() const { return Begin; } - SymbolRef getEnd() const { return End; } +class IteratorModeling + : public Checker<check::PostCall, check::PostStmt<MaterializeTemporaryExpr>, + check::Bind, check::LiveSymbols, check::DeadSymbols> { - ContainerData newBegin(SymbolRef B) const { return ContainerData(B, End); } - - ContainerData newEnd(SymbolRef E) const { return ContainerData(Begin, E); } - - bool operator==(const ContainerData &X) const { - return Begin == X.Begin && End == X.End; - } - - bool operator!=(const ContainerData &X) const { - return Begin != X.Begin || End != X.End; - } - - void Profile(llvm::FoldingSetNodeID &ID) const { - ID.Add(Begin); - ID.Add(End); - } -}; - -class IteratorChecker - : public Checker<check::PreCall, check::PostCall, - check::PostStmt<MaterializeTemporaryExpr>, check::Bind, - check::LiveSymbols, check::DeadSymbols> { - - std::unique_ptr<BugType> OutOfRangeBugType; - std::unique_ptr<BugType> MismatchedBugType; - std::unique_ptr<BugType> InvalidatedBugType; - - void handleComparison(CheckerContext &C, const Expr *CE, const SVal &RetVal, + void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal, const SVal &LVal, const SVal &RVal, OverloadedOperatorKind Op) const; void processComparison(CheckerContext &C, ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, const SVal &RetVal, OverloadedOperatorKind Op) const; - void verifyAccess(CheckerContext &C, const SVal &Val) const; - void verifyDereference(CheckerContext &C, const SVal &Val) const; void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter, bool Postfix) const; void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter, bool Postfix) const; - void handleRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op, - const SVal &RetVal, const SVal &LHS, - const SVal &RHS) const; + void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE, + OverloadedOperatorKind Op, const SVal &RetVal, + const SVal &LHS, const SVal &RHS) const; void handleBegin(CheckerContext &C, const Expr *CE, const SVal &RetVal, const SVal &Cont) const; void handleEnd(CheckerContext &C, const Expr *CE, const SVal &RetVal, @@ -215,42 +121,12 @@ class IteratorChecker void handleEraseAfter(CheckerContext &C, const SVal &Iter) const; void handleEraseAfter(CheckerContext &C, const SVal &Iter1, const SVal &Iter2) const; - void verifyIncrement(CheckerContext &C, const SVal &Iter) const; - void verifyDecrement(CheckerContext &C, const SVal &Iter) const; - void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op, - const SVal &LHS, const SVal &RHS) const; - void verifyMatch(CheckerContext &C, const SVal &Iter, - const MemRegion *Cont) const; - void verifyMatch(CheckerContext &C, const SVal &Iter1, - const SVal &Iter2) const; - IteratorPosition advancePosition(CheckerContext &C, OverloadedOperatorKind Op, - const IteratorPosition &Pos, - const SVal &Distance) const; - void reportOutOfRangeBug(const StringRef &Message, const SVal &Val, - CheckerContext &C, ExplodedNode *ErrNode) const; - void reportMismatchedBug(const StringRef &Message, const SVal &Val1, - const SVal &Val2, CheckerContext &C, - ExplodedNode *ErrNode) const; - void reportMismatchedBug(const StringRef &Message, const SVal &Val, - const MemRegion *Reg, CheckerContext &C, - ExplodedNode *ErrNode) const; - void reportInvalidatedBug(const StringRef &Message, const SVal &Val, - CheckerContext &C, ExplodedNode *ErrNode) const; + void printState(raw_ostream &Out, ProgramStateRef State, const char *NL, + const char *Sep) const override; public: - IteratorChecker(); - - enum CheckKind { - CK_IteratorRangeChecker, - CK_MismatchedIteratorChecker, - CK_InvalidatedIteratorChecker, - CK_NumCheckKinds - }; - - DefaultBool ChecksEnabled[CK_NumCheckKinds]; - CheckerNameRef CheckNames[CK_NumCheckKinds]; + IteratorModeling() {} - void checkPreCall(const CallEvent &Call, CheckerContext &C) const; void checkPostCall(const CallEvent &Call, CheckerContext &C) const; void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const; void checkPostStmt(const CXXConstructExpr *CCE, CheckerContext &C) const; @@ -260,19 +136,7 @@ public: void checkLiveSymbols(ProgramStateRef State, SymbolReaper &SR) const; void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; }; -} // namespace - -REGISTER_MAP_WITH_PROGRAMSTATE(IteratorSymbolMap, SymbolRef, IteratorPosition) -REGISTER_MAP_WITH_PROGRAMSTATE(IteratorRegionMap, const MemRegion *, - IteratorPosition) -REGISTER_MAP_WITH_PROGRAMSTATE(ContainerMap, const MemRegion *, ContainerData) - -namespace { - -bool isIteratorType(const QualType &Type); -bool isIterator(const CXXRecordDecl *CRD); -bool isComparisonOperator(OverloadedOperatorKind OK); bool isBeginCall(const FunctionDecl *Func); bool isEndCall(const FunctionDecl *Func); bool isAssignCall(const FunctionDecl *Func); @@ -283,17 +147,8 @@ bool isPopBackCall(const FunctionDecl *Func); bool isPushFrontCall(const FunctionDecl *Func); bool isEmplaceFrontCall(const FunctionDecl *Func); bool isPopFrontCall(const FunctionDecl *Func); -bool isInsertCall(const FunctionDecl *Func); -bool isEraseCall(const FunctionDecl *Func); -bool isEraseAfterCall(const FunctionDecl *Func); -bool isEmplaceCall(const FunctionDecl *Func); bool isAssignmentOperator(OverloadedOperatorKind OK); bool isSimpleComparisonOperator(OverloadedOperatorKind OK); -bool isAccessOperator(OverloadedOperatorKind OK); -bool isDereferenceOperator(OverloadedOperatorKind OK); -bool isIncrementOperator(OverloadedOperatorKind OK); -bool isDecrementOperator(OverloadedOperatorKind OK); -bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK); bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg); bool frontModifiable(ProgramStateRef State, const MemRegion *Reg); bool backModifiable(ProgramStateRef State, const MemRegion *Reg); @@ -307,10 +162,8 @@ ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, const Expr *E, QualType T, const LocationContext *LCtx, unsigned BlockCount); -const IteratorPosition *getIteratorPosition(ProgramStateRef State, - const SVal &Val); -ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val, - const IteratorPosition &Pos); +ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, + const ContainerData &CData); ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val); ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, long Scale); @@ -341,222 +194,16 @@ ProgramStateRef rebaseSymbolInIteratorPositionsIf( SymbolRef NewSym, SymbolRef CondSym, BinaryOperator::Opcode Opc); ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, bool Equal); -const ContainerData *getContainerData(ProgramStateRef State, - const MemRegion *Cont); -ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, - const ContainerData &CData); +SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr, + SymbolRef OldSym, SymbolRef NewSym); bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont); bool isBoundThroughLazyCompoundVal(const Environment &Env, const MemRegion *Reg); -bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos); -bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos); -bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos); -bool isZero(ProgramStateRef State, const NonLoc &Val); -} // namespace - -IteratorChecker::IteratorChecker() { - OutOfRangeBugType.reset( - new BugType(this, "Iterator out of range", "Misuse of STL APIs")); - MismatchedBugType.reset( - new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs", - /*SuppressOnSink=*/true)); - InvalidatedBugType.reset( - new BugType(this, "Iterator invalidated", "Misuse of STL APIs")); -} - -void IteratorChecker::checkPreCall(const CallEvent &Call, - CheckerContext &C) const { - // Check for out of range access or access of invalidated position and - // iterator mismatches - const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); - if (!Func) - return; - - if (Func->isOverloadedOperator()) { - if (ChecksEnabled[CK_InvalidatedIteratorChecker] && - isAccessOperator(Func->getOverloadedOperator())) { - // Check for any kind of access of invalidated iterator positions - if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - verifyAccess(C, InstCall->getCXXThisVal()); - } else { - verifyAccess(C, Call.getArgSVal(0)); - } - } - if (ChecksEnabled[CK_IteratorRangeChecker]) { - if (isIncrementOperator(Func->getOverloadedOperator())) { - // Check for out-of-range incrementions - if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - verifyIncrement(C, InstCall->getCXXThisVal()); - } else { - if (Call.getNumArgs() >= 1) { - verifyIncrement(C, Call.getArgSVal(0)); - } - } - } else if (isDecrementOperator(Func->getOverloadedOperator())) { - // Check for out-of-range decrementions - if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - verifyDecrement(C, InstCall->getCXXThisVal()); - } else { - if (Call.getNumArgs() >= 1) { - verifyDecrement(C, Call.getArgSVal(0)); - } - } - } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) { - if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - // Check for out-of-range incrementions and decrementions - if (Call.getNumArgs() >= 1 && - Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { - verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(), - InstCall->getCXXThisVal(), - Call.getArgSVal(0)); - } - } else { - if (Call.getNumArgs() >= 2 && - Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) { - verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(), - Call.getArgSVal(0), Call.getArgSVal(1)); - } - } - } else if (isDereferenceOperator(Func->getOverloadedOperator())) { - // Check for dereference of out-of-range iterators - if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - verifyDereference(C, InstCall->getCXXThisVal()); - } else { - verifyDereference(C, Call.getArgSVal(0)); - } - } - } else if (ChecksEnabled[CK_MismatchedIteratorChecker] && - isComparisonOperator(Func->getOverloadedOperator())) { - // Check for comparisons of iterators of different containers - if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - if (Call.getNumArgs() < 1) - return; - - if (!isIteratorType(InstCall->getCXXThisExpr()->getType()) || - !isIteratorType(Call.getArgExpr(0)->getType())) - return; - - verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0)); - } else { - if (Call.getNumArgs() < 2) - return; - - if (!isIteratorType(Call.getArgExpr(0)->getType()) || - !isIteratorType(Call.getArgExpr(1)->getType())) - return; - - verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1)); - } - } - } else if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { - if (!ChecksEnabled[CK_MismatchedIteratorChecker]) - return; - - const auto *ContReg = InstCall->getCXXThisVal().getAsRegion(); - if (!ContReg) - return; - // Check for erase, insert and emplace using iterator of another container - if (isEraseCall(Func) || isEraseAfterCall(Func)) { - verifyMatch(C, Call.getArgSVal(0), - InstCall->getCXXThisVal().getAsRegion()); - if (Call.getNumArgs() == 2) { - verifyMatch(C, Call.getArgSVal(1), - InstCall->getCXXThisVal().getAsRegion()); - } - } else if (isInsertCall(Func)) { - verifyMatch(C, Call.getArgSVal(0), - InstCall->getCXXThisVal().getAsRegion()); - if (Call.getNumArgs() == 3 && - isIteratorType(Call.getArgExpr(1)->getType()) && - isIteratorType(Call.getArgExpr(2)->getType())) { - verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2)); - } - } else if (isEmplaceCall(Func)) { - verifyMatch(C, Call.getArgSVal(0), - InstCall->getCXXThisVal().getAsRegion()); - } - } else if (isa<CXXConstructorCall>(&Call)) { - // Check match of first-last iterator pair in a constructor of a container - if (Call.getNumArgs() < 2) - return; - - const auto *Ctr = cast<CXXConstructorDecl>(Call.getDecl()); - if (Ctr->getNumParams() < 2) - return; - - if (Ctr->getParamDecl(0)->getName() != "first" || - Ctr->getParamDecl(1)->getName() != "last") - return; - - if (!isIteratorType(Call.getArgExpr(0)->getType()) || - !isIteratorType(Call.getArgExpr(1)->getType())) - return; - - verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1)); - } else { - // The main purpose of iterators is to abstract away from different - // containers and provide a (maybe limited) uniform access to them. - // This implies that any correctly written template function that - // works on multiple containers using iterators takes different - // template parameters for different containers. So we can safely - // assume that passing iterators of different containers as arguments - // whose type replaces the same template parameter is a bug. - // - // Example: - // template<typename I1, typename I2> - // void f(I1 first1, I1 last1, I2 first2, I2 last2); - // - // In this case the first two arguments to f() must be iterators must belong - // to the same container and the last to also to the same container but - // not necessarily to the same as the first two. - - if (!ChecksEnabled[CK_MismatchedIteratorChecker]) - return; - - const auto *Templ = Func->getPrimaryTemplate(); - if (!Templ) - return; - - const auto *TParams = Templ->getTemplateParameters(); - const auto *TArgs = Func->getTemplateSpecializationArgs(); - - // Iterate over all the template parameters - for (size_t I = 0; I < TParams->size(); ++I) { - const auto *TPDecl = dyn_cast<TemplateTypeParmDecl>(TParams->getParam(I)); - if (!TPDecl) - continue; - - if (TPDecl->isParameterPack()) - continue; - const auto TAType = TArgs->get(I).getAsType(); - if (!isIteratorType(TAType)) - continue; - - SVal LHS = UndefinedVal(); - - // For every template parameter which is an iterator type in the - // instantiation look for all functions' parameters' type by it and - // check whether they belong to the same container - for (auto J = 0U; J < Func->getNumParams(); ++J) { - const auto *Param = Func->getParamDecl(J); - const auto *ParamType = - Param->getType()->getAs<SubstTemplateTypeParmType>(); - if (!ParamType || - ParamType->getReplacedParameter()->getDecl() != TPDecl) - continue; - if (LHS.isUndef()) { - LHS = Call.getArgSVal(J); - } else { - verifyMatch(C, LHS, Call.getArgSVal(J)); - } - } - } - } -} +} // namespace -void IteratorChecker::checkPostCall(const CallEvent &Call, - CheckerContext &C) const { +void IteratorModeling::checkPostCall(const CallEvent &Call, + CheckerContext &C) const { // Record new iterator positions and iterator position changes const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); if (!Func) @@ -590,10 +237,14 @@ void IteratorChecker::checkPostCall(const CallEvent &Call, Call.getArgSVal(1), Op); return; } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) { + const auto *OrigExpr = Call.getOriginExpr(); + if (!OrigExpr) + return; + if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { if (Call.getNumArgs() >= 1 && Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { - handleRandomIncrOrDecr(C, Func->getOverloadedOperator(), + handleRandomIncrOrDecr(C, OrigExpr, Func->getOverloadedOperator(), Call.getReturnValue(), InstCall->getCXXThisVal(), Call.getArgSVal(0)); return; @@ -601,7 +252,7 @@ void IteratorChecker::checkPostCall(const CallEvent &Call, } else { if (Call.getNumArgs() >= 2 && Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) { - handleRandomIncrOrDecr(C, Func->getOverloadedOperator(), + handleRandomIncrOrDecr(C, OrigExpr, Func->getOverloadedOperator(), Call.getReturnValue(), Call.getArgSVal(0), Call.getArgSVal(1)); return; @@ -746,8 +397,8 @@ void IteratorChecker::checkPostCall(const CallEvent &Call, } } -void IteratorChecker::checkBind(SVal Loc, SVal Val, const Stmt *S, - CheckerContext &C) const { +void IteratorModeling::checkBind(SVal Loc, SVal Val, const Stmt *S, + CheckerContext &C) const { auto State = C.getState(); const auto *Pos = getIteratorPosition(State, Val); if (Pos) { @@ -762,24 +413,23 @@ void IteratorChecker::checkBind(SVal Loc, SVal Val, const Stmt *S, } } -void IteratorChecker::checkPostStmt(const MaterializeTemporaryExpr *MTE, - CheckerContext &C) const { +void IteratorModeling::checkPostStmt(const MaterializeTemporaryExpr *MTE, + CheckerContext &C) const { /* Transfer iterator state to temporary objects */ auto State = C.getState(); - const auto *Pos = - getIteratorPosition(State, C.getSVal(MTE->GetTemporaryExpr())); + const auto *Pos = getIteratorPosition(State, C.getSVal(MTE->getSubExpr())); if (!Pos) return; State = setIteratorPosition(State, C.getSVal(MTE), *Pos); C.addTransition(State); } -void IteratorChecker::checkLiveSymbols(ProgramStateRef State, - SymbolReaper &SR) const { +void IteratorModeling::checkLiveSymbols(ProgramStateRef State, + SymbolReaper &SR) const { // Keep symbolic expressions of iterator positions, container begins and ends // alive auto RegionMap = State->get<IteratorRegionMap>(); - for (const auto Reg : RegionMap) { + for (const auto &Reg : RegionMap) { const auto Offset = Reg.second.getOffset(); for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i) if (isa<SymbolData>(*i)) @@ -787,7 +437,7 @@ void IteratorChecker::checkLiveSymbols(ProgramStateRef State, } auto SymbolMap = State->get<IteratorSymbolMap>(); - for (const auto Sym : SymbolMap) { + for (const auto &Sym : SymbolMap) { const auto Offset = Sym.second.getOffset(); for (auto i = Offset->symbol_begin(); i != Offset->symbol_end(); ++i) if (isa<SymbolData>(*i)) @@ -795,7 +445,7 @@ void IteratorChecker::checkLiveSymbols(ProgramStateRef State, } auto ContMap = State->get<ContainerMap>(); - for (const auto Cont : ContMap) { + for (const auto &Cont : ContMap) { const auto CData = Cont.second; if (CData.getBegin()) { SR.markLive(CData.getBegin()); @@ -810,13 +460,13 @@ void IteratorChecker::checkLiveSymbols(ProgramStateRef State, } } -void IteratorChecker::checkDeadSymbols(SymbolReaper &SR, - CheckerContext &C) const { +void IteratorModeling::checkDeadSymbols(SymbolReaper &SR, + CheckerContext &C) const { // Cleanup auto State = C.getState(); auto RegionMap = State->get<IteratorRegionMap>(); - for (const auto Reg : RegionMap) { + for (const auto &Reg : RegionMap) { if (!SR.isLiveRegion(Reg.first)) { // The region behind the `LazyCompoundVal` is often cleaned up before // the `LazyCompoundVal` itself. If there are iterator positions keyed @@ -828,14 +478,14 @@ void IteratorChecker::checkDeadSymbols(SymbolReaper &SR, } auto SymbolMap = State->get<IteratorSymbolMap>(); - for (const auto Sym : SymbolMap) { + for (const auto &Sym : SymbolMap) { if (!SR.isLive(Sym.first)) { State = State->remove<IteratorSymbolMap>(Sym.first); } } auto ContMap = State->get<ContainerMap>(); - for (const auto Cont : ContMap) { + for (const auto &Cont : ContMap) { if (!SR.isLiveRegion(Cont.first)) { // We must keep the container data while it has live iterators to be able // to compare them to the begin and the end of the container. @@ -848,8 +498,8 @@ void IteratorChecker::checkDeadSymbols(SymbolReaper &SR, C.addTransition(State); } -void IteratorChecker::handleComparison(CheckerContext &C, const Expr *CE, - const SVal &RetVal, const SVal &LVal, +void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE, + SVal RetVal, const SVal &LVal, const SVal &RVal, OverloadedOperatorKind Op) const { // Record the operands and the operator of the comparison for the next @@ -888,13 +538,23 @@ void IteratorChecker::handleComparison(CheckerContext &C, const Expr *CE, RPos = getIteratorPosition(State, RVal); } + // We cannot make assumpotions on `UnknownVal`. Let us conjure a symbol + // instead. + if (RetVal.isUnknown()) { + auto &SymMgr = C.getSymbolManager(); + auto *LCtx = C.getLocationContext(); + RetVal = nonloc::SymbolVal(SymMgr.conjureSymbol( + CE, LCtx, C.getASTContext().BoolTy, C.blockCount())); + State = State->BindExpr(CE, LCtx, RetVal); + } + processComparison(C, State, LPos->getOffset(), RPos->getOffset(), RetVal, Op); } -void IteratorChecker::processComparison(CheckerContext &C, - ProgramStateRef State, SymbolRef Sym1, - SymbolRef Sym2, const SVal &RetVal, - OverloadedOperatorKind Op) const { +void IteratorModeling::processComparison(CheckerContext &C, + ProgramStateRef State, SymbolRef Sym1, + SymbolRef Sym2, const SVal &RetVal, + OverloadedOperatorKind Op) const { if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) { if ((State = relateSymbols(State, Sym1, Sym2, (Op == OO_EqualEqual) == @@ -909,7 +569,7 @@ void IteratorChecker::processComparison(CheckerContext &C, const auto ConditionVal = RetVal.getAs<DefinedSVal>(); if (!ConditionVal) return; - + if (auto StateTrue = relateSymbols(State, Sym1, Sym2, Op == OO_EqualEqual)) { StateTrue = StateTrue->assume(*ConditionVal, true); C.addTransition(StateTrue); @@ -921,75 +581,68 @@ void IteratorChecker::processComparison(CheckerContext &C, } } -void IteratorChecker::verifyDereference(CheckerContext &C, - const SVal &Val) const { - auto State = C.getState(); - const auto *Pos = getIteratorPosition(State, Val); - if (Pos && isPastTheEnd(State, *Pos)) { - auto *N = C.generateErrorNode(State); - if (!N) - return; - reportOutOfRangeBug("Past-the-end iterator dereferenced.", Val, C, N); - return; - } -} - -void IteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const { - auto State = C.getState(); - const auto *Pos = getIteratorPosition(State, Val); - if (Pos && !Pos->isValid()) { - auto *N = C.generateErrorNode(State); - if (!N) { - return; - } - reportInvalidatedBug("Invalidated iterator accessed.", Val, C, N); - } -} - -void IteratorChecker::handleIncrement(CheckerContext &C, const SVal &RetVal, - const SVal &Iter, bool Postfix) const { +void IteratorModeling::handleIncrement(CheckerContext &C, const SVal &RetVal, + const SVal &Iter, bool Postfix) const { // Increment the symbolic expressions which represents the position of the // iterator auto State = C.getState(); + auto &BVF = C.getSymbolManager().getBasicVals(); + const auto *Pos = getIteratorPosition(State, Iter); - if (Pos) { - auto &SymMgr = C.getSymbolManager(); - auto &BVF = SymMgr.getBasicVals(); - const auto NewPos = - advancePosition(C, OO_Plus, *Pos, + if (!Pos) + return; + + auto NewState = + advancePosition(State, Iter, OO_Plus, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); - State = setIteratorPosition(State, Iter, NewPos); - State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos); - C.addTransition(State); - } + assert(NewState && + "Advancing position by concrete int should always be successful"); + + const auto *NewPos = getIteratorPosition(NewState, Iter); + assert(NewPos && + "Iterator should have position after successful advancement"); + + State = setIteratorPosition(State, Iter, *NewPos); + State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos); + C.addTransition(State); } -void IteratorChecker::handleDecrement(CheckerContext &C, const SVal &RetVal, - const SVal &Iter, bool Postfix) const { +void IteratorModeling::handleDecrement(CheckerContext &C, const SVal &RetVal, + const SVal &Iter, bool Postfix) const { // Decrement the symbolic expressions which represents the position of the // iterator auto State = C.getState(); + auto &BVF = C.getSymbolManager().getBasicVals(); + const auto *Pos = getIteratorPosition(State, Iter); - if (Pos) { - auto &SymMgr = C.getSymbolManager(); - auto &BVF = SymMgr.getBasicVals(); - const auto NewPos = - advancePosition(C, OO_Minus, *Pos, + if (!Pos) + return; + + auto NewState = + advancePosition(State, Iter, OO_Minus, nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); - State = setIteratorPosition(State, Iter, NewPos); - State = setIteratorPosition(State, RetVal, Postfix ? *Pos : NewPos); - C.addTransition(State); - } + assert(NewState && + "Advancing position by concrete int should always be successful"); + + const auto *NewPos = getIteratorPosition(NewState, Iter); + assert(NewPos && + "Iterator should have position after successful advancement"); + + State = setIteratorPosition(State, Iter, *NewPos); + State = setIteratorPosition(State, RetVal, Postfix ? *Pos : *NewPos); + C.addTransition(State); } -void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C, - OverloadedOperatorKind Op, - const SVal &RetVal, - const SVal &LHS, - const SVal &RHS) const { +void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, + const Expr *CE, + OverloadedOperatorKind Op, + const SVal &RetVal, + const SVal &LHS, + const SVal &RHS) const { // Increment or decrement the symbolic expressions which represents the // position of the iterator auto State = C.getState(); + const auto *Pos = getIteratorPosition(State, LHS); if (!Pos) return; @@ -1001,142 +654,23 @@ void IteratorChecker::handleRandomIncrOrDecr(CheckerContext &C, } auto &TgtVal = (Op == OO_PlusEqual || Op == OO_MinusEqual) ? LHS : RetVal; - State = - setIteratorPosition(State, TgtVal, advancePosition(C, Op, *Pos, *value)); - C.addTransition(State); -} -void IteratorChecker::verifyIncrement(CheckerContext &C, - const SVal &Iter) const { - auto &BVF = C.getSValBuilder().getBasicValueFactory(); - verifyRandomIncrOrDecr(C, OO_Plus, Iter, - nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); -} + auto NewState = + advancePosition(State, LHS, Op, *value); + if (NewState) { + const auto *NewPos = getIteratorPosition(NewState, LHS); + assert(NewPos && + "Iterator should have position after successful advancement"); -void IteratorChecker::verifyDecrement(CheckerContext &C, - const SVal &Iter) const { - auto &BVF = C.getSValBuilder().getBasicValueFactory(); - verifyRandomIncrOrDecr(C, OO_Minus, Iter, - nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); -} - -void IteratorChecker::verifyRandomIncrOrDecr(CheckerContext &C, - OverloadedOperatorKind Op, - const SVal &LHS, - const SVal &RHS) const { - auto State = C.getState(); - - // If the iterator is initially inside its range, then the operation is valid - const auto *Pos = getIteratorPosition(State, LHS); - if (!Pos) - return; - - auto Value = RHS; - if (auto ValAsLoc = RHS.getAs<Loc>()) { - Value = State->getRawSVal(*ValAsLoc); - } - - if (Value.isUnknown()) - return; - - // Incremention or decremention by 0 is never a bug. - if (isZero(State, Value.castAs<NonLoc>())) - return; - - // The result may be the past-end iterator of the container, but any other - // out of range position is undefined behaviour - if (isAheadOfRange(State, advancePosition(C, Op, *Pos, Value))) { - auto *N = C.generateErrorNode(State); - if (!N) - return; - reportOutOfRangeBug("Iterator decremented ahead of its valid range.", LHS, - C, N); - } - if (isBehindPastTheEnd(State, advancePosition(C, Op, *Pos, Value))) { - auto *N = C.generateErrorNode(State); - if (!N) - return; - reportOutOfRangeBug("Iterator incremented behind the past-the-end " - "iterator.", LHS, C, N); - } -} - -void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter, - const MemRegion *Cont) const { - // Verify match between a container and the container of an iterator - Cont = Cont->getMostDerivedObjectRegion(); - - if (const auto *ContSym = Cont->getSymbolicBase()) { - if (isa<SymbolConjured>(ContSym->getSymbol())) - return; - } - - auto State = C.getState(); - const auto *Pos = getIteratorPosition(State, Iter); - if (!Pos) - return; - - const auto *IterCont = Pos->getContainer(); - - // Skip symbolic regions based on conjured symbols. Two conjured symbols - // may or may not be the same. For example, the same function can return - // the same or a different container but we get different conjured symbols - // for each call. This may cause false positives so omit them from the check. - if (const auto *ContSym = IterCont->getSymbolicBase()) { - if (isa<SymbolConjured>(ContSym->getSymbol())) - return; - } - - if (IterCont != Cont) { - auto *N = C.generateNonFatalErrorNode(State); - if (!N) { - return; - } - reportMismatchedBug("Container accessed using foreign iterator argument.", - Iter, Cont, C, N); - } -} - -void IteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter1, - const SVal &Iter2) const { - // Verify match between the containers of two iterators - auto State = C.getState(); - const auto *Pos1 = getIteratorPosition(State, Iter1); - if (!Pos1) - return; - - const auto *IterCont1 = Pos1->getContainer(); - - // Skip symbolic regions based on conjured symbols. Two conjured symbols - // may or may not be the same. For example, the same function can return - // the same or a different container but we get different conjured symbols - // for each call. This may cause false positives so omit them from the check. - if (const auto *ContSym = IterCont1->getSymbolicBase()) { - if (isa<SymbolConjured>(ContSym->getSymbol())) - return; - } - - const auto *Pos2 = getIteratorPosition(State, Iter2); - if (!Pos2) - return; - - const auto *IterCont2 = Pos2->getContainer(); - if (const auto *ContSym = IterCont2->getSymbolicBase()) { - if (isa<SymbolConjured>(ContSym->getSymbol())) - return; - } - - if (IterCont1 != IterCont2) { - auto *N = C.generateNonFatalErrorNode(State); - if (!N) - return; - reportMismatchedBug("Iterators of different containers used where the " - "same container is expected.", Iter1, Iter2, C, N); + State = setIteratorPosition(NewState, TgtVal, *NewPos); + C.addTransition(State); + } else { + assignToContainer(C, CE, TgtVal, Pos->getContainer()); } } -void IteratorChecker::handleBegin(CheckerContext &C, const Expr *CE, - const SVal &RetVal, const SVal &Cont) const { +void IteratorModeling::handleBegin(CheckerContext &C, const Expr *CE, + const SVal &RetVal, const SVal &Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -1157,8 +691,8 @@ void IteratorChecker::handleBegin(CheckerContext &C, const Expr *CE, C.addTransition(State); } -void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE, - const SVal &RetVal, const SVal &Cont) const { +void IteratorModeling::handleEnd(CheckerContext &C, const Expr *CE, + const SVal &RetVal, const SVal &Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -1179,9 +713,9 @@ void IteratorChecker::handleEnd(CheckerContext &C, const Expr *CE, C.addTransition(State); } -void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE, - const SVal &RetVal, - const MemRegion *Cont) const { +void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE, + const SVal &RetVal, + const MemRegion *Cont) const { Cont = Cont->getMostDerivedObjectRegion(); auto State = C.getState(); @@ -1194,8 +728,8 @@ void IteratorChecker::assignToContainer(CheckerContext &C, const Expr *CE, C.addTransition(State); } -void IteratorChecker::handleAssign(CheckerContext &C, const SVal &Cont, - const Expr *CE, const SVal &OldCont) const { +void IteratorModeling::handleAssign(CheckerContext &C, const SVal &Cont, + const Expr *CE, const SVal &OldCont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -1270,7 +804,7 @@ void IteratorChecker::handleAssign(CheckerContext &C, const SVal &Cont, C.addTransition(State); } -void IteratorChecker::handleClear(CheckerContext &C, const SVal &Cont) const { +void IteratorModeling::handleClear(CheckerContext &C, const SVal &Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -1296,8 +830,8 @@ void IteratorChecker::handleClear(CheckerContext &C, const SVal &Cont) const { C.addTransition(State); } -void IteratorChecker::handlePushBack(CheckerContext &C, - const SVal &Cont) const { +void IteratorModeling::handlePushBack(CheckerContext &C, + const SVal &Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -1334,7 +868,8 @@ void IteratorChecker::handlePushBack(CheckerContext &C, C.addTransition(State); } -void IteratorChecker::handlePopBack(CheckerContext &C, const SVal &Cont) const { +void IteratorModeling::handlePopBack(CheckerContext &C, + const SVal &Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -1371,8 +906,8 @@ void IteratorChecker::handlePopBack(CheckerContext &C, const SVal &Cont) const { } } -void IteratorChecker::handlePushFront(CheckerContext &C, - const SVal &Cont) const { +void IteratorModeling::handlePushFront(CheckerContext &C, + const SVal &Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -1404,8 +939,8 @@ void IteratorChecker::handlePushFront(CheckerContext &C, } } -void IteratorChecker::handlePopFront(CheckerContext &C, - const SVal &Cont) const { +void IteratorModeling::handlePopFront(CheckerContext &C, + const SVal &Cont) const { const auto *ContReg = Cont.getAsRegion(); if (!ContReg) return; @@ -1438,7 +973,7 @@ void IteratorChecker::handlePopFront(CheckerContext &C, } } -void IteratorChecker::handleInsert(CheckerContext &C, const SVal &Iter) const { +void IteratorModeling::handleInsert(CheckerContext &C, const SVal &Iter) const { auto State = C.getState(); const auto *Pos = getIteratorPosition(State, Iter); if (!Pos) @@ -1463,7 +998,7 @@ void IteratorChecker::handleInsert(CheckerContext &C, const SVal &Iter) const { } } -void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter) const { +void IteratorModeling::handleErase(CheckerContext &C, const SVal &Iter) const { auto State = C.getState(); const auto *Pos = getIteratorPosition(State, Iter); if (!Pos) @@ -1491,8 +1026,8 @@ void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter) const { C.addTransition(State); } -void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter1, - const SVal &Iter2) const { +void IteratorModeling::handleErase(CheckerContext &C, const SVal &Iter1, + const SVal &Iter2) const { auto State = C.getState(); const auto *Pos1 = getIteratorPosition(State, Iter1); const auto *Pos2 = getIteratorPosition(State, Iter2); @@ -1523,8 +1058,8 @@ void IteratorChecker::handleErase(CheckerContext &C, const SVal &Iter1, C.addTransition(State); } -void IteratorChecker::handleEraseAfter(CheckerContext &C, - const SVal &Iter) const { +void IteratorModeling::handleEraseAfter(CheckerContext &C, + const SVal &Iter) const { auto State = C.getState(); const auto *Pos = getIteratorPosition(State, Iter); if (!Pos) @@ -1544,8 +1079,8 @@ void IteratorChecker::handleEraseAfter(CheckerContext &C, C.addTransition(State); } -void IteratorChecker::handleEraseAfter(CheckerContext &C, const SVal &Iter1, - const SVal &Iter2) const { +void IteratorModeling::handleEraseAfter(CheckerContext &C, const SVal &Iter1, + const SVal &Iter2) const { auto State = C.getState(); const auto *Pos1 = getIteratorPosition(State, Iter1); const auto *Pos2 = getIteratorPosition(State, Iter2); @@ -1558,145 +1093,62 @@ void IteratorChecker::handleEraseAfter(CheckerContext &C, const SVal &Iter1, C.addTransition(State); } -IteratorPosition IteratorChecker::advancePosition(CheckerContext &C, - OverloadedOperatorKind Op, - const IteratorPosition &Pos, - const SVal &Distance) const { - auto State = C.getState(); - auto &SymMgr = C.getSymbolManager(); - auto &SVB = C.getSValBuilder(); +void IteratorModeling::printState(raw_ostream &Out, ProgramStateRef State, + const char *NL, const char *Sep) const { - assert ((Op == OO_Plus || Op == OO_PlusEqual || - Op == OO_Minus || Op == OO_MinusEqual) && - "Advance operator must be one of +, -, += and -=."); - auto BinOp = (Op == OO_Plus || Op == OO_PlusEqual) ? BO_Add : BO_Sub; - if (const auto IntDist = Distance.getAs<nonloc::ConcreteInt>()) { - // For concrete integers we can calculate the new position - return Pos.setTo(SVB.evalBinOp(State, BinOp, - nonloc::SymbolVal(Pos.getOffset()), *IntDist, - SymMgr.getType(Pos.getOffset())) - .getAsSymbol()); - } else { - // For other symbols create a new symbol to keep expressions simple - const auto &LCtx = C.getLocationContext(); - const auto NewPosSym = SymMgr.conjureSymbol(nullptr, LCtx, - SymMgr.getType(Pos.getOffset()), - C.blockCount()); - State = assumeNoOverflow(State, NewPosSym, 4); - return Pos.setTo(NewPosSym); + auto ContMap = State->get<ContainerMap>(); + + if (!ContMap.isEmpty()) { + Out << Sep << "Container Data :" << NL; + for (const auto &Cont : ContMap) { + Cont.first->dumpToStream(Out); + Out << " : [ "; + const auto CData = Cont.second; + if (CData.getBegin()) + CData.getBegin()->dumpToStream(Out); + else + Out << "<Unknown>"; + Out << " .. "; + if (CData.getEnd()) + CData.getEnd()->dumpToStream(Out); + else + Out << "<Unknown>"; + Out << " ]" << NL; + } } -} -void IteratorChecker::reportOutOfRangeBug(const StringRef &Message, - const SVal &Val, CheckerContext &C, - ExplodedNode *ErrNode) const { - auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message, - ErrNode); - R->markInteresting(Val); - C.emitReport(std::move(R)); -} + auto SymbolMap = State->get<IteratorSymbolMap>(); + auto RegionMap = State->get<IteratorRegionMap>(); -void IteratorChecker::reportMismatchedBug(const StringRef &Message, - const SVal &Val1, const SVal &Val2, - CheckerContext &C, - ExplodedNode *ErrNode) const { - auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message, - ErrNode); - R->markInteresting(Val1); - R->markInteresting(Val2); - C.emitReport(std::move(R)); -} + if (!SymbolMap.isEmpty() || !RegionMap.isEmpty()) { + Out << Sep << "Iterator Positions :" << NL; + for (const auto &Sym : SymbolMap) { + Sym.first->dumpToStream(Out); + Out << " : "; + const auto Pos = Sym.second; + Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == "; + Pos.getContainer()->dumpToStream(Out); + Out<<" ; Offset == "; + Pos.getOffset()->dumpToStream(Out); + } -void IteratorChecker::reportMismatchedBug(const StringRef &Message, - const SVal &Val, const MemRegion *Reg, - CheckerContext &C, - ExplodedNode *ErrNode) const { - auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message, - ErrNode); - R->markInteresting(Val); - R->markInteresting(Reg); - C.emitReport(std::move(R)); + for (const auto &Reg : RegionMap) { + Reg.first->dumpToStream(Out); + Out << " : "; + const auto Pos = Reg.second; + Out << (Pos.isValid() ? "Valid" : "Invalid") << " ; Container == "; + Pos.getContainer()->dumpToStream(Out); + Out<<" ; Offset == "; + Pos.getOffset()->dumpToStream(Out); + } + } } -void IteratorChecker::reportInvalidatedBug(const StringRef &Message, - const SVal &Val, CheckerContext &C, - ExplodedNode *ErrNode) const { - auto R = std::make_unique<PathSensitiveBugReport>(*InvalidatedBugType, - Message, ErrNode); - R->markInteresting(Val); - C.emitReport(std::move(R)); -} namespace { -bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); -bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); -bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); -bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, - BinaryOperator::Opcode Opc); -bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2, - BinaryOperator::Opcode Opc); const CXXRecordDecl *getCXXRecordDecl(ProgramStateRef State, const MemRegion *Reg); -SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymbolRef Expr, - SymbolRef OldSym, SymbolRef NewSym); - -bool isIteratorType(const QualType &Type) { - if (Type->isPointerType()) - return true; - - const auto *CRD = Type->getUnqualifiedDesugaredType()->getAsCXXRecordDecl(); - return isIterator(CRD); -} - -bool isIterator(const CXXRecordDecl *CRD) { - if (!CRD) - return false; - - const auto Name = CRD->getName(); - if (!(Name.endswith_lower("iterator") || Name.endswith_lower("iter") || - Name.endswith_lower("it"))) - return false; - - bool HasCopyCtor = false, HasCopyAssign = true, HasDtor = false, - HasPreIncrOp = false, HasPostIncrOp = false, HasDerefOp = false; - for (const auto *Method : CRD->methods()) { - if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(Method)) { - if (Ctor->isCopyConstructor()) { - HasCopyCtor = !Ctor->isDeleted() && Ctor->getAccess() == AS_public; - } - continue; - } - if (const auto *Dtor = dyn_cast<CXXDestructorDecl>(Method)) { - HasDtor = !Dtor->isDeleted() && Dtor->getAccess() == AS_public; - continue; - } - if (Method->isCopyAssignmentOperator()) { - HasCopyAssign = !Method->isDeleted() && Method->getAccess() == AS_public; - continue; - } - if (!Method->isOverloadedOperator()) - continue; - const auto OPK = Method->getOverloadedOperator(); - if (OPK == OO_PlusPlus) { - HasPreIncrOp = HasPreIncrOp || (Method->getNumParams() == 0); - HasPostIncrOp = HasPostIncrOp || (Method->getNumParams() == 1); - continue; - } - if (OPK == OO_Star) { - HasDerefOp = (Method->getNumParams() == 0); - continue; - } - } - - return HasCopyCtor && HasCopyAssign && HasDtor && HasPreIncrOp && - HasPostIncrOp && HasDerefOp; -} - -bool isComparisonOperator(OverloadedOperatorKind OK) { - return OK == OO_EqualEqual || OK == OO_ExclaimEqual || OK == OO_Less || - OK == OO_LessEqual || OK == OO_Greater || OK == OO_GreaterEqual; -} bool isBeginCall(const FunctionDecl *Func) { const auto *IdInfo = Func->getIdentifier(); @@ -1784,85 +1236,12 @@ bool isPopFrontCall(const FunctionDecl *Func) { return IdInfo->getName() == "pop_front"; } -bool isInsertCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() < 2 || Func->getNumParams() > 3) - return false; - if (!isIteratorType(Func->getParamDecl(0)->getType())) - return false; - return IdInfo->getName() == "insert"; -} - -bool isEmplaceCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() < 2) - return false; - if (!isIteratorType(Func->getParamDecl(0)->getType())) - return false; - return IdInfo->getName() == "emplace"; -} - -bool isEraseCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() < 1 || Func->getNumParams() > 2) - return false; - if (!isIteratorType(Func->getParamDecl(0)->getType())) - return false; - if (Func->getNumParams() == 2 && - !isIteratorType(Func->getParamDecl(1)->getType())) - return false; - return IdInfo->getName() == "erase"; -} - -bool isEraseAfterCall(const FunctionDecl *Func) { - const auto *IdInfo = Func->getIdentifier(); - if (!IdInfo) - return false; - if (Func->getNumParams() < 1 || Func->getNumParams() > 2) - return false; - if (!isIteratorType(Func->getParamDecl(0)->getType())) - return false; - if (Func->getNumParams() == 2 && - !isIteratorType(Func->getParamDecl(1)->getType())) - return false; - return IdInfo->getName() == "erase_after"; -} - bool isAssignmentOperator(OverloadedOperatorKind OK) { return OK == OO_Equal; } bool isSimpleComparisonOperator(OverloadedOperatorKind OK) { return OK == OO_EqualEqual || OK == OO_ExclaimEqual; } -bool isAccessOperator(OverloadedOperatorKind OK) { - return isDereferenceOperator(OK) || isIncrementOperator(OK) || - isDecrementOperator(OK) || isRandomIncrOrDecrOperator(OK); -} - -bool isDereferenceOperator(OverloadedOperatorKind OK) { - return OK == OO_Star || OK == OO_Arrow || OK == OO_ArrowStar || - OK == OO_Subscript; -} - -bool isIncrementOperator(OverloadedOperatorKind OK) { - return OK == OO_PlusPlus; -} - -bool isDecrementOperator(OverloadedOperatorKind OK) { - return OK == OO_MinusMinus; -} - -bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK) { - return OK == OO_Plus || OK == OO_PlusEqual || OK == OO_Minus || - OK == OO_MinusEqual; -} - bool hasSubscriptOperator(ProgramStateRef State, const MemRegion *Reg) { const auto *CRD = getCXXRecordDecl(State, Reg); if (!CRD) @@ -1985,52 +1364,62 @@ ProgramStateRef createContainerEnd(ProgramStateRef State, const MemRegion *Cont, return setContainerData(State, Cont, CData); } -const ContainerData *getContainerData(ProgramStateRef State, - const MemRegion *Cont) { - return State->get<ContainerMap>(Cont); -} - ProgramStateRef setContainerData(ProgramStateRef State, const MemRegion *Cont, const ContainerData &CData) { return State->set<ContainerMap>(Cont, CData); } -const IteratorPosition *getIteratorPosition(ProgramStateRef State, - const SVal &Val) { +ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) { if (auto Reg = Val.getAsRegion()) { Reg = Reg->getMostDerivedObjectRegion(); - return State->get<IteratorRegionMap>(Reg); + return State->remove<IteratorRegionMap>(Reg); } else if (const auto Sym = Val.getAsSymbol()) { - return State->get<IteratorSymbolMap>(Sym); + return State->remove<IteratorSymbolMap>(Sym); } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) { - return State->get<IteratorRegionMap>(LCVal->getRegion()); + return State->remove<IteratorRegionMap>(LCVal->getRegion()); } return nullptr; } -ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val, - const IteratorPosition &Pos) { - if (auto Reg = Val.getAsRegion()) { - Reg = Reg->getMostDerivedObjectRegion(); - return State->set<IteratorRegionMap>(Reg, Pos); - } else if (const auto Sym = Val.getAsSymbol()) { - return State->set<IteratorSymbolMap>(Sym, Pos); - } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) { - return State->set<IteratorRegionMap>(LCVal->getRegion(), Pos); +// This function tells the analyzer's engine that symbols produced by our +// checker, most notably iterator positions, are relatively small. +// A distance between items in the container should not be very large. +// By assuming that it is within around 1/8 of the address space, +// we can help the analyzer perform operations on these symbols +// without being afraid of integer overflows. +// FIXME: Should we provide it as an API, so that all checkers could use it? +ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, + long Scale) { + SValBuilder &SVB = State->getStateManager().getSValBuilder(); + BasicValueFactory &BV = SVB.getBasicValueFactory(); + + QualType T = Sym->getType(); + assert(T->isSignedIntegerOrEnumerationType()); + APSIntType AT = BV.getAPSIntType(T); + + ProgramStateRef NewState = State; + + llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale); + SVal IsCappedFromAbove = + SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym), + nonloc::ConcreteInt(Max), SVB.getConditionType()); + if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) { + NewState = NewState->assume(*DV, true); + if (!NewState) + return State; } - return nullptr; -} -ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) { - if (auto Reg = Val.getAsRegion()) { - Reg = Reg->getMostDerivedObjectRegion(); - return State->remove<IteratorRegionMap>(Reg); - } else if (const auto Sym = Val.getAsSymbol()) { - return State->remove<IteratorSymbolMap>(Sym); - } else if (const auto LCVal = Val.getAs<nonloc::LazyCompoundVal>()) { - return State->remove<IteratorRegionMap>(LCVal->getRegion()); + llvm::APSInt Min = -Max; + SVal IsCappedFromBelow = + SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym), + nonloc::ConcreteInt(Min), SVB.getConditionType()); + if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) { + NewState = NewState->assume(*DV, true); + if (!NewState) + return State; } - return nullptr; + + return NewState; } ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1, @@ -2067,13 +1456,13 @@ ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1, bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) { auto RegionMap = State->get<IteratorRegionMap>(); - for (const auto Reg : RegionMap) { + for (const auto &Reg : RegionMap) { if (Reg.second.getContainer() == Cont) return true; } auto SymbolMap = State->get<IteratorSymbolMap>(); - for (const auto Sym : SymbolMap) { + for (const auto &Sym : SymbolMap) { if (Sym.second.getContainer() == Cont) return true; } @@ -2083,7 +1472,7 @@ bool hasLiveIterators(ProgramStateRef State, const MemRegion *Cont) { bool isBoundThroughLazyCompoundVal(const Environment &Env, const MemRegion *Reg) { - for (const auto Binding: Env) { + for (const auto &Binding : Env) { if (const auto LCVal = Binding.second.getAs<nonloc::LazyCompoundVal>()) { if (LCVal->getRegion() == Reg) return true; @@ -2093,54 +1482,13 @@ bool isBoundThroughLazyCompoundVal(const Environment &Env, return false; } -// This function tells the analyzer's engine that symbols produced by our -// checker, most notably iterator positions, are relatively small. -// A distance between items in the container should not be very large. -// By assuming that it is within around 1/8 of the address space, -// we can help the analyzer perform operations on these symbols -// without being afraid of integer overflows. -// FIXME: Should we provide it as an API, so that all checkers could use it? -ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym, - long Scale) { - SValBuilder &SVB = State->getStateManager().getSValBuilder(); - BasicValueFactory &BV = SVB.getBasicValueFactory(); - - QualType T = Sym->getType(); - assert(T->isSignedIntegerOrEnumerationType()); - APSIntType AT = BV.getAPSIntType(T); - - ProgramStateRef NewState = State; - - llvm::APSInt Max = AT.getMaxValue() / AT.getValue(Scale); - SVal IsCappedFromAbove = - SVB.evalBinOpNN(State, BO_LE, nonloc::SymbolVal(Sym), - nonloc::ConcreteInt(Max), SVB.getConditionType()); - if (auto DV = IsCappedFromAbove.getAs<DefinedSVal>()) { - NewState = NewState->assume(*DV, true); - if (!NewState) - return State; - } - - llvm::APSInt Min = -Max; - SVal IsCappedFromBelow = - SVB.evalBinOpNN(State, BO_GE, nonloc::SymbolVal(Sym), - nonloc::ConcreteInt(Min), SVB.getConditionType()); - if (auto DV = IsCappedFromBelow.getAs<DefinedSVal>()) { - NewState = NewState->assume(*DV, true); - if (!NewState) - return State; - } - - return NewState; -} - template <typename Condition, typename Process> ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond, Process Proc) { auto &RegionMapFactory = State->get_context<IteratorRegionMap>(); auto RegionMap = State->get<IteratorRegionMap>(); bool Changed = false; - for (const auto Reg : RegionMap) { + for (const auto &Reg : RegionMap) { if (Cond(Reg.second)) { RegionMap = RegionMapFactory.add(RegionMap, Reg.first, Proc(Reg.second)); Changed = true; @@ -2153,7 +1501,7 @@ ProgramStateRef processIteratorPositions(ProgramStateRef State, Condition Cond, auto &SymbolMapFactory = State->get_context<IteratorSymbolMap>(); auto SymbolMap = State->get<IteratorSymbolMap>(); Changed = false; - for (const auto Sym : SymbolMap) { + for (const auto &Sym : SymbolMap) { if (Cond(Sym.second)) { SymbolMap = SymbolMapFactory.add(SymbolMap, Sym.first, Proc(Sym.second)); Changed = true; @@ -2280,111 +1628,12 @@ SymbolRef rebaseSymbol(ProgramStateRef State, SValBuilder &SVB, SymMgr.getType(OrigExpr)).getAsSymbol(); } -bool isZero(ProgramStateRef State, const NonLoc &Val) { - auto &BVF = State->getBasicVals(); - return compare(State, Val, - nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))), - BO_EQ); -} - -bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) { - const auto *Cont = Pos.getContainer(); - const auto *CData = getContainerData(State, Cont); - if (!CData) - return false; - - const auto End = CData->getEnd(); - if (End) { - if (isEqual(State, Pos.getOffset(), End)) { - return true; - } - } - - return false; -} - -bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) { - const auto *Cont = Pos.getContainer(); - const auto *CData = getContainerData(State, Cont); - if (!CData) - return false; - - const auto Beg = CData->getBegin(); - if (Beg) { - if (isLess(State, Pos.getOffset(), Beg)) { - return true; - } - } - - return false; -} - -bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) { - const auto *Cont = Pos.getContainer(); - const auto *CData = getContainerData(State, Cont); - if (!CData) - return false; - - const auto End = CData->getEnd(); - if (End) { - if (isGreater(State, Pos.getOffset(), End)) { - return true; - } - } - - return false; -} - -bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { - return compare(State, Sym1, Sym2, BO_LT); -} - -bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { - return compare(State, Sym1, Sym2, BO_GT); -} - -bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { - return compare(State, Sym1, Sym2, BO_EQ); -} - -bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2, - BinaryOperator::Opcode Opc) { - return compare(State, nonloc::SymbolVal(Sym1), nonloc::SymbolVal(Sym2), Opc); -} - -bool compare(ProgramStateRef State, NonLoc NL1, NonLoc NL2, - BinaryOperator::Opcode Opc) { - auto &SVB = State->getStateManager().getSValBuilder(); - - const auto comparison = - SVB.evalBinOp(State, Opc, NL1, NL2, SVB.getConditionType()); - - assert(comparison.getAs<DefinedSVal>() && - "Symbol comparison must be a `DefinedSVal`"); - - return !State->assume(comparison.castAs<DefinedSVal>(), false); -} - } // namespace void ento::registerIteratorModeling(CheckerManager &mgr) { - mgr.registerChecker<IteratorChecker>(); + mgr.registerChecker<IteratorModeling>(); } bool ento::shouldRegisterIteratorModeling(const LangOptions &LO) { return true; } - -#define REGISTER_CHECKER(name) \ - void ento::register##name(CheckerManager &Mgr) { \ - auto *checker = Mgr.getChecker<IteratorChecker>(); \ - checker->ChecksEnabled[IteratorChecker::CK_##name] = true; \ - checker->CheckNames[IteratorChecker::CK_##name] = \ - Mgr.getCurrentCheckerName(); \ - } \ - \ - bool ento::shouldRegister##name(const LangOptions &LO) { return true; } - -REGISTER_CHECKER(IteratorRangeChecker) -REGISTER_CHECKER(MismatchedIteratorChecker) -REGISTER_CHECKER(InvalidatedIteratorChecker) diff --git a/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp new file mode 100644 index 000000000000..bd8b84d464b6 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/IteratorRangeChecker.cpp @@ -0,0 +1,273 @@ +//===-- IteratorRangeChecker.cpp ----------------------------------*- C++ -*--// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines a checker for dereference of the past-the-end iterator and +// out-of-range increments and decrements. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" + + +#include "Iterator.h" + +using namespace clang; +using namespace ento; +using namespace iterator; + +namespace { + +class IteratorRangeChecker + : public Checker<check::PreCall> { + + std::unique_ptr<BugType> OutOfRangeBugType; + + void verifyDereference(CheckerContext &C, const SVal &Val) const; + void verifyIncrement(CheckerContext &C, const SVal &Iter) const; + void verifyDecrement(CheckerContext &C, const SVal &Iter) const; + void verifyRandomIncrOrDecr(CheckerContext &C, OverloadedOperatorKind Op, + const SVal &LHS, const SVal &RHS) const; + void reportBug(const StringRef &Message, const SVal &Val, + CheckerContext &C, ExplodedNode *ErrNode) const; +public: + IteratorRangeChecker(); + + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + +}; + +bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos); +bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos); +bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos); +bool isZero(ProgramStateRef State, const NonLoc &Val); + +} //namespace + +IteratorRangeChecker::IteratorRangeChecker() { + OutOfRangeBugType.reset( + new BugType(this, "Iterator out of range", "Misuse of STL APIs")); +} + +void IteratorRangeChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + // Check for out of range access + const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); + if (!Func) + return; + + if (Func->isOverloadedOperator()) { + if (isIncrementOperator(Func->getOverloadedOperator())) { + // Check for out-of-range incrementions + if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { + verifyIncrement(C, InstCall->getCXXThisVal()); + } else { + if (Call.getNumArgs() >= 1) { + verifyIncrement(C, Call.getArgSVal(0)); + } + } + } else if (isDecrementOperator(Func->getOverloadedOperator())) { + // Check for out-of-range decrementions + if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { + verifyDecrement(C, InstCall->getCXXThisVal()); + } else { + if (Call.getNumArgs() >= 1) { + verifyDecrement(C, Call.getArgSVal(0)); + } + } + } else if (isRandomIncrOrDecrOperator(Func->getOverloadedOperator())) { + if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { + // Check for out-of-range incrementions and decrementions + if (Call.getNumArgs() >= 1 && + Call.getArgExpr(0)->getType()->isIntegralOrEnumerationType()) { + verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(), + InstCall->getCXXThisVal(), + Call.getArgSVal(0)); + } + } else { + if (Call.getNumArgs() >= 2 && + Call.getArgExpr(1)->getType()->isIntegralOrEnumerationType()) { + verifyRandomIncrOrDecr(C, Func->getOverloadedOperator(), + Call.getArgSVal(0), Call.getArgSVal(1)); + } + } + } else if (isDereferenceOperator(Func->getOverloadedOperator())) { + // Check for dereference of out-of-range iterators + if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { + verifyDereference(C, InstCall->getCXXThisVal()); + } else { + verifyDereference(C, Call.getArgSVal(0)); + } + } + } +} + +void IteratorRangeChecker::verifyDereference(CheckerContext &C, + const SVal &Val) const { + auto State = C.getState(); + const auto *Pos = getIteratorPosition(State, Val); + if (Pos && isPastTheEnd(State, *Pos)) { + auto *N = C.generateErrorNode(State); + if (!N) + return; + reportBug("Past-the-end iterator dereferenced.", Val, C, N); + return; + } +} + +void IteratorRangeChecker::verifyIncrement(CheckerContext &C, + const SVal &Iter) const { + auto &BVF = C.getSValBuilder().getBasicValueFactory(); + verifyRandomIncrOrDecr(C, OO_Plus, Iter, + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); +} + +void IteratorRangeChecker::verifyDecrement(CheckerContext &C, + const SVal &Iter) const { + auto &BVF = C.getSValBuilder().getBasicValueFactory(); + verifyRandomIncrOrDecr(C, OO_Minus, Iter, + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(1)))); +} + +void IteratorRangeChecker::verifyRandomIncrOrDecr(CheckerContext &C, + OverloadedOperatorKind Op, + const SVal &LHS, + const SVal &RHS) const { + auto State = C.getState(); + + auto Value = RHS; + if (auto ValAsLoc = RHS.getAs<Loc>()) { + Value = State->getRawSVal(*ValAsLoc); + } + + if (Value.isUnknown()) + return; + + // Incremention or decremention by 0 is never a bug. + if (isZero(State, Value.castAs<NonLoc>())) + return; + + // The result may be the past-end iterator of the container, but any other + // out of range position is undefined behaviour + auto StateAfter = advancePosition(State, LHS, Op, Value); + if (!StateAfter) + return; + + const auto *PosAfter = getIteratorPosition(StateAfter, LHS); + assert(PosAfter && + "Iterator should have position after successful advancement"); + if (isAheadOfRange(State, *PosAfter)) { + auto *N = C.generateErrorNode(State); + if (!N) + return; + reportBug("Iterator decremented ahead of its valid range.", LHS, + C, N); + } + if (isBehindPastTheEnd(State, *PosAfter)) { + auto *N = C.generateErrorNode(State); + if (!N) + return; + reportBug("Iterator incremented behind the past-the-end " + "iterator.", LHS, C, N); + } +} + +void IteratorRangeChecker::reportBug(const StringRef &Message, + const SVal &Val, CheckerContext &C, + ExplodedNode *ErrNode) const { + auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message, + ErrNode); + R->markInteresting(Val); + C.emitReport(std::move(R)); +} + +namespace { + +bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); +bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); +bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2); + +bool isZero(ProgramStateRef State, const NonLoc &Val) { + auto &BVF = State->getBasicVals(); + return compare(State, Val, + nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))), + BO_EQ); +} + +bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) { + const auto *Cont = Pos.getContainer(); + const auto *CData = getContainerData(State, Cont); + if (!CData) + return false; + + const auto End = CData->getEnd(); + if (End) { + if (isEqual(State, Pos.getOffset(), End)) { + return true; + } + } + + return false; +} + +bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos) { + const auto *Cont = Pos.getContainer(); + const auto *CData = getContainerData(State, Cont); + if (!CData) + return false; + + const auto Beg = CData->getBegin(); + if (Beg) { + if (isLess(State, Pos.getOffset(), Beg)) { + return true; + } + } + + return false; +} + +bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos) { + const auto *Cont = Pos.getContainer(); + const auto *CData = getContainerData(State, Cont); + if (!CData) + return false; + + const auto End = CData->getEnd(); + if (End) { + if (isGreater(State, Pos.getOffset(), End)) { + return true; + } + } + + return false; +} + +bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { + return compare(State, Sym1, Sym2, BO_LT); +} + +bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { + return compare(State, Sym1, Sym2, BO_GT); +} + +bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2) { + return compare(State, Sym1, Sym2, BO_EQ); +} + +} // namespace + +void ento::registerIteratorRangeChecker(CheckerManager &mgr) { + mgr.registerChecker<IteratorRangeChecker>(); +} + +bool ento::shouldRegisterIteratorRangeChecker(const LangOptions &LO) { + return true; +} diff --git a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp index a81015b6e524..79de1844e745 100644 --- a/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/LocalizationChecker.cpp @@ -1077,7 +1077,10 @@ void EmptyLocalizationContextChecker::checkASTDecl( AnalysisDeclContext *DCtx = Mgr.getAnalysisDeclContext(M); const Stmt *Body = M->getBody(); - assert(Body); + if (!Body) { + assert(M->isSynthesizedAccessorStub()); + continue; + } MethodCrawler MC(M->getCanonicalDecl(), BR, this, Mgr, DCtx); MC.VisitStmt(Body); diff --git a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp index d8fd125f4003..d73e2eb92d42 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MIGChecker.cpp @@ -21,6 +21,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/Attr.h" #include "clang/Analysis/AnyCall.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" diff --git a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp index d964a1668eaa..410721d8b6ff 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MacOSXAPIChecker.cpp @@ -14,8 +14,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/AST/Attr.h" #include "clang/Basic/TargetInfo.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index a82449951873..09306383d53f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -1469,6 +1469,9 @@ void MallocChecker::checkPostObjCMessage(const ObjCMethodCall &Call, if (!*FreeWhenDone) return; + if (Call.hasNonZeroCallbackArg()) + return; + bool IsKnownToBeAllocatedMemory; ProgramStateRef State = FreeMemAux(C, Call.getArgExpr(0), Call.getOriginExpr(), C.getState(), @@ -2525,19 +2528,18 @@ MallocChecker::LeakInfo MallocChecker::getAllocationSite(const ExplodedNode *N, // Find the most recent expression bound to the symbol in the current // context. - if (!ReferenceRegion) { - if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) { - SVal Val = State->getSVal(MR); - if (Val.getAsLocSymbol() == Sym) { - const VarRegion* VR = MR->getBaseRegion()->getAs<VarRegion>(); - // Do not show local variables belonging to a function other than - // where the error is reported. - if (!VR || - (VR->getStackFrame() == LeakContext->getStackFrame())) - ReferenceRegion = MR; - } + if (!ReferenceRegion) { + if (const MemRegion *MR = C.getLocationRegionIfPostStore(N)) { + SVal Val = State->getSVal(MR); + if (Val.getAsLocSymbol() == Sym) { + const VarRegion *VR = MR->getBaseRegion()->getAs<VarRegion>(); + // Do not show local variables belonging to a function other than + // where the error is reported. + if (!VR || (VR->getStackFrame() == LeakContext->getStackFrame())) + ReferenceRegion = MR; } } + } // Allocation node, is the last node in the current or parent context in // which the symbol was tracked. diff --git a/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp new file mode 100644 index 000000000000..143910588959 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/MismatchedIteratorChecker.cpp @@ -0,0 +1,295 @@ +//===-- MismatchedIteratorChecker.cpp -----------------------------*- C++ -*--// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Defines a checker for mistakenly applying a foreign iterator on a container +// and for using iterators of two different containers in a context where +// iterators of the same container should be used. +// +//===----------------------------------------------------------------------===// + +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" +#include "clang/StaticAnalyzer/Core/Checker.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" + + +#include "Iterator.h" + +using namespace clang; +using namespace ento; +using namespace iterator; + +namespace { + +class MismatchedIteratorChecker + : public Checker<check::PreCall> { + + std::unique_ptr<BugType> MismatchedBugType; + + void verifyMatch(CheckerContext &C, const SVal &Iter, + const MemRegion *Cont) const; + void verifyMatch(CheckerContext &C, const SVal &Iter1, + const SVal &Iter2) const; + void reportBug(const StringRef &Message, const SVal &Val1, + const SVal &Val2, CheckerContext &C, + ExplodedNode *ErrNode) const; + void reportBug(const StringRef &Message, const SVal &Val, + const MemRegion *Reg, CheckerContext &C, + ExplodedNode *ErrNode) const; + +public: + MismatchedIteratorChecker(); + + void checkPreCall(const CallEvent &Call, CheckerContext &C) const; + +}; + +} // namespace + +MismatchedIteratorChecker::MismatchedIteratorChecker() { + MismatchedBugType.reset( + new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs", + /*SuppressOnSink=*/true)); +} + +void MismatchedIteratorChecker::checkPreCall(const CallEvent &Call, + CheckerContext &C) const { + // Check for iterator mismatches + const auto *Func = dyn_cast_or_null<FunctionDecl>(Call.getDecl()); + if (!Func) + return; + + if (Func->isOverloadedOperator() && + isComparisonOperator(Func->getOverloadedOperator())) { + // Check for comparisons of iterators of different containers + if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { + if (Call.getNumArgs() < 1) + return; + + if (!isIteratorType(InstCall->getCXXThisExpr()->getType()) || + !isIteratorType(Call.getArgExpr(0)->getType())) + return; + + verifyMatch(C, InstCall->getCXXThisVal(), Call.getArgSVal(0)); + } else { + if (Call.getNumArgs() < 2) + return; + + if (!isIteratorType(Call.getArgExpr(0)->getType()) || + !isIteratorType(Call.getArgExpr(1)->getType())) + return; + + verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1)); + } + } else if (const auto *InstCall = dyn_cast<CXXInstanceCall>(&Call)) { + const auto *ContReg = InstCall->getCXXThisVal().getAsRegion(); + if (!ContReg) + return; + // Check for erase, insert and emplace using iterator of another container + if (isEraseCall(Func) || isEraseAfterCall(Func)) { + verifyMatch(C, Call.getArgSVal(0), + InstCall->getCXXThisVal().getAsRegion()); + if (Call.getNumArgs() == 2) { + verifyMatch(C, Call.getArgSVal(1), + InstCall->getCXXThisVal().getAsRegion()); + } + } else if (isInsertCall(Func)) { + verifyMatch(C, Call.getArgSVal(0), + InstCall->getCXXThisVal().getAsRegion()); + if (Call.getNumArgs() == 3 && + isIteratorType(Call.getArgExpr(1)->getType()) && + isIteratorType(Call.getArgExpr(2)->getType())) { + verifyMatch(C, Call.getArgSVal(1), Call.getArgSVal(2)); + } + } else if (isEmplaceCall(Func)) { + verifyMatch(C, Call.getArgSVal(0), + InstCall->getCXXThisVal().getAsRegion()); + } + } else if (isa<CXXConstructorCall>(&Call)) { + // Check match of first-last iterator pair in a constructor of a container + if (Call.getNumArgs() < 2) + return; + + const auto *Ctr = cast<CXXConstructorDecl>(Call.getDecl()); + if (Ctr->getNumParams() < 2) + return; + + if (Ctr->getParamDecl(0)->getName() != "first" || + Ctr->getParamDecl(1)->getName() != "last") + return; + + if (!isIteratorType(Call.getArgExpr(0)->getType()) || + !isIteratorType(Call.getArgExpr(1)->getType())) + return; + + verifyMatch(C, Call.getArgSVal(0), Call.getArgSVal(1)); + } else { + // The main purpose of iterators is to abstract away from different + // containers and provide a (maybe limited) uniform access to them. + // This implies that any correctly written template function that + // works on multiple containers using iterators takes different + // template parameters for different containers. So we can safely + // assume that passing iterators of different containers as arguments + // whose type replaces the same template parameter is a bug. + // + // Example: + // template<typename I1, typename I2> + // void f(I1 first1, I1 last1, I2 first2, I2 last2); + // + // In this case the first two arguments to f() must be iterators must belong + // to the same container and the last to also to the same container but + // not necessarily to the same as the first two. + + const auto *Templ = Func->getPrimaryTemplate(); + if (!Templ) + return; + + const auto *TParams = Templ->getTemplateParameters(); + const auto *TArgs = Func->getTemplateSpecializationArgs(); + + // Iterate over all the template parameters + for (size_t I = 0; I < TParams->size(); ++I) { + const auto *TPDecl = dyn_cast<TemplateTypeParmDecl>(TParams->getParam(I)); + if (!TPDecl) + continue; + + if (TPDecl->isParameterPack()) + continue; + + const auto TAType = TArgs->get(I).getAsType(); + if (!isIteratorType(TAType)) + continue; + + SVal LHS = UndefinedVal(); + + // For every template parameter which is an iterator type in the + // instantiation look for all functions' parameters' type by it and + // check whether they belong to the same container + for (auto J = 0U; J < Func->getNumParams(); ++J) { + const auto *Param = Func->getParamDecl(J); + const auto *ParamType = + Param->getType()->getAs<SubstTemplateTypeParmType>(); + if (!ParamType || + ParamType->getReplacedParameter()->getDecl() != TPDecl) + continue; + if (LHS.isUndef()) { + LHS = Call.getArgSVal(J); + } else { + verifyMatch(C, LHS, Call.getArgSVal(J)); + } + } + } + } +} + +void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter, + const MemRegion *Cont) const { + // Verify match between a container and the container of an iterator + Cont = Cont->getMostDerivedObjectRegion(); + + if (const auto *ContSym = Cont->getSymbolicBase()) { + if (isa<SymbolConjured>(ContSym->getSymbol())) + return; + } + + auto State = C.getState(); + const auto *Pos = getIteratorPosition(State, Iter); + if (!Pos) + return; + + const auto *IterCont = Pos->getContainer(); + + // Skip symbolic regions based on conjured symbols. Two conjured symbols + // may or may not be the same. For example, the same function can return + // the same or a different container but we get different conjured symbols + // for each call. This may cause false positives so omit them from the check. + if (const auto *ContSym = IterCont->getSymbolicBase()) { + if (isa<SymbolConjured>(ContSym->getSymbol())) + return; + } + + if (IterCont != Cont) { + auto *N = C.generateNonFatalErrorNode(State); + if (!N) { + return; + } + reportBug("Container accessed using foreign iterator argument.", + Iter, Cont, C, N); + } +} + +void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, + const SVal &Iter1, + const SVal &Iter2) const { + // Verify match between the containers of two iterators + auto State = C.getState(); + const auto *Pos1 = getIteratorPosition(State, Iter1); + if (!Pos1) + return; + + const auto *IterCont1 = Pos1->getContainer(); + + // Skip symbolic regions based on conjured symbols. Two conjured symbols + // may or may not be the same. For example, the same function can return + // the same or a different container but we get different conjured symbols + // for each call. This may cause false positives so omit them from the check. + if (const auto *ContSym = IterCont1->getSymbolicBase()) { + if (isa<SymbolConjured>(ContSym->getSymbol())) + return; + } + + const auto *Pos2 = getIteratorPosition(State, Iter2); + if (!Pos2) + return; + + const auto *IterCont2 = Pos2->getContainer(); + if (const auto *ContSym = IterCont2->getSymbolicBase()) { + if (isa<SymbolConjured>(ContSym->getSymbol())) + return; + } + + if (IterCont1 != IterCont2) { + auto *N = C.generateNonFatalErrorNode(State); + if (!N) + return; + reportBug("Iterators of different containers used where the " + "same container is expected.", Iter1, Iter2, C, N); + } +} + +void MismatchedIteratorChecker::reportBug(const StringRef &Message, + const SVal &Val1, + const SVal &Val2, + CheckerContext &C, + ExplodedNode *ErrNode) const { + auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message, + ErrNode); + R->markInteresting(Val1); + R->markInteresting(Val2); + C.emitReport(std::move(R)); +} + +void MismatchedIteratorChecker::reportBug(const StringRef &Message, + const SVal &Val, const MemRegion *Reg, + CheckerContext &C, + ExplodedNode *ErrNode) const { + auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message, + ErrNode); + R->markInteresting(Val); + R->markInteresting(Reg); + C.emitReport(std::move(R)); +} + +void ento::registerMismatchedIteratorChecker(CheckerManager &mgr) { + mgr.registerChecker<MismatchedIteratorChecker>(); +} + +bool ento::shouldRegisterMismatchedIteratorChecker(const LangOptions &LO) { + return true; +} diff --git a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp index 1473c05d7e3f..40eb113e3f8e 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MoveChecker.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/Attr.h" #include "clang/AST/ExprCXX.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" @@ -685,7 +686,7 @@ void MoveChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); TrackedRegionMapTy TrackedRegions = State->get<TrackedRegionMap>(); - for (TrackedRegionMapTy::value_type E : TrackedRegions) { + for (auto E : TrackedRegions) { const MemRegion *Region = E.first; bool IsRegDead = !SymReaper.isLiveRegion(Region); diff --git a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp index 43dbe57b8432..6efba433eed2 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NonnullGlobalConstantsChecker.cpp @@ -36,6 +36,7 @@ class NonnullGlobalConstantsChecker : public Checker<check::Location> { mutable IdentifierInfo *NSStringII = nullptr; mutable IdentifierInfo *CFStringRefII = nullptr; mutable IdentifierInfo *CFBooleanRefII = nullptr; + mutable IdentifierInfo *CFNullRefII = nullptr; public: NonnullGlobalConstantsChecker() {} @@ -61,6 +62,7 @@ void NonnullGlobalConstantsChecker::initIdentifierInfo(ASTContext &Ctx) const { NSStringII = &Ctx.Idents.get("NSString"); CFStringRefII = &Ctx.Idents.get("CFStringRef"); CFBooleanRefII = &Ctx.Idents.get("CFBooleanRef"); + CFNullRefII = &Ctx.Idents.get("CFNullRef"); } /// Add an assumption that const string-like globals are non-null. @@ -136,7 +138,7 @@ bool NonnullGlobalConstantsChecker::isNonnullType(QualType Ty) const { T->getInterfaceDecl()->getIdentifier() == NSStringII; } else if (auto *T = dyn_cast<TypedefType>(Ty)) { IdentifierInfo* II = T->getDecl()->getIdentifier(); - return II == CFStringRefII || II == CFBooleanRefII; + return II == CFStringRefII || II == CFBooleanRefII || II == CFNullRefII; } return false; } diff --git a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp index 4322ac207112..922048733c7c 100644 --- a/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/NullabilityChecker.cpp @@ -728,11 +728,6 @@ void NullabilityChecker::checkPreCall(const CallEvent &Call, } continue; } - // No tracked nullability yet. - if (ArgExprTypeLevelNullability != Nullability::Nullable) - continue; - State = State->set<NullabilityMap>( - Region, NullabilityState(ArgExprTypeLevelNullability, ArgExpr)); } if (State != OrigState) C.addTransition(State); diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index c254408351c8..47099f2afb6a 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -19,84 +19,90 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h" +#include <functional> using namespace clang; using namespace ento; +using namespace std::placeholders; namespace { struct StreamState { enum Kind { Opened, Closed, OpenFailed, Escaped } K; - const Stmt *S; - StreamState(Kind k, const Stmt *s) : K(k), S(s) {} + StreamState(Kind k) : K(k) {} bool isOpened() const { return K == Opened; } bool isClosed() const { return K == Closed; } //bool isOpenFailed() const { return K == OpenFailed; } //bool isEscaped() const { return K == Escaped; } - bool operator==(const StreamState &X) const { - return K == X.K && S == X.S; - } + bool operator==(const StreamState &X) const { return K == X.K; } - static StreamState getOpened(const Stmt *s) { return StreamState(Opened, s); } - static StreamState getClosed(const Stmt *s) { return StreamState(Closed, s); } - static StreamState getOpenFailed(const Stmt *s) { - return StreamState(OpenFailed, s); - } - static StreamState getEscaped(const Stmt *s) { - return StreamState(Escaped, s); - } + static StreamState getOpened() { return StreamState(Opened); } + static StreamState getClosed() { return StreamState(Closed); } + static StreamState getOpenFailed() { return StreamState(OpenFailed); } + static StreamState getEscaped() { return StreamState(Escaped); } void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); - ID.AddPointer(S); } }; class StreamChecker : public Checker<eval::Call, check::DeadSymbols > { - mutable IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread, - *II_fwrite, - *II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos, - *II_clearerr, *II_feof, *II_ferror, *II_fileno; mutable std::unique_ptr<BuiltinBug> BT_nullfp, BT_illegalwhence, BT_doubleclose, BT_ResourceLeak; public: - StreamChecker() - : II_fopen(nullptr), II_tmpfile(nullptr), II_fclose(nullptr), - II_fread(nullptr), II_fwrite(nullptr), II_fseek(nullptr), - II_ftell(nullptr), II_rewind(nullptr), II_fgetpos(nullptr), - II_fsetpos(nullptr), II_clearerr(nullptr), II_feof(nullptr), - II_ferror(nullptr), II_fileno(nullptr) {} - bool evalCall(const CallEvent &Call, CheckerContext &C) const; void checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const; private: - void Fopen(CheckerContext &C, const CallExpr *CE) const; - void Tmpfile(CheckerContext &C, const CallExpr *CE) const; - void Fclose(CheckerContext &C, const CallExpr *CE) const; - void Fread(CheckerContext &C, const CallExpr *CE) const; - void Fwrite(CheckerContext &C, const CallExpr *CE) const; - void Fseek(CheckerContext &C, const CallExpr *CE) const; - void Ftell(CheckerContext &C, const CallExpr *CE) const; - void Rewind(CheckerContext &C, const CallExpr *CE) const; - void Fgetpos(CheckerContext &C, const CallExpr *CE) const; - void Fsetpos(CheckerContext &C, const CallExpr *CE) const; - void Clearerr(CheckerContext &C, const CallExpr *CE) const; - void Feof(CheckerContext &C, const CallExpr *CE) const; - void Ferror(CheckerContext &C, const CallExpr *CE) const; - void Fileno(CheckerContext &C, const CallExpr *CE) const; + using FnCheck = std::function<void(const StreamChecker *, const CallEvent &, + CheckerContext &)>; - void OpenFileAux(CheckerContext &C, const CallExpr *CE) const; + CallDescriptionMap<FnCheck> Callbacks = { + {{"fopen"}, &StreamChecker::evalFopen}, + {{"freopen", 3}, &StreamChecker::evalFreopen}, + {{"tmpfile"}, &StreamChecker::evalFopen}, + {{"fclose", 1}, &StreamChecker::evalFclose}, + {{"fread", 4}, + std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}, + {{"fwrite", 4}, + std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 3)}, + {{"fseek", 3}, &StreamChecker::evalFseek}, + {{"ftell", 1}, + std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {{"rewind", 1}, + std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {{"fgetpos", 2}, + std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {{"fsetpos", 2}, + std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {{"clearerr", 1}, + std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {{"feof", 1}, + std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {{"ferror", 1}, + std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + {{"fileno", 1}, + std::bind(&StreamChecker::checkArgNullStream, _1, _2, _3, 0)}, + }; - ProgramStateRef CheckNullStream(SVal SV, ProgramStateRef state, - CheckerContext &C) const; - ProgramStateRef CheckDoubleClose(const CallExpr *CE, ProgramStateRef state, - CheckerContext &C) const; + void evalFopen(const CallEvent &Call, CheckerContext &C) const; + void evalFreopen(const CallEvent &Call, CheckerContext &C) const; + void evalFclose(const CallEvent &Call, CheckerContext &C) const; + void evalFseek(const CallEvent &Call, CheckerContext &C) const; + + void checkArgNullStream(const CallEvent &Call, CheckerContext &C, + unsigned ArgI) const; + bool checkNullStream(SVal SV, CheckerContext &C, + ProgramStateRef &State) const; + void checkFseekWhence(SVal SV, CheckerContext &C, + ProgramStateRef &State) const; + bool checkDoubleClose(const CallEvent &Call, CheckerContext &C, + ProgramStateRef &State) const; }; } // end anonymous namespace @@ -109,115 +115,36 @@ bool StreamChecker::evalCall(const CallEvent &Call, CheckerContext &C) const { if (!FD || FD->getKind() != Decl::Function) return false; - const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); - if (!CE) + // Recognize "global C functions" with only integral or pointer arguments + // (and matching name) as stream functions. + if (!Call.isGlobalCFunction()) return false; - - ASTContext &Ctx = C.getASTContext(); - if (!II_fopen) - II_fopen = &Ctx.Idents.get("fopen"); - if (!II_tmpfile) - II_tmpfile = &Ctx.Idents.get("tmpfile"); - if (!II_fclose) - II_fclose = &Ctx.Idents.get("fclose"); - if (!II_fread) - II_fread = &Ctx.Idents.get("fread"); - if (!II_fwrite) - II_fwrite = &Ctx.Idents.get("fwrite"); - if (!II_fseek) - II_fseek = &Ctx.Idents.get("fseek"); - if (!II_ftell) - II_ftell = &Ctx.Idents.get("ftell"); - if (!II_rewind) - II_rewind = &Ctx.Idents.get("rewind"); - if (!II_fgetpos) - II_fgetpos = &Ctx.Idents.get("fgetpos"); - if (!II_fsetpos) - II_fsetpos = &Ctx.Idents.get("fsetpos"); - if (!II_clearerr) - II_clearerr = &Ctx.Idents.get("clearerr"); - if (!II_feof) - II_feof = &Ctx.Idents.get("feof"); - if (!II_ferror) - II_ferror = &Ctx.Idents.get("ferror"); - if (!II_fileno) - II_fileno = &Ctx.Idents.get("fileno"); - - if (FD->getIdentifier() == II_fopen) { - Fopen(C, CE); - return true; - } - if (FD->getIdentifier() == II_tmpfile) { - Tmpfile(C, CE); - return true; - } - if (FD->getIdentifier() == II_fclose) { - Fclose(C, CE); - return true; - } - if (FD->getIdentifier() == II_fread) { - Fread(C, CE); - return true; - } - if (FD->getIdentifier() == II_fwrite) { - Fwrite(C, CE); - return true; - } - if (FD->getIdentifier() == II_fseek) { - Fseek(C, CE); - return true; - } - if (FD->getIdentifier() == II_ftell) { - Ftell(C, CE); - return true; - } - if (FD->getIdentifier() == II_rewind) { - Rewind(C, CE); - return true; - } - if (FD->getIdentifier() == II_fgetpos) { - Fgetpos(C, CE); - return true; - } - if (FD->getIdentifier() == II_fsetpos) { - Fsetpos(C, CE); - return true; - } - if (FD->getIdentifier() == II_clearerr) { - Clearerr(C, CE); - return true; - } - if (FD->getIdentifier() == II_feof) { - Feof(C, CE); - return true; - } - if (FD->getIdentifier() == II_ferror) { - Ferror(C, CE); - return true; - } - if (FD->getIdentifier() == II_fileno) { - Fileno(C, CE); - return true; + for (auto P : Call.parameters()) { + QualType T = P->getType(); + if (!T->isIntegralOrEnumerationType() && !T->isPointerType()) + return false; } - return false; -} + const FnCheck *Callback = Callbacks.lookup(Call); + if (!Callback) + return false; -void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) const { - OpenFileAux(C, CE); -} + (*Callback)(this, Call, C); -void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) const { - OpenFileAux(C, CE); + return C.isDifferent(); } -void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const { +void StreamChecker::evalFopen(const CallEvent &Call, CheckerContext &C) const { ProgramStateRef state = C.getState(); SValBuilder &svalBuilder = C.getSValBuilder(); const LocationContext *LCtx = C.getPredecessor()->getLocationContext(); - DefinedSVal RetVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, - C.blockCount()) - .castAs<DefinedSVal>(); + auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); + if (!CE) + return; + + DefinedSVal RetVal = + svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount()) + .castAs<DefinedSVal>(); state = state->BindExpr(CE, C.getLocationContext(), RetVal); ConstraintManager &CM = C.getConstraintManager(); @@ -226,145 +153,153 @@ void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) const { ProgramStateRef stateNotNull, stateNull; std::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal); - if (SymbolRef Sym = RetVal.getAsSymbol()) { - // if RetVal is not NULL, set the symbol's state to Opened. - stateNotNull = - stateNotNull->set<StreamMap>(Sym,StreamState::getOpened(CE)); - stateNull = - stateNull->set<StreamMap>(Sym, StreamState::getOpenFailed(CE)); + SymbolRef Sym = RetVal.getAsSymbol(); + assert(Sym && "RetVal must be a symbol here."); + stateNotNull = stateNotNull->set<StreamMap>(Sym, StreamState::getOpened()); + stateNull = stateNull->set<StreamMap>(Sym, StreamState::getOpenFailed()); - C.addTransition(stateNotNull); - C.addTransition(stateNull); - } + C.addTransition(stateNotNull); + C.addTransition(stateNull); } -void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = CheckDoubleClose(CE, C.getState(), C); - if (state) - C.addTransition(state); -} +void StreamChecker::evalFreopen(const CallEvent &Call, + CheckerContext &C) const { + ProgramStateRef State = C.getState(); -void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = C.getState(); - if (!CheckNullStream(C.getSVal(CE->getArg(3)), state, C)) + auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr()); + if (!CE) return; -} -void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = C.getState(); - if (!CheckNullStream(C.getSVal(CE->getArg(3)), state, C)) + Optional<DefinedSVal> StreamVal = Call.getArgSVal(2).getAs<DefinedSVal>(); + if (!StreamVal) return; -} - -void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = C.getState(); - if (!(state = CheckNullStream(C.getSVal(CE->getArg(0)), state, C))) + // Do not allow NULL as passed stream pointer. + // This is not specified in the man page but may crash on some system. + checkNullStream(*StreamVal, C, State); + // Check if error was generated. + if (C.isDifferent()) return; - // Check the legality of the 'whence' argument of 'fseek'. - SVal Whence = state->getSVal(CE->getArg(2), C.getLocationContext()); - Optional<nonloc::ConcreteInt> CI = Whence.getAs<nonloc::ConcreteInt>(); - if (!CI) + SymbolRef StreamSym = StreamVal->getAsSymbol(); + // Do not care about special values for stream ("(FILE *)0x12345"?). + if (!StreamSym) return; - int64_t x = CI->getValue().getSExtValue(); - if (x >= 0 && x <= 2) - return; + // Generate state for non-failed case. + // Return value is the passed stream pointer. + // According to the documentations, the stream is closed first + // but any close error is ignored. The state changes to (or remains) opened. + ProgramStateRef StateRetNotNull = + State->BindExpr(CE, C.getLocationContext(), *StreamVal); + // Generate state for NULL return value. + // Stream switches to OpenFailed state. + ProgramStateRef StateRetNull = State->BindExpr(CE, C.getLocationContext(), + C.getSValBuilder().makeNull()); - if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) { - if (!BT_illegalwhence) - BT_illegalwhence.reset( - new BuiltinBug(this, "Illegal whence argument", - "The whence argument to fseek() should be " - "SEEK_SET, SEEK_END, or SEEK_CUR.")); - C.emitReport(std::make_unique<PathSensitiveBugReport>( - *BT_illegalwhence, BT_illegalwhence->getDescription(), N)); - } -} + StateRetNotNull = + StateRetNotNull->set<StreamMap>(StreamSym, StreamState::getOpened()); + StateRetNull = + StateRetNull->set<StreamMap>(StreamSym, StreamState::getOpenFailed()); -void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = C.getState(); - if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C)) - return; + C.addTransition(StateRetNotNull); + C.addTransition(StateRetNull); } -void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = C.getState(); - if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C)) - return; +void StreamChecker::evalFclose(const CallEvent &Call, CheckerContext &C) const { + ProgramStateRef State = C.getState(); + if (checkDoubleClose(Call, C, State)) + C.addTransition(State); } -void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = C.getState(); - if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C)) +void StreamChecker::evalFseek(const CallEvent &Call, CheckerContext &C) const { + const Expr *AE2 = Call.getArgExpr(2); + if (!AE2) return; -} -void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = C.getState(); - if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C)) - return; -} + ProgramStateRef State = C.getState(); -void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = C.getState(); - if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C)) + bool StateChanged = checkNullStream(Call.getArgSVal(0), C, State); + // Check if error was generated. + if (C.isDifferent()) return; -} -void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = C.getState(); - if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C)) - return; -} + // Check the legality of the 'whence' argument of 'fseek'. + checkFseekWhence(State->getSVal(AE2, C.getLocationContext()), C, State); -void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = C.getState(); - if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C)) - return; + if (!C.isDifferent() && StateChanged) + C.addTransition(State); + + return; } -void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) const { - ProgramStateRef state = C.getState(); - if (!CheckNullStream(C.getSVal(CE->getArg(0)), state, C)) - return; +void StreamChecker::checkArgNullStream(const CallEvent &Call, CheckerContext &C, + unsigned ArgI) const { + ProgramStateRef State = C.getState(); + if (checkNullStream(Call.getArgSVal(ArgI), C, State)) + C.addTransition(State); } -ProgramStateRef StreamChecker::CheckNullStream(SVal SV, ProgramStateRef state, - CheckerContext &C) const { +bool StreamChecker::checkNullStream(SVal SV, CheckerContext &C, + ProgramStateRef &State) const { Optional<DefinedSVal> DV = SV.getAs<DefinedSVal>(); if (!DV) - return nullptr; + return false; ConstraintManager &CM = C.getConstraintManager(); - ProgramStateRef stateNotNull, stateNull; - std::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV); + ProgramStateRef StateNotNull, StateNull; + std::tie(StateNotNull, StateNull) = CM.assumeDual(C.getState(), *DV); - if (!stateNotNull && stateNull) { - if (ExplodedNode *N = C.generateErrorNode(stateNull)) { + if (!StateNotNull && StateNull) { + if (ExplodedNode *N = C.generateErrorNode(StateNull)) { if (!BT_nullfp) BT_nullfp.reset(new BuiltinBug(this, "NULL stream pointer", "Stream pointer might be NULL.")); C.emitReport(std::make_unique<PathSensitiveBugReport>( *BT_nullfp, BT_nullfp->getDescription(), N)); } - return nullptr; + return false; + } + + if (StateNotNull) { + State = StateNotNull; + return true; + } + + return false; +} + +void StreamChecker::checkFseekWhence(SVal SV, CheckerContext &C, + ProgramStateRef &State) const { + Optional<nonloc::ConcreteInt> CI = SV.getAs<nonloc::ConcreteInt>(); + if (!CI) + return; + + int64_t X = CI->getValue().getSExtValue(); + if (X >= 0 && X <= 2) + return; + + if (ExplodedNode *N = C.generateNonFatalErrorNode(State)) { + if (!BT_illegalwhence) + BT_illegalwhence.reset( + new BuiltinBug(this, "Illegal whence argument", + "The whence argument to fseek() should be " + "SEEK_SET, SEEK_END, or SEEK_CUR.")); + C.emitReport(std::make_unique<PathSensitiveBugReport>( + *BT_illegalwhence, BT_illegalwhence->getDescription(), N)); } - return stateNotNull; } -ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE, - ProgramStateRef state, - CheckerContext &C) const { - SymbolRef Sym = C.getSVal(CE->getArg(0)).getAsSymbol(); +bool StreamChecker::checkDoubleClose(const CallEvent &Call, CheckerContext &C, + ProgramStateRef &State) const { + SymbolRef Sym = Call.getArgSVal(0).getAsSymbol(); if (!Sym) - return state; + return false; - const StreamState *SS = state->get<StreamMap>(Sym); + const StreamState *SS = State->get<StreamMap>(Sym); // If the file stream is not tracked, return. if (!SS) - return state; + return false; // Check: Double close a File Descriptor could cause undefined behaviour. // Conforming to man-pages @@ -378,19 +313,21 @@ ProgramStateRef StreamChecker::CheckDoubleClose(const CallExpr *CE, C.emitReport(std::make_unique<PathSensitiveBugReport>( *BT_doubleclose, BT_doubleclose->getDescription(), N)); } - return nullptr; + return false; } // Close the File Descriptor. - return state->set<StreamMap>(Sym, StreamState::getClosed(CE)); + State = State->set<StreamMap>(Sym, StreamState::getClosed()); + + return true; } void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { - ProgramStateRef state = C.getState(); + ProgramStateRef State = C.getState(); // TODO: Clean up the state. - const StreamMapTy &Map = state->get<StreamMap>(); + const StreamMapTy &Map = State->get<StreamMap>(); for (const auto &I: Map) { SymbolRef Sym = I.first; const StreamState &SS = I.second; @@ -399,7 +336,7 @@ void StreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, ExplodedNode *N = C.generateErrorNode(); if (!N) - return; + continue; if (!BT_ResourceLeak) BT_ResourceLeak.reset( diff --git a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp index 574d4ed1e600..5b46ffb656cf 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Taint.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/Taint.cpp @@ -37,9 +37,7 @@ void taint::printTaint(ProgramStateRef State, raw_ostream &Out, const char *NL, Out << I.first << " : " << I.second << NL; } -void dumpTaint(ProgramStateRef State) { - printTaint(State, llvm::errs()); -} +void dumpTaint(ProgramStateRef State) { printTaint(State, llvm::errs()); } ProgramStateRef taint::addTaint(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, @@ -64,8 +62,8 @@ ProgramStateRef taint::addTaint(ProgramStateRef State, SVal V, // region of the parent region. if (auto LCV = V.getAs<nonloc::LazyCompoundVal>()) { if (Optional<SVal> binding = - State->getStateManager().getStoreManager() - .getDefaultBinding(*LCV)) { + State->getStateManager().getStoreManager().getDefaultBinding( + *LCV)) { if (SymbolRef Sym = binding->getAsSymbol()) return addPartialTaint(State, Sym, LCV->getRegion(), Kind); } @@ -94,6 +92,32 @@ ProgramStateRef taint::addTaint(ProgramStateRef State, SymbolRef Sym, return NewState; } +ProgramStateRef taint::removeTaint(ProgramStateRef State, SVal V) { + SymbolRef Sym = V.getAsSymbol(); + if (Sym) + return removeTaint(State, Sym); + + const MemRegion *R = V.getAsRegion(); + return removeTaint(State, R); +} + +ProgramStateRef taint::removeTaint(ProgramStateRef State, const MemRegion *R) { + if (const SymbolicRegion *SR = dyn_cast_or_null<SymbolicRegion>(R)) + return removeTaint(State, SR->getSymbol()); + return State; +} + +ProgramStateRef taint::removeTaint(ProgramStateRef State, SymbolRef Sym) { + // If this is a symbol cast, remove the cast before adding the taint. Taint + // is cast agnostic. + while (const SymbolCast *SC = dyn_cast<SymbolCast>(Sym)) + Sym = SC->getOperand(); + + ProgramStateRef NewState = State->remove<TaintMap>(Sym); + assert(NewState); + return NewState; +} + ProgramStateRef taint::addPartialTaint(ProgramStateRef State, SymbolRef ParentSym, const SubRegion *SubRegion, @@ -157,7 +181,8 @@ bool taint::isTainted(ProgramStateRef State, SymbolRef Sym, TaintTagType Kind) { // Traverse all the symbols this symbol depends on to see if any are tainted. for (SymExpr::symbol_iterator SI = Sym->symbol_begin(), - SE = Sym->symbol_end(); SI != SE; ++SI) { + SE = Sym->symbol_end(); + SI != SE; ++SI) { if (!isa<SymbolData>(*SI)) continue; diff --git a/clang/lib/StaticAnalyzer/Checkers/Taint.h b/clang/lib/StaticAnalyzer/Checkers/Taint.h index 8940916c1933..659a3c898d56 100644 --- a/clang/lib/StaticAnalyzer/Checkers/Taint.h +++ b/clang/lib/StaticAnalyzer/Checkers/Taint.h @@ -27,34 +27,39 @@ using TaintTagType = unsigned; static constexpr TaintTagType TaintTagGeneric = 0; /// Create a new state in which the value of the statement is marked as tainted. -LLVM_NODISCARD ProgramStateRef -addTaint(ProgramStateRef State, const Stmt *S, const LocationContext *LCtx, - TaintTagType Kind = TaintTagGeneric); +LLVM_NODISCARD ProgramStateRef addTaint(ProgramStateRef State, const Stmt *S, + const LocationContext *LCtx, + TaintTagType Kind = TaintTagGeneric); /// Create a new state in which the value is marked as tainted. -LLVM_NODISCARD ProgramStateRef -addTaint(ProgramStateRef State, SVal V, - TaintTagType Kind = TaintTagGeneric); +LLVM_NODISCARD ProgramStateRef addTaint(ProgramStateRef State, SVal V, + TaintTagType Kind = TaintTagGeneric); /// Create a new state in which the symbol is marked as tainted. -LLVM_NODISCARD ProgramStateRef -addTaint(ProgramStateRef State, SymbolRef Sym, - TaintTagType Kind = TaintTagGeneric); +LLVM_NODISCARD ProgramStateRef addTaint(ProgramStateRef State, SymbolRef Sym, + TaintTagType Kind = TaintTagGeneric); /// Create a new state in which the pointer represented by the region /// is marked as tainted. -LLVM_NODISCARD ProgramStateRef -addTaint(ProgramStateRef State, const MemRegion *R, - TaintTagType Kind = TaintTagGeneric); +LLVM_NODISCARD ProgramStateRef addTaint(ProgramStateRef State, + const MemRegion *R, + TaintTagType Kind = TaintTagGeneric); + +LLVM_NODISCARD ProgramStateRef removeTaint(ProgramStateRef State, SVal V); + +LLVM_NODISCARD ProgramStateRef removeTaint(ProgramStateRef State, + const MemRegion *R); + +LLVM_NODISCARD ProgramStateRef removeTaint(ProgramStateRef State, + SymbolRef Sym); /// Create a new state in a which a sub-region of a given symbol is tainted. /// This might be necessary when referring to regions that can not have an /// individual symbol, e.g. if they are represented by the default binding of /// a LazyCompoundVal. -LLVM_NODISCARD ProgramStateRef -addPartialTaint(ProgramStateRef State, - SymbolRef ParentSym, const SubRegion *SubRegion, - TaintTagType Kind = TaintTagGeneric); +LLVM_NODISCARD ProgramStateRef addPartialTaint( + ProgramStateRef State, SymbolRef ParentSym, const SubRegion *SubRegion, + TaintTagType Kind = TaintTagGeneric); /// Check if the statement has a tainted value in the given state. bool isTainted(ProgramStateRef State, const Stmt *S, @@ -99,4 +104,3 @@ public: } // namespace clang #endif - diff --git a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp index 12cee5f8d4f7..fd93fc33115f 100644 --- a/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp @@ -11,8 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" +#include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" +#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" #include "clang/StaticAnalyzer/Core/Checker.h" diff --git a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp index 73e1a0d0000f..fdd03c75920d 100644 --- a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp @@ -43,6 +43,9 @@ AnalysisManager::AnalysisManager(ASTContext &ASTCtx, CreateConstraintMgr(constraintmgr), CheckerMgr(checkerMgr), options(Options) { AnaCtxMgr.getCFGBuildOptions().setAllAlwaysAdd(); + AnaCtxMgr.getCFGBuildOptions().OmitImplicitValueInitializers = true; + AnaCtxMgr.getCFGBuildOptions().AddCXXDefaultInitExprInAggregates = + Options.ShouldIncludeDefaultInitForAggregates; } AnalysisManager::~AnalysisManager() { diff --git a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp index 7ba93b858baf..0525b5c41e34 100644 --- a/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp +++ b/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp @@ -505,7 +505,7 @@ NoStoreFuncVisitor::findRegionOfInterestInRecord( // Recursively examine the base classes. // Note that following base classes does not increase the recursion depth. if (const auto *RDX = dyn_cast<CXXRecordDecl>(RD)) - for (const auto II : RDX->bases()) + for (const auto &II : RDX->bases()) if (const RecordDecl *RRD = II.getType()->getAsRecordDecl()) if (Optional<RegionVector> Out = findRegionOfInterestInRecord(RRD, State, R, Vec, depth)) @@ -1606,9 +1606,6 @@ SuppressInlineDefensiveChecksVisitor(DefinedSVal Value, const ExplodedNode *N) AnalyzerOptions &Options = N->getState()->getAnalysisManager().options; if (!Options.ShouldSuppressInlinedDefensiveChecks) IsSatisfied = true; - - assert(N->getState()->isNull(V).isConstrainedTrue() && - "The visitor only tracks the cases where V is constrained to 0"); } void SuppressInlineDefensiveChecksVisitor::Profile( @@ -1639,13 +1636,12 @@ SuppressInlineDefensiveChecksVisitor::VisitNode(const ExplodedNode *Succ, // Check if in the previous state it was feasible for this value // to *not* be null. - if (!Pred->getState()->isNull(V).isConstrainedTrue()) { + if (!Pred->getState()->isNull(V).isConstrainedTrue() && + Succ->getState()->isNull(V).isConstrainedTrue()) { IsSatisfied = true; - assert(Succ->getState()->isNull(V).isConstrainedTrue()); - // Check if this is inlined defensive checks. - const LocationContext *CurLC =Succ->getLocationContext(); + const LocationContext *CurLC = Succ->getLocationContext(); const LocationContext *ReportLC = BR.getErrorNode()->getLocationContext(); if (CurLC != ReportLC && !CurLC->isParentOf(ReportLC)) { BR.markInvalid("Suppress IDC", CurLC); @@ -2012,11 +2008,16 @@ bool bugreporter::trackExpressionValue(const ExplodedNode *InputNode, // Add visitor, which will suppress inline defensive checks. if (auto DV = V.getAs<DefinedSVal>()) - if (!DV->isZeroConstant() && LVState->isNull(*DV).isConstrainedTrue() && - EnableNullFPSuppression) + if (!DV->isZeroConstant() && EnableNullFPSuppression) { + // Note that LVNode may be too late (i.e., too far from the InputNode) + // because the lvalue may have been computed before the inlined call + // was evaluated. InputNode may as well be too early here, because + // the symbol is already dead; this, however, is fine because we can + // still find the node in which it collapsed to null previously. report.addVisitor( - std::make_unique<SuppressInlineDefensiveChecksVisitor>(*DV, - LVNode)); + std::make_unique<SuppressInlineDefensiveChecksVisitor>( + *DV, InputNode)); + } if (auto KV = V.getAs<KnownSVal>()) report.addVisitor(std::make_unique<FindLastStoreBRVisitor>( diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 5f04a59ba055..168d6fe6ec48 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -14,6 +14,7 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -29,20 +30,20 @@ #include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/PathDiagnostic.h" #include "clang/Analysis/ProgramPoint.h" -#include "clang/CrossTU/CrossTranslationUnit.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/Specifiers.h" +#include "clang/CrossTU/CrossTranslationUnit.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h" #include "clang/StaticAnalyzer/Core/PathSensitive/DynamicType.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeInfo.h" #include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h" -#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "clang/StaticAnalyzer/Core/PathSensitive/Store.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" @@ -519,7 +520,7 @@ static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx, // TODO: Support allocator calls. if (Call.getKind() != CE_CXXAllocator) - if (Call.isArgumentConstructedDirectly(Idx)) + if (Call.isArgumentConstructedDirectly(Call.getASTArgumentIndex(Idx))) continue; // TODO: Allocators should receive the correct size and possibly alignment, @@ -1080,7 +1081,7 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const { const ObjCPropertyDecl *ObjCMethodCall::getAccessedProperty() const { // Look for properties accessed with property syntax (foo.bar = ...) - if ( getMessageKind() == OCM_PropertyAccess) { + if (getMessageKind() == OCM_PropertyAccess) { const PseudoObjectExpr *POE = getContainingPseudoObjectExpr(); assert(POE && "Property access without PseudoObjectExpr?"); @@ -1309,6 +1310,8 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const { } const ObjCMethodDecl *MD = Val.getValue(); + if (MD && !MD->hasBody()) + MD = MD->getCanonicalDecl(); if (CanBeSubClassed) return RuntimeDefinition(MD, Receiver); else diff --git a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp index f676bd895283..a9361837cf68 100644 --- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -91,7 +91,7 @@ void CheckerManager::runCheckersOnASTDecl(const Decl *D, AnalysisManager& mgr, } assert(checkers); - for (const auto checker : *checkers) + for (const auto &checker : *checkers) checker(D, mgr, BR); } @@ -99,7 +99,7 @@ void CheckerManager::runCheckersOnASTBody(const Decl *D, AnalysisManager& mgr, BugReporter &BR) { assert(D && D->hasBody()); - for (const auto BodyChecker : BodyCheckers) + for (const auto &BodyChecker : BodyCheckers) BodyChecker(D, mgr, BR); } @@ -402,7 +402,7 @@ void CheckerManager::runCheckersForBind(ExplodedNodeSet &Dst, void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR, ExprEngine &Eng) { - for (const auto EndAnalysisChecker : EndAnalysisCheckers) + for (const auto &EndAnalysisChecker : EndAnalysisCheckers) EndAnalysisChecker(G, BR, Eng); } @@ -455,7 +455,7 @@ void CheckerManager::runCheckersForEndFunction(NodeBuilderContext &BC, // creates a successor for Pred, we do not need to generate an // autotransition for it. NodeBuilder Bldr(Pred, Dst, BC); - for (const auto checkFn : EndFunctionCheckers) { + for (const auto &checkFn : EndFunctionCheckers) { const ProgramPoint &L = FunctionExitPoint(RS, Pred->getLocationContext(), checkFn.Checker); CheckerContext C(Bldr, Eng, Pred, L); @@ -542,7 +542,7 @@ void CheckerManager::runCheckersForNewAllocator( /// Run checkers for live symbols. void CheckerManager::runCheckersForLiveSymbols(ProgramStateRef state, SymbolReaper &SymReaper) { - for (const auto LiveSymbolsChecker : LiveSymbolsCheckers) + for (const auto &LiveSymbolsChecker : LiveSymbolsCheckers) LiveSymbolsChecker(state, SymReaper); } @@ -599,7 +599,7 @@ CheckerManager::runCheckersForRegionChanges(ProgramStateRef state, ArrayRef<const MemRegion *> Regions, const LocationContext *LCtx, const CallEvent *Call) { - for (const auto RegionChangesChecker : RegionChangesCheckers) { + for (const auto &RegionChangesChecker : RegionChangesCheckers) { // If any checker declares the state infeasible (or if it starts that way), // bail out. if (!state) @@ -621,7 +621,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, (Kind != PSK_DirectEscapeOnCall && Kind != PSK_IndirectEscapeOnCall)) && "Call must not be NULL when escaping on call"); - for (const auto PointerEscapeChecker : PointerEscapeCheckers) { + for (const auto &PointerEscapeChecker : PointerEscapeCheckers) { // If any checker declares the state infeasible (or if it starts that // way), bail out. if (!State) @@ -635,7 +635,7 @@ CheckerManager::runCheckersForPointerEscape(ProgramStateRef State, ProgramStateRef CheckerManager::runCheckersForEvalAssume(ProgramStateRef state, SVal Cond, bool Assumption) { - for (const auto EvalAssumeChecker : EvalAssumeCheckers) { + for (const auto &EvalAssumeChecker : EvalAssumeCheckers) { // If any checker declares the state infeasible (or if it starts that way), // bail out. if (!state) @@ -658,7 +658,7 @@ void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst, NodeBuilder B(Pred, checkDst, Eng.getBuilderContext()); // Check if any of the EvalCall callbacks can evaluate the call. - for (const auto EvalCallChecker : EvalCallCheckers) { + for (const auto &EvalCallChecker : EvalCallCheckers) { // TODO: Support the situation when the call doesn't correspond // to any Expr. ProgramPoint L = ProgramPoint::getProgramPoint( @@ -697,7 +697,7 @@ void CheckerManager::runCheckersOnEndOfTranslationUnit( const TranslationUnitDecl *TU, AnalysisManager &mgr, BugReporter &BR) { - for (const auto EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers) + for (const auto &EndOfTranslationUnitChecker : EndOfTranslationUnitCheckers) EndOfTranslationUnitChecker(TU, mgr, BR); } @@ -904,6 +904,6 @@ CheckerManager::getCachedStmtCheckersFor(const Stmt *S, bool isPreVisit) { } CheckerManager::~CheckerManager() { - for (const auto CheckerDtor : CheckerDtors) + for (const auto &CheckerDtor : CheckerDtors) CheckerDtor(); } diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index e92e95354f5f..f917a4c8637b 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -728,7 +728,8 @@ void ExprEngine::removeDead(ExplodedNode *Pred, ExplodedNodeSet &Out, // Create a state in which dead bindings are removed from the environment // and the store. TODO: The function should just return new env and store, // not a new state. - CleanedState = StateMgr.removeDeadBindings(CleanedState, SFC, SymReaper); + CleanedState = StateMgr.removeDeadBindingsFromEnvironmentAndStore( + CleanedState, SFC, SymReaper); // Process any special transfer function for dead symbols. // A tag to track convenience transitions, which can be removed at cleanup. @@ -1171,13 +1172,16 @@ void ExprEngine::VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *BTE, } } -ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, SVal V, - PointerEscapeKind K) const { +ProgramStateRef ExprEngine::escapeValues(ProgramStateRef State, + ArrayRef<SVal> Vs, + PointerEscapeKind K, + const CallEvent *Call) const { class CollectReachableSymbolsCallback final : public SymbolVisitor { - InvalidatedSymbols Symbols; + InvalidatedSymbols &Symbols; public: - explicit CollectReachableSymbolsCallback(ProgramStateRef) {} + explicit CollectReachableSymbolsCallback(InvalidatedSymbols &Symbols) + : Symbols(Symbols) {} const InvalidatedSymbols &getSymbols() const { return Symbols; } @@ -1186,11 +1190,13 @@ ProgramStateRef ExprEngine::escapeValue(ProgramStateRef State, SVal V, return true; } }; + InvalidatedSymbols Symbols; + CollectReachableSymbolsCallback CallBack(Symbols); + for (SVal V : Vs) + State->scanReachableSymbols(V, CallBack); - const CollectReachableSymbolsCallback &Scanner = - State->scanReachableSymbols<CollectReachableSymbolsCallback>(V); return getCheckerManager().runCheckersForPointerEscape( - State, Scanner.getSymbols(), /*CallEvent*/ nullptr, K, nullptr); + State, CallBack.getSymbols(), Call, K, nullptr); } void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, @@ -1245,6 +1251,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OMPParallelForDirectiveClass: case Stmt::OMPParallelForSimdDirectiveClass: case Stmt::OMPParallelSectionsDirectiveClass: + case Stmt::OMPParallelMasterDirectiveClass: case Stmt::OMPTaskDirectiveClass: case Stmt::OMPTaskyieldDirectiveClass: case Stmt::OMPBarrierDirectiveClass: @@ -1268,6 +1275,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::OMPMasterTaskLoopDirectiveClass: case Stmt::OMPMasterTaskLoopSimdDirectiveClass: case Stmt::OMPParallelMasterTaskLoopDirectiveClass: + case Stmt::OMPParallelMasterTaskLoopSimdDirectiveClass: case Stmt::OMPDistributeDirectiveClass: case Stmt::OMPDistributeParallelForDirectiveClass: case Stmt::OMPDistributeParallelForSimdDirectiveClass: @@ -1313,6 +1321,11 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::WhileStmtClass: case Expr::MSDependentExistsStmtClass: llvm_unreachable("Stmt should not be in analyzer evaluation loop"); + case Stmt::ImplicitValueInitExprClass: + // These nodes are shared in the CFG and would case caching out. + // Moreover, no additional evaluation required for them, the + // analyzer can reconstruct these values from the AST. + llvm_unreachable("Should be pruned from CFG"); case Stmt::ObjCSubscriptRefExprClass: case Stmt::ObjCPropertyRefExprClass: @@ -1383,7 +1396,6 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, case Stmt::IntegerLiteralClass: case Stmt::FixedPointLiteralClass: case Stmt::CharacterLiteralClass: - case Stmt::ImplicitValueInitExprClass: case Stmt::CXXScalarValueInitExprClass: case Stmt::CXXBoolLiteralExprClass: case Stmt::ObjCBoolLiteralExprClass: @@ -1426,7 +1438,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, bool IsTemporary = false; if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(ArgE)) { - ArgE = MTE->GetTemporaryExpr(); + ArgE = MTE->getSubExpr(); IsTemporary = true; } @@ -1481,7 +1493,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred, for (auto Child : Ex->children()) { assert(Child); SVal Val = State->getSVal(Child, LCtx); - State = escapeValue(State, Val, PSK_EscapeOther); + State = escapeValues(State, Val, PSK_EscapeOther); } Bldr2.generateNode(S, N, State); @@ -2682,33 +2694,52 @@ void ExprEngine::VisitAtomicExpr(const AtomicExpr *AE, ExplodedNode *Pred, // destructor. We won't see the destructor during analysis, but it's there. // (4) We are binding to a MemRegion with stack storage that the store // does not understand. -ProgramStateRef -ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, - SVal Val, const LocationContext *LCtx) { +ProgramStateRef ExprEngine::processPointerEscapedOnBind( + ProgramStateRef State, ArrayRef<std::pair<SVal, SVal>> LocAndVals, + const LocationContext *LCtx, PointerEscapeKind Kind, + const CallEvent *Call) { + SmallVector<SVal, 8> Escaped; + for (const std::pair<SVal, SVal> &LocAndVal : LocAndVals) { + // Cases (1) and (2). + const MemRegion *MR = LocAndVal.first.getAsRegion(); + if (!MR || !MR->hasStackStorage()) { + Escaped.push_back(LocAndVal.second); + continue; + } + + // Case (3). + if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion())) + if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame()) + if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl()) + if (!RD->hasTrivialDestructor()) { + Escaped.push_back(LocAndVal.second); + continue; + } - // Cases (1) and (2). - const MemRegion *MR = Loc.getAsRegion(); - if (!MR || !MR->hasStackStorage()) - return escapeValue(State, Val, PSK_EscapeOnBind); + // Case (4): in order to test that, generate a new state with the binding + // added. If it is the same state, then it escapes (since the store cannot + // represent the binding). + // Do this only if we know that the store is not supposed to generate the + // same state. + SVal StoredVal = State->getSVal(MR); + if (StoredVal != LocAndVal.second) + if (State == + (State->bindLoc(loc::MemRegionVal(MR), LocAndVal.second, LCtx))) + Escaped.push_back(LocAndVal.second); + } - // Case (3). - if (const auto *VR = dyn_cast<VarRegion>(MR->getBaseRegion())) - if (VR->hasStackParametersStorage() && VR->getStackFrame()->inTopFrame()) - if (const auto *RD = VR->getValueType()->getAsCXXRecordDecl()) - if (!RD->hasTrivialDestructor()) - return escapeValue(State, Val, PSK_EscapeOnBind); + if (Escaped.empty()) + return State; - // Case (4): in order to test that, generate a new state with the binding - // added. If it is the same state, then it escapes (since the store cannot - // represent the binding). - // Do this only if we know that the store is not supposed to generate the - // same state. - SVal StoredVal = State->getSVal(MR); - if (StoredVal != Val) - if (State == (State->bindLoc(loc::MemRegionVal(MR), Val, LCtx))) - return escapeValue(State, Val, PSK_EscapeOnBind); + return escapeValues(State, Escaped, Kind, Call); +} - return State; +ProgramStateRef +ExprEngine::processPointerEscapedOnBind(ProgramStateRef State, SVal Loc, + SVal Val, const LocationContext *LCtx) { + std::pair<SVal, SVal> LocAndVal(Loc, Val); + return processPointerEscapedOnBind(State, LocAndVal, LCtx, PSK_EscapeOnBind, + nullptr); } ProgramStateRef diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 02a398c77ac8..b17f26aa9c53 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -102,8 +102,8 @@ void ExprEngine::VisitBinaryOperator(const BinaryOperator* B, state = state->BindExpr(B, LCtx, Result); } else { // If we cannot evaluate the operation escape the operands. - state = escapeValue(state, LeftV, PSK_EscapeOther); - state = escapeValue(state, RightV, PSK_EscapeOther); + state = escapeValues(state, LeftV, PSK_EscapeOther); + state = escapeValues(state, RightV, PSK_EscapeOther); } Bldr.generateNode(B, *it, state); @@ -275,7 +275,7 @@ ProgramStateRef ExprEngine::handleLValueBitCast( V = evalMinus(V); state = state->BindExpr(CastE, LCtx, V); if (V.isUnknown() && !OrigV.isUnknown()) { - state = escapeValue(state, OrigV, PSK_EscapeOther); + state = escapeValues(state, OrigV, PSK_EscapeOther); } Bldr.generateNode(CastE, Pred, state); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 058be985540d..b816aab7c18f 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -27,7 +27,7 @@ void ExprEngine::CreateCXXTemporaryObject(const MaterializeTemporaryExpr *ME, ExplodedNode *Pred, ExplodedNodeSet &Dst) { StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); - const Expr *tempExpr = ME->GetTemporaryExpr()->IgnoreParens(); + const Expr *tempExpr = ME->getSubExpr()->IgnoreParens(); ProgramStateRef state = Pred->getState(); const LocationContext *LCtx = Pred->getLocationContext(); diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 345d4d817dea..01a371e664b2 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/Decl.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" #include "PrettyStackTraceLocationContext.h" #include "clang/AST/CXXInheritance.h" @@ -592,9 +593,45 @@ void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred, for (auto I : dstCallEvaluated) finishArgumentConstruction(dstArgumentCleanup, I, Call); - // Finally, run any post-call checks. - getCheckerManager().runCheckersForPostCall(Dst, dstArgumentCleanup, + ExplodedNodeSet dstPostCall; + getCheckerManager().runCheckersForPostCall(dstPostCall, dstArgumentCleanup, Call, *this); + + // Escaping symbols conjured during invalidating the regions above. + // Note that, for inlined calls the nodes were put back into the worklist, + // so we can assume that every node belongs to a conservative call at this + // point. + + // Run pointerEscape callback with the newly conjured symbols. + SmallVector<std::pair<SVal, SVal>, 8> Escaped; + for (auto I : dstPostCall) { + NodeBuilder B(I, Dst, *currBldrCtx); + ProgramStateRef State = I->getState(); + Escaped.clear(); + { + unsigned Arg = -1; + for (const ParmVarDecl *PVD : Call.parameters()) { + ++Arg; + QualType ParamTy = PVD->getType(); + if (ParamTy.isNull() || + (!ParamTy->isPointerType() && !ParamTy->isReferenceType())) + continue; + QualType Pointee = ParamTy->getPointeeType(); + if (Pointee.isConstQualified() || Pointee->isVoidType()) + continue; + if (const MemRegion *MR = Call.getArgSVal(Arg).getAsRegion()) + Escaped.emplace_back(loc::MemRegionVal(MR), State->getSVal(MR, Pointee)); + } + } + + State = processPointerEscapedOnBind(State, Escaped, I->getLocationContext(), + PSK_EscapeOutParameters, &Call); + + if (State == I->getState()) + Dst.insert(I); + else + B.generateNode(I->getLocation(), State, I); + } } ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, @@ -670,8 +707,7 @@ ProgramStateRef ExprEngine::bindReturnValue(const CallEvent &Call, // Conservatively evaluate call by invalidating regions and binding // a conjured return value. void ExprEngine::conservativeEvalCall(const CallEvent &Call, NodeBuilder &Bldr, - ExplodedNode *Pred, - ProgramStateRef State) { + ExplodedNode *Pred, ProgramStateRef State) { State = Call.invalidateRegions(currBldrCtx->blockCount(), State); State = bindReturnValue(Call, Pred->getLocationContext(), State); diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index f50d82de3b28..14006f79fd0f 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -91,10 +91,9 @@ ProgramStateManager::~ProgramStateManager() { I->second.second(I->second.first); } -ProgramStateRef -ProgramStateManager::removeDeadBindings(ProgramStateRef state, - const StackFrameContext *LCtx, - SymbolReaper& SymReaper) { +ProgramStateRef ProgramStateManager::removeDeadBindingsFromEnvironmentAndStore( + ProgramStateRef state, const StackFrameContext *LCtx, + SymbolReaper &SymReaper) { // This code essentially performs a "mark-and-sweep" of the VariableBindings. // The roots are any Block-level exprs and Decls that our liveness algorithm @@ -112,8 +111,7 @@ ProgramStateManager::removeDeadBindings(ProgramStateRef state, NewState.setStore(newStore); SymReaper.setReapedStore(newStore); - ProgramStateRef Result = getPersistentState(NewState); - return ConstraintMgr->removeDeadBindings(Result, SymReaper); + return getPersistentState(NewState); } ProgramStateRef ProgramState::bindLoc(Loc LV, diff --git a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp index 5d2ef59e2d66..4797f564a837 100644 --- a/clang/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/clang/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -1951,7 +1951,8 @@ RegionStoreManager::getBindingForFieldOrElementCommon(RegionBindingsConstRef B, if (hasSymbolicIndex) return UnknownVal(); - if (!hasPartialLazyBinding) + // Additionally allow introspection of a block's internal layout. + if (!hasPartialLazyBinding && !isa<BlockDataRegion>(R->getBaseRegion())) return UndefinedVal(); } diff --git a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp index 190ab7e21dbc..12332aaf936f 100644 --- a/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp +++ b/clang/lib/StaticAnalyzer/Core/SarifDiagnostics.cpp @@ -17,6 +17,7 @@ #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/JSON.h" #include "llvm/Support/Path.h" @@ -27,10 +28,12 @@ using namespace ento; namespace { class SarifDiagnostics : public PathDiagnosticConsumer { std::string OutputFile; + const LangOptions &LO; public: - SarifDiagnostics(AnalyzerOptions &, const std::string &Output) - : OutputFile(Output) {} + SarifDiagnostics(AnalyzerOptions &, const std::string &Output, + const LangOptions &LO) + : OutputFile(Output), LO(LO) {} ~SarifDiagnostics() override = default; void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, @@ -45,9 +48,9 @@ public: void ento::createSarifDiagnosticConsumer( AnalyzerOptions &AnalyzerOpts, PathDiagnosticConsumers &C, - const std::string &Output, const Preprocessor &, + const std::string &Output, const Preprocessor &PP, const cross_tu::CrossTranslationUnitContext &) { - C.push_back(new SarifDiagnostics(AnalyzerOpts, Output)); + C.push_back(new SarifDiagnostics(AnalyzerOpts, Output, PP.getLangOpts())); } static StringRef getFileName(const FileEntry &FE) { @@ -142,26 +145,56 @@ static json::Object createArtifactLocation(const FileEntry &FE, return json::Object{{"uri", FileURI}, {"index", Index}}; } -static json::Object createTextRegion(SourceRange R, const SourceManager &SM) { +static unsigned int adjustColumnPos(const SourceManager &SM, SourceLocation Loc, + unsigned int TokenLen = 0) { + assert(!Loc.isInvalid() && "invalid Loc when adjusting column position"); + + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedExpansionLoc(Loc); + assert(LocInfo.second > SM.getExpansionColumnNumber(Loc) && + "position in file is before column number?"); + + bool InvalidBuffer = false; + const MemoryBuffer *Buf = SM.getBuffer(LocInfo.first, &InvalidBuffer); + assert(!InvalidBuffer && "got an invalid buffer for the location's file"); + assert(Buf->getBufferSize() >= (LocInfo.second + TokenLen) && + "token extends past end of buffer?"); + + // Adjust the offset to be the start of the line, since we'll be counting + // Unicode characters from there until our column offset. + unsigned int Off = LocInfo.second - (SM.getExpansionColumnNumber(Loc) - 1); + unsigned int Ret = 1; + while (Off < (LocInfo.second + TokenLen)) { + Off += getNumBytesForUTF8(Buf->getBuffer()[Off]); + Ret++; + } + + return Ret; +} + +static json::Object createTextRegion(const LangOptions &LO, SourceRange R, + const SourceManager &SM) { json::Object Region{ {"startLine", SM.getExpansionLineNumber(R.getBegin())}, - {"startColumn", SM.getExpansionColumnNumber(R.getBegin())}, + {"startColumn", adjustColumnPos(SM, R.getBegin())}, }; if (R.getBegin() == R.getEnd()) { - Region["endColumn"] = SM.getExpansionColumnNumber(R.getBegin()); + Region["endColumn"] = adjustColumnPos(SM, R.getBegin()); } else { Region["endLine"] = SM.getExpansionLineNumber(R.getEnd()); - Region["endColumn"] = SM.getExpansionColumnNumber(R.getEnd()) + 1; + Region["endColumn"] = adjustColumnPos( + SM, R.getEnd(), + Lexer::MeasureTokenLength(R.getEnd(), SM, LO)); } return Region; } -static json::Object createPhysicalLocation(SourceRange R, const FileEntry &FE, +static json::Object createPhysicalLocation(const LangOptions &LO, + SourceRange R, const FileEntry &FE, const SourceManager &SMgr, json::Array &Artifacts) { return json::Object{ {{"artifactLocation", createArtifactLocation(FE, Artifacts)}, - {"region", createTextRegion(R, SMgr)}}}; + {"region", createTextRegion(LO, R, SMgr)}}}; } enum class Importance { Important, Essential, Unimportant }; @@ -213,7 +246,8 @@ static Importance calculateImportance(const PathDiagnosticPiece &Piece) { return Importance::Unimportant; } -static json::Object createThreadFlow(const PathPieces &Pieces, +static json::Object createThreadFlow(const LangOptions &LO, + const PathPieces &Pieces, json::Array &Artifacts) { const SourceManager &SMgr = Pieces.front()->getLocation().getManager(); json::Array Locations; @@ -221,7 +255,7 @@ static json::Object createThreadFlow(const PathPieces &Pieces, const PathDiagnosticLocation &P = Piece->getLocation(); Locations.push_back(createThreadFlowLocation( createLocation(createPhysicalLocation( - P.asRange(), + LO, P.asRange(), *P.asLocation().getExpansionLoc().getFileEntry(), SMgr, Artifacts), Piece->getString()), @@ -230,13 +264,15 @@ static json::Object createThreadFlow(const PathPieces &Pieces, return json::Object{{"locations", std::move(Locations)}}; } -static json::Object createCodeFlow(const PathPieces &Pieces, +static json::Object createCodeFlow(const LangOptions &LO, + const PathPieces &Pieces, json::Array &Artifacts) { return json::Object{ - {"threadFlows", json::Array{createThreadFlow(Pieces, Artifacts)}}}; + {"threadFlows", json::Array{createThreadFlow(LO, Pieces, Artifacts)}}}; } -static json::Object createResult(const PathDiagnostic &Diag, +static json::Object createResult(const LangOptions &LO, + const PathDiagnostic &Diag, json::Array &Artifacts, const StringMap<unsigned> &RuleMapping) { const PathPieces &Path = Diag.path.flatten(false); @@ -247,10 +283,10 @@ static json::Object createResult(const PathDiagnostic &Diag, return json::Object{ {"message", createMessage(Diag.getVerboseDescription())}, - {"codeFlows", json::Array{createCodeFlow(Path, Artifacts)}}, + {"codeFlows", json::Array{createCodeFlow(LO, Path, Artifacts)}}, {"locations", json::Array{createLocation(createPhysicalLocation( - Diag.getLocation().asRange(), + LO, Diag.getLocation().asRange(), *Diag.getLocation().asLocation().getExpansionLoc().getFileEntry(), SMgr, Artifacts))}}, {"ruleIndex", Iter->getValue()}, @@ -320,18 +356,20 @@ static json::Object createTool(std::vector<const PathDiagnostic *> &Diags, {"rules", createRules(Diags, RuleMapping)}}}}; } -static json::Object createRun(std::vector<const PathDiagnostic *> &Diags) { +static json::Object createRun(const LangOptions &LO, + std::vector<const PathDiagnostic *> &Diags) { json::Array Results, Artifacts; StringMap<unsigned> RuleMapping; json::Object Tool = createTool(Diags, RuleMapping); llvm::for_each(Diags, [&](const PathDiagnostic *D) { - Results.push_back(createResult(*D, Artifacts, RuleMapping)); + Results.push_back(createResult(LO, *D, Artifacts, RuleMapping)); }); return json::Object{{"tool", std::move(Tool)}, {"results", std::move(Results)}, - {"artifacts", std::move(Artifacts)}}; + {"artifacts", std::move(Artifacts)}, + {"columnKind", "unicodeCodePoints"}}; } void SarifDiagnostics::FlushDiagnosticsImpl( @@ -351,6 +389,6 @@ void SarifDiagnostics::FlushDiagnosticsImpl( {"$schema", "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json"}, {"version", "2.1.0"}, - {"runs", json::Array{createRun(Diags)}}}; + {"runs", json::Array{createRun(LO, Diags)}}}; OS << llvm::formatv("{0:2}\n", json::Value(std::move(Sarif))); } diff --git a/clang/lib/StaticAnalyzer/Core/Store.cpp b/clang/lib/StaticAnalyzer/Core/Store.cpp index b4ab6877726c..b33129c88cea 100644 --- a/clang/lib/StaticAnalyzer/Core/Store.cpp +++ b/clang/lib/StaticAnalyzer/Core/Store.cpp @@ -393,6 +393,11 @@ SVal StoreManager::attemptDownCast(SVal Base, QualType TargetType, return UnknownVal(); } +static bool hasSameUnqualifiedPointeeType(QualType ty1, QualType ty2) { + return ty1->getPointeeType().getCanonicalType().getTypePtr() == + ty2->getPointeeType().getCanonicalType().getTypePtr(); +} + /// CastRetrievedVal - Used by subclasses of StoreManager to implement /// implicit casts that arise from loads from regions that are reinterpreted /// as another region. @@ -421,10 +426,11 @@ SVal StoreManager::CastRetrievedVal(SVal V, const TypedValueRegion *R, // FIXME: We really need a single good function to perform casts for us // correctly every time we need it. if (castTy->isPointerType() && !castTy->isVoidPointerType()) - if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(V.getAsRegion())) - if (SR->getSymbol()->getType().getCanonicalType() != - castTy.getCanonicalType()) - return loc::MemRegionVal(castRegion(SR, castTy)); + if (const auto *SR = dyn_cast_or_null<SymbolicRegion>(V.getAsRegion())) { + QualType sr = SR->getSymbol()->getType(); + if (!hasSameUnqualifiedPointeeType(sr, castTy)) + return loc::MemRegionVal(castRegion(SR, castTy)); + } return svalBuilder.dispatchCast(V, castTy); } diff --git a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp index 8236907ea773..fea8100c3b3b 100644 --- a/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -722,13 +722,6 @@ std::string AnalysisConsumer::getFunctionName(const Decl *D) { } else if (const auto *OCD = dyn_cast<ObjCCategoryImplDecl>(DC)) { OS << OCD->getClassInterface()->getName() << '(' << OCD->getName() << ')'; - } else if (isa<ObjCProtocolDecl>(DC)) { - // We can extract the type of the class from the self pointer. - if (ImplicitParamDecl *SelfDecl = OMD->getSelfDecl()) { - QualType ClassTy = - cast<ObjCObjectPointerType>(SelfDecl->getType())->getPointeeType(); - ClassTy.print(OS, PrintingPolicy(LangOptions())); - } } OS << ' ' << OMD->getSelector().getAsString() << ']'; diff --git a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp index e00fd976f6b8..f5c05281adab 100644 --- a/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/CheckerRegistry.cpp @@ -591,7 +591,8 @@ void CheckerRegistry::printCheckerOptionList(raw_ostream &Out) const { /*MinLineWidth*/ 90); Out << "\n\n"; }; - for (const std::pair<StringRef, const CmdLineOption &> &Entry : OptionMap) { + for (const std::pair<const StringRef, const CmdLineOption &> &Entry : + OptionMap) { const CmdLineOption &Option = Entry.second; std::string FullOption = (Entry.first + ":" + Option.OptionName).str(); diff --git a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp index 687fda75db48..7baae6778ebd 100644 --- a/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp +++ b/clang/lib/StaticAnalyzer/Frontend/ModelInjector.cpp @@ -11,6 +11,7 @@ #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LangStandard.h" #include "clang/Basic/Stack.h" +#include "clang/AST/DeclObjC.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendAction.h" diff --git a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp index 00db7702cd8b..4d495228cb51 100644 --- a/clang/lib/Tooling/ASTDiff/ASTDiff.cpp +++ b/clang/lib/Tooling/ASTDiff/ASTDiff.cpp @@ -787,7 +787,7 @@ void ASTDiff::Impl::addOptimalMapping(Mapping &M, NodeId Id1, return; ZhangShashaMatcher Matcher(*this, T1, T2, Id1, Id2); std::vector<std::pair<NodeId, NodeId>> R = Matcher.getMatchingNodes(); - for (const auto Tuple : R) { + for (const auto &Tuple : R) { NodeId Src = Tuple.first; NodeId Dst = Tuple.second; if (!M.hasSrc(Src) && !M.hasDst(Dst)) diff --git a/clang/lib/Tooling/ArgumentsAdjusters.cpp b/clang/lib/Tooling/ArgumentsAdjusters.cpp index f56d08c47b9a..a609e4ed2469 100644 --- a/clang/lib/Tooling/ArgumentsAdjusters.cpp +++ b/clang/lib/Tooling/ArgumentsAdjusters.cpp @@ -13,20 +13,32 @@ #include "clang/Tooling/ArgumentsAdjusters.h" #include "clang/Basic/LLVM.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringRef.h" #include <cstddef> +#include <vector> namespace clang { namespace tooling { -/// Add -fsyntax-only option to the command line arguments. +/// Add -fsyntax-only option and drop options that triggers output generation. ArgumentsAdjuster getClangSyntaxOnlyAdjuster() { return [](const CommandLineArguments &Args, StringRef /*unused*/) { CommandLineArguments AdjustedArgs; bool HasSyntaxOnly = false; + const std::vector<llvm::StringRef> OutputCommands = { + // FIXME: Add other options that generate output. + "-save-temps", + "--save-temps", + }; for (size_t i = 0, e = Args.size(); i < e; ++i) { StringRef Arg = Args[i]; - // FIXME: Remove options that generate output. + // Skip output commands. + if (llvm::any_of(OutputCommands, [&Arg](llvm::StringRef OutputCommand) { + return Arg.startswith(OutputCommand); + })) + continue; + if (!Arg.startswith("-fcolor-diagnostics") && !Arg.startswith("-fdiagnostics-color")) AdjustedArgs.push_back(Args[i]); diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp index 7436c7256327..b4d5a29ca695 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp @@ -122,6 +122,32 @@ DependencyScanningFilesystemSharedCache::get(StringRef Key) { return It.first->getValue(); } +/// Whitelist file extensions that should be minimized, treating no extension as +/// a source file that should be minimized. +/// +/// This is kinda hacky, it would be better if we knew what kind of file Clang +/// was expecting instead. +static bool shouldMinimize(StringRef Filename) { + StringRef Ext = llvm::sys::path::extension(Filename); + if (Ext.empty()) + return true; // C++ standard library + return llvm::StringSwitch<bool>(Ext) + .CasesLower(".c", ".cc", ".cpp", ".c++", ".cxx", true) + .CasesLower(".h", ".hh", ".hpp", ".h++", ".hxx", true) + .CasesLower(".m", ".mm", true) + .CasesLower(".i", ".ii", ".mi", ".mmi", true) + .CasesLower(".def", ".inc", true) + .Default(false); +} + + +static bool shouldCacheStatFailures(StringRef Filename) { + StringRef Ext = llvm::sys::path::extension(Filename); + if (Ext.empty()) + return false; // This may be the module cache directory. + return shouldMinimize(Filename); // Only cache stat failures on source files. +} + llvm::ErrorOr<const CachedFileSystemEntry *> DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry( const StringRef Filename) { @@ -132,7 +158,8 @@ DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry( // FIXME: Handle PCM/PCH files. // FIXME: Handle module map files. - bool KeepOriginalSource = IgnoredFiles.count(Filename); + bool KeepOriginalSource = IgnoredFiles.count(Filename) || + !shouldMinimize(Filename); DependencyScanningFilesystemSharedCache::SharedFileSystemEntry &SharedCacheEntry = SharedCache.get(Filename); const CachedFileSystemEntry *Result; @@ -143,9 +170,16 @@ DependencyScanningWorkerFilesystem::getOrCreateFileSystemEntry( if (!CacheEntry.isValid()) { llvm::vfs::FileSystem &FS = getUnderlyingFS(); auto MaybeStatus = FS.status(Filename); - if (!MaybeStatus) - CacheEntry = CachedFileSystemEntry(MaybeStatus.getError()); - else if (MaybeStatus->isDirectory()) + if (!MaybeStatus) { + if (!shouldCacheStatFailures(Filename)) + // HACK: We need to always restat non source files if the stat fails. + // This is because Clang first looks up the module cache and module + // files before building them, and then looks for them again. If we + // cache the stat failure, it won't see them the second time. + return MaybeStatus.getError(); + else + CacheEntry = CachedFileSystemEntry(MaybeStatus.getError()); + } else if (MaybeStatus->isDirectory()) CacheEntry = CachedFileSystemEntry::createDirectoryEntry( std::move(*MaybeStatus)); else diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp index e5cebe381000..93bb0cde439d 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp @@ -12,8 +12,8 @@ using namespace clang; using namespace tooling; using namespace dependencies; -DependencyScanningService::DependencyScanningService(ScanningMode Mode, - bool ReuseFileManager, - bool SkipExcludedPPRanges) - : Mode(Mode), ReuseFileManager(ReuseFileManager), +DependencyScanningService::DependencyScanningService( + ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager, + bool SkipExcludedPPRanges) + : Mode(Mode), Format(Format), ReuseFileManager(ReuseFileManager), SkipExcludedPPRanges(SkipExcludedPPRanges) {} diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp index 82b3ae806c65..f643c538f8f9 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @@ -1,4 +1,4 @@ -//===- DependencyScanningTool.cpp - clang-scan-deps service ------------===// +//===- DependencyScanningTool.cpp - clang-scan-deps service ---------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,18 +8,29 @@ #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" #include "clang/Frontend/Utils.h" +#include "llvm/Support/JSON.h" + +static llvm::json::Array toJSONSorted(const llvm::StringSet<> &Set) { + std::vector<llvm::StringRef> Strings; + for (auto &&I : Set) + Strings.push_back(I.getKey()); + std::sort(Strings.begin(), Strings.end()); + return llvm::json::Array(Strings); +} namespace clang{ namespace tooling{ namespace dependencies{ -DependencyScanningTool::DependencyScanningTool(DependencyScanningService &Service, -const tooling::CompilationDatabase &Compilations) : Worker(Service), Compilations(Compilations) {} +DependencyScanningTool::DependencyScanningTool( + DependencyScanningService &Service) + : Format(Service.getFormat()), Worker(Service) { +} -llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(const std::string &Input, - StringRef CWD) { +llvm::Expected<std::string> DependencyScanningTool::getDependencyFile( + const tooling::CompilationDatabase &Compilations, StringRef CWD) { /// Prints out all of the gathered dependencies into a string. - class DependencyPrinterConsumer : public DependencyConsumer { + class MakeDependencyPrinterConsumer : public DependencyConsumer { public: void handleFileDependency(const DependencyOutputOptions &Opts, StringRef File) override { @@ -28,6 +39,14 @@ llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(const std: Dependencies.push_back(File); } + void handleModuleDependency(ModuleDeps MD) override { + // These are ignored for the make format as it can't support the full + // set of deps, and handleFileDependency handles enough for implicitly + // built modules to work. + } + + void handleContextHash(std::string Hash) override {} + void printDependencies(std::string &S) { if (!Opts) return; @@ -56,14 +75,98 @@ llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(const std: std::vector<std::string> Dependencies; }; - DependencyPrinterConsumer Consumer; - auto Result = - Worker.computeDependencies(Input, CWD, Compilations, Consumer); - if (Result) - return std::move(Result); - std::string Output; - Consumer.printDependencies(Output); - return Output; + class FullDependencyPrinterConsumer : public DependencyConsumer { + public: + void handleFileDependency(const DependencyOutputOptions &Opts, + StringRef File) override { + Dependencies.push_back(File); + } + + void handleModuleDependency(ModuleDeps MD) override { + ClangModuleDeps[MD.ContextHash + MD.ModuleName] = std::move(MD); + } + + void handleContextHash(std::string Hash) override { + ContextHash = std::move(Hash); + } + + void printDependencies(std::string &S, StringRef MainFile) { + // Sort the modules by name to get a deterministic order. + std::vector<StringRef> Modules; + for (auto &&Dep : ClangModuleDeps) + Modules.push_back(Dep.first); + std::sort(Modules.begin(), Modules.end()); + + llvm::raw_string_ostream OS(S); + + using namespace llvm::json; + + Array Imports; + for (auto &&ModName : Modules) { + auto &MD = ClangModuleDeps[ModName]; + if (MD.ImportedByMainFile) + Imports.push_back(MD.ModuleName); + } + + Array Mods; + for (auto &&ModName : Modules) { + auto &MD = ClangModuleDeps[ModName]; + Object Mod{ + {"name", MD.ModuleName}, + {"file-deps", toJSONSorted(MD.FileDeps)}, + {"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)}, + {"clang-modulemap-file", MD.ClangModuleMapFile}, + }; + Mods.push_back(std::move(Mod)); + } + + Object O{ + {"input-file", MainFile}, + {"clang-context-hash", ContextHash}, + {"file-deps", Dependencies}, + {"clang-module-deps", std::move(Imports)}, + {"clang-modules", std::move(Mods)}, + }; + + S = llvm::formatv("{0:2},\n", Value(std::move(O))).str(); + return; + } + + private: + std::vector<std::string> Dependencies; + std::unordered_map<std::string, ModuleDeps> ClangModuleDeps; + std::string ContextHash; + }; + + + // We expect a single command here because if a source file occurs multiple + // times in the original CDB, then `computeDependencies` would run the + // `DependencyScanningAction` once for every time the input occured in the + // CDB. Instead we split up the CDB into single command chunks to avoid this + // behavior. + assert(Compilations.getAllCompileCommands().size() == 1 && + "Expected a compilation database with a single command!"); + std::string Input = Compilations.getAllCompileCommands().front().Filename; + + if (Format == ScanningOutputFormat::Make) { + MakeDependencyPrinterConsumer Consumer; + auto Result = + Worker.computeDependencies(Input, CWD, Compilations, Consumer); + if (Result) + return std::move(Result); + std::string Output; + Consumer.printDependencies(Output); + return Output; + } else { + FullDependencyPrinterConsumer Consumer; + auto Result = + Worker.computeDependencies(Input, CWD, Compilations, Consumer); + if (Result) + return std::move(Result); + std::string Output; + Consumer.printDependencies(Output, Input); + return Output; + } } } // end namespace dependencies diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index f382c202f8c2..edf2cf8bd70f 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -14,6 +14,7 @@ #include "clang/Frontend/Utils.h" #include "clang/Lex/PreprocessorOptions.h" #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" +#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" #include "clang/Tooling/Tooling.h" using namespace clang; @@ -72,9 +73,11 @@ public: DependencyScanningAction( StringRef WorkingDirectory, DependencyConsumer &Consumer, llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS, - ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings) + ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings, + ScanningOutputFormat Format) : WorkingDirectory(WorkingDirectory), Consumer(Consumer), - DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings) {} + DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), + Format(Format) {} bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, FileManager *FileMgr, @@ -131,9 +134,20 @@ public: // We need at least one -MT equivalent for the generator to work. if (Opts->Targets.empty()) Opts->Targets = {"clang-scan-deps dependency"}; - Compiler.addDependencyCollector( - std::make_shared<DependencyConsumerForwarder>(std::move(Opts), - Consumer)); + + switch (Format) { + case ScanningOutputFormat::Make: + Compiler.addDependencyCollector( + std::make_shared<DependencyConsumerForwarder>(std::move(Opts), + Consumer)); + break; + case ScanningOutputFormat::Full: + Compiler.addDependencyCollector( + std::make_shared<ModuleDepCollector>(Compiler, Consumer)); + break; + } + + Consumer.handleContextHash(Compiler.getInvocation().getModuleHash()); auto Action = std::make_unique<PreprocessOnlyAction>(); const bool Result = Compiler.ExecuteAction(*Action); @@ -147,12 +161,14 @@ private: DependencyConsumer &Consumer; llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS; ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings; + ScanningOutputFormat Format; }; } // end anonymous namespace DependencyScanningWorker::DependencyScanningWorker( - DependencyScanningService &Service) { + DependencyScanningService &Service) + : Format(Service.getFormat()) { DiagOpts = new DiagnosticOptions(); PCHContainerOps = std::make_shared<PCHContainerOperations>(); RealFS = new ProxyFileSystemWithoutChdir(llvm::vfs::getRealFileSystem()); @@ -195,7 +211,7 @@ llvm::Error DependencyScanningWorker::computeDependencies( Tool.setPrintErrorMessage(false); Tool.setDiagnosticConsumer(&DC); DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS, - PPSkipMappings.get()); + PPSkipMappings.get(), Format); return !Tool.run(&Action); }); } diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp new file mode 100644 index 000000000000..422940047f2d --- /dev/null +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -0,0 +1,135 @@ +//===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" + +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" + +using namespace clang; +using namespace tooling; +using namespace dependencies; + +void ModuleDepCollectorPP::FileChanged(SourceLocation Loc, + FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) { + if (Reason != PPCallbacks::EnterFile) + return; + + SourceManager &SM = Instance.getSourceManager(); + + // Dependency generation really does want to go all the way to the + // file entry for a source location to find out what is depended on. + // We do not want #line markers to affect dependency generation! + Optional<FileEntryRef> File = + SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(Loc))); + if (!File) + return; + + StringRef FileName = + llvm::sys::path::remove_leading_dotslash(File->getName()); + + MDC.MainDeps.push_back(FileName); +} + +void ModuleDepCollectorPP::InclusionDirective( + SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, + bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, const Module *Imported, + SrcMgr::CharacteristicKind FileType) { + if (!File && !Imported) { + // This is a non-modular include that HeaderSearch failed to find. Add it + // here as `FileChanged` will never see it. + MDC.MainDeps.push_back(FileName); + } + + if (!Imported) + return; + + MDC.Deps[MDC.ContextHash + Imported->getTopLevelModule()->getFullModuleName()] + .ImportedByMainFile = true; + DirectDeps.insert(Imported->getTopLevelModule()); +} + +void ModuleDepCollectorPP::EndOfMainFile() { + FileID MainFileID = Instance.getSourceManager().getMainFileID(); + MDC.MainFile = + Instance.getSourceManager().getFileEntryForID(MainFileID)->getName(); + + for (const Module *M : DirectDeps) { + handleTopLevelModule(M); + } + + for (auto &&I : MDC.Deps) + MDC.Consumer.handleModuleDependency(I.second); + + DependencyOutputOptions Opts; + for (auto &&I : MDC.MainDeps) + MDC.Consumer.handleFileDependency(Opts, I); +} + +void ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { + assert(M == M->getTopLevelModule() && "Expected top level module!"); + + auto ModI = MDC.Deps.insert( + std::make_pair(MDC.ContextHash + M->getFullModuleName(), ModuleDeps{})); + + if (!ModI.first->second.ModuleName.empty()) + return; + + ModuleDeps &MD = ModI.first->second; + + const FileEntry *ModuleMap = Instance.getPreprocessor() + .getHeaderSearchInfo() + .getModuleMap() + .getContainingModuleMapFile(M); + + MD.ClangModuleMapFile = ModuleMap ? ModuleMap->getName() : ""; + MD.ModuleName = M->getFullModuleName(); + MD.ModulePCMPath = M->getASTFile()->getName(); + MD.ContextHash = MDC.ContextHash; + serialization::ModuleFile *MF = + MDC.Instance.getASTReader()->getModuleManager().lookup(M->getASTFile()); + MDC.Instance.getASTReader()->visitInputFiles( + *MF, true, true, [&](const serialization::InputFile &IF, bool isSystem) { + MD.FileDeps.insert(IF.getFile()->getName()); + }); + + addAllSubmoduleDeps(M, MD); +} + +void ModuleDepCollectorPP::addAllSubmoduleDeps(const Module *M, + ModuleDeps &MD) { + addModuleDep(M, MD); + + for (const Module *SubM : M->submodules()) + addAllSubmoduleDeps(SubM, MD); +} + +void ModuleDepCollectorPP::addModuleDep(const Module *M, ModuleDeps &MD) { + for (const Module *Import : M->Imports) { + if (Import->getTopLevelModule() != M->getTopLevelModule()) { + MD.ClangModuleDeps.insert(Import->getTopLevelModuleName()); + handleTopLevelModule(Import->getTopLevelModule()); + } + } +} + +ModuleDepCollector::ModuleDepCollector(CompilerInstance &I, + DependencyConsumer &C) + : Instance(I), Consumer(C), ContextHash(I.getInvocation().getModuleHash()) { +} + +void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { + PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(Instance, *this)); +} + +void ModuleDepCollector::attachToASTReader(ASTReader &R) {} diff --git a/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp new file mode 100644 index 000000000000..99298316718b --- /dev/null +++ b/clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp @@ -0,0 +1,90 @@ +//===- ExpandResponseFileCompilationDataBase.cpp --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Tooling/CompilationDatabase.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/StringSaver.h" + +namespace clang { +namespace tooling { +namespace { + +class ExpandResponseFilesDatabase : public CompilationDatabase { +public: + ExpandResponseFilesDatabase( + std::unique_ptr<CompilationDatabase> Base, + llvm::cl::TokenizerCallback Tokenizer, + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) + : Base(std::move(Base)), Tokenizer(Tokenizer), FS(std::move(FS)) { + assert(this->Base != nullptr); + assert(this->Tokenizer != nullptr); + assert(this->FS != nullptr); + } + + std::vector<std::string> getAllFiles() const override { + return Base->getAllFiles(); + } + + std::vector<CompileCommand> + getCompileCommands(StringRef FilePath) const override { + return expand(Base->getCompileCommands(FilePath)); + } + + std::vector<CompileCommand> getAllCompileCommands() const override { + return expand(Base->getAllCompileCommands()); + } + +private: + std::vector<CompileCommand> expand(std::vector<CompileCommand> Cmds) const { + for (auto &Cmd : Cmds) { + bool SeenRSPFile = false; + llvm::SmallVector<const char *, 20> Argv; + Argv.reserve(Cmd.CommandLine.size()); + for (auto &Arg : Cmd.CommandLine) { + Argv.push_back(Arg.c_str()); + SeenRSPFile |= Arg.front() == '@'; + } + if (!SeenRSPFile) + continue; + llvm::BumpPtrAllocator Alloc; + llvm::StringSaver Saver(Alloc); + llvm::cl::ExpandResponseFiles(Saver, Tokenizer, Argv, false, false, *FS, + llvm::StringRef(Cmd.Directory)); + // Don't assign directly, Argv aliases CommandLine. + std::vector<std::string> ExpandedArgv(Argv.begin(), Argv.end()); + Cmd.CommandLine = std::move(ExpandedArgv); + } + return Cmds; + } + +private: + std::unique_ptr<CompilationDatabase> Base; + llvm::cl::TokenizerCallback Tokenizer; + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS; +}; + +} // namespace + +std::unique_ptr<CompilationDatabase> +expandResponseFiles(std::unique_ptr<CompilationDatabase> Base, + llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS) { + auto Tokenizer = llvm::Triple(llvm::sys::getProcessTriple()).isOSWindows() + ? llvm::cl::TokenizeWindowsCommandLine + : llvm::cl::TokenizeGNUCommandLine; + return std::make_unique<ExpandResponseFilesDatabase>( + std::move(Base), Tokenizer, std::move(FS)); +} + +} // namespace tooling +} // namespace clang diff --git a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp index e746bbb7f87b..37a0816c803e 100644 --- a/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp +++ b/clang/lib/Tooling/Inclusions/HeaderIncludes.cpp @@ -184,6 +184,10 @@ IncludeCategoryManager::IncludeCategoryManager(const IncludeStyle &Style, FileName.endswith(".cpp") || FileName.endswith(".c++") || FileName.endswith(".cxx") || FileName.endswith(".m") || FileName.endswith(".mm"); + if (!Style.IncludeIsMainSourceRegex.empty()) { + llvm::Regex MainFileRegex(Style.IncludeIsMainSourceRegex); + IsMainFile |= MainFileRegex.match(FileName); + } } int IncludeCategoryManager::getIncludePriority(StringRef IncludeName, @@ -364,6 +368,5 @@ tooling::Replacements HeaderIncludes::remove(llvm::StringRef IncludeName, return Result; } - } // namespace tooling } // namespace clang diff --git a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp index 59b66abe65e9..2cc819a498c6 100644 --- a/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp +++ b/clang/lib/Tooling/InterpolatingCompilationDatabase.cpp @@ -191,7 +191,8 @@ struct TransferableCommand { OldArgs.data() + OldPos, OldArgs.data() + Pos); } - if (Std != LangStandard::lang_unspecified) // -std take precedence over -x + // Make use of -std iff -x was missing. + if (Type == types::TY_INVALID && Std != LangStandard::lang_unspecified) Type = toType(LangStandard::getLangStandardForKind(Std).getLanguage()); Type = foldType(*Type); // The contract is to store None instead of TY_INVALID. diff --git a/clang/lib/Tooling/JSONCompilationDatabase.cpp b/clang/lib/Tooling/JSONCompilationDatabase.cpp index f19a0f7550b9..04dd4dbf6248 100644 --- a/clang/lib/Tooling/JSONCompilationDatabase.cpp +++ b/clang/lib/Tooling/JSONCompilationDatabase.cpp @@ -29,6 +29,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/StringSaver.h" +#include "llvm/Support/VirtualFileSystem.h" #include "llvm/Support/YAMLParser.h" #include "llvm/Support/raw_ostream.h" #include <cassert> @@ -168,7 +169,8 @@ class JSONCompilationDatabasePlugin : public CompilationDatabasePlugin { auto Base = JSONCompilationDatabase::loadFromFile( JSONDatabasePath, ErrorMessage, JSONCommandLineSyntax::AutoDetect); return Base ? inferTargetAndDriverMode( - inferMissingCompileCommands(std::move(Base))) + inferMissingCompileCommands(expandResponseFiles( + std::move(Base), llvm::vfs::getRealFileSystem()))) : nullptr; } }; diff --git a/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp b/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp index 7dfd3988d904..70a4df07ea67 100644 --- a/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp +++ b/clang/lib/Tooling/Refactoring/ASTSelectionRequirements.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h" +#include "clang/AST/Attr.h" using namespace clang; using namespace tooling; diff --git a/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp b/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp index e26248f50c29..d966a5ef23c2 100644 --- a/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp +++ b/clang/lib/Tooling/Refactoring/Rename/USRFindingAction.cpp @@ -39,6 +39,8 @@ namespace clang { namespace tooling { const NamedDecl *getCanonicalSymbolDeclaration(const NamedDecl *FoundDecl) { + if (!FoundDecl) + return nullptr; // If FoundDecl is a constructor or destructor, we want to instead take // the Decl of the corresponding class. if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FoundDecl)) @@ -65,7 +67,7 @@ public: std::vector<std::string> Find() { // Fill OverriddenMethods and PartialSpecs storages. - TraverseDecl(Context.getTranslationUnitDecl()); + TraverseAST(Context); if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(FoundDecl)) { addUSRsOfOverridenFunctions(MethodDecl); for (const auto &OverriddenMethod : OverriddenMethods) { diff --git a/clang/lib/Tooling/Syntax/BuildTree.cpp b/clang/lib/Tooling/Syntax/BuildTree.cpp index a0b653df133d..aa8844771d37 100644 --- a/clang/lib/Tooling/Syntax/BuildTree.cpp +++ b/clang/lib/Tooling/Syntax/BuildTree.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// #include "clang/Tooling/Syntax/BuildTree.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Stmt.h" #include "clang/Basic/LLVM.h" @@ -21,12 +23,17 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include <map> using namespace clang; +LLVM_ATTRIBUTE_UNUSED +static bool isImplicitExpr(clang::Expr *E) { return E->IgnoreImplicit() != E; } + /// A helper class for constructing the syntax tree while traversing a clang /// AST. /// @@ -44,7 +51,10 @@ using namespace clang; /// Call finalize() to finish building the tree and consume the root node. class syntax::TreeBuilder { public: - TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) {} + TreeBuilder(syntax::Arena &Arena) : Arena(Arena), Pending(Arena) { + for (const auto &T : Arena.tokenBuffer().expandedTokens()) + LocationToToken.insert({T.location().getRawEncoding(), &T}); + } llvm::BumpPtrAllocator &allocator() { return Arena.allocator(); } @@ -52,8 +62,25 @@ public: /// Range. void foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New); + /// Must be called with the range of each `DeclaratorDecl`. Ensures the + /// corresponding declarator nodes are covered by `SimpleDeclaration`. + void noticeDeclaratorRange(llvm::ArrayRef<syntax::Token> Range); + + /// Notifies that we should not consume trailing semicolon when computing + /// token range of \p D. + void noticeDeclaratorWithoutSemicolon(Decl *D); + + /// Mark the \p Child node with a corresponding \p Role. All marked children + /// should be consumed by foldNode. + /// (!) when called on expressions (clang::Expr is derived from clang::Stmt), + /// wraps expressions into expression statement. + void markStmtChild(Stmt *Child, NodeRole Role); + /// Should be called for expressions in non-statement position to avoid + /// wrapping into expression statement. + void markExprChild(Expr *Child, NodeRole Role); + /// Set role for a token starting at \p Loc. - void markChildToken(SourceLocation Loc, tok::TokenKind Kind, NodeRole R); + void markChildToken(SourceLocation Loc, NodeRole R); /// Finish building the tree and consume the root node. syntax::TranslationUnit *finalize() && { @@ -62,10 +89,12 @@ public: assert(Tokens.back().kind() == tok::eof); // Build the root of the tree, consuming all the children. - Pending.foldChildren(Tokens.drop_back(), + Pending.foldChildren(Arena, Tokens.drop_back(), new (Arena.allocator()) syntax::TranslationUnit); - return cast<syntax::TranslationUnit>(std::move(Pending).finalize()); + auto *TU = cast<syntax::TranslationUnit>(std::move(Pending).finalize()); + TU->assertInvariantsRecursive(); + return TU; } /// getRange() finds the syntax tokens corresponding to the passed source @@ -81,13 +110,43 @@ public: return llvm::makeArrayRef(findToken(First), std::next(findToken(Last))); } llvm::ArrayRef<syntax::Token> getRange(const Decl *D) const { - return getRange(D->getBeginLoc(), D->getEndLoc()); + auto Tokens = getRange(D->getBeginLoc(), D->getEndLoc()); + if (llvm::isa<NamespaceDecl>(D)) + return Tokens; + if (DeclsWithoutSemicolons.count(D)) + return Tokens; + // FIXME: do not consume trailing semicolon on function definitions. + // Most declarations own a semicolon in syntax trees, but not in clang AST. + return withTrailingSemicolon(Tokens); } - llvm::ArrayRef<syntax::Token> getRange(const Stmt *S) const { - return getRange(S->getBeginLoc(), S->getEndLoc()); + llvm::ArrayRef<syntax::Token> getExprRange(const Expr *E) const { + return getRange(E->getBeginLoc(), E->getEndLoc()); + } + /// Find the adjusted range for the statement, consuming the trailing + /// semicolon when needed. + llvm::ArrayRef<syntax::Token> getStmtRange(const Stmt *S) const { + auto Tokens = getRange(S->getBeginLoc(), S->getEndLoc()); + if (isa<CompoundStmt>(S)) + return Tokens; + + // Some statements miss a trailing semicolon, e.g. 'return', 'continue' and + // all statements that end with those. Consume this semicolon here. + if (Tokens.back().kind() == tok::semi) + return Tokens; + return withTrailingSemicolon(Tokens); } private: + llvm::ArrayRef<syntax::Token> + withTrailingSemicolon(llvm::ArrayRef<syntax::Token> Tokens) const { + assert(!Tokens.empty()); + assert(Tokens.back().kind() != tok::eof); + // (!) we never consume 'eof', so looking at the next token is ok. + if (Tokens.back().kind() != tok::semi && Tokens.end()->kind() == tok::semi) + return llvm::makeArrayRef(Tokens.begin(), Tokens.end() + 1); + return Tokens; + } + /// Finds a token starting at \p L. The token must exist. const syntax::Token *findToken(SourceLocation L) const; @@ -103,11 +162,16 @@ private: assert(A.tokenBuffer().expandedTokens().back().kind() == tok::eof); // Create all leaf nodes. // Note that we do not have 'eof' in the tree. - for (auto &T : A.tokenBuffer().expandedTokens().drop_back()) - Trees.insert(Trees.end(), - {&T, NodeAndRole{new (A.allocator()) syntax::Leaf(&T)}}); + for (auto &T : A.tokenBuffer().expandedTokens().drop_back()) { + auto *L = new (A.allocator()) syntax::Leaf(&T); + L->Original = true; + L->CanModify = A.tokenBuffer().spelledForExpanded(T).hasValue(); + Trees.insert(Trees.end(), {&T, NodeAndRole{L}}); + } } + ~Forest() { assert(DelayedFolds.empty()); } + void assignRole(llvm::ArrayRef<syntax::Token> Range, syntax::NodeRole Role) { assert(!Range.empty()); @@ -120,30 +184,47 @@ private: It->second.Role = Role; } - /// Add \p Node to the forest and fill its children nodes based on the \p - /// NodeRange. - void foldChildren(llvm::ArrayRef<syntax::Token> NodeTokens, + /// Add \p Node to the forest and attach child nodes based on \p Tokens. + void foldChildren(const syntax::Arena &A, + llvm::ArrayRef<syntax::Token> Tokens, syntax::Tree *Node) { - assert(!NodeTokens.empty()); - assert(Node->firstChild() == nullptr && "node already has children"); + // Execute delayed folds inside `Tokens`. + auto BeginExecuted = DelayedFolds.lower_bound(Tokens.begin()); + auto It = BeginExecuted; + for (; It != DelayedFolds.end() && It->second.End <= Tokens.end(); ++It) + foldChildrenEager(A, llvm::makeArrayRef(It->first, It->second.End), + It->second.Node); + DelayedFolds.erase(BeginExecuted, It); - auto *FirstToken = NodeTokens.begin(); - auto BeginChildren = Trees.lower_bound(FirstToken); - assert(BeginChildren != Trees.end() && - BeginChildren->first == FirstToken && - "fold crosses boundaries of existing subtrees"); - auto EndChildren = Trees.lower_bound(NodeTokens.end()); - assert((EndChildren == Trees.end() || - EndChildren->first == NodeTokens.end()) && - "fold crosses boundaries of existing subtrees"); + // Attach children to `Node`. + foldChildrenEager(A, Tokens, Node); + } - // (!) we need to go in reverse order, because we can only prepend. - for (auto It = EndChildren; It != BeginChildren; --It) - Node->prependChildLowLevel(std::prev(It)->second.Node, - std::prev(It)->second.Role); + /// Schedule a call to `foldChildren` that will only be executed when + /// containing node is folded. The range of delayed nodes can be extended by + /// calling `extendDelayedFold`. Only one delayed node for each starting + /// token is allowed. + void foldChildrenDelayed(llvm::ArrayRef<syntax::Token> Tokens, + syntax::Tree *Node) { + assert(!Tokens.empty()); + bool Inserted = + DelayedFolds.insert({Tokens.begin(), DelayedFold{Tokens.end(), Node}}) + .second; + (void)Inserted; + assert(Inserted && "Multiple delayed folds start at the same token"); + } - Trees.erase(BeginChildren, EndChildren); - Trees.insert({FirstToken, NodeAndRole(Node)}); + /// If there a delayed fold, starting at `ExtendedRange.begin()`, extends + /// its endpoint to `ExtendedRange.end()` and returns true. + /// Otherwise, returns false. + bool extendDelayedFold(llvm::ArrayRef<syntax::Token> ExtendedRange) { + assert(!ExtendedRange.empty()); + auto It = DelayedFolds.find(ExtendedRange.data()); + if (It == DelayedFolds.end()) + return false; + assert(It->second.End <= ExtendedRange.end()); + It->second.End = ExtendedRange.end(); + return true; } // EXPECTS: all tokens were consumed and are owned by a single root node. @@ -171,6 +252,35 @@ private: } private: + /// Implementation detail of `foldChildren`, does acutal folding ignoring + /// delayed folds. + void foldChildrenEager(const syntax::Arena &A, + llvm::ArrayRef<syntax::Token> Tokens, + syntax::Tree *Node) { + assert(Node->firstChild() == nullptr && "node already has children"); + + auto *FirstToken = Tokens.begin(); + auto BeginChildren = Trees.lower_bound(FirstToken); + assert((BeginChildren == Trees.end() || + BeginChildren->first == FirstToken) && + "fold crosses boundaries of existing subtrees"); + auto EndChildren = Trees.lower_bound(Tokens.end()); + assert( + (EndChildren == Trees.end() || EndChildren->first == Tokens.end()) && + "fold crosses boundaries of existing subtrees"); + + // (!) we need to go in reverse order, because we can only prepend. + for (auto It = EndChildren; It != BeginChildren; --It) + Node->prependChildLowLevel(std::prev(It)->second.Node, + std::prev(It)->second.Role); + + // Mark that this node came from the AST and is backed by the source code. + Node->Original = true; + Node->CanModify = A.tokenBuffer().spelledForExpanded(Tokens).hasValue(); + + Trees.erase(BeginChildren, EndChildren); + Trees.insert({FirstToken, NodeAndRole(Node)}); + } /// A with a role that should be assigned to it when adding to a parent. struct NodeAndRole { explicit NodeAndRole(syntax::Node *Node) @@ -181,16 +291,29 @@ private: }; /// Maps from the start token to a subtree starting at that token. + /// Keys in the map are pointers into the array of expanded tokens, so + /// pointer order corresponds to the order of preprocessor tokens. /// FIXME: storing the end tokens is redundant. /// FIXME: the key of a map is redundant, it is also stored in NodeForRange. std::map<const syntax::Token *, NodeAndRole> Trees; + + /// See documentation of `foldChildrenDelayed` for details. + struct DelayedFold { + const syntax::Token *End = nullptr; + syntax::Tree *Node = nullptr; + }; + std::map<const syntax::Token *, DelayedFold> DelayedFolds; }; /// For debugging purposes. std::string str() { return Pending.str(Arena); } syntax::Arena &Arena; + /// To quickly find tokens by their start location. + llvm::DenseMap</*SourceLocation*/ unsigned, const syntax::Token *> + LocationToToken; Forest Pending; + llvm::DenseSet<Decl *> DeclsWithoutSemicolons; }; namespace { @@ -201,20 +324,34 @@ public: bool shouldTraversePostOrder() const { return true; } - bool TraverseDecl(Decl *D) { - if (!D || isa<TranslationUnitDecl>(D)) - return RecursiveASTVisitor::TraverseDecl(D); - if (!llvm::isa<TranslationUnitDecl>(D->getDeclContext())) - return true; // Only build top-level decls for now, do not recurse. - return RecursiveASTVisitor::TraverseDecl(D); + bool WalkUpFromDeclaratorDecl(DeclaratorDecl *D) { + // Ensure declarators are covered by SimpleDeclaration. + Builder.noticeDeclaratorRange(Builder.getRange(D)); + // FIXME: build nodes for the declarator too. + return true; + } + bool WalkUpFromTypedefNameDecl(TypedefNameDecl *D) { + // Also a declarator. + Builder.noticeDeclaratorRange(Builder.getRange(D)); + // FIXME: build nodes for the declarator too. + return true; } bool VisitDecl(Decl *D) { - assert(llvm::isa<TranslationUnitDecl>(D->getDeclContext()) && - "expected a top-level decl"); assert(!D->isImplicit()); Builder.foldNode(Builder.getRange(D), - new (allocator()) syntax::TopLevelDeclaration()); + new (allocator()) syntax::UnknownDeclaration()); + return true; + } + + bool WalkUpFromTagDecl(TagDecl *C) { + // FIXME: build the ClassSpecifier node. + if (C->isFreeStanding()) { + // Class is a declaration specifier and needs a spanning declaration node. + Builder.foldNode(Builder.getRange(C), + new (allocator()) syntax::SimpleDeclaration); + return true; + } return true; } @@ -227,16 +364,238 @@ public: bool WalkUpFromCompoundStmt(CompoundStmt *S) { using NodeRole = syntax::NodeRole; - Builder.markChildToken(S->getLBracLoc(), tok::l_brace, - NodeRole::CompoundStatement_lbrace); - Builder.markChildToken(S->getRBracLoc(), tok::r_brace, - NodeRole::CompoundStatement_rbrace); + Builder.markChildToken(S->getLBracLoc(), NodeRole::OpenParen); + for (auto *Child : S->body()) + Builder.markStmtChild(Child, NodeRole::CompoundStatement_statement); + Builder.markChildToken(S->getRBracLoc(), NodeRole::CloseParen); - Builder.foldNode(Builder.getRange(S), + Builder.foldNode(Builder.getStmtRange(S), new (allocator()) syntax::CompoundStatement); return true; } + // Some statements are not yet handled by syntax trees. + bool WalkUpFromStmt(Stmt *S) { + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::UnknownStatement); + return true; + } + + bool TraverseCXXForRangeStmt(CXXForRangeStmt *S) { + // We override to traverse range initializer as VarDecl. + // RAV traverses it as a statement, we produce invalid node kinds in that + // case. + // FIXME: should do this in RAV instead? + if (S->getInit() && !TraverseStmt(S->getInit())) + return false; + if (S->getLoopVariable() && !TraverseDecl(S->getLoopVariable())) + return false; + if (S->getRangeInit() && !TraverseStmt(S->getRangeInit())) + return false; + if (S->getBody() && !TraverseStmt(S->getBody())) + return false; + return true; + } + + bool TraverseStmt(Stmt *S) { + if (auto *DS = llvm::dyn_cast_or_null<DeclStmt>(S)) { + // We want to consume the semicolon, make sure SimpleDeclaration does not. + for (auto *D : DS->decls()) + Builder.noticeDeclaratorWithoutSemicolon(D); + } else if (auto *E = llvm::dyn_cast_or_null<Expr>(S)) { + // (!) do not recurse into subexpressions. + // we do not have syntax trees for expressions yet, so we only want to see + // the first top-level expression. + return WalkUpFromExpr(E->IgnoreImplicit()); + } + return RecursiveASTVisitor::TraverseStmt(S); + } + + // Some expressions are not yet handled by syntax trees. + bool WalkUpFromExpr(Expr *E) { + assert(!isImplicitExpr(E) && "should be handled by TraverseStmt"); + Builder.foldNode(Builder.getExprRange(E), + new (allocator()) syntax::UnknownExpression); + return true; + } + + bool WalkUpFromNamespaceDecl(NamespaceDecl *S) { + auto Tokens = Builder.getRange(S); + if (Tokens.front().kind() == tok::coloncolon) { + // Handle nested namespace definitions. Those start at '::' token, e.g. + // namespace a^::b {} + // FIXME: build corresponding nodes for the name of this namespace. + return true; + } + Builder.foldNode(Tokens, new (allocator()) syntax::NamespaceDefinition); + return true; + } + + // The code below is very regular, it could even be generated with some + // preprocessor magic. We merely assign roles to the corresponding children + // and fold resulting nodes. + bool WalkUpFromDeclStmt(DeclStmt *S) { + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::DeclarationStatement); + return true; + } + + bool WalkUpFromNullStmt(NullStmt *S) { + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::EmptyStatement); + return true; + } + + bool WalkUpFromSwitchStmt(SwitchStmt *S) { + Builder.markChildToken(S->getSwitchLoc(), + syntax::NodeRole::IntroducerKeyword); + Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::SwitchStatement); + return true; + } + + bool WalkUpFromCaseStmt(CaseStmt *S) { + Builder.markChildToken(S->getKeywordLoc(), + syntax::NodeRole::IntroducerKeyword); + Builder.markExprChild(S->getLHS(), syntax::NodeRole::CaseStatement_value); + Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement); + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::CaseStatement); + return true; + } + + bool WalkUpFromDefaultStmt(DefaultStmt *S) { + Builder.markChildToken(S->getKeywordLoc(), + syntax::NodeRole::IntroducerKeyword); + Builder.markStmtChild(S->getSubStmt(), syntax::NodeRole::BodyStatement); + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::DefaultStatement); + return true; + } + + bool WalkUpFromIfStmt(IfStmt *S) { + Builder.markChildToken(S->getIfLoc(), syntax::NodeRole::IntroducerKeyword); + Builder.markStmtChild(S->getThen(), + syntax::NodeRole::IfStatement_thenStatement); + Builder.markChildToken(S->getElseLoc(), + syntax::NodeRole::IfStatement_elseKeyword); + Builder.markStmtChild(S->getElse(), + syntax::NodeRole::IfStatement_elseStatement); + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::IfStatement); + return true; + } + + bool WalkUpFromForStmt(ForStmt *S) { + Builder.markChildToken(S->getForLoc(), syntax::NodeRole::IntroducerKeyword); + Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::ForStatement); + return true; + } + + bool WalkUpFromWhileStmt(WhileStmt *S) { + Builder.markChildToken(S->getWhileLoc(), + syntax::NodeRole::IntroducerKeyword); + Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::WhileStatement); + return true; + } + + bool WalkUpFromContinueStmt(ContinueStmt *S) { + Builder.markChildToken(S->getContinueLoc(), + syntax::NodeRole::IntroducerKeyword); + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::ContinueStatement); + return true; + } + + bool WalkUpFromBreakStmt(BreakStmt *S) { + Builder.markChildToken(S->getBreakLoc(), + syntax::NodeRole::IntroducerKeyword); + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::BreakStatement); + return true; + } + + bool WalkUpFromReturnStmt(ReturnStmt *S) { + Builder.markChildToken(S->getReturnLoc(), + syntax::NodeRole::IntroducerKeyword); + Builder.markExprChild(S->getRetValue(), + syntax::NodeRole::ReturnStatement_value); + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::ReturnStatement); + return true; + } + + bool WalkUpFromCXXForRangeStmt(CXXForRangeStmt *S) { + Builder.markChildToken(S->getForLoc(), syntax::NodeRole::IntroducerKeyword); + Builder.markStmtChild(S->getBody(), syntax::NodeRole::BodyStatement); + Builder.foldNode(Builder.getStmtRange(S), + new (allocator()) syntax::RangeBasedForStatement); + return true; + } + + bool WalkUpFromEmptyDecl(EmptyDecl *S) { + Builder.foldNode(Builder.getRange(S), + new (allocator()) syntax::EmptyDeclaration); + return true; + } + + bool WalkUpFromStaticAssertDecl(StaticAssertDecl *S) { + Builder.markExprChild(S->getAssertExpr(), + syntax::NodeRole::StaticAssertDeclaration_condition); + Builder.markExprChild(S->getMessage(), + syntax::NodeRole::StaticAssertDeclaration_message); + Builder.foldNode(Builder.getRange(S), + new (allocator()) syntax::StaticAssertDeclaration); + return true; + } + + bool WalkUpFromLinkageSpecDecl(LinkageSpecDecl *S) { + Builder.foldNode(Builder.getRange(S), + new (allocator()) syntax::LinkageSpecificationDeclaration); + return true; + } + + bool WalkUpFromNamespaceAliasDecl(NamespaceAliasDecl *S) { + Builder.foldNode(Builder.getRange(S), + new (allocator()) syntax::NamespaceAliasDefinition); + return true; + } + + bool WalkUpFromUsingDirectiveDecl(UsingDirectiveDecl *S) { + Builder.foldNode(Builder.getRange(S), + new (allocator()) syntax::UsingNamespaceDirective); + return true; + } + + bool WalkUpFromUsingDecl(UsingDecl *S) { + Builder.foldNode(Builder.getRange(S), + new (allocator()) syntax::UsingDeclaration); + return true; + } + + bool WalkUpFromUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *S) { + Builder.foldNode(Builder.getRange(S), + new (allocator()) syntax::UsingDeclaration); + return true; + } + + bool WalkUpFromUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *S) { + Builder.foldNode(Builder.getRange(S), + new (allocator()) syntax::UsingDeclaration); + return true; + } + + bool WalkUpFromTypeAliasDecl(TypeAliasDecl *S) { + Builder.foldNode(Builder.getRange(S), + new (allocator()) syntax::TypeAliasDeclaration); + return true; + } + private: /// A small helper to save some typing. llvm::BumpPtrAllocator &allocator() { return Builder.allocator(); } @@ -248,25 +607,55 @@ private: void syntax::TreeBuilder::foldNode(llvm::ArrayRef<syntax::Token> Range, syntax::Tree *New) { - Pending.foldChildren(Range, New); + Pending.foldChildren(Arena, Range, New); +} + +void syntax::TreeBuilder::noticeDeclaratorRange( + llvm::ArrayRef<syntax::Token> Range) { + if (Pending.extendDelayedFold(Range)) + return; + Pending.foldChildrenDelayed(Range, + new (allocator()) syntax::SimpleDeclaration); +} + +void syntax::TreeBuilder::noticeDeclaratorWithoutSemicolon(Decl *D) { + DeclsWithoutSemicolons.insert(D); } -void syntax::TreeBuilder::markChildToken(SourceLocation Loc, - tok::TokenKind Kind, NodeRole Role) { +void syntax::TreeBuilder::markChildToken(SourceLocation Loc, NodeRole Role) { if (Loc.isInvalid()) return; Pending.assignRole(*findToken(Loc), Role); } +void syntax::TreeBuilder::markStmtChild(Stmt *Child, NodeRole Role) { + if (!Child) + return; + + auto Range = getStmtRange(Child); + // This is an expression in a statement position, consume the trailing + // semicolon and form an 'ExpressionStatement' node. + if (auto *E = dyn_cast<Expr>(Child)) { + Pending.assignRole(getExprRange(E), + NodeRole::ExpressionStatement_expression); + // (!) 'getRange(Stmt)' ensures this already covers a trailing semicolon. + Pending.foldChildren(Arena, Range, + new (allocator()) syntax::ExpressionStatement); + } + Pending.assignRole(Range, Role); +} + +void syntax::TreeBuilder::markExprChild(Expr *Child, NodeRole Role) { + if (!Child) + return; + + Pending.assignRole(getExprRange(Child), Role); +} + const syntax::Token *syntax::TreeBuilder::findToken(SourceLocation L) const { - auto Tokens = Arena.tokenBuffer().expandedTokens(); - auto &SM = Arena.sourceManager(); - auto It = llvm::partition_point(Tokens, [&](const syntax::Token &T) { - return SM.isBeforeInTranslationUnit(T.location(), L); - }); - assert(It != Tokens.end()); - assert(It->location() == L); - return &*It; + auto It = LocationToToken.find(L.getRawEncoding()); + assert(It != LocationToToken.end()); + return It->second; } syntax::TranslationUnit * diff --git a/clang/lib/Tooling/Syntax/ComputeReplacements.cpp b/clang/lib/Tooling/Syntax/ComputeReplacements.cpp new file mode 100644 index 000000000000..30b3ee17d092 --- /dev/null +++ b/clang/lib/Tooling/Syntax/ComputeReplacements.cpp @@ -0,0 +1,126 @@ +//===- ComputeReplacements.cpp --------------------------------*- C++ -*-=====// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "clang/Tooling/Core/Replacement.h" +#include "clang/Tooling/Syntax/Mutations.h" +#include "clang/Tooling/Syntax/Tokens.h" +#include "llvm/Support/Error.h" + +using namespace clang; + +namespace { +using ProcessTokensFn = llvm::function_ref<void(llvm::ArrayRef<syntax::Token>, + bool /*IsOriginal*/)>; +/// Enumerates spans of tokens from the tree consecutively laid out in memory. +void enumerateTokenSpans(const syntax::Tree *Root, ProcessTokensFn Callback) { + struct Enumerator { + Enumerator(ProcessTokensFn Callback) + : SpanBegin(nullptr), SpanEnd(nullptr), SpanIsOriginal(false), + Callback(Callback) {} + + void run(const syntax::Tree *Root) { + process(Root); + // Report the last span to the user. + if (SpanBegin) + Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal); + } + + private: + void process(const syntax::Node *N) { + if (auto *T = dyn_cast<syntax::Tree>(N)) { + for (auto *C = T->firstChild(); C != nullptr; C = C->nextSibling()) + process(C); + return; + } + + auto *L = cast<syntax::Leaf>(N); + if (SpanEnd == L->token() && SpanIsOriginal == L->isOriginal()) { + // Extend the current span. + ++SpanEnd; + return; + } + // Report the current span to the user. + if (SpanBegin) + Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal); + // Start recording a new span. + SpanBegin = L->token(); + SpanEnd = SpanBegin + 1; + SpanIsOriginal = L->isOriginal(); + } + + const syntax::Token *SpanBegin; + const syntax::Token *SpanEnd; + bool SpanIsOriginal; + ProcessTokensFn Callback; + }; + + return Enumerator(Callback).run(Root); +} + +syntax::FileRange rangeOfExpanded(const syntax::Arena &A, + llvm::ArrayRef<syntax::Token> Expanded) { + auto &Buffer = A.tokenBuffer(); + auto &SM = A.sourceManager(); + + // Check that \p Expanded actually points into expanded tokens. + assert(Buffer.expandedTokens().begin() <= Expanded.begin()); + assert(Expanded.end() < Buffer.expandedTokens().end()); + + if (Expanded.empty()) + // (!) empty tokens must always point before end(). + return syntax::FileRange( + SM, SM.getExpansionLoc(Expanded.begin()->location()), /*Length=*/0); + + auto Spelled = Buffer.spelledForExpanded(Expanded); + assert(Spelled && "could not find spelled tokens for expanded"); + return syntax::Token::range(SM, Spelled->front(), Spelled->back()); +} +} // namespace + +tooling::Replacements +syntax::computeReplacements(const syntax::Arena &A, + const syntax::TranslationUnit &TU) { + auto &Buffer = A.tokenBuffer(); + auto &SM = A.sourceManager(); + + tooling::Replacements Replacements; + // Text inserted by the replacement we are building now. + std::string Replacement; + auto emitReplacement = [&](llvm::ArrayRef<syntax::Token> ReplacedRange) { + if (ReplacedRange.empty() && Replacement.empty()) + return; + llvm::cantFail(Replacements.add(tooling::Replacement( + SM, rangeOfExpanded(A, ReplacedRange).toCharRange(SM), Replacement))); + Replacement = ""; + }; + + const syntax::Token *NextOriginal = Buffer.expandedTokens().begin(); + enumerateTokenSpans( + &TU, [&](llvm::ArrayRef<syntax::Token> Tokens, bool IsOriginal) { + if (!IsOriginal) { + Replacement += + syntax::Token::range(SM, Tokens.front(), Tokens.back()).text(SM); + return; + } + assert(NextOriginal <= Tokens.begin()); + // We are looking at a span of original tokens. + if (NextOriginal != Tokens.begin()) { + // There is a gap, record a replacement or deletion. + emitReplacement(llvm::makeArrayRef(NextOriginal, Tokens.begin())); + } else { + // No gap, but we may have pending insertions. Emit them now. + emitReplacement(llvm::makeArrayRef(NextOriginal, /*Length=*/0)); + } + NextOriginal = Tokens.end(); + }); + + // We might have pending replacements at the end of file. If so, emit them. + emitReplacement(llvm::makeArrayRef( + NextOriginal, Buffer.expandedTokens().drop_back().end())); + + return Replacements; +} diff --git a/clang/lib/Tooling/Syntax/Mutations.cpp b/clang/lib/Tooling/Syntax/Mutations.cpp new file mode 100644 index 000000000000..72458528202e --- /dev/null +++ b/clang/lib/Tooling/Syntax/Mutations.cpp @@ -0,0 +1,98 @@ +//===- Mutations.cpp ------------------------------------------*- C++ -*-=====// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "clang/Tooling/Syntax/Mutations.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Lex/Token.h" +#include "clang/Tooling/Core/Replacement.h" +#include "clang/Tooling/Syntax/BuildTree.h" +#include "clang/Tooling/Syntax/Nodes.h" +#include "clang/Tooling/Syntax/Tokens.h" +#include "clang/Tooling/Syntax/Tree.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/Support/Casting.h" +#include <cassert> +#include <string> + +using namespace clang; + +// This class has access to the internals of tree nodes. Its sole purpose is to +// define helpers that allow implementing the high-level mutation operations. +class syntax::MutationsImpl { +public: + /// Add a new node with a specified role. + static void addAfter(syntax::Node *Anchor, syntax::Node *New, NodeRole Role) { + assert(Anchor != nullptr); + assert(New->Parent == nullptr); + assert(New->NextSibling == nullptr); + assert(!New->isDetached()); + assert(Role != NodeRole::Detached); + + New->Role = static_cast<unsigned>(Role); + auto *P = Anchor->parent(); + P->replaceChildRangeLowLevel(Anchor, Anchor, New); + + P->assertInvariants(); + } + + /// Replace the node, keeping the role. + static void replace(syntax::Node *Old, syntax::Node *New) { + assert(Old != nullptr); + assert(Old->Parent != nullptr); + assert(Old->canModify()); + assert(New->Parent == nullptr); + assert(New->NextSibling == nullptr); + assert(New->isDetached()); + + New->Role = Old->Role; + auto *P = Old->parent(); + P->replaceChildRangeLowLevel(findPrevious(Old), Old->nextSibling(), New); + + P->assertInvariants(); + } + + /// Completely remove the node from its parent. + static void remove(syntax::Node *N) { + auto *P = N->parent(); + P->replaceChildRangeLowLevel(findPrevious(N), N->nextSibling(), + /*New=*/nullptr); + + P->assertInvariants(); + N->assertInvariants(); + } + +private: + static syntax::Node *findPrevious(syntax::Node *N) { + if (N->parent()->firstChild() == N) + return nullptr; + for (syntax::Node *C = N->parent()->firstChild(); C != nullptr; + C = C->nextSibling()) { + if (C->nextSibling() == N) + return C; + } + llvm_unreachable("could not find a child node"); + } +}; + +void syntax::removeStatement(syntax::Arena &A, syntax::Statement *S) { + assert(S); + assert(S->canModify()); + + if (isa<CompoundStatement>(S->parent())) { + // A child of CompoundStatement can just be safely removed. + MutationsImpl::remove(S); + return; + } + // For the rest, we have to replace with an empty statement. + if (isa<EmptyStatement>(S)) + return; // already an empty statement, nothing to do. + + MutationsImpl::replace(S, createEmptyStatement(A)); +} diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp index 061ed73bbebd..5b0c5107c134 100644 --- a/clang/lib/Tooling/Syntax/Nodes.cpp +++ b/clang/lib/Tooling/Syntax/Nodes.cpp @@ -16,20 +16,233 @@ llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeKind K) { return OS << "Leaf"; case NodeKind::TranslationUnit: return OS << "TranslationUnit"; - case NodeKind::TopLevelDeclaration: - return OS << "TopLevelDeclaration"; + case NodeKind::UnknownExpression: + return OS << "UnknownExpression"; + case NodeKind::UnknownStatement: + return OS << "UnknownStatement"; + case NodeKind::DeclarationStatement: + return OS << "DeclarationStatement"; + case NodeKind::EmptyStatement: + return OS << "EmptyStatement"; + case NodeKind::SwitchStatement: + return OS << "SwitchStatement"; + case NodeKind::CaseStatement: + return OS << "CaseStatement"; + case NodeKind::DefaultStatement: + return OS << "DefaultStatement"; + case NodeKind::IfStatement: + return OS << "IfStatement"; + case NodeKind::ForStatement: + return OS << "ForStatement"; + case NodeKind::WhileStatement: + return OS << "WhileStatement"; + case NodeKind::ContinueStatement: + return OS << "ContinueStatement"; + case NodeKind::BreakStatement: + return OS << "BreakStatement"; + case NodeKind::ReturnStatement: + return OS << "ReturnStatement"; + case NodeKind::RangeBasedForStatement: + return OS << "RangeBasedForStatement"; + case NodeKind::ExpressionStatement: + return OS << "ExpressionStatement"; case NodeKind::CompoundStatement: return OS << "CompoundStatement"; + case NodeKind::UnknownDeclaration: + return OS << "UnknownDeclaration"; + case NodeKind::EmptyDeclaration: + return OS << "EmptyDeclaration"; + case NodeKind::StaticAssertDeclaration: + return OS << "StaticAssertDeclaration"; + case NodeKind::LinkageSpecificationDeclaration: + return OS << "LinkageSpecificationDeclaration"; + case NodeKind::SimpleDeclaration: + return OS << "SimpleDeclaration"; + case NodeKind::NamespaceDefinition: + return OS << "NamespaceDefinition"; + case NodeKind::NamespaceAliasDefinition: + return OS << "NamespaceAliasDefinition"; + case NodeKind::UsingNamespaceDirective: + return OS << "UsingNamespaceDirective"; + case NodeKind::UsingDeclaration: + return OS << "UsingDeclaration"; + case NodeKind::TypeAliasDeclaration: + return OS << "TypeAliasDeclaration"; } llvm_unreachable("unknown node kind"); } +llvm::raw_ostream &syntax::operator<<(llvm::raw_ostream &OS, NodeRole R) { + switch (R) { + case syntax::NodeRole::Detached: + return OS << "Detached"; + case syntax::NodeRole::Unknown: + return OS << "Unknown"; + case syntax::NodeRole::OpenParen: + return OS << "OpenParen"; + case syntax::NodeRole::CloseParen: + return OS << "CloseParen"; + case syntax::NodeRole::IntroducerKeyword: + return OS << "IntroducerKeyword"; + case syntax::NodeRole::BodyStatement: + return OS << "BodyStatement"; + case syntax::NodeRole::CaseStatement_value: + return OS << "CaseStatement_value"; + case syntax::NodeRole::IfStatement_thenStatement: + return OS << "IfStatement_thenStatement"; + case syntax::NodeRole::IfStatement_elseKeyword: + return OS << "IfStatement_elseKeyword"; + case syntax::NodeRole::IfStatement_elseStatement: + return OS << "IfStatement_elseStatement"; + case syntax::NodeRole::ReturnStatement_value: + return OS << "ReturnStatement_value"; + case syntax::NodeRole::ExpressionStatement_expression: + return OS << "ExpressionStatement_expression"; + case syntax::NodeRole::CompoundStatement_statement: + return OS << "CompoundStatement_statement"; + case syntax::NodeRole::StaticAssertDeclaration_condition: + return OS << "StaticAssertDeclaration_condition"; + case syntax::NodeRole::StaticAssertDeclaration_message: + return OS << "StaticAssertDeclaration_message"; + } + llvm_unreachable("invalid role"); +} + +syntax::Leaf *syntax::SwitchStatement::switchKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::IntroducerKeyword)); +} + +syntax::Statement *syntax::SwitchStatement::body() { + return llvm::cast_or_null<syntax::Statement>( + findChild(syntax::NodeRole::BodyStatement)); +} + +syntax::Leaf *syntax::CaseStatement::caseKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::IntroducerKeyword)); +} + +syntax::Expression *syntax::CaseStatement::value() { + return llvm::cast_or_null<syntax::Expression>( + findChild(syntax::NodeRole::CaseStatement_value)); +} + +syntax::Statement *syntax::CaseStatement::body() { + return llvm::cast_or_null<syntax::Statement>( + findChild(syntax::NodeRole::BodyStatement)); +} + +syntax::Leaf *syntax::DefaultStatement::defaultKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::IntroducerKeyword)); +} + +syntax::Statement *syntax::DefaultStatement::body() { + return llvm::cast_or_null<syntax::Statement>( + findChild(syntax::NodeRole::BodyStatement)); +} + +syntax::Leaf *syntax::IfStatement::ifKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::IntroducerKeyword)); +} + +syntax::Statement *syntax::IfStatement::thenStatement() { + return llvm::cast_or_null<syntax::Statement>( + findChild(syntax::NodeRole::IfStatement_thenStatement)); +} + +syntax::Leaf *syntax::IfStatement::elseKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::IfStatement_elseKeyword)); +} + +syntax::Statement *syntax::IfStatement::elseStatement() { + return llvm::cast_or_null<syntax::Statement>( + findChild(syntax::NodeRole::IfStatement_elseStatement)); +} + +syntax::Leaf *syntax::ForStatement::forKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::IntroducerKeyword)); +} + +syntax::Statement *syntax::ForStatement::body() { + return llvm::cast_or_null<syntax::Statement>( + findChild(syntax::NodeRole::BodyStatement)); +} + +syntax::Leaf *syntax::WhileStatement::whileKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::IntroducerKeyword)); +} + +syntax::Statement *syntax::WhileStatement::body() { + return llvm::cast_or_null<syntax::Statement>( + findChild(syntax::NodeRole::BodyStatement)); +} + +syntax::Leaf *syntax::ContinueStatement::continueKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::IntroducerKeyword)); +} + +syntax::Leaf *syntax::BreakStatement::breakKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::IntroducerKeyword)); +} + +syntax::Leaf *syntax::ReturnStatement::returnKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::IntroducerKeyword)); +} + +syntax::Expression *syntax::ReturnStatement::value() { + return llvm::cast_or_null<syntax::Expression>( + findChild(syntax::NodeRole::ReturnStatement_value)); +} + +syntax::Leaf *syntax::RangeBasedForStatement::forKeyword() { + return llvm::cast_or_null<syntax::Leaf>( + findChild(syntax::NodeRole::IntroducerKeyword)); +} + +syntax::Statement *syntax::RangeBasedForStatement::body() { + return llvm::cast_or_null<syntax::Statement>( + findChild(syntax::NodeRole::BodyStatement)); +} + +syntax::Expression *syntax::ExpressionStatement::expression() { + return llvm::cast_or_null<syntax::Expression>( + findChild(syntax::NodeRole::ExpressionStatement_expression)); +} + syntax::Leaf *syntax::CompoundStatement::lbrace() { return llvm::cast_or_null<syntax::Leaf>( - findChild(NodeRole::CompoundStatement_lbrace)); + findChild(syntax::NodeRole::OpenParen)); +} + +std::vector<syntax::Statement *> syntax::CompoundStatement::statements() { + std::vector<syntax::Statement *> Children; + for (auto *C = firstChild(); C; C = C->nextSibling()) { + if (C->role() == syntax::NodeRole::CompoundStatement_statement) + Children.push_back(llvm::cast<syntax::Statement>(C)); + } + return Children; } syntax::Leaf *syntax::CompoundStatement::rbrace() { return llvm::cast_or_null<syntax::Leaf>( - findChild(NodeRole::CompoundStatement_rbrace)); + findChild(syntax::NodeRole::CloseParen)); +} + +syntax::Expression *syntax::StaticAssertDeclaration::condition() { + return llvm::cast_or_null<syntax::Expression>( + findChild(syntax::NodeRole::StaticAssertDeclaration_condition)); +} + +syntax::Expression *syntax::StaticAssertDeclaration::message() { + return llvm::cast_or_null<syntax::Expression>( + findChild(syntax::NodeRole::StaticAssertDeclaration_message)); } diff --git a/clang/lib/Tooling/Syntax/Synthesis.cpp b/clang/lib/Tooling/Syntax/Synthesis.cpp new file mode 100644 index 000000000000..aa01a34c761f --- /dev/null +++ b/clang/lib/Tooling/Syntax/Synthesis.cpp @@ -0,0 +1,45 @@ +//===- Synthesis.cpp ------------------------------------------*- C++ -*-=====// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "clang/Tooling/Syntax/BuildTree.h" + +using namespace clang; + +/// Exposes private syntax tree APIs required to implement node synthesis. +/// Should not be used for anything else. +class syntax::FactoryImpl { +public: + static void setCanModify(syntax::Node *N) { N->CanModify = true; } + + static void prependChildLowLevel(syntax::Tree *T, syntax::Node *Child, + syntax::NodeRole R) { + T->prependChildLowLevel(Child, R); + } +}; + +clang::syntax::Leaf *syntax::createPunctuation(clang::syntax::Arena &A, + clang::tok::TokenKind K) { + auto Tokens = A.lexBuffer(llvm::MemoryBuffer::getMemBuffer( + clang::tok::getPunctuatorSpelling(K))) + .second; + assert(Tokens.size() == 1); + assert(Tokens.front().kind() == K); + auto *L = new (A.allocator()) clang::syntax::Leaf(Tokens.begin()); + FactoryImpl::setCanModify(L); + L->assertInvariants(); + return L; +} + +clang::syntax::EmptyStatement * +syntax::createEmptyStatement(clang::syntax::Arena &A) { + auto *S = new (A.allocator()) clang::syntax::EmptyStatement; + FactoryImpl::setCanModify(S); + FactoryImpl::prependChildLowLevel(S, createPunctuation(A, clang::tok::semi), + NodeRole::Unknown); + S->assertInvariants(); + return S; +} diff --git a/clang/lib/Tooling/Syntax/Tokens.cpp b/clang/lib/Tooling/Syntax/Tokens.cpp index a2c3bc137d6b..3df1c064923a 100644 --- a/clang/lib/Tooling/Syntax/Tokens.cpp +++ b/clang/lib/Tooling/Syntax/Tokens.cpp @@ -67,7 +67,7 @@ FileRange syntax::Token::range(const SourceManager &SM, auto F = First.range(SM); auto L = Last.range(SM); assert(F.file() == L.file() && "tokens from different files"); - assert(F.endOffset() <= L.beginOffset() && "wrong order of tokens"); + assert((F == L || F.endOffset() <= L.beginOffset()) && "wrong order of tokens"); return FileRange(F.file(), F.beginOffset(), L.endOffset()); } @@ -119,6 +119,28 @@ llvm::StringRef FileRange::text(const SourceManager &SM) const { return Text.substr(Begin, length()); } +llvm::ArrayRef<syntax::Token> TokenBuffer::expandedTokens(SourceRange R) const { + if (R.isInvalid()) + return {}; + const Token *Begin = + llvm::partition_point(expandedTokens(), [&](const syntax::Token &T) { + return SourceMgr->isBeforeInTranslationUnit(T.location(), R.getBegin()); + }); + const Token *End = + llvm::partition_point(expandedTokens(), [&](const syntax::Token &T) { + return !SourceMgr->isBeforeInTranslationUnit(R.getEnd(), T.location()); + }); + if (Begin > End) + return {}; + return {Begin, End}; +} + +CharSourceRange FileRange::toCharRange(const SourceManager &SM) const { + return CharSourceRange( + SourceRange(SM.getComposedLoc(File, Begin), SM.getComposedLoc(File, End)), + /*IsTokenRange=*/false); +} + std::pair<const syntax::Token *, const TokenBuffer::Mapping *> TokenBuffer::spelledForExpandedToken(const syntax::Token *Expanded) const { assert(Expanded); @@ -232,6 +254,30 @@ TokenBuffer::expansionStartingAt(const syntax::Token *Spelled) const { return E; } +llvm::ArrayRef<syntax::Token> +syntax::spelledTokensTouching(SourceLocation Loc, + const syntax::TokenBuffer &Tokens) { + assert(Loc.isFileID()); + llvm::ArrayRef<syntax::Token> All = + Tokens.spelledTokens(Tokens.sourceManager().getFileID(Loc)); + auto *Right = llvm::partition_point( + All, [&](const syntax::Token &Tok) { return Tok.location() < Loc; }); + bool AcceptRight = Right != All.end() && Right->location() <= Loc; + bool AcceptLeft = Right != All.begin() && (Right - 1)->endLocation() >= Loc; + return llvm::makeArrayRef(Right - (AcceptLeft ? 1 : 0), + Right + (AcceptRight ? 1 : 0)); +} + +const syntax::Token * +syntax::spelledIdentifierTouching(SourceLocation Loc, + const syntax::TokenBuffer &Tokens) { + for (const syntax::Token &Tok : spelledTokensTouching(Loc, Tokens)) { + if (Tok.kind() == tok::identifier) + return &Tok; + } + return nullptr; +} + std::vector<const syntax::Token *> TokenBuffer::macroExpansions(FileID FID) const { auto FileIt = Files.find(FID); diff --git a/clang/lib/Tooling/Syntax/Tree.cpp b/clang/lib/Tooling/Syntax/Tree.cpp index 1549b6724fa4..9a6270ec4cce 100644 --- a/clang/lib/Tooling/Syntax/Tree.cpp +++ b/clang/lib/Tooling/Syntax/Tree.cpp @@ -11,9 +11,27 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" +#include <cassert> using namespace clang; +namespace { +static void traverse(const syntax::Node *N, + llvm::function_ref<void(const syntax::Node *)> Visit) { + if (auto *T = dyn_cast<syntax::Tree>(N)) { + for (auto *C = T->firstChild(); C; C = C->nextSibling()) + traverse(C, Visit); + } + Visit(N); +} +static void traverse(syntax::Node *N, + llvm::function_ref<void(syntax::Node *)> Visit) { + traverse(static_cast<const syntax::Node *>(N), [&](const syntax::Node *N) { + Visit(const_cast<syntax::Node *>(N)); + }); +} +} // namespace + syntax::Arena::Arena(SourceManager &SourceMgr, const LangOptions &LangOpts, TokenBuffer Tokens) : SourceMgr(SourceMgr), LangOpts(LangOpts), Tokens(std::move(Tokens)) {} @@ -40,7 +58,10 @@ bool syntax::Leaf::classof(const Node *N) { syntax::Node::Node(NodeKind Kind) : Parent(nullptr), NextSibling(nullptr), Kind(static_cast<unsigned>(Kind)), - Role(static_cast<unsigned>(NodeRole::Detached)) {} + Role(static_cast<unsigned>(NodeRole::Detached)), Original(false), + CanModify(false) {} + +bool syntax::Node::isDetached() const { return role() == NodeRole::Detached; } bool syntax::Tree::classof(const Node *N) { return N->kind() > NodeKind::Leaf; } @@ -56,15 +77,53 @@ void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) { this->FirstChild = Child; } -namespace { -static void traverse(const syntax::Node *N, - llvm::function_ref<void(const syntax::Node *)> Visit) { - if (auto *T = dyn_cast<syntax::Tree>(N)) { - for (auto *C = T->firstChild(); C; C = C->nextSibling()) - traverse(C, Visit); +void syntax::Tree::replaceChildRangeLowLevel(Node *BeforeBegin, Node *End, + Node *New) { + assert(!BeforeBegin || BeforeBegin->Parent == this); + +#ifndef NDEBUG + for (auto *N = New; N; N = N->nextSibling()) { + assert(N->Parent == nullptr); + assert(N->role() != NodeRole::Detached && "Roles must be set"); + // FIXME: sanity-check the role. } - Visit(N); +#endif + + // Detach old nodes. + for (auto *N = !BeforeBegin ? FirstChild : BeforeBegin->nextSibling(); + N != End;) { + auto *Next = N->NextSibling; + + N->Role = static_cast<unsigned>(NodeRole::Detached); + N->Parent = nullptr; + N->NextSibling = nullptr; + if (N->Original) + traverse(N, [&](Node *C) { C->Original = false; }); + + N = Next; + } + + // Attach new nodes. + if (BeforeBegin) + BeforeBegin->NextSibling = New ? New : End; + else + FirstChild = New ? New : End; + + if (New) { + auto *Last = New; + for (auto *N = New; N != nullptr; N = N->nextSibling()) { + Last = N; + N->Parent = this; + } + Last->NextSibling = End; + } + + // Mark the node as modified. + for (auto *T = this; T && T->Original; T = T->Parent) + T->Original = false; } + +namespace { static void dumpTokens(llvm::raw_ostream &OS, ArrayRef<syntax::Token> Tokens, const SourceManager &SM) { assert(!Tokens.empty()); @@ -85,13 +144,16 @@ static void dumpTokens(llvm::raw_ostream &OS, ArrayRef<syntax::Token> Tokens, static void dumpTree(llvm::raw_ostream &OS, const syntax::Node *N, const syntax::Arena &A, std::vector<bool> IndentMask) { - if (N->role() != syntax::NodeRole::Unknown) { - // FIXME: print the symbolic name of a role. - if (N->role() == syntax::NodeRole::Detached) - OS << "*: "; - else - OS << static_cast<int>(N->role()) << ": "; - } + std::string Marks; + if (!N->isOriginal()) + Marks += "M"; + if (N->role() == syntax::NodeRole::Detached) + Marks += "*"; // FIXME: find a nice way to print other roles. + if (!N->canModify()) + Marks += "I"; + if (!Marks.empty()) + OS << Marks << ": "; + if (auto *L = llvm::dyn_cast<syntax::Leaf>(N)) { dumpTokens(OS, *L->token(), A.sourceManager()); OS << "\n"; @@ -136,10 +198,60 @@ std::string syntax::Node::dumpTokens(const Arena &A) const { if (!L) return; ::dumpTokens(OS, *L->token(), A.sourceManager()); + OS << " "; }); return OS.str(); } +void syntax::Node::assertInvariants() const { +#ifndef NDEBUG + if (isDetached()) + assert(parent() == nullptr); + else + assert(parent() != nullptr); + + auto *T = dyn_cast<Tree>(this); + if (!T) + return; + for (auto *C = T->firstChild(); C; C = C->nextSibling()) { + if (T->isOriginal()) + assert(C->isOriginal()); + assert(!C->isDetached()); + assert(C->parent() == T); + } +#endif +} + +void syntax::Node::assertInvariantsRecursive() const { +#ifndef NDEBUG + traverse(this, [&](const syntax::Node *N) { N->assertInvariants(); }); +#endif +} + +syntax::Leaf *syntax::Tree::firstLeaf() { + auto *T = this; + while (auto *C = T->firstChild()) { + if (auto *L = dyn_cast<syntax::Leaf>(C)) + return L; + T = cast<syntax::Tree>(C); + } + return nullptr; +} + +syntax::Leaf *syntax::Tree::lastLeaf() { + auto *T = this; + while (auto *C = T->firstChild()) { + // Find the last child. + while (auto *Next = C->nextSibling()) + C = Next; + + if (auto *L = dyn_cast<syntax::Leaf>(C)) + return L; + T = cast<syntax::Tree>(C); + } + return nullptr; +} + syntax::Node *syntax::Tree::findChild(NodeRole R) { for (auto *C = FirstChild; C; C = C->nextSibling()) { if (C->role() == R) diff --git a/clang/lib/Tooling/Tooling.cpp b/clang/lib/Tooling/Tooling.cpp index 1d6a968331b5..4a0618c50e42 100644 --- a/clang/lib/Tooling/Tooling.cpp +++ b/clang/lib/Tooling/Tooling.cpp @@ -619,7 +619,7 @@ buildASTFromCode(StringRef Code, StringRef FileName, std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( StringRef Code, const std::vector<std::string> &Args, StringRef FileName, StringRef ToolName, std::shared_ptr<PCHContainerOperations> PCHContainerOps, - ArgumentsAdjuster Adjuster) { + ArgumentsAdjuster Adjuster, const FileContentMappings &VirtualMappedFiles) { std::vector<std::unique_ptr<ASTUnit>> ASTs; ASTBuilderAction Action(ASTs); llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayFileSystem( @@ -636,6 +636,12 @@ std::unique_ptr<ASTUnit> buildASTFromCodeWithArgs( InMemoryFileSystem->addFile(FileName, 0, llvm::MemoryBuffer::getMemBufferCopy(Code)); + for (auto &FilenameWithContent : VirtualMappedFiles) { + InMemoryFileSystem->addFile( + FilenameWithContent.first, 0, + llvm::MemoryBuffer::getMemBuffer(FilenameWithContent.second)); + } + if (!Invocation.run()) return nullptr; diff --git a/clang/lib/Tooling/Transformer/RewriteRule.cpp b/clang/lib/Tooling/Transformer/RewriteRule.cpp index 6fa558f7b2ee..20d3a371950a 100644 --- a/clang/lib/Tooling/Transformer/RewriteRule.cpp +++ b/clang/lib/Tooling/Transformer/RewriteRule.cpp @@ -43,7 +43,7 @@ transformer::detail::translateEdits(const MatchResult &Result, // it as is currently done. if (!EditRange) return SmallVector<Transformation, 0>(); - auto Replacement = Edit.Replacement(Result); + auto Replacement = Edit.Replacement->eval(Result); if (!Replacement) return Replacement.takeError(); transformer::detail::Transformation T; @@ -54,13 +54,35 @@ transformer::detail::translateEdits(const MatchResult &Result, return Transformations; } -ASTEdit transformer::change(RangeSelector S, TextGenerator Replacement) { +ASTEdit transformer::changeTo(RangeSelector S, TextGenerator Replacement) { ASTEdit E; E.TargetRange = std::move(S); E.Replacement = std::move(Replacement); return E; } +namespace { +/// A \c TextGenerator that always returns a fixed string. +class SimpleTextGenerator : public MatchComputation<std::string> { + std::string S; + +public: + SimpleTextGenerator(std::string S) : S(std::move(S)) {} + llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &, + std::string *Result) const override { + Result->append(S); + return llvm::Error::success(); + } + std::string toString() const override { + return (llvm::Twine("text(\"") + S + "\")").str(); + } +}; +} // namespace + +ASTEdit transformer::remove(RangeSelector S) { + return change(std::move(S), std::make_shared<SimpleTextGenerator>("")); +} + RewriteRule transformer::makeRule(DynTypedMatcher M, SmallVector<ASTEdit, 1> Edits, TextGenerator Explanation) { return RewriteRule{{RewriteRule::Case{ @@ -176,3 +198,7 @@ transformer::detail::findSelectedCase(const MatchResult &Result, } constexpr llvm::StringLiteral RewriteRule::RootID; + +TextGenerator tooling::text(std::string M) { + return std::make_shared<SimpleTextGenerator>(std::move(M)); +} diff --git a/clang/lib/Tooling/Transformer/Stencil.cpp b/clang/lib/Tooling/Transformer/Stencil.cpp index 984950a54e96..8710e3cdf60f 100644 --- a/clang/lib/Tooling/Transformer/Stencil.cpp +++ b/clang/lib/Tooling/Transformer/Stencil.cpp @@ -15,6 +15,7 @@ #include "clang/Lex/Lexer.h" #include "clang/Tooling/Transformer/SourceCode.h" #include "clang/Tooling/Transformer/SourceCodeBuilders.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Errc.h" #include <atomic> @@ -58,7 +59,9 @@ struct DebugPrintNodeData { enum class UnaryNodeOperator { Parens, Deref, - Address, + MaybeDeref, + AddressOf, + MaybeAddressOf, }; // Generic container for stencil operations with a (single) node-id argument. @@ -77,19 +80,24 @@ struct SelectorData { // A stencil operation to build a member access `e.m` or `e->m`, as appropriate. struct AccessData { - AccessData(StringRef BaseId, StencilPart Member) + AccessData(StringRef BaseId, Stencil Member) : BaseId(BaseId), Member(std::move(Member)) {} std::string BaseId; - StencilPart Member; + Stencil Member; }; struct IfBoundData { - IfBoundData(StringRef Id, StencilPart TruePart, StencilPart FalsePart) - : Id(Id), TruePart(std::move(TruePart)), FalsePart(std::move(FalsePart)) { - } + IfBoundData(StringRef Id, Stencil TrueStencil, Stencil FalseStencil) + : Id(Id), TrueStencil(std::move(TrueStencil)), + FalseStencil(std::move(FalseStencil)) {} std::string Id; - StencilPart TruePart; - StencilPart FalsePart; + Stencil TrueStencil; + Stencil FalseStencil; +}; + +struct SequenceData { + SequenceData(std::vector<Stencil> Stencils) : Stencils(std::move(Stencils)) {} + std::vector<Stencil> Stencils; }; std::string toStringData(const RawTextData &Data) { @@ -115,9 +123,15 @@ std::string toStringData(const UnaryOperationData &Data) { case UnaryNodeOperator::Deref: OpName = "deref"; break; - case UnaryNodeOperator::Address: + case UnaryNodeOperator::MaybeDeref: + OpName = "maybeDeref"; + break; + case UnaryNodeOperator::AddressOf: OpName = "addressOf"; break; + case UnaryNodeOperator::MaybeAddressOf: + OpName = "maybeAddressOf"; + break; } return (OpName + "(\"" + Data.Id + "\")").str(); } @@ -126,13 +140,14 @@ std::string toStringData(const SelectorData &) { return "selection(...)"; } std::string toStringData(const AccessData &Data) { return (llvm::Twine("access(\"") + Data.BaseId + "\", " + - Data.Member.toString() + ")") + Data.Member->toString() + ")") .str(); } std::string toStringData(const IfBoundData &Data) { return (llvm::Twine("ifBound(\"") + Data.Id + "\", " + - Data.TruePart.toString() + ", " + Data.FalsePart.toString() + ")") + Data.TrueStencil->toString() + ", " + Data.FalseStencil->toString() + + ")") .str(); } @@ -140,6 +155,14 @@ std::string toStringData(const MatchConsumer<std::string> &) { return "run(...)"; } +std::string toStringData(const SequenceData &Data) { + llvm::SmallVector<std::string, 2> Parts; + Parts.reserve(Data.Stencils.size()); + for (const auto &S : Data.Stencils) + Parts.push_back(S->toString()); + return (llvm::Twine("seq(") + llvm::join(Parts, ", ") + ")").str(); +} + // The `evalData()` overloads evaluate the given stencil data to a string, given // the match result, and append it to `Result`. We define an overload for each // type of stencil data. @@ -176,7 +199,21 @@ Error evalData(const UnaryOperationData &Data, case UnaryNodeOperator::Deref: Source = tooling::buildDereference(*E, *Match.Context); break; - case UnaryNodeOperator::Address: + case UnaryNodeOperator::MaybeDeref: + if (!E->getType()->isAnyPointerType()) { + *Result += tooling::getText(*E, *Match.Context); + return Error::success(); + } + Source = tooling::buildDereference(*E, *Match.Context); + break; + case UnaryNodeOperator::AddressOf: + Source = tooling::buildAddressOf(*E, *Match.Context); + break; + case UnaryNodeOperator::MaybeAddressOf: + if (E->getType()->isAnyPointerType()) { + *Result += tooling::getText(*E, *Match.Context); + return Error::success(); + } Source = tooling::buildAddressOf(*E, *Match.Context); break; } @@ -214,14 +251,14 @@ Error evalData(const AccessData &Data, const MatchFinder::MatchResult &Match, errc::invalid_argument, "Could not construct object text from ID: " + Data.BaseId); } - return Data.Member.eval(Match, Result); + return Data.Member->eval(Match, Result); } Error evalData(const IfBoundData &Data, const MatchFinder::MatchResult &Match, std::string *Result) { auto &M = Match.Nodes.getMap(); - return (M.find(Data.Id) != M.end() ? Data.TruePart : Data.FalsePart) - .eval(Match, Result); + return (M.find(Data.Id) != M.end() ? Data.TrueStencil : Data.FalseStencil) + ->eval(Match, Result); } Error evalData(const MatchConsumer<std::string> &Fn, @@ -233,13 +270,20 @@ Error evalData(const MatchConsumer<std::string> &Fn, return Error::success(); } -template <typename T> -class StencilPartImpl : public StencilPartInterface { +Error evalData(const SequenceData &Data, const MatchFinder::MatchResult &Match, + std::string *Result) { + for (const auto &S : Data.Stencils) + if (auto Err = S->eval(Match, Result)) + return Err; + return Error::success(); +} + +template <typename T> class StencilImpl : public StencilInterface { T Data; public: template <typename... Ps> - explicit StencilPartImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {} + explicit StencilImpl(Ps &&... Args) : Data(std::forward<Ps>(Args)...) {} Error eval(const MatchFinder::MatchResult &Match, std::string *Result) const override { @@ -250,69 +294,67 @@ public: }; } // namespace -StencilPart Stencil::wrap(StringRef Text) { - return transformer::text(Text); +Stencil transformer::detail::makeStencil(StringRef Text) { return text(Text); } + +Stencil transformer::detail::makeStencil(RangeSelector Selector) { + return selection(std::move(Selector)); } -StencilPart Stencil::wrap(RangeSelector Selector) { - return transformer::selection(std::move(Selector)); +Stencil transformer::text(StringRef Text) { + return std::make_shared<StencilImpl<RawTextData>>(Text); } -void Stencil::append(Stencil OtherStencil) { - for (auto &Part : OtherStencil.Parts) - Parts.push_back(std::move(Part)); +Stencil transformer::selection(RangeSelector Selector) { + return std::make_shared<StencilImpl<SelectorData>>(std::move(Selector)); } -llvm::Expected<std::string> -Stencil::eval(const MatchFinder::MatchResult &Match) const { - std::string Result; - for (const auto &Part : Parts) - if (auto Err = Part.eval(Match, &Result)) - return std::move(Err); - return Result; +Stencil transformer::dPrint(StringRef Id) { + return std::make_shared<StencilImpl<DebugPrintNodeData>>(Id); } -StencilPart transformer::text(StringRef Text) { - return StencilPart(std::make_shared<StencilPartImpl<RawTextData>>(Text)); +Stencil transformer::expression(llvm::StringRef Id) { + return std::make_shared<StencilImpl<UnaryOperationData>>( + UnaryNodeOperator::Parens, Id); } -StencilPart transformer::selection(RangeSelector Selector) { - return StencilPart( - std::make_shared<StencilPartImpl<SelectorData>>(std::move(Selector))); +Stencil transformer::deref(llvm::StringRef ExprId) { + return std::make_shared<StencilImpl<UnaryOperationData>>( + UnaryNodeOperator::Deref, ExprId); } -StencilPart transformer::dPrint(StringRef Id) { - return StencilPart(std::make_shared<StencilPartImpl<DebugPrintNodeData>>(Id)); +Stencil transformer::maybeDeref(llvm::StringRef ExprId) { + return std::make_shared<StencilImpl<UnaryOperationData>>( + UnaryNodeOperator::MaybeDeref, ExprId); } -StencilPart transformer::expression(llvm::StringRef Id) { - return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>( - UnaryNodeOperator::Parens, Id)); +Stencil transformer::addressOf(llvm::StringRef ExprId) { + return std::make_shared<StencilImpl<UnaryOperationData>>( + UnaryNodeOperator::AddressOf, ExprId); } -StencilPart transformer::deref(llvm::StringRef ExprId) { - return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>( - UnaryNodeOperator::Deref, ExprId)); +Stencil transformer::maybeAddressOf(llvm::StringRef ExprId) { + return std::make_shared<StencilImpl<UnaryOperationData>>( + UnaryNodeOperator::MaybeAddressOf, ExprId); } -StencilPart transformer::addressOf(llvm::StringRef ExprId) { - return StencilPart(std::make_shared<StencilPartImpl<UnaryOperationData>>( - UnaryNodeOperator::Address, ExprId)); +Stencil transformer::access(StringRef BaseId, Stencil Member) { + return std::make_shared<StencilImpl<AccessData>>(BaseId, std::move(Member)); } -StencilPart transformer::access(StringRef BaseId, StencilPart Member) { - return StencilPart( - std::make_shared<StencilPartImpl<AccessData>>(BaseId, std::move(Member))); +Stencil transformer::ifBound(StringRef Id, Stencil TrueStencil, + Stencil FalseStencil) { + return std::make_shared<StencilImpl<IfBoundData>>(Id, std::move(TrueStencil), + std::move(FalseStencil)); } -StencilPart transformer::ifBound(StringRef Id, StencilPart TruePart, - StencilPart FalsePart) { - return StencilPart(std::make_shared<StencilPartImpl<IfBoundData>>( - Id, std::move(TruePart), std::move(FalsePart))); +Stencil transformer::run(MatchConsumer<std::string> Fn) { + return std::make_shared<StencilImpl<MatchConsumer<std::string>>>( + std::move(Fn)); } -StencilPart transformer::run(MatchConsumer<std::string> Fn) { - return StencilPart( - std::make_shared<StencilPartImpl<MatchConsumer<std::string>>>( - std::move(Fn))); +Stencil transformer::catVector(std::vector<Stencil> Parts) { + // Only one argument, so don't wrap in sequence. + if (Parts.size() == 1) + return std::move(Parts[0]); + return std::make_shared<StencilImpl<SequenceData>>(std::move(Parts)); } |
