diff options
Diffstat (limited to 'clang/lib')
61 files changed, 1246 insertions, 434 deletions
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp index 91ab66f..2243ac0 100644 --- a/clang/lib/AST/ASTConcept.cpp +++ b/clang/lib/AST/ASTConcept.cpp @@ -86,7 +86,7 @@ ConceptReference * ConceptReference::Create(const ASTContext &C, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, - NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + NamedDecl *FoundDecl, TemplateDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten) { return new (C) ConceptReference(NNS, TemplateKWLoc, ConceptNameInfo, FoundDecl, NamedConcept, ArgsAsWritten); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 16cf114..3a16111 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -80,6 +80,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" #include "llvm/Support/Capacity.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MD5.h" @@ -717,13 +718,13 @@ comments::FullComment *ASTContext::getCommentForDecl( return FC; } -void -ASTContext::CanonicalTemplateTemplateParm::Profile(llvm::FoldingSetNodeID &ID, - const ASTContext &C, - TemplateTemplateParmDecl *Parm) { +void ASTContext::CanonicalTemplateTemplateParm::Profile( + llvm::FoldingSetNodeID &ID, const ASTContext &C, + TemplateTemplateParmDecl *Parm) { ID.AddInteger(Parm->getDepth()); ID.AddInteger(Parm->getPosition()); ID.AddBoolean(Parm->isParameterPack()); + ID.AddInteger(Parm->templateParameterKind()); TemplateParameterList *Params = Parm->getTemplateParameters(); ID.AddInteger(Params->size()); @@ -829,7 +830,9 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( TemplateTemplateParmDecl *CanonTTP = TemplateTemplateParmDecl::Create( *this, getTranslationUnitDecl(), SourceLocation(), TTP->getDepth(), - TTP->getPosition(), TTP->isParameterPack(), nullptr, /*Typename=*/false, + TTP->getPosition(), TTP->isParameterPack(), nullptr, + TTP->templateParameterKind(), + /*Typename=*/false, TemplateParameterList::Create(*this, SourceLocation(), SourceLocation(), CanonParams, SourceLocation(), /*RequiresClause=*/nullptr)); @@ -6643,7 +6646,7 @@ ASTContext::getUnaryTransformType(QualType BaseType, QualType UnderlyingType, QualType ASTContext::getAutoTypeInternal( QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent, - bool IsPack, ConceptDecl *TypeConstraintConcept, + bool IsPack, TemplateDecl *TypeConstraintConcept, ArrayRef<TemplateArgument> TypeConstraintArgs, bool IsCanon) const { if (DeducedType.isNull() && Keyword == AutoTypeKeyword::Auto && !TypeConstraintConcept && !IsDependent) @@ -6652,7 +6655,8 @@ QualType ASTContext::getAutoTypeInternal( // Look in the folding set for an existing type. llvm::FoldingSetNodeID ID; bool IsDeducedDependent = - !DeducedType.isNull() && DeducedType->isDependentType(); + isa_and_nonnull<TemplateTemplateParmDecl>(TypeConstraintConcept) || + (!DeducedType.isNull() && DeducedType->isDependentType()); AutoType::Profile(ID, *this, DeducedType, Keyword, IsDependent || IsDeducedDependent, TypeConstraintConcept, TypeConstraintArgs); @@ -6665,7 +6669,8 @@ QualType ASTContext::getAutoTypeInternal( Canon = DeducedType.getCanonicalType(); } else if (TypeConstraintConcept) { bool AnyNonCanonArgs = false; - ConceptDecl *CanonicalConcept = TypeConstraintConcept->getCanonicalDecl(); + auto *CanonicalConcept = + cast<TemplateDecl>(TypeConstraintConcept->getCanonicalDecl()); auto CanonicalConceptArgs = ::getCanonicalTemplateArguments( *this, TypeConstraintArgs, AnyNonCanonArgs); if (CanonicalConcept != TypeConstraintConcept || AnyNonCanonArgs) { @@ -6701,7 +6706,7 @@ QualType ASTContext::getAutoTypeInternal( QualType ASTContext::getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent, bool IsPack, - ConceptDecl *TypeConstraintConcept, + TemplateDecl *TypeConstraintConcept, ArrayRef<TemplateArgument> TypeConstraintArgs) const { assert((!IsPack || IsDependent) && "only use IsPack for a dependent pack"); assert((!IsDependent || DeducedType.isNull()) && @@ -14387,8 +14392,8 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, if (KW != AY->getKeyword()) return QualType(); - ConceptDecl *CD = ::getCommonDecl(AX->getTypeConstraintConcept(), - AY->getTypeConstraintConcept()); + TemplateDecl *CD = ::getCommonDecl(AX->getTypeConstraintConcept(), + AY->getTypeConstraintConcept()); SmallVector<TemplateArgument, 8> As; if (CD && getCommonTemplateArguments(Ctx, As, AX->getTypeConstraintArguments(), diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index b9bdabe0b..8e2927b 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -6268,8 +6268,8 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { ToD, D, Importer.getToContext(), Importer.getToContext().getTranslationUnitDecl(), *LocationOrErr, D->getDepth(), D->getPosition(), D->isParameterPack(), - (*NameOrErr).getAsIdentifierInfo(), D->wasDeclaredWithTypename(), - *TemplateParamsOrErr)) + (*NameOrErr).getAsIdentifierInfo(), D->templateParameterKind(), + D->wasDeclaredWithTypename(), *TemplateParamsOrErr)) return ToD; if (Error Err = importTemplateParameterDefaultArgument(D, ToD)) diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 22bb4cb..0e2023f 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -2313,7 +2313,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } // Check template parameter lists. - return IsStructurallyEquivalent(Context, D1->getTemplateParameters(), + return D1->templateParameterKind() == D2->templateParameterKind() && + IsStructurallyEquivalent(Context, D1->getTemplateParameters(), D2->getTemplateParameters()); } diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp index d474605..8e7206e 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.cpp @@ -135,8 +135,8 @@ int32_t ByteCodeEmitter::getOffset(LabelTy Label) { /// Helper to write bytecode and bail out if 32-bit offsets become invalid. /// Pointers will be automatically marshalled as 32-bit IDs. template <typename T> -static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, - bool &Success) { +static void emit(Program &P, llvm::SmallVectorImpl<std::byte> &Code, + const T &Val, bool &Success) { size_t ValPos = Code.size(); size_t Size; @@ -153,7 +153,7 @@ static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, // Access must be aligned! assert(aligned(ValPos)); assert(aligned(ValPos + Size)); - Code.resize(ValPos + Size); + Code.resize_for_overwrite(ValPos + Size); if constexpr (!std::is_pointer_v<T>) { new (Code.data() + ValPos) T(Val); @@ -166,7 +166,7 @@ static void emit(Program &P, std::vector<std::byte> &Code, const T &Val, /// Emits a serializable value. These usually (potentially) contain /// heap-allocated memory and aren't trivially copyable. template <typename T> -static void emitSerialized(std::vector<std::byte> &Code, const T &Val, +static void emitSerialized(llvm::SmallVectorImpl<std::byte> &Code, const T &Val, bool &Success) { size_t ValPos = Code.size(); size_t Size = align(Val.bytesToSerialize()); @@ -179,32 +179,32 @@ static void emitSerialized(std::vector<std::byte> &Code, const T &Val, // Access must be aligned! assert(aligned(ValPos)); assert(aligned(ValPos + Size)); - Code.resize(ValPos + Size); + Code.resize_for_overwrite(ValPos + Size); Val.serialize(Code.data() + ValPos); } template <> -void emit(Program &P, std::vector<std::byte> &Code, const Floating &Val, - bool &Success) { +void emit(Program &P, llvm::SmallVectorImpl<std::byte> &Code, + const Floating &Val, bool &Success) { emitSerialized(Code, Val, Success); } template <> -void emit(Program &P, std::vector<std::byte> &Code, +void emit(Program &P, llvm::SmallVectorImpl<std::byte> &Code, const IntegralAP<false> &Val, bool &Success) { emitSerialized(Code, Val, Success); } template <> -void emit(Program &P, std::vector<std::byte> &Code, const IntegralAP<true> &Val, - bool &Success) { +void emit(Program &P, llvm::SmallVectorImpl<std::byte> &Code, + const IntegralAP<true> &Val, bool &Success) { emitSerialized(Code, Val, Success); } template <> -void emit(Program &P, std::vector<std::byte> &Code, const FixedPoint &Val, - bool &Success) { +void emit(Program &P, llvm::SmallVectorImpl<std::byte> &Code, + const FixedPoint &Val, bool &Success) { emitSerialized(Code, Val, Success); } diff --git a/clang/lib/AST/ByteCode/ByteCodeEmitter.h b/clang/lib/AST/ByteCode/ByteCodeEmitter.h index 9e9dd5e..8a02911 100644 --- a/clang/lib/AST/ByteCode/ByteCodeEmitter.h +++ b/clang/lib/AST/ByteCode/ByteCodeEmitter.h @@ -88,7 +88,7 @@ private: /// Location of label relocations. llvm::DenseMap<LabelTy, llvm::SmallVector<unsigned, 5>> LabelRelocs; /// Program code. - std::vector<std::byte> Code; + llvm::SmallVector<std::byte> Code; /// Opcode to expression mapping. SourceMap SrcMap; diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 6e451ac..5bcac39 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -201,6 +201,28 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) { return this->emitInvalidCast(CastKind::Volatile, /*Fatal=*/true, CE); OptPrimType SubExprT = classify(SubExpr->getType()); + // Try to load the value directly. This is purely a performance + // optimization. + if (SubExprT) { + if (const auto *DRE = dyn_cast<DeclRefExpr>(SubExpr)) { + const ValueDecl *D = DRE->getDecl(); + bool IsReference = D->getType()->isReferenceType(); + + if (!IsReference) { + if (Context::shouldBeGloballyIndexed(D)) { + if (auto GlobalIndex = P.getGlobal(D)) + return this->emitGetGlobal(*SubExprT, *GlobalIndex, CE); + } else if (auto It = Locals.find(D); It != Locals.end()) { + return this->emitGetLocal(*SubExprT, It->second.Offset, CE); + } else if (const auto *PVD = dyn_cast<ParmVarDecl>(D)) { + if (auto It = this->Params.find(PVD); It != this->Params.end()) { + return this->emitGetParam(*SubExprT, It->second.Offset, CE); + } + } + } + } + } + // Prepare storage for the result. if (!Initializing && !SubExprT) { std::optional<unsigned> LocalIndex = allocateLocal(SubExpr); @@ -3857,10 +3879,7 @@ template <class Emitter> bool Compiler<Emitter>::VisitAddrLabelExpr(const AddrLabelExpr *E) { assert(E->getType()->isVoidPointerType()); - unsigned Offset = - allocateLocalPrimitive(E->getLabel(), PT_Ptr, /*IsConst=*/true); - - return this->emitGetLocal(PT_Ptr, Offset, E); + return this->emitDummyPtr(E, E); } template <class Emitter> @@ -5895,7 +5914,7 @@ bool Compiler<Emitter>::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) { const CXXRecordDecl *ClosureClass = MD->getParent(); const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator(); - assert(ClosureClass->captures_begin() == ClosureClass->captures_end()); + assert(ClosureClass->captures().empty()); const Function *Func = this->getFunction(LambdaCallOp); if (!Func) return false; diff --git a/clang/lib/AST/ByteCode/Context.cpp b/clang/lib/AST/ByteCode/Context.cpp index 7215e1dd..f7f528c 100644 --- a/clang/lib/AST/ByteCode/Context.cpp +++ b/clang/lib/AST/ByteCode/Context.cpp @@ -45,12 +45,12 @@ bool Context::isPotentialConstantExpr(State &Parent, const FunctionDecl *FD) { Compiler<ByteCodeEmitter>(*this, *P).compileFunc( FD, const_cast<Function *>(Func)); - ++EvalID; - // And run it. - if (!Run(Parent, Func)) + if (!Func->isValid()) return false; - return Func->isValid(); + ++EvalID; + // And run it. + return Run(Parent, Func); } void Context::isPotentialConstantExprUnevaluated(State &Parent, const Expr *E, @@ -474,7 +474,7 @@ const Function *Context::getOrCreateFunction(const FunctionDecl *FuncDecl) { IsLambdaStaticInvoker = true; const CXXRecordDecl *ClosureClass = MD->getParent(); - assert(ClosureClass->captures_begin() == ClosureClass->captures_end()); + assert(ClosureClass->captures().empty()); if (ClosureClass->isGenericLambda()) { const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator(); assert(MD->isFunctionTemplateSpecialization() && diff --git a/clang/lib/AST/ByteCode/EvalEmitter.cpp b/clang/lib/AST/ByteCode/EvalEmitter.cpp index 81ebc56..fd7f342 100644 --- a/clang/lib/AST/ByteCode/EvalEmitter.cpp +++ b/clang/lib/AST/ByteCode/EvalEmitter.cpp @@ -282,6 +282,10 @@ bool EvalEmitter::emitGetLocal(uint32_t I, const SourceInfo &Info) { using T = typename PrimConv<OpType>::T; Block *B = getLocal(I); + + if (!CheckLocalLoad(S, OpPC, Pointer(B))) + return false; + S.Stk.push<T>(*reinterpret_cast<T *>(B->data())); return true; } diff --git a/clang/lib/AST/ByteCode/Function.h b/clang/lib/AST/ByteCode/Function.h index 64bffc4..92363b6 100644 --- a/clang/lib/AST/ByteCode/Function.h +++ b/clang/lib/AST/ByteCode/Function.h @@ -236,7 +236,7 @@ private: bool HasRVO, bool IsLambdaStaticInvoker); /// Sets the code of a function. - void setCode(unsigned NewFrameSize, std::vector<std::byte> &&NewCode, + void setCode(unsigned NewFrameSize, llvm::SmallVector<std::byte> &&NewCode, SourceMap &&NewSrcMap, llvm::SmallVector<Scope, 2> &&NewScopes, bool NewHasBody) { FrameSize = NewFrameSize; @@ -266,7 +266,7 @@ private: /// Size of the argument stack. unsigned ArgSize; /// Program code. - std::vector<std::byte> Code; + llvm::SmallVector<std::byte> Code; /// Opcode-to-expression mapping. SourceMap SrcMap; /// List of block descriptors. diff --git a/clang/lib/AST/ByteCode/Interp.cpp b/clang/lib/AST/ByteCode/Interp.cpp index 224d65c..f2366f6 100644 --- a/clang/lib/AST/ByteCode/Interp.cpp +++ b/clang/lib/AST/ByteCode/Interp.cpp @@ -715,23 +715,6 @@ static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr, return false; } -bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { - if (Ptr.isInitialized()) - return true; - - assert(S.getLangOpts().CPlusPlus); - const auto *VD = cast<VarDecl>(Ptr.getDeclDesc()->asValueDecl()); - if ((!VD->hasConstantInitialization() && - VD->mightBeUsableInConstantExpressions(S.getASTContext())) || - (S.getLangOpts().OpenCL && !S.getLangOpts().CPlusPlus11 && - !VD->hasICEInitializer(S.getASTContext()))) { - const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD; - S.Note(VD->getLocation(), diag::note_declared_at); - } - return false; -} - static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!Ptr.isWeak()) return true; @@ -745,6 +728,37 @@ static bool CheckWeak(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return false; } +// The list of checks here is just the one from CheckLoad, but with the +// ones removed that are impossible on primitive global values. +// For example, since those can't be members of structs, they also can't +// be mutable. +bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { + if (!CheckExtern(S, OpPC, Ptr)) + return false; + if (!CheckConstant(S, OpPC, Ptr)) + return false; + if (!CheckDummy(S, OpPC, Ptr, AK_Read)) + return false; + if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) + return false; + if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) + return false; + if (!CheckWeak(S, OpPC, Ptr)) + return false; + if (!CheckVolatile(S, OpPC, Ptr, AK_Read)) + return false; + return true; +} + +// Similarly, for local loads. +bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { + if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) + return false; + if (!CheckVolatile(S, OpPC, Ptr, AK_Read)) + return false; + return true; +} + bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK) { if (!CheckLive(S, OpPC, Ptr, AK)) diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 9a325ab..61e7769 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -91,8 +91,9 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, AccessKinds AK); -/// Check if a global variable is initialized. -bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr); +/// Checks a direct load of a primitive value from a global or local variable. +bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); +bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); /// Checks if a value can be stored in a block. bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr); @@ -1465,14 +1466,8 @@ bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { template <PrimType Name, class T = typename PrimConv<Name>::T> bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { const Pointer &Ptr = S.P.getPtrGlobal(I); - if (!CheckConstant(S, OpPC, Ptr.getFieldDesc())) - return false; - if (Ptr.isExtern()) - return false; - // If a global variable is uninitialized, that means the initializer we've - // compiled for it wasn't a constant expression. Diagnose that. - if (!CheckGlobalInitialized(S, OpPC, Ptr)) + if (!CheckGlobalLoad(S, OpPC, Ptr)) return false; S.Stk.push<T>(Ptr.deref<T>()); diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 14ec93e..87334d9 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -806,7 +806,7 @@ clang::computeDependence(OverloadExpr *E, bool KnownDependent, ~NestedNameSpecifierDependence::Dependent); for (auto *D : E->decls()) { if (D->getDeclContext()->isDependentContext() || - isa<UnresolvedUsingValueDecl>(D)) + isa<UnresolvedUsingValueDecl>(D) || isa<TemplateTemplateParmDecl>(D)) Deps |= ExprDependence::TypeValueInstantiation; } // If we have explicit template arguments, check for dependent diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 1588be4..5471f31 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -1233,6 +1233,9 @@ getExplicitVisibilityAux(const NamedDecl *ND, bool IsMostRecent) { assert(!IsMostRecent || ND == ND->getMostRecentDecl()); + if (isa<ConceptDecl>(ND)) + return {}; + // Check the declaration itself first. if (std::optional<Visibility> V = getVisibilityOf(ND, kind)) return V; diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 673e3f7..037a28c4 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -1983,7 +1983,7 @@ CXXRecordDecl::getVisibleConversionFunctions() const { ASTContext &Ctx = getASTContext(); ASTUnresolvedSet *Set; - if (bases_begin() == bases_end()) { + if (bases().empty()) { // If root class, all conversions are visible. Set = &data().Conversions.get(Ctx); } else { diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 9273f58..f4265dd0 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -1443,7 +1443,7 @@ void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) { lastPos = pos + 1; } - if (OMD->param_begin() == OMD->param_end()) + if (OMD->parameters().empty()) Out << name; if (OMD->isVariadic()) @@ -1480,8 +1480,7 @@ void DeclPrinter::VisitObjCImplementationDecl(ObjCImplementationDecl *OID) { } Indentation -= Policy.Indentation; Out << "}\n"; - } - else if (SID || (OID->decls_begin() != OID->decls_end())) { + } else if (SID || !OID->decls().empty()) { Out << "\n"; eolnOut = true; } @@ -1540,8 +1539,7 @@ void DeclPrinter::VisitObjCInterfaceDecl(ObjCInterfaceDecl *OID) { } Indentation -= Policy.Indentation; Out << "}\n"; - } - else if (SID || (OID->decls_begin() != OID->decls_end())) { + } else if (SID || !OID->decls().empty()) { Out << "\n"; eolnOut = true; } diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 5035f2d..bc4a299 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -162,6 +162,7 @@ void TemplateParameterList::Profile(llvm::FoldingSetNodeID &ID, } const auto *TTP = cast<TemplateTemplateParmDecl>(D); ID.AddInteger(2); + ID.AddInteger(TTP->templateParameterKind()); ID.AddBoolean(TTP->isParameterPack()); TTP->getTemplateParameters()->Profile(ID, C); } @@ -184,7 +185,8 @@ unsigned TemplateParameterList::getMinRequiredArguments() const { } else if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(P)) { if (NTTP->hasDefaultArgument()) break; - } else if (cast<TemplateTemplateParmDecl>(P)->hasDefaultArgument()) + } else if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(P); + TTP && TTP->hasDefaultArgument()) break; ++NumRequiredArgs; @@ -873,38 +875,40 @@ void TemplateTemplateParmDecl::anchor() {} TemplateTemplateParmDecl::TemplateTemplateParmDecl( DeclContext *DC, SourceLocation L, unsigned D, unsigned P, - IdentifierInfo *Id, bool Typename, TemplateParameterList *Params, - ArrayRef<TemplateParameterList *> Expansions) + IdentifierInfo *Id, TemplateNameKind Kind, bool Typename, + TemplateParameterList *Params, ArrayRef<TemplateParameterList *> Expansions) : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), - TemplateParmPosition(D, P), Typename(Typename), ParameterPack(true), - ExpandedParameterPack(true), NumExpandedParams(Expansions.size()) { + TemplateParmPosition(D, P), ParameterKind(Kind), Typename(Typename), + ParameterPack(true), ExpandedParameterPack(true), + NumExpandedParams(Expansions.size()) { llvm::uninitialized_copy(Expansions, getTrailingObjects()); } -TemplateTemplateParmDecl * -TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, - SourceLocation L, unsigned D, unsigned P, - bool ParameterPack, IdentifierInfo *Id, - bool Typename, TemplateParameterList *Params) { +TemplateTemplateParmDecl *TemplateTemplateParmDecl::Create( + const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, bool ParameterPack, IdentifierInfo *Id, TemplateNameKind Kind, + bool Typename, TemplateParameterList *Params) { return new (C, DC) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id, - Typename, Params); + Kind, Typename, Params); } TemplateTemplateParmDecl * TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, - IdentifierInfo *Id, bool Typename, - TemplateParameterList *Params, + IdentifierInfo *Id, TemplateNameKind Kind, + bool Typename, TemplateParameterList *Params, ArrayRef<TemplateParameterList *> Expansions) { return new (C, DC, additionalSizeToAlloc<TemplateParameterList *>(Expansions.size())) - TemplateTemplateParmDecl(DC, L, D, P, Id, Typename, Params, Expansions); + TemplateTemplateParmDecl(DC, L, D, P, Id, Kind, Typename, Params, + Expansions); } TemplateTemplateParmDecl * TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { - return new (C, ID) TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, - false, nullptr, false, nullptr); + return new (C, ID) TemplateTemplateParmDecl( + nullptr, SourceLocation(), 0, 0, false, nullptr, + TemplateNameKind::TNK_Type_template, false, nullptr); } TemplateTemplateParmDecl * @@ -913,7 +917,8 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, auto *TTP = new (C, ID, additionalSizeToAlloc<TemplateParameterList *>(NumExpansions)) TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, nullptr, - false, nullptr, {}); + TemplateNameKind::TNK_Type_template, false, + nullptr, {}); TTP->NumExpandedParams = NumExpansions; return TTP; } diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 5833a64..a099e97 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -396,6 +396,16 @@ SourceLocation CXXPseudoDestructorExpr::getEndLoc() const { return End; } +static bool UnresolvedLookupExprIsVariableOrConceptParameterPack( + UnresolvedSetIterator Begin, UnresolvedSetIterator End) { + if (std::distance(Begin, End) != 1) + return false; + NamedDecl *ND = *Begin; + if (const auto *TTP = llvm::dyn_cast<TemplateTemplateParmDecl>(ND)) + return TTP->isParameterPack(); + return false; +} + // UnresolvedLookupExpr UnresolvedLookupExpr::UnresolvedLookupExpr( const ASTContext &Context, CXXRecordDecl *NamingClass, @@ -404,9 +414,11 @@ UnresolvedLookupExpr::UnresolvedLookupExpr( const TemplateArgumentListInfo *TemplateArgs, UnresolvedSetIterator Begin, UnresolvedSetIterator End, bool KnownDependent, bool KnownInstantiationDependent) - : OverloadExpr(UnresolvedLookupExprClass, Context, QualifierLoc, - TemplateKWLoc, NameInfo, TemplateArgs, Begin, End, - KnownDependent, KnownInstantiationDependent, false), + : OverloadExpr( + UnresolvedLookupExprClass, Context, QualifierLoc, TemplateKWLoc, + NameInfo, TemplateArgs, Begin, End, KnownDependent, + KnownInstantiationDependent, + UnresolvedLookupExprIsVariableOrConceptParameterPack(Begin, End)), NamingClass(NamingClass) { UnresolvedLookupExprBits.RequiresADL = RequiresADL; } @@ -1714,8 +1726,8 @@ SizeOfPackExpr *SizeOfPackExpr::CreateDeserialized(ASTContext &Context, return new (Storage) SizeOfPackExpr(EmptyShell(), NumPartialArgs); } -NonTypeTemplateParmDecl *SubstNonTypeTemplateParmExpr::getParameter() const { - return cast<NonTypeTemplateParmDecl>( +NamedDecl *SubstNonTypeTemplateParmExpr::getParameter() const { + return cast<NamedDecl>( getReplacedTemplateParameterList(getAssociatedDecl())->asArray()[Index]); } @@ -1758,9 +1770,12 @@ QualType SubstNonTypeTemplateParmExpr::getParameterType( const ASTContext &Context) const { // Note that, for a class type NTTP, we will have an lvalue of type 'const // T', so we can't just compute this from the type and value category. + + QualType Type = getType(); + if (isReferenceParameter()) - return Context.getLValueReferenceType(getType()); - return getType().getUnqualifiedType(); + return Context.getLValueReferenceType(Type); + return Type.getUnqualifiedType(); } SubstNonTypeTemplateParmPackExpr::SubstNonTypeTemplateParmPackExpr( @@ -1997,9 +2012,10 @@ CXXFoldExpr::CXXFoldExpr(QualType T, UnresolvedLookupExpr *Callee, NumExpansions(NumExpansions) { CXXFoldExprBits.Opcode = Opcode; // We rely on asserted invariant to distinguish left and right folds. - assert(((LHS && LHS->containsUnexpandedParameterPack()) != - (RHS && RHS->containsUnexpandedParameterPack())) && - "Exactly one of LHS or RHS should contain an unexpanded pack"); + if (LHS && RHS) + assert(LHS->containsUnexpandedParameterPack() != + RHS->containsUnexpandedParameterPack() && + "Exactly one of LHS or RHS should contain an unexpanded pack"); SubExprs[SubExpr::Callee] = Callee; SubExprs[SubExpr::LHS] = LHS; SubExprs[SubExpr::RHS] = RHS; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 20b7c44..3a47fa8 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -8436,7 +8436,7 @@ public: // doesn't have an implicit argument passed in. const CXXRecordDecl *ClosureClass = MD->getParent(); assert( - ClosureClass->captures_begin() == ClosureClass->captures_end() && + ClosureClass->captures().empty() && "Number of captures must be zero for conversion to function-ptr"); const CXXMethodDecl *LambdaCallOp = diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 2a66793..5233648 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -529,7 +529,7 @@ private: void mangleUnqualifiedBlock(const BlockDecl *Block); void mangleTemplateParamDecl(const NamedDecl *Decl); void mangleTemplateParameterList(const TemplateParameterList *Params); - void mangleTypeConstraint(const ConceptDecl *Concept, + void mangleTypeConstraint(const TemplateDecl *Concept, ArrayRef<TemplateArgument> Arguments); void mangleTypeConstraint(const TypeConstraint *Constraint); void mangleRequiresClause(const Expr *RequiresClause); @@ -2080,7 +2080,7 @@ void CXXNameMangler::mangleTemplateParameterList( } void CXXNameMangler::mangleTypeConstraint( - const ConceptDecl *Concept, ArrayRef<TemplateArgument> Arguments) { + const TemplateDecl *Concept, ArrayRef<TemplateArgument> Arguments) { const DeclContext *DC = Context.getEffectiveDeclContext(Concept); if (!Arguments.empty()) mangleTemplateName(Concept, Arguments); diff --git a/clang/lib/AST/Mangle.cpp b/clang/lib/AST/Mangle.cpp index 9652fdb..0bfb51c 100644 --- a/clang/lib/AST/Mangle.cpp +++ b/clang/lib/AST/Mangle.cpp @@ -161,9 +161,9 @@ void MangleContext::mangleName(GlobalDecl GD, raw_ostream &Out) { if (const AsmLabelAttr *ALA = D->getAttr<AsmLabelAttr>()) { // If we have an asm name, then we use it as the mangling. - // If the label isn't literal, or if this is an alias for an LLVM intrinsic, + // If the label is an alias for an LLVM intrinsic, // do not add a "\01" prefix. - if (!ALA->getIsLiteralLabel() || ALA->getLabel().starts_with("llvm.")) { + if (ALA->getLabel().starts_with("llvm.")) { Out << ALA->getLabel(); return; } diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index 60ec10a..f21e645 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -314,14 +314,17 @@ OpenACCTileClause *OpenACCTileClause::Create(const ASTContext &C, return new (Mem) OpenACCTileClause(BeginLoc, LParenLoc, SizeExprs, EndLoc); } -OpenACCPrivateClause *OpenACCPrivateClause::Create(const ASTContext &C, - SourceLocation BeginLoc, - SourceLocation LParenLoc, - ArrayRef<Expr *> VarList, - SourceLocation EndLoc) { - void *Mem = C.Allocate( - OpenACCPrivateClause::totalSizeToAlloc<Expr *>(VarList.size())); - return new (Mem) OpenACCPrivateClause(BeginLoc, LParenLoc, VarList, EndLoc); +OpenACCPrivateClause * +OpenACCPrivateClause::Create(const ASTContext &C, SourceLocation BeginLoc, + SourceLocation LParenLoc, ArrayRef<Expr *> VarList, + ArrayRef<VarDecl *> InitRecipes, + SourceLocation EndLoc) { + assert(VarList.size() == InitRecipes.size()); + void *Mem = + C.Allocate(OpenACCPrivateClause::totalSizeToAlloc<Expr *, VarDecl *>( + VarList.size(), InitRecipes.size())); + return new (Mem) + OpenACCPrivateClause(BeginLoc, LParenLoc, VarList, InitRecipes, EndLoc); } OpenACCFirstPrivateClause *OpenACCFirstPrivateClause::Create( diff --git a/clang/lib/AST/QualTypeNames.cpp b/clang/lib/AST/QualTypeNames.cpp index b43bcd8..9731b3a 100644 --- a/clang/lib/AST/QualTypeNames.cpp +++ b/clang/lib/AST/QualTypeNames.cpp @@ -273,7 +273,7 @@ static NestedNameSpecifier *createNestedNameSpecifierForScopeOf( // // Make the situation is 'useable' but looking a bit odd by // picking a random instance as the declaring context. - if (ClassTempl->spec_begin() != ClassTempl->spec_end()) { + if (!ClassTempl->specializations().empty()) { Decl = *(ClassTempl->spec_begin()); Outer = dyn_cast<NamedDecl>(Decl); OuterNS = dyn_cast<NamespaceDecl>(Decl); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index c61450e..57834ca 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2636,6 +2636,9 @@ void OpenACCClauseProfiler::VisitCollapseClause( void OpenACCClauseProfiler::VisitPrivateClause( const OpenACCPrivateClause &Clause) { VisitClauseWithVarList(Clause); + + for (auto *VD : Clause.getInitRecipes()) + Profiler.VisitDecl(VD); } void OpenACCClauseProfiler::VisitFirstPrivateClause( diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp index 7c89dea..7a0f740 100644 --- a/clang/lib/AST/TemplateBase.cpp +++ b/clang/lib/AST/TemplateBase.cpp @@ -339,6 +339,17 @@ bool TemplateArgument::isPackExpansion() const { llvm_unreachable("Invalid TemplateArgument Kind!"); } +bool TemplateArgument::isConceptOrConceptTemplateParameter() const { + if (getKind() == TemplateArgument::Template) { + if (isa<ConceptDecl>(getAsTemplate().getAsTemplateDecl())) + return true; + else if (auto *TTP = dyn_cast_if_present<TemplateTemplateParmDecl>( + getAsTemplate().getAsTemplateDecl())) + return TTP->templateParameterKind() == TNK_Concept_template; + } + return false; +} + bool TemplateArgument::containsUnexpandedParameterPack() const { return getDependence() & TemplateArgumentDependence::UnexpandedPack; } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 7444a2f..141edc8 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -5338,7 +5338,7 @@ void clang::FixedPointValueToString(SmallVectorImpl<char> &Str, AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, TypeDependence ExtraDependence, QualType Canon, - ConceptDecl *TypeConstraintConcept, + TemplateDecl *TypeConstraintConcept, ArrayRef<TemplateArgument> TypeConstraintArgs) : DeducedType(Auto, DeducedAsType, ExtraDependence, Canon) { AutoTypeBits.Keyword = llvm::to_underlying(Keyword); @@ -5346,6 +5346,9 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, this->TypeConstraintConcept = TypeConstraintConcept; assert(TypeConstraintConcept || AutoTypeBits.NumArgs == 0); if (TypeConstraintConcept) { + if (isa<TemplateTemplateParmDecl>(TypeConstraintConcept)) + addDependence(TypeDependence::DependentInstantiation); + auto *ArgBuffer = const_cast<TemplateArgument *>(getTypeConstraintArguments().data()); for (const TemplateArgument &Arg : TypeConstraintArgs) { @@ -5361,7 +5364,7 @@ AutoType::AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, void AutoType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType Deduced, AutoTypeKeyword Keyword, - bool IsDependent, ConceptDecl *CD, + bool IsDependent, TemplateDecl *CD, ArrayRef<TemplateArgument> Arguments) { ID.AddPointer(Deduced.getAsOpaquePtr()); ID.AddInteger((unsigned)Keyword); diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp index 32095cb..907cb5f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp @@ -119,7 +119,8 @@ CIRGenFunction::getOpenACCDataOperandInfo(const Expr *e) { if (const auto *memExpr = dyn_cast<MemberExpr>(curVarExpr)) return {exprLoc, emitMemberExpr(memExpr).getPointer(), exprString, - curVarExpr->getType(), std::move(bounds)}; + curVarExpr->getType().getNonReferenceType().getUnqualifiedType(), + std::move(bounds)}; // Sema has made sure that only 4 types of things can get here, array // subscript, array section, member expr, or DRE to a var decl (or the @@ -127,5 +128,6 @@ CIRGenFunction::getOpenACCDataOperandInfo(const Expr *e) { // right. const auto *dre = cast<DeclRefExpr>(curVarExpr); return {exprLoc, emitDeclRefLValue(dre).getPointer(), exprString, - curVarExpr->getType(), std::move(bounds)}; + curVarExpr->getType().getNonReferenceType().getUnqualifiedType(), + std::move(bounds)}; } diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp index 5a6e665..bb9054a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenACCClause.cpp @@ -358,8 +358,8 @@ class OpenACCClauseCIREmitter final template <typename RecipeTy> RecipeTy getOrCreateRecipe(ASTContext &astCtx, const Expr *varRef, - DeclContext *dc, QualType baseType, - mlir::Value mainOp) { + const VarDecl *varRecipe, DeclContext *dc, + QualType baseType, mlir::Value mainOp) { mlir::ModuleOp mod = builder.getBlock()->getParent()->getParentOfType<mlir::ModuleOp>(); @@ -398,12 +398,6 @@ class OpenACCClauseCIREmitter final auto recipe = RecipeTy::create(modBuilder, loc, recipeName, mainOp.getType()); - // Magic-up a var-decl so we can use normal init/destruction operations for - // a variable declaration. - VarDecl &tempDecl = *VarDecl::Create( - astCtx, dc, varRef->getBeginLoc(), varRef->getBeginLoc(), - &astCtx.Idents.get("openacc.private.init"), baseType, - astCtx.getTrivialTypeSourceInfo(baseType), SC_Auto); CIRGenFunction::AutoVarEmission tempDeclEmission{ CIRGenFunction::AutoVarEmission::invalid()}; @@ -422,9 +416,11 @@ class OpenACCClauseCIREmitter final "OpenACC non-private recipe init"); } - tempDeclEmission = - cgf.emitAutoVarAlloca(tempDecl, builder.saveInsertionPoint()); - cgf.emitAutoVarInit(tempDeclEmission); + if (varRecipe) { + tempDeclEmission = + cgf.emitAutoVarAlloca(*varRecipe, builder.saveInsertionPoint()); + cgf.emitAutoVarInit(tempDeclEmission); + } mlir::acc::YieldOp::create(builder, locEnd); } @@ -439,7 +435,7 @@ class OpenACCClauseCIREmitter final } // Destroy section (doesn't currently exist). - if (tempDecl.needsDestruction(cgf.getContext())) { + if (varRecipe && varRecipe->needsDestruction(cgf.getContext())) { llvm::SmallVector<mlir::Type> argsTys{mainOp.getType()}; llvm::SmallVector<mlir::Location> argsLocs{loc}; mlir::Block *block = builder.createBlock(&recipe.getDestroyRegion(), @@ -450,7 +446,7 @@ class OpenACCClauseCIREmitter final mlir::Type elementTy = mlir::cast<cir::PointerType>(mainOp.getType()).getPointee(); Address addr{block->getArgument(0), elementTy, - cgf.getContext().getDeclAlign(&tempDecl)}; + cgf.getContext().getDeclAlign(varRecipe)}; cgf.emitDestroy(addr, baseType, cgf.getDestroyer(QualType::DK_cxx_destructor)); @@ -1080,9 +1076,10 @@ public: void VisitPrivateClause(const OpenACCPrivateClause &clause) { if constexpr (isOneOfTypes<OpTy, mlir::acc::ParallelOp, mlir::acc::SerialOp, mlir::acc::LoopOp>) { - for (const Expr *var : clause.getVarList()) { + for (const auto [varExpr, varRecipe] : + llvm::zip_equal(clause.getVarList(), clause.getInitRecipes())) { CIRGenFunction::OpenACCDataOperandInfo opInfo = - cgf.getOpenACCDataOperandInfo(var); + cgf.getOpenACCDataOperandInfo(varExpr); auto privateOp = mlir::acc::PrivateOp::create( builder, opInfo.beginLoc, opInfo.varValue, /*structured=*/true, /*implicit=*/false, opInfo.name, opInfo.bounds); @@ -1091,8 +1088,9 @@ public: { mlir::OpBuilder::InsertionGuard guardCase(builder); auto recipe = getOrCreateRecipe<mlir::acc::PrivateRecipeOp>( - cgf.getContext(), var, Decl::castToDeclContext(cgf.curFuncDecl), - opInfo.baseType, privateOp.getResult()); + cgf.getContext(), varExpr, varRecipe, + Decl::castToDeclContext(cgf.curFuncDecl), opInfo.baseType, + privateOp.getResult()); // TODO: OpenACC: The dialect is going to change in the near future to // have these be on a different operation, so when that changes, we // probably need to change these here. diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 1ce834d..5f50b1cc 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -2630,7 +2630,8 @@ StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { // existing information in the DWARF. The type is assumed to be 'void *'. void CGDebugInfo::emitVTableSymbol(llvm::GlobalVariable *VTable, const CXXRecordDecl *RD) { - if (!CGM.getTarget().getCXXABI().isItaniumFamily()) + if (!CGM.getTarget().getCXXABI().isItaniumFamily() || + CGM.getTarget().getTriple().isOSBinFormatCOFF()) return; if (DebugKind <= llvm::codegenoptions::DebugLineTablesOnly) return; diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index e3232b6..a7f9298 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -817,6 +817,9 @@ public: case RISCVInterruptAttr::supervisor: Kind = "supervisor"; break; + case RISCVInterruptAttr::rnmi: + Kind = "rnmi"; + break; case RISCVInterruptAttr::qcinest: Kind = "qci-nest"; break; diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index 0781683..5e463b9 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -857,6 +857,9 @@ void AMDGPUToolChain::addClangTargetOptions( CC1Args.push_back("-fvisibility=hidden"); CC1Args.push_back("-fapply-global-visibility-to-externs"); } + + if (DeviceOffloadingKind == Action::OFK_None) + addOpenCLBuiltinsLib(getDriver(), DriverArgs, CC1Args); } void AMDGPUToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 334fcbb..53fd525 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -2985,6 +2985,43 @@ void tools::addHIPRuntimeLibArgs(const ToolChain &TC, Compilation &C, } } +void tools::addOpenCLBuiltinsLib(const Driver &D, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) { + // Check whether user specifies a libclc bytecode library + const Arg *A = DriverArgs.getLastArg(options::OPT_libclc_lib_EQ); + if (!A) + return; + + // Find device libraries in <LLVM_DIR>/lib/clang/<ver>/lib/libclc/ + SmallString<128> LibclcPath(D.ResourceDir); + llvm::sys::path::append(LibclcPath, "lib", "libclc"); + + // If the namespec is of the form :filename, search for that file. + StringRef LibclcNamespec(A->getValue()); + bool FilenameSearch = LibclcNamespec.consume_front(":"); + SmallString<128> LibclcTargetFile(LibclcNamespec); + + if (FilenameSearch && llvm::sys::fs::exists(LibclcTargetFile)) { + CC1Args.push_back("-mlink-builtin-bitcode"); + CC1Args.push_back(DriverArgs.MakeArgString(LibclcTargetFile)); + } else { + // Search the library paths for the file + if (!FilenameSearch) + LibclcTargetFile += ".bc"; + + llvm::sys::path::append(LibclcPath, LibclcTargetFile); + if (llvm::sys::fs::exists(LibclcPath)) { + CC1Args.push_back("-mlink-builtin-bitcode"); + CC1Args.push_back(DriverArgs.MakeArgString(LibclcPath)); + } else { + // Since the user requested a library, if we haven't one then report an + // error. + D.Diag(diag::err_drv_libclc_not_found) << LibclcTargetFile; + } + } +} + void tools::addOutlineAtomicsArgs(const Driver &D, const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index 2d69f8c..a7d6a068 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -84,29 +84,28 @@ public: if (!IsCollectingDecls) return; if (!D || isa<TranslationUnitDecl>(D) || isa<LinkageSpecDecl>(D) || - isa<NamespaceDecl>(D)) { + isa<NamespaceDecl>(D) || isa<ExportDecl>(D)) { // These decls cover a lot of nested declarations that might not be used, // reducing the granularity and making the output less useful. return; } - auto *DC = D->getLexicalDeclContext(); - if (!DC || !DC->isFileContext()) { - // We choose to work at namespace level to reduce complexity and the - // number of cases we care about. + if (isa<ParmVarDecl>(D)) { + // Parameters are covered by their functions. return; } + auto *DC = D->getLexicalDeclContext(); + if (!DC || !shouldIncludeDeclsIn(DC)) + return; PendingDecls.push_back(D); - if (auto *NS = dyn_cast<NamespaceDecl>(DC)) { - // Add any namespaces we have not seen before. - // Note that we filter out namespaces from DeclRead as it includes too - // all redeclarations and we only want the ones that had other used - // declarations. - while (NS && ProcessedNamespaces.insert(NS).second) { - PendingDecls.push_back(NS); - - NS = dyn_cast<NamespaceDecl>(NS->getLexicalParent()); - } + for (; (isa<ExportDecl>(DC) || isa<NamespaceDecl>(DC)) && + ProcessedDeclContexts.insert(DC).second; + DC = DC->getLexicalParent()) { + // Add any interesting decl contexts that we have not seen before. + // Note that we filter them out from DeclRead as that would include all + // redeclarations of namespaces, potentially those that do not have any + // imported declarations. + PendingDecls.push_back(cast<Decl>(DC)); } } @@ -205,12 +204,38 @@ public: private: std::vector<const Decl *> PendingDecls; - llvm::SmallPtrSet<const NamespaceDecl *, 0> ProcessedNamespaces; + llvm::SmallPtrSet<const DeclContext *, 0> ProcessedDeclContexts; bool IsCollectingDecls = true; const SourceManager &SM; std::unique_ptr<llvm::raw_ostream> OS; + static bool shouldIncludeDeclsIn(const DeclContext *DC) { + assert(DC && "DC is null"); + // We choose to work at namespace level to reduce complexity and the number + // of cases we care about. + // We still need to carefully handle composite declarations like + // `ExportDecl`. + for (; DC; DC = DC->getLexicalParent()) { + if (DC->isFileContext()) + return true; + if (isa<ExportDecl>(DC)) + continue; // Depends on the parent. + return false; + } + llvm_unreachable("DeclContext chain must end with a translation unit"); + } + llvm::SmallVector<CharSourceRange, 2> getRangesToMark(const Decl *D) { + if (auto *ED = dyn_cast<ExportDecl>(D)) { + if (!ED->hasBraces()) + return {SM.getExpansionRange(ED->getExportLoc())}; + + return {SM.getExpansionRange(SourceRange( + ED->getExportLoc(), + lexForLBrace(ED->getExportLoc(), D->getLangOpts()))), + SM.getExpansionRange(ED->getRBraceLoc())}; + } + auto *NS = dyn_cast<NamespaceDecl>(D); if (!NS) return {SM.getExpansionRange(D->getSourceRange())}; @@ -232,17 +257,7 @@ private: } } } - auto &LangOpts = D->getLangOpts(); - // Now skip one token, the next should be the lbrace. - Token Tok; - if (Lexer::getRawToken(TokenBeforeLBrace, Tok, SM, LangOpts, true) || - Lexer::getRawToken(Tok.getEndLoc(), Tok, SM, LangOpts, true) || - Tok.getKind() != tok::l_brace) { - // On error or if we did not find the token we expected, avoid marking - // everything inside the namespace as used. - return {}; - } - LBraceLoc = Tok.getLocation(); + LBraceLoc = lexForLBrace(TokenBeforeLBrace, D->getLangOpts()); } return {SM.getExpansionRange(SourceRange(NS->getBeginLoc(), LBraceLoc)), SM.getExpansionRange(NS->getRBraceLoc())}; @@ -285,6 +300,20 @@ private: OS->flush(); } + + SourceLocation lexForLBrace(SourceLocation TokenBeforeLBrace, + const LangOptions &LangOpts) { + // Now skip one token, the next should be the lbrace. + Token Tok; + if (Lexer::getRawToken(TokenBeforeLBrace, Tok, SM, LangOpts, true) || + Lexer::getRawToken(Tok.getEndLoc(), Tok, SM, LangOpts, true) || + Tok.getKind() != tok::l_brace) { + // On error or if we did not find the token we expected, avoid marking + // everything inside the namespace as used. + return SourceLocation(); + } + return Tok.getLocation(); + } }; /// Dumps deserialized declarations. diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index e47caeb..5fb3f92 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3310,6 +3310,7 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, case NameClassificationKind::TypeTemplate: case NameClassificationKind::UndeclaredNonType: case NameClassificationKind::UndeclaredTemplate: + case NameClassificationKind::Concept: // Not a previously-declared non-type entity. MightBeDeclarator = false; break; @@ -3320,7 +3321,6 @@ Parser::DiagnoseMissingSemiAfterTagDefinition(DeclSpec &DS, AccessSpecifier AS, case NameClassificationKind::OverloadSet: case NameClassificationKind::VarTemplate: case NameClassificationKind::FunctionTemplate: - case NameClassificationKind::Concept: // Might be a redeclaration of a prior entity. break; } diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 9a04bf2..0277dfb 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -711,41 +711,61 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth, } } - // Provide an ExtWarn if the C++1z feature of using 'typename' here is used. - // Generate a meaningful error if the user forgot to put class before the - // identifier, comma, or greater. Provide a fixit if the identifier, comma, - // or greater appear immediately or after 'struct'. In the latter case, - // replace the keyword with 'class'. + TemplateNameKind Kind = TemplateNameKind::TNK_Non_template; + SourceLocation NameLoc; + IdentifierInfo *ParamName = nullptr; + SourceLocation EllipsisLoc; bool TypenameKeyword = false; - if (!TryConsumeToken(tok::kw_class)) { + + if (TryConsumeToken(tok::kw_class)) { + Kind = TemplateNameKind::TNK_Type_template; + } else { + + // Provide an ExtWarn if the C++1z feature of using 'typename' here is used. + // Generate a meaningful error if the user forgot to put class before the + // identifier, comma, or greater. Provide a fixit if the identifier, comma, + // or greater appear immediately or after 'struct'. In the latter case, + // replace the keyword with 'class'. bool Replace = Tok.isOneOf(tok::kw_typename, tok::kw_struct); const Token &Next = Tok.is(tok::kw_struct) ? NextToken() : Tok; if (Tok.is(tok::kw_typename)) { TypenameKeyword = true; + Kind = TemplateNameKind::TNK_Type_template; Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_template_template_param_typename : diag::ext_template_template_param_typename) - << (!getLangOpts().CPlusPlus17 - ? FixItHint::CreateReplacement(Tok.getLocation(), "class") - : FixItHint()); + << (!getLangOpts().CPlusPlus17 + ? FixItHint::CreateReplacement(Tok.getLocation(), "class") + : FixItHint()); + Kind = TemplateNameKind::TNK_Type_template; + } else if (TryConsumeToken(tok::kw_concept)) { + Kind = TemplateNameKind::TNK_Concept_template; + } else if (TryConsumeToken(tok::kw_auto)) { + Kind = TemplateNameKind::TNK_Var_template; } else if (Next.isOneOf(tok::identifier, tok::comma, tok::greater, tok::greatergreater, tok::ellipsis)) { + // Provide a fixit if the identifier, comma, + // or greater appear immediately or after 'struct'. In the latter case, + // replace the keyword with 'class'. Diag(Tok.getLocation(), diag::err_class_on_template_template_param) << getLangOpts().CPlusPlus17 << (Replace ? FixItHint::CreateReplacement(Tok.getLocation(), "class") : FixItHint::CreateInsertion(Tok.getLocation(), "class ")); - } else - Diag(Tok.getLocation(), diag::err_class_on_template_template_param) - << getLangOpts().CPlusPlus17; - + } if (Replace) ConsumeToken(); } + if (!getLangOpts().CPlusPlus26 && + (Kind == TemplateNameKind::TNK_Concept_template || + Kind == TemplateNameKind::TNK_Var_template)) { + Diag(PrevTokLocation, diag::err_cxx26_template_template_params) + << (Kind == TemplateNameKind::TNK_Concept_template); + } + // Parse the ellipsis, if given. - SourceLocation EllipsisLoc; if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) Diag(EllipsisLoc, getLangOpts().CPlusPlus11 @@ -753,8 +773,7 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth, : diag::ext_variadic_templates); // Get the identifier, if given. - SourceLocation NameLoc = Tok.getLocation(); - IdentifierInfo *ParamName = nullptr; + NameLoc = Tok.getLocation(); if (Tok.is(tok::identifier)) { ParamName = Tok.getIdentifierInfo(); ConsumeToken(); @@ -792,7 +811,7 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth, } return Actions.ActOnTemplateTemplateParameter( - getCurScope(), TemplateLoc, ParamList, TypenameKeyword, EllipsisLoc, + getCurScope(), TemplateLoc, Kind, TypenameKeyword, ParamList, EllipsisLoc, ParamName, NameLoc, Depth, Position, EqualLoc, DefaultArg); } @@ -1201,7 +1220,8 @@ static bool isEndOfTemplateArgument(Token Tok) { ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { if (!Tok.is(tok::identifier) && !Tok.is(tok::coloncolon) && - !Tok.is(tok::annot_cxxscope)) + !Tok.is(tok::annot_cxxscope) && !Tok.is(tok::annot_template_id) && + !Tok.is(tok::annot_non_type)) return ParsedTemplateArgument(); // C++0x [temp.arg.template]p1: @@ -1245,12 +1265,27 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { /*EnteringContext=*/false, Template)) Result = ParsedTemplateArgument(SS, Template, Name.StartLocation); } - } else if (Tok.is(tok::identifier)) { + } else if (Tok.is(tok::identifier) || Tok.is(tok::annot_template_id) || + Tok.is(tok::annot_non_type)) { // We may have a (non-dependent) template name. TemplateTy Template; UnqualifiedId Name; - Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); - ConsumeToken(); // the identifier + if (Tok.is(tok::annot_non_type)) { + NamedDecl *ND = getNonTypeAnnotation(Tok); + if (!isa<VarTemplateDecl>(ND)) + return Result; + Name.setIdentifier(ND->getIdentifier(), Tok.getLocation()); + ConsumeAnnotationToken(); + } else if (Tok.is(tok::annot_template_id)) { + TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); + if (TemplateId->LAngleLoc.isValid()) + return Result; + Name.setIdentifier(TemplateId->Name, Tok.getLocation()); + ConsumeAnnotationToken(); + } else { + Name.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeToken(); // the identifier + } TryConsumeToken(tok::ellipsis, EllipsisLoc); @@ -1261,7 +1296,8 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { /*hasTemplateKeyword=*/false, Name, /*ObjectType=*/nullptr, /*EnteringContext=*/false, Template, MemberOfUnknownSpecialization); - if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { + if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template || + TNK == TNK_Var_template || TNK == TNK_Concept_template) { // We have an id-expression that refers to a class template or // (C++0x) alias template. Result = ParsedTemplateArgument(SS, Template, Name.StartLocation); @@ -1301,13 +1337,12 @@ ParsedTemplateArgument Parser::ParseTemplateArgument() { { TentativeParsingAction TPA(*this); - ParsedTemplateArgument TemplateTemplateArgument - = ParseTemplateTemplateArgument(); + ParsedTemplateArgument TemplateTemplateArgument = + ParseTemplateTemplateArgument(); if (!TemplateTemplateArgument.isInvalid()) { TPA.Commit(); return TemplateTemplateArgument; } - // Revert this tentative parse to parse a non-type template argument. TPA.Revert(); } diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index b58100c..2a731a1 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1376,7 +1376,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, // If we annotated then the current token should not still be :: // FIXME we may want to also check for tok::annot_typename but // currently don't have a test case. - if (Tok.isNot(tok::annot_cxxscope)) + if (Tok.isNot(tok::annot_cxxscope) && Tok.isNot(tok::identifier)) break; } diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index ff50b3f..a8cfe20 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1838,7 +1838,8 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC, case NameClassificationKind::TypeTemplate: if (Next.isNot(tok::less)) { - // This may be a type template being used as a template template argument. + // This may be a type or variable template being used as a template + // template argument. if (SS.isNotEmpty()) AnnotateScopeToken(SS, !WasScopeAnnotation); return AnnotatedNameKind::TemplateName; @@ -1852,10 +1853,10 @@ Parser::TryAnnotateName(CorrectionCandidateCallback *CCC, Classification.getKind() == NameClassificationKind::Concept; // We have a template name followed by '<'. Consume the identifier token so // we reach the '<' and annotate it. - if (Next.is(tok::less)) - ConsumeToken(); UnqualifiedId Id; Id.setIdentifier(Name, NameLoc); + if (Next.is(tok::less)) + ConsumeToken(); if (AnnotateTemplateIdToken( TemplateTy::make(Classification.getTemplateName()), Classification.getTemplateNameKind(), SS, SourceLocation(), Id, diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 924becf..cfb2f60 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -443,9 +443,7 @@ void Sema::Initialize() { if (getLangOpts().MSVCCompat) { if (getLangOpts().CPlusPlus && IdResolver.begin(&Context.Idents.get("type_info")) == IdResolver.end()) - PushOnScopeChains( - Context.buildImplicitRecord("type_info", TagTypeKind::Class), - TUScope); + PushOnScopeChains(Context.getMSTypeInfoTagDecl(), TUScope); addImplicitTypedef("size_t", Context.getSizeType()); } diff --git a/clang/lib/Sema/SemaAMDGPU.cpp b/clang/lib/Sema/SemaAMDGPU.cpp index a5fbd70..1913bb8 100644 --- a/clang/lib/Sema/SemaAMDGPU.cpp +++ b/clang/lib/Sema/SemaAMDGPU.cpp @@ -82,7 +82,7 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, return checkMovDPPFunctionCall(TheCall, 5, 1); case AMDGPU::BI__builtin_amdgcn_mov_dpp8: return checkMovDPPFunctionCall(TheCall, 2, 1); - case AMDGPU::BI__builtin_amdgcn_update_dpp: { + case AMDGPU::BI__builtin_amdgcn_update_dpp: return checkMovDPPFunctionCall(TheCall, 6, 2); case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_f16_fp8: case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk8_bf16_fp8: @@ -100,7 +100,6 @@ bool SemaAMDGPU::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f32_fp6: case AMDGPU::BI__builtin_amdgcn_cvt_scale_pk16_f32_bf6: return SemaRef.BuiltinConstantArgRange(TheCall, 2, 0, 7); - } default: return false; } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index bc87611..3c4511b 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -35,6 +35,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" +#include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/UnresolvedSet.h" @@ -3716,7 +3717,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, } void Sema::CheckConstrainedAuto(const AutoType *AutoT, SourceLocation Loc) { - if (ConceptDecl *Decl = AutoT->getTypeConstraintConcept()) { + if (TemplateDecl *Decl = AutoT->getTypeConstraintConcept()) { DiagnoseUseOfDecl(Decl, Loc); } } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 3eaf2eb..b5eb825 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -3269,11 +3269,10 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, continue; if (isa<InferredNoReturnAttr>(I)) { - if (auto *FD = dyn_cast<FunctionDecl>(New)) { - if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) - continue; // Don't propagate inferred noreturn attributes to explicit - // specializations. - } + if (auto *FD = dyn_cast<FunctionDecl>(New); + FD && + FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + continue; // Don't propagate inferred noreturn attributes to explicit } if (mergeDeclAttribute(*this, New, I, LocalAMK)) @@ -8113,9 +8112,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } - NewVD->addAttr(AsmLabelAttr::Create(Context, Label, - /*IsLiteralLabel=*/true, - SE->getStrTokenLoc(0))); + NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0))); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I = ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); @@ -10345,9 +10342,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (Expr *E = D.getAsmLabel()) { // The parser guarantees this is a string. StringLiteral *SE = cast<StringLiteral>(E); - NewFD->addAttr(AsmLabelAttr::Create(Context, SE->getString(), - /*IsLiteralLabel=*/true, - SE->getStrTokenLoc(0))); + NewFD->addAttr( + AsmLabelAttr::Create(Context, SE->getString(), SE->getStrTokenLoc(0))); } else if (!ExtnameUndeclaredIdentifiers.empty()) { llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I = ExtnameUndeclaredIdentifiers.find(NewFD->getIdentifier()); @@ -20598,8 +20594,8 @@ void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, LookupOrdinaryName); AttributeCommonInfo Info(AliasName, SourceRange(AliasNameLoc), AttributeCommonInfo::Form::Pragma()); - AsmLabelAttr *Attr = AsmLabelAttr::CreateImplicit( - Context, AliasName->getName(), /*IsLiteralLabel=*/true, Info); + AsmLabelAttr *Attr = + AsmLabelAttr::CreateImplicit(Context, AliasName->getName(), Info); // If a declaration that: // 1) declares a function or a variable diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index e4c2543..6793d6d 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2903,8 +2903,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // in BuildTemplateIdExpr(). // The single lookup result must be a variable template declaration. if (Id.getKind() == UnqualifiedIdKind::IK_TemplateId && Id.TemplateId && - Id.TemplateId->Kind == TNK_Var_template) { - assert(R.getAsSingle<VarTemplateDecl>() && + (Id.TemplateId->Kind == TNK_Var_template || + Id.TemplateId->Kind == TNK_Concept_template)) { + assert(R.getAsSingle<TemplateDecl>() && "There should only be one declaration found."); } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 7b9c638..1dd38c0 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -3713,7 +3713,7 @@ ValueDecl *InitializedEntity::getDecl() const { case EK_ParenAggInitMember: case EK_Binding: case EK_TemplateParameter: - return Variable.VariableOrMember; + return cast<ValueDecl>(Variable.VariableOrMember); case EK_Parameter: case EK_Parameter_CF_Audited: diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 8bfea62..8212646 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -17,6 +17,7 @@ #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/SourceManager.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Scope.h" #include "clang/Sema/Sema.h" #include "llvm/ADT/StringExtras.h" @@ -641,21 +642,13 @@ ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind CK, Expr *VarExpr, if (!InnerExpr || InnerExpr->isTypeDependent()) return VarExpr; - const auto *RD = InnerExpr->getType()->getAsCXXRecordDecl(); + auto *RD = InnerExpr->getType()->getAsCXXRecordDecl(); // if this isn't a C++ record decl, we can create/copy/destroy this thing at // will without problem, so this is a success. if (!RD) return VarExpr; - // TODO: OpenACC: - // Private must have default ctor + dtor in InnerExpr - // FirstPrivate must have copyctor + dtor in InnerExpr - // Reduction must have copyctor + dtor + operation in InnerExpr - - // TODO OpenACC: It isn't clear what the requirements are for default - // constructor/copy constructor are for First private and reduction, but - // private requires a default constructor. if (CK == OpenACCClauseKind::Private) { bool HasNonDeletedDefaultCtor = llvm::find_if(RD->ctors(), [](const CXXConstructorDecl *CD) { @@ -668,6 +661,26 @@ ExprResult CheckVarType(SemaOpenACC &S, OpenACCClauseKind CK, Expr *VarExpr, << clang::diag::AccVarReferencedReason::DefCtor; return ExprError(); } + } else if (CK == OpenACCClauseKind::FirstPrivate) { + if (!RD->hasSimpleCopyConstructor()) { + Sema::SpecialMemberOverloadResult SMOR = S.SemaRef.LookupSpecialMember( + RD, CXXSpecialMemberKind::CopyConstructor, /*ConstArg=*/true, + /*VolatileArg=*/false, /*RValueThis=*/false, /*ConstThis=*/false, + /*VolatileThis=*/false); + + if (SMOR.getKind() != Sema::SpecialMemberOverloadResult::Success || + SMOR.getMethod()->isDeleted()) { + S.Diag(InnerExpr->getBeginLoc(), + clang::diag::warn_acc_var_referenced_lacks_op) + << InnerExpr->getType() << CK + << clang::diag::AccVarReferencedReason::CopyCtor; + return ExprError(); + } + } + } else if (CK == OpenACCClauseKind::Reduction) { + // TODO: OpenACC: + // Reduction must have copyctor + dtor + operation in InnerExpr I think? + // Need to confirm when implementing this part. } // All 3 things need to make sure they have a dtor. @@ -2552,3 +2565,50 @@ ExprResult SemaOpenACC::ActOnOpenACCAsteriskSizeExpr(SourceLocation AsteriskLoc) { return BuildOpenACCAsteriskSizeExpr(AsteriskLoc); } + +VarDecl *SemaOpenACC::CreateInitRecipe(const Expr *VarExpr) { + // Strip off any array subscripts/array section exprs to get to the type of + // the variable. + while (isa_and_present<ArraySectionExpr, ArraySubscriptExpr>(VarExpr)) { + if (const auto *AS = dyn_cast<ArraySectionExpr>(VarExpr)) + VarExpr = AS->getBase()->IgnoreParenImpCasts(); + else if (const auto *Sub = dyn_cast<ArraySubscriptExpr>(VarExpr)) + VarExpr = Sub->getBase()->IgnoreParenImpCasts(); + } + + // If for some reason the expression is invalid, or this is dependent, just + // fill in with nullptr. We'll count on TreeTransform to make this if + // necessary. + if (!VarExpr || VarExpr->getType()->isDependentType()) + return nullptr; + + QualType VarTy = + VarExpr->getType().getNonReferenceType().getUnqualifiedType(); + + VarDecl *Recipe = VarDecl::Create( + getASTContext(), SemaRef.getCurContext(), VarExpr->getBeginLoc(), + VarExpr->getBeginLoc(), + &getASTContext().Idents.get("openacc.private.init"), VarTy, + getASTContext().getTrivialTypeSourceInfo(VarTy), SC_Auto); + + ExprResult Init; + + { + // Trap errors so we don't get weird ones here. If we can't init, we'll just + // swallow the errors. + Sema::TentativeAnalysisScope Trap{SemaRef}; + InitializedEntity Entity = InitializedEntity::InitializeVariable(Recipe); + InitializationKind Kind = + InitializationKind::CreateDefault(Recipe->getLocation()); + + InitializationSequence InitSeq(SemaRef.SemaRef, Entity, Kind, {}); + Init = InitSeq.Perform(SemaRef.SemaRef, Entity, Kind, {}); + } + + if (Init.get()) { + Recipe->setInit(Init.get()); + Recipe->setInitStyle(VarDecl::CallInit); + } + + return Recipe; +} diff --git a/clang/lib/Sema/SemaOpenACCClause.cpp b/clang/lib/Sema/SemaOpenACCClause.cpp index b54a012..9f1a617 100644 --- a/clang/lib/Sema/SemaOpenACCClause.cpp +++ b/clang/lib/Sema/SemaOpenACCClause.cpp @@ -795,9 +795,15 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitPrivateClause( // really isn't anything to do here. GCC does some duplicate-finding, though // it isn't apparent in the standard where this is justified. - return OpenACCPrivateClause::Create(Ctx, Clause.getBeginLoc(), - Clause.getLParenLoc(), - Clause.getVarList(), Clause.getEndLoc()); + llvm::SmallVector<VarDecl *> InitRecipes; + + // Assemble the recipes list. + for (const Expr *VarExpr : Clause.getVarList()) + InitRecipes.push_back(SemaRef.CreateInitRecipe(VarExpr)); + + return OpenACCPrivateClause::Create( + Ctx, Clause.getBeginLoc(), Clause.getLParenLoc(), Clause.getVarList(), + InitRecipes, Clause.getEndLoc()); } OpenACCClause *SemaOpenACCClauseVisitor::VisitFirstPrivateClause( diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp index 994cd07..7b16d08 100644 --- a/clang/lib/Sema/SemaRISCV.cpp +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -1552,9 +1552,11 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) { HasSiFiveCLICType = true; break; case RISCVInterruptAttr::supervisor: + case RISCVInterruptAttr::rnmi: case RISCVInterruptAttr::qcinest: case RISCVInterruptAttr::qcinonest: - // "supervisor" and "qci-(no)nest" cannot be combined with any other types + // "supervisor", "rnmi" and "qci-(no)nest" cannot be combined with any + // other types HasUnaryType = true; break; } @@ -1608,6 +1610,14 @@ void SemaRISCV::handleInterruptAttr(Decl *D, const ParsedAttr &AL) { return; } } break; + case RISCVInterruptAttr::rnmi: { + if (!HasFeature("smrnmi")) { + Diag(AL.getLoc(), + diag::err_riscv_attribute_interrupt_requires_extension) + << RISCVInterruptAttr::ConvertInterruptTypeToStr(Type) << "Smrnmi"; + return; + } + } break; default: break; } diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index 3f89843..a5f9202 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2284,7 +2284,11 @@ StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, // we can diagnose if we don't see any variable declarations. This // covers a case like declaring a typedef, function, or structure // type rather than a variable. - NonVarSeen = DI; + // + // Note, _Static_assert is acceptable because it does not declare an + // identifier at all, so "for object having" does not apply. + if (!isa<StaticAssertDecl>(DI)) + NonVarSeen = DI; } } // Diagnose if we saw a non-variable declaration but no variable diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 21fed2e..b6b8932 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TemplateName.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/DiagnosticSema.h" @@ -38,6 +39,7 @@ #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/SaveAndRestore.h" #include <optional> @@ -306,9 +308,11 @@ TemplateNameKind Sema::isTemplateName(Scope *S, isa<TypeAliasTemplateDecl>(TD) || isa<VarTemplateDecl>(TD) || isa<BuiltinTemplateDecl>(TD) || isa<ConceptDecl>(TD)); TemplateKind = - isa<VarTemplateDecl>(TD) ? TNK_Var_template : - isa<ConceptDecl>(TD) ? TNK_Concept_template : - TNK_Type_template; + isa<TemplateTemplateParmDecl>(TD) + ? dyn_cast<TemplateTemplateParmDecl>(TD)->templateParameterKind() + : isa<VarTemplateDecl>(TD) ? TNK_Var_template + : isa<ConceptDecl>(TD) ? TNK_Concept_template + : TNK_Type_template; } } @@ -1071,12 +1075,26 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { bool Sema::CheckTypeConstraint(TemplateIdAnnotation *TypeConstr) { TemplateName TN = TypeConstr->Template.get(); - ConceptDecl *CD = cast<ConceptDecl>(TN.getAsTemplateDecl()); + NamedDecl *CD = nullptr; + bool IsTypeConcept = false; + bool RequiresArguments = false; + if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TN.getAsTemplateDecl())) { + IsTypeConcept = TTP->isTypeConceptTemplateParam(); + RequiresArguments = + TTP->getTemplateParameters()->getMinRequiredArguments() > 1; + CD = TTP; + } else { + CD = TN.getAsTemplateDecl(); + IsTypeConcept = cast<ConceptDecl>(CD)->isTypeConcept(); + RequiresArguments = cast<ConceptDecl>(CD) + ->getTemplateParameters() + ->getMinRequiredArguments() > 1; + } // C++2a [temp.param]p4: // [...] The concept designated by a type-constraint shall be a type // concept ([temp.concept]). - if (!CD->isTypeConcept()) { + if (!IsTypeConcept) { Diag(TypeConstr->TemplateNameLoc, diag::err_type_constraint_non_type_concept); return true; @@ -1087,8 +1105,7 @@ bool Sema::CheckTypeConstraint(TemplateIdAnnotation *TypeConstr) { bool WereArgsSpecified = TypeConstr->LAngleLoc.isValid(); - if (!WereArgsSpecified && - CD->getTemplateParameters()->getMinRequiredArguments() > 1) { + if (!WereArgsSpecified && RequiresArguments) { Diag(TypeConstr->TemplateNameLoc, diag::err_type_constraint_missing_arguments) << CD; @@ -1115,7 +1132,7 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, return true; TemplateName TN = TypeConstr->Template.get(); - ConceptDecl *CD = cast<ConceptDecl>(TN.getAsTemplateDecl()); + TemplateDecl *CD = cast<TemplateDecl>(TN.getAsTemplateDecl()); UsingShadowDecl *USD = TN.getAsUsingShadowDecl(); DeclarationNameInfo ConceptName(DeclarationName(TypeConstr->Name), @@ -1143,7 +1160,7 @@ bool Sema::BuildTypeConstraint(const CXXScopeSpec &SS, template <typename ArgumentLocAppender> static ExprResult formImmediatelyDeclaredConstraint( Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, - ConceptDecl *NamedConcept, NamedDecl *FoundDecl, SourceLocation LAngleLoc, + NamedDecl *NamedConcept, NamedDecl *FoundDecl, SourceLocation LAngleLoc, SourceLocation RAngleLoc, QualType ConstrainedType, SourceLocation ParamNameLoc, ArgumentLocAppender Appender, SourceLocation EllipsisLoc) { @@ -1162,10 +1179,19 @@ static ExprResult formImmediatelyDeclaredConstraint( // constraint of T. [...] CXXScopeSpec SS; SS.Adopt(NS); - ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId( - SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, - /*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, NamedConcept, - &ConstraintArgs); + ExprResult ImmediatelyDeclaredConstraint; + if (auto *CD = dyn_cast<ConceptDecl>(NamedConcept)) { + ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId( + SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, + /*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, CD, + &ConstraintArgs); + } + // We have a template template parameter + else { + auto *CDT = dyn_cast<TemplateTemplateParmDecl>(NamedConcept); + ImmediatelyDeclaredConstraint = S.CheckVarOrConceptTemplateTemplateId( + SS, NameInfo, CDT, SourceLocation(), &ConstraintArgs); + } if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid()) return ImmediatelyDeclaredConstraint; @@ -1191,7 +1217,8 @@ static ExprResult formImmediatelyDeclaredConstraint( bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, - ConceptDecl *NamedConcept, NamedDecl *FoundDecl, + TemplateDecl *NamedConcept, + NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc) { @@ -1588,11 +1615,15 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, return Param; } +/// ActOnTemplateTemplateParameter - Called when a C++ template template +/// parameter (e.g. T in template <template \<typename> class T> class array) +/// has been parsed. S is the current scope. NamedDecl *Sema::ActOnTemplateTemplateParameter( - Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params, - bool Typename, SourceLocation EllipsisLoc, IdentifierInfo *Name, - SourceLocation NameLoc, unsigned Depth, unsigned Position, - SourceLocation EqualLoc, ParsedTemplateArgument Default) { + Scope *S, SourceLocation TmpLoc, TemplateNameKind Kind, bool Typename, + TemplateParameterList *Params, SourceLocation EllipsisLoc, + IdentifierInfo *Name, SourceLocation NameLoc, unsigned Depth, + unsigned Position, SourceLocation EqualLoc, + ParsedTemplateArgument Default) { assert(S->isTemplateParamScope() && "Template template parameter not in template parameter scope!"); @@ -1609,7 +1640,7 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter( TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create( Context, Context.getTranslationUnitDecl(), NameLoc.isInvalid() ? TmpLoc : NameLoc, Depth, Position, IsParameterPack, - Name, Typename, Params); + Name, Kind, Typename, Params); Param->setAccess(AS_public); if (Param->isParameterPack()) @@ -1658,6 +1689,14 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter( return Param; } + TemplateName Name = + DefaultArg.getArgument().getAsTemplateOrTemplatePattern(); + TemplateDecl *Template = Name.getAsTemplateDecl(); + if (Template && + !CheckDeclCompatibleWithTemplateTemplate(Template, Param, DefaultArg)) { + return Param; + } + // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(DefaultArg.getLocation(), DefaultArg.getArgument().getAsTemplate(), @@ -2667,6 +2706,18 @@ struct DependencyChecker : DynamicRecursiveASTVisitor { return DynamicRecursiveASTVisitor::VisitDeclRefExpr(E); } + bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *ULE) override { + if (ULE->isConceptReference() || ULE->isVarDeclReference()) { + if (auto *TTP = ULE->getTemplateTemplateDecl()) { + if (Matches(TTP->getDepth(), ULE->getExprLoc())) + return false; + } + for (auto &TLoc : ULE->template_arguments()) + DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc(TLoc); + } + return DynamicRecursiveASTVisitor::VisitUnresolvedLookupExpr(ULE); + } + bool VisitSubstTemplateTypeParmType(SubstTemplateTypeParmType *T) override { return TraverseType(T->getReplacementType()); } @@ -4047,8 +4098,10 @@ static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized, static TemplateSpecializationKind getTemplateSpecializationKind(Decl *D); -static bool isTemplateArgumentTemplateParameter( - const TemplateArgument &Arg, unsigned Depth, unsigned Index) { +static bool isTemplateArgumentTemplateParameter(const TemplateArgument &Arg, + NamedDecl *Param, + unsigned Depth, + unsigned Index) { switch (Arg.getKind()) { case TemplateArgument::Null: case TemplateArgument::NullPtr: @@ -4104,7 +4157,8 @@ static bool isSameAsPrimaryTemplate(TemplateParameterList *Params, Arg = Arg.pack_begin()->getPackExpansionPattern(); } - if (!isTemplateArgumentTemplateParameter(Arg, Depth, I)) + if (!isTemplateArgumentTemplateParameter(Arg, Params->getParam(I), Depth, + I)) return false; } @@ -4694,6 +4748,43 @@ ExprResult Sema::CheckVarTemplateId( return BuildDeclarationNameExpr(SS, NameInfo, Var, FoundD, TemplateArgs); } +ExprResult Sema::CheckVarOrConceptTemplateTemplateId( + const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, + TemplateTemplateParmDecl *Template, SourceLocation TemplateLoc, + const TemplateArgumentListInfo *TemplateArgs) { + assert(Template && "A variable template id without template?"); + + if (Template->templateParameterKind() != TemplateNameKind::TNK_Var_template && + Template->templateParameterKind() != + TemplateNameKind::TNK_Concept_template) + return ExprResult(); + + // Check that the template argument list is well-formed for this template. + CheckTemplateArgumentInfo CTAI; + if (CheckTemplateArgumentList( + Template, TemplateLoc, + // FIXME: TemplateArgs will not be modified because + // UpdateArgsWithConversions is false, however, we should + // CheckTemplateArgumentList to be const-correct. + const_cast<TemplateArgumentListInfo &>(*TemplateArgs), + /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, CTAI, + /*UpdateArgsWithConversions=*/false)) + return true; + + UnresolvedSet<1> R; + R.addDecl(Template); + + // FIXME: We model references to variable template and concept parameters + // as an UnresolvedLookupExpr. This is because they encapsulate the same + // data, can generally be used in the same places and work the same way. + // However, it might be cleaner to use a dedicated AST node in the long run. + return UnresolvedLookupExpr::Create( + getASTContext(), nullptr, SS.getWithLocInContext(getASTContext()), + SourceLocation(), NameInfo, false, TemplateArgs, R.begin(), R.end(), + /*KnownDependent=*/false, + /*KnownInstantiationDependent=*/false); +} + void Sema::diagnoseMissingTemplateArguments(TemplateName Name, SourceLocation Loc) { Diag(Loc, diag::err_template_missing_args) @@ -4804,21 +4895,29 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS, KnownDependent = true; } + // We don't want lookup warnings at this point. + R.suppressDiagnostics(); + if (R.getAsSingle<ConceptDecl>()) { return CheckConceptTemplateId(SS, TemplateKWLoc, R.getLookupNameInfo(), R.getRepresentativeDecl(), R.getAsSingle<ConceptDecl>(), TemplateArgs); } - // We don't want lookup warnings at this point. - R.suppressDiagnostics(); + // Check variable template ids (C++17) and concept template parameters + // (C++26). + UnresolvedLookupExpr *ULE; + if (R.getAsSingle<TemplateTemplateParmDecl>()) + return CheckVarOrConceptTemplateTemplateId( + SS, R.getLookupNameInfo(), R.getAsSingle<TemplateTemplateParmDecl>(), + TemplateKWLoc, TemplateArgs); - UnresolvedLookupExpr *ULE = UnresolvedLookupExpr::Create( + // Function templates + ULE = UnresolvedLookupExpr::Create( Context, R.getNamingClass(), SS.getWithLocInContext(Context), TemplateKWLoc, R.getLookupNameInfo(), RequiresADL, TemplateArgs, R.begin(), R.end(), KnownDependent, /*KnownInstantiationDependent=*/false); - // Model the templates with UnresolvedTemplateTy. The expression should then // either be transformed in an instantiation or be diagnosed in // CheckPlaceholderExpr. @@ -5609,12 +5708,25 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, TemplateArgumentLoc &ArgLoc, break; case TemplateArgument::Expression: - case TemplateArgument::Type: + case TemplateArgument::Type: { + auto Kind = 0; + switch (TempParm->templateParameterKind()) { + case TemplateNameKind::TNK_Var_template: + Kind = 1; + break; + case TemplateNameKind::TNK_Concept_template: + Kind = 2; + break; + default: + break; + } + // We have a template template parameter but the template // argument does not refer to a template. Diag(ArgLoc.getLocation(), diag::err_template_arg_must_be_template) - << getLangOpts().CPlusPlus11; + << Kind << getLangOpts().CPlusPlus11; return true; + } case TemplateArgument::Declaration: case TemplateArgument::Integral: @@ -6359,7 +6471,7 @@ enum NullPointerValueKind { /// Determine whether the given template argument is a null pointer /// value of the appropriate type. static NullPointerValueKind -isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, +isNullPointerValueTemplateArgument(Sema &S, NamedDecl *Param, QualType ParamType, Expr *Arg, Decl *Entity = nullptr) { if (Arg->isValueDependent() || Arg->isTypeDependent()) @@ -6464,9 +6576,10 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, /// Checks whether the given template argument is compatible with its /// template parameter. -static bool CheckTemplateArgumentIsCompatibleWithParameter( - Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn, - Expr *Arg, QualType ArgType) { +static bool +CheckTemplateArgumentIsCompatibleWithParameter(Sema &S, NamedDecl *Param, + QualType ParamType, Expr *ArgIn, + Expr *Arg, QualType ArgType) { bool ObjCLifetimeConversion; if (ParamType->isPointerType() && !ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType() && @@ -6522,7 +6635,7 @@ static bool CheckTemplateArgumentIsCompatibleWithParameter( /// Checks whether the given template argument is the address /// of an object or function according to C++ [temp.arg.nontype]p1. static bool CheckTemplateArgumentAddressOfObjectOrFunction( - Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn, + Sema &S, NamedDecl *Param, QualType ParamType, Expr *ArgIn, TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted) { bool Invalid = false; Expr *Arg = ArgIn; @@ -6784,11 +6897,9 @@ static bool CheckTemplateArgumentAddressOfObjectOrFunction( /// Checks whether the given template argument is a pointer to /// member constant according to C++ [temp.arg.nontype]p1. -static bool -CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param, - QualType ParamType, Expr *&ResultArg, - TemplateArgument &SugaredConverted, - TemplateArgument &CanonicalConverted) { +static bool CheckTemplateArgumentPointerToMember( + Sema &S, NamedDecl *Param, QualType ParamType, Expr *&ResultArg, + TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted) { bool Invalid = false; Expr *Arg = ResultArg; @@ -6919,8 +7030,15 @@ CheckTemplateArgumentPointerToMember(Sema &S, NonTypeTemplateParmDecl *Param, return true; } -ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, - QualType ParamType, Expr *Arg, +/// Check a template argument against its corresponding +/// non-type template parameter. +/// +/// This routine implements the semantics of C++ [temp.arg.nontype]. +/// If an error occurred, it returns ExprError(); otherwise, it +/// returns the converted template argument. \p ParamType is the +/// type of the non-type template parameter after it has been instantiated. +ExprResult Sema::CheckTemplateArgument(NamedDecl *Param, QualType ParamType, + Expr *Arg, TemplateArgument &SugaredConverted, TemplateArgument &CanonicalConverted, bool StrictCheck, @@ -6974,7 +7092,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return ExprError(); } else { TemplateDeductionInfo Info(DeductionArg->getExprLoc(), - Param->getDepth() + 1); + Param->getTemplateDepth() + 1); ParamType = QualType(); TemplateDeductionResult Result = DeduceAutoType(TSI->getTypeLoc(), DeductionArg, ParamType, Info, @@ -6986,13 +7104,14 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // checking the template argument list. /*IgnoreConstraints=*/true); if (Result == TemplateDeductionResult::AlreadyDiagnosed) { - if (ParamType.isNull()) - return ExprError(); + return ExprError(); } else if (Result != TemplateDeductionResult::Success) { - Diag(Arg->getExprLoc(), - diag::err_non_type_template_parm_type_deduction_failure) - << Param->getDeclName() << Param->getType() << Arg->getType() - << Arg->getSourceRange(); + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + Diag(Arg->getExprLoc(), + diag::err_non_type_template_parm_type_deduction_failure) + << Param->getDeclName() << NTTP->getType() << Arg->getType() + << Arg->getSourceRange(); + } NoteTemplateParameterLocation(*Param); return ExprError(); } @@ -7387,7 +7506,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (IntegerType->isUnsignedIntegerOrEnumerationType() && (OldValue.isSigned() && OldValue.isNegative())) { Diag(Arg->getBeginLoc(), diag::warn_template_arg_negative) - << toString(OldValue, 10) << toString(Value, 10) << Param->getType() + << toString(OldValue, 10) << toString(Value, 10) << ParamType << Arg->getSourceRange(); NoteTemplateParameterLocation(*Param); } @@ -7402,7 +7521,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, RequiredBits = OldValue.getSignificantBits(); if (RequiredBits > AllowedBits) { Diag(Arg->getBeginLoc(), diag::warn_template_arg_too_large) - << toString(OldValue, 10) << toString(Value, 10) << Param->getType() + << toString(OldValue, 10) << toString(Value, 10) << ParamType << Arg->getSourceRange(); NoteTemplateParameterLocation(*Param); } @@ -7581,6 +7700,81 @@ static void DiagnoseTemplateParameterListArityMismatch( Sema &S, TemplateParameterList *New, TemplateParameterList *Old, Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc); +bool Sema::CheckDeclCompatibleWithTemplateTemplate( + TemplateDecl *Template, TemplateTemplateParmDecl *Param, + const TemplateArgumentLoc &Arg) { + // C++0x [temp.arg.template]p1: + // A template-argument for a template template-parameter shall be + // the name of a class template or an alias template, expressed as an + // id-expression. When the template-argument names a class template, only + // primary class templates are considered when matching the + // template template argument with the corresponding parameter; + // partial specializations are not considered even if their + // parameter lists match that of the template template parameter. + // + + TemplateNameKind Kind = TNK_Non_template; + unsigned DiagFoundKind = 0; + + if (auto *TTP = llvm::dyn_cast<TemplateTemplateParmDecl>(Template)) { + switch (TTP->templateParameterKind()) { + case TemplateNameKind::TNK_Concept_template: + DiagFoundKind = 3; + break; + case TemplateNameKind::TNK_Var_template: + DiagFoundKind = 2; + break; + default: + DiagFoundKind = 1; + break; + } + Kind = TTP->templateParameterKind(); + } else if (isa<ConceptDecl>(Template)) { + Kind = TemplateNameKind::TNK_Concept_template; + DiagFoundKind = 3; + } else if (isa<FunctionTemplateDecl>(Template)) { + Kind = TemplateNameKind::TNK_Function_template; + DiagFoundKind = 0; + } else if (isa<VarTemplateDecl>(Template)) { + Kind = TemplateNameKind::TNK_Var_template; + DiagFoundKind = 2; + } else if (isa<ClassTemplateDecl>(Template) || + isa<TypeAliasTemplateDecl>(Template) || + isa<BuiltinTemplateDecl>(Template)) { + Kind = TemplateNameKind::TNK_Type_template; + DiagFoundKind = 1; + } else { + assert(false && "Unexpected Decl"); + } + + if (Kind == Param->templateParameterKind()) { + return true; + } + + unsigned DiagKind = 0; + switch (Param->templateParameterKind()) { + case TemplateNameKind::TNK_Concept_template: + DiagKind = 2; + break; + case TemplateNameKind::TNK_Var_template: + DiagKind = 1; + break; + default: + DiagKind = 0; + break; + } + Diag(Arg.getLocation(), diag::err_template_arg_not_valid_template) + << DiagKind; + Diag(Template->getLocation(), diag::note_template_arg_refers_to_template_here) + << DiagFoundKind << Template; + return false; +} + +/// Check a template argument against its corresponding +/// template template parameter. +/// +/// This routine implements the semantics of C++ [temp.arg.template]. +/// It returns true if an error occurred, and false otherwise. bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, TemplateParameterList *Params, TemplateArgumentLoc &Arg, @@ -7597,27 +7791,8 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, if (Template->isInvalidDecl()) return true; - // C++0x [temp.arg.template]p1: - // A template-argument for a template template-parameter shall be - // the name of a class template or an alias template, expressed as an - // id-expression. When the template-argument names a class template, only - // primary class templates are considered when matching the - // template template argument with the corresponding parameter; - // partial specializations are not considered even if their - // parameter lists match that of the template template parameter. - // - // Note that we also allow template template parameters here, which - // will happen when we are dealing with, e.g., class template - // partial specializations. - if (!isa<ClassTemplateDecl>(Template) && - !isa<TemplateTemplateParmDecl>(Template) && - !isa<TypeAliasTemplateDecl>(Template) && - !isa<BuiltinTemplateDecl>(Template)) { - assert(isa<FunctionTemplateDecl>(Template) && - "Only function templates are possible here"); - Diag(Arg.getLocation(), diag::err_template_arg_not_valid_template); - Diag(Template->getLocation(), diag::note_template_arg_refers_here_func) - << Template; + if (!CheckDeclCompatibleWithTemplateTemplate(Template, Param, Arg)) { + return true; } // C++1z [temp.arg.template]p3: (DR 150) @@ -7689,6 +7864,10 @@ void Sema::NoteTemplateParameterLocation(const NamedDecl &Decl) { diag::note_template_param_external); } +/// Given a non-type template argument that refers to a +/// declaration and the type of its corresponding non-type template +/// parameter, produce an expression that properly refers to that +/// declaration. ExprResult Sema::BuildExpressionFromDeclTemplateArgument( const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc, NamedDecl *TemplateParam) { @@ -8009,34 +8188,40 @@ static bool MatchTemplateParameterKind( return false; } - // For non-type template parameters, check the type of the parameter. - if (NonTypeTemplateParmDecl *OldNTTP - = dyn_cast<NonTypeTemplateParmDecl>(Old)) { + if (NonTypeTemplateParmDecl *OldNTTP = + dyn_cast<NonTypeTemplateParmDecl>(Old)) { NonTypeTemplateParmDecl *NewNTTP = cast<NonTypeTemplateParmDecl>(New); - // C++20 [temp.over.link]p6: - // Two [non-type] template-parameters are equivalent [if] they have - // equivalent types ignoring the use of type-constraints for - // placeholder types - QualType OldType = S.Context.getUnconstrainedType(OldNTTP->getType()); - QualType NewType = S.Context.getUnconstrainedType(NewNTTP->getType()); - if (!S.Context.hasSameType(OldType, NewType)) { - 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 we are matching a template template argument to a template + // 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_TemplateTemplateParmMatch || + (!OldNTTP->getType()->isDependentType() && + !NewNTTP->getType()->isDependentType())) { + // C++20 [temp.over.link]p6: + // Two [non-type] template-parameters are equivalent [if] they have + // equivalent types ignoring the use of type-constraints for + // placeholder types + QualType OldType = S.Context.getUnconstrainedType(OldNTTP->getType()); + QualType NewType = S.Context.getUnconstrainedType(NewNTTP->getType()); + if (!S.Context.hasSameType(OldType, NewType)) { + 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 false; } } // For template template parameters, check the template parameter types. @@ -8045,6 +8230,8 @@ static bool MatchTemplateParameterKind( else if (TemplateTemplateParmDecl *OldTTP = dyn_cast<TemplateTemplateParmDecl>(Old)) { TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New); + if (OldTTP->templateParameterKind() != NewTTP->templateParameterKind()) + return false; if (!S.TemplateParameterListsAreEqual( NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom, OldTTP->getTemplateParameters(), Complain, @@ -8056,6 +8243,7 @@ static bool MatchTemplateParameterKind( } if (Kind != Sema::TPL_TemplateParamsEquivalent && + Kind != Sema::TPL_TemplateTemplateParmMatch && !isa<TemplateTemplateParmDecl>(Old)) { const Expr *NewC = nullptr, *OldC = nullptr; @@ -8421,6 +8609,11 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs( if (isa<NonTypeTemplateParmDecl>(DRE->getDecl())) continue; + if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(ArgExpr); + ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) { + continue; + } + // C++ [temp.class.spec]p9: // Within the argument list of a class template partial // specialization, the following restrictions apply: @@ -9032,13 +9225,15 @@ void Sema::CheckConceptRedefinition(ConceptDecl *NewDecl, Context.setPrimaryMergedDecl(NewDecl, OldConcept->getCanonicalDecl()); } -bool Sema::CheckConceptUseInDefinition(ConceptDecl *Concept, - SourceLocation Loc) { - if (!Concept->isInvalidDecl() && !Concept->hasDefinition()) { - Diag(Loc, diag::err_recursive_concept) << Concept; - Diag(Concept->getLocation(), diag::note_declared_at); +bool Sema::CheckConceptUseInDefinition(NamedDecl *Concept, SourceLocation Loc) { + if (auto *CE = llvm::dyn_cast<ConceptDecl>(Concept); + CE && !CE->isInvalidDecl() && !CE->hasDefinition()) { + Diag(Loc, diag::err_recursive_concept) << CE; + Diag(CE->getLocation(), diag::note_declared_at); return true; } + // Concept template parameters don't have a definition and can't + // be defined recursively. return false; } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 9e56e697..0d70321 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -37,6 +37,7 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TemplateKinds.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Sema.h" @@ -146,11 +147,7 @@ static void MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, bool OnlyDeduced, unsigned Level, llvm::SmallBitVector &Deduced); -/// If the given expression is of a form that permits the deduction -/// of a non-type template parameter, return the declaration of that -/// non-type template parameter. -static const NonTypeTemplateParmDecl * -getDeducedParameterFromExpr(const Expr *E, unsigned Depth) { +static const Expr *unwrapExpressionForDeduction(const Expr *E) { // If we are within an alias template, the expression may have undergone // any number of parameter substitutions already. while (true) { @@ -170,18 +167,100 @@ getDeducedParameterFromExpr(const Expr *E, unsigned Depth) { } else break; } + return E; +} + +class NonTypeOrVarTemplateParmDecl { +public: + NonTypeOrVarTemplateParmDecl(const NamedDecl *Template) : Template(Template) { + assert( + !Template || isa<NonTypeTemplateParmDecl>(Template) || + (isa<TemplateTemplateParmDecl>(Template) && + (cast<TemplateTemplateParmDecl>(Template)->templateParameterKind() == + TNK_Var_template || + cast<TemplateTemplateParmDecl>(Template)->templateParameterKind() == + TNK_Concept_template))); + } + + QualType getType() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return NTTP->getType(); + return getTemplate()->templateParameterKind() == TNK_Concept_template + ? getTemplate()->getASTContext().BoolTy + : getTemplate()->getASTContext().DependentTy; + } + + unsigned getDepth() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return NTTP->getDepth(); + return getTemplate()->getDepth(); + } + + unsigned getIndex() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return NTTP->getIndex(); + return getTemplate()->getIndex(); + } + + const TemplateTemplateParmDecl *getTemplate() const { + return cast<TemplateTemplateParmDecl>(Template); + } + + const NonTypeTemplateParmDecl *getNTTP() const { + return cast<NonTypeTemplateParmDecl>(Template); + } + + TemplateParameter asTemplateParam() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return const_cast<NonTypeTemplateParmDecl *>(NTTP); + return const_cast<TemplateTemplateParmDecl *>(getTemplate()); + } + + bool isExpandedParameterPack() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return NTTP->isExpandedParameterPack(); + return getTemplate()->isExpandedParameterPack(); + } + + SourceLocation getLocation() const { + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template)) + return NTTP->getLocation(); + return getTemplate()->getLocation(); + } + + operator bool() const { return Template; } +private: + const NamedDecl *Template; +}; + +/// If the given expression is of a form that permits the deduction +/// of a non-type template parameter, return the declaration of that +/// non-type template parameter. +static NonTypeOrVarTemplateParmDecl +getDeducedNTTParameterFromExpr(const Expr *E, unsigned Depth) { + // If we are within an alias template, the expression may have undergone + // any number of parameter substitutions already. + E = unwrapExpressionForDeduction(E); if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl())) if (NTTP->getDepth() == Depth) return NTTP; + if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E); + ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) { + if (auto *TTP = ULE->getTemplateTemplateDecl()) { + + if (TTP->getDepth() == Depth) + return TTP; + } + } return nullptr; } -static const NonTypeTemplateParmDecl * -getDeducedParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) { - return getDeducedParameterFromExpr(E, Info.getDeducedDepth()); +static const NonTypeOrVarTemplateParmDecl +getDeducedNTTParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) { + return getDeducedNTTParameterFromExpr(E, Info.getDeducedDepth()); } /// Determine whether two declaration pointers refer to the same @@ -386,29 +465,28 @@ checkDeducedTemplateArguments(ASTContext &Context, /// deduction is funneled through here. static TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, + const NonTypeOrVarTemplateParmDecl NTTP, const DeducedTemplateArgument &NewDeduced, QualType ValueType, TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool *HasDeducedAnyParam) { - assert(NTTP->getDepth() == Info.getDeducedDepth() && + assert(NTTP.getDepth() == Info.getDeducedDepth() && "deducing non-type template argument with wrong depth"); DeducedTemplateArgument Result = checkDeducedTemplateArguments( - S.Context, Deduced[NTTP->getIndex()], NewDeduced); + S.Context, Deduced[NTTP.getIndex()], NewDeduced); if (Result.isNull()) { - Info.Param = const_cast<NonTypeTemplateParmDecl*>(NTTP); - Info.FirstArg = Deduced[NTTP->getIndex()]; + Info.Param = NTTP.asTemplateParam(); + Info.FirstArg = Deduced[NTTP.getIndex()]; Info.SecondArg = NewDeduced; return TemplateDeductionResult::Inconsistent; } - - Deduced[NTTP->getIndex()] = Result; + Deduced[NTTP.getIndex()] = Result; if (!S.getLangOpts().CPlusPlus17) return TemplateDeductionResult::Success; - if (NTTP->isExpandedParameterPack()) + if (NTTP.isExpandedParameterPack()) // FIXME: We may still need to deduce parts of the type here! But we // don't have any way to find which slice of the type to use, and the // type stored on the NTTP itself is nonsense. Perhaps the type of an @@ -417,7 +495,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, // Get the type of the parameter for deduction. If it's a (dependent) array // or function type, we will not have decayed it yet, so do that now. - QualType ParamType = S.Context.getAdjustedParameterType(NTTP->getType()); + QualType ParamType = S.Context.getAdjustedParameterType(NTTP.getType()); if (auto *Expansion = dyn_cast<PackExpansionType>(ParamType)) ParamType = Expansion->getPattern(); @@ -444,7 +522,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, /// from the given integral constant. static TemplateDeductionResult DeduceNonTypeTemplateArgument( Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value, + NonTypeOrVarTemplateParmDecl NTTP, const llvm::APSInt &Value, QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool *HasDeducedAnyParam) { @@ -459,14 +537,14 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument( /// from the given null pointer template argument type. static TemplateDeductionResult DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, + NonTypeOrVarTemplateParmDecl NTTP, QualType NullPtrType, TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool *HasDeducedAnyParam) { Expr *Value = S.ImpCastExprToType( new (S.Context) CXXNullPtrLiteralExpr(S.Context.NullPtrTy, - NTTP->getLocation()), + NTTP.getLocation()), NullPtrType, NullPtrType->isMemberPointerType() ? CK_NullToMemberPointer : CK_NullToPointer) @@ -482,7 +560,7 @@ DeduceNullPtrTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, /// \returns true if deduction succeeded, false otherwise. static TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, Expr *Value, + NonTypeOrVarTemplateParmDecl NTTP, Expr *Value, TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool *HasDeducedAnyParam) { @@ -497,7 +575,7 @@ DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, /// \returns true if deduction succeeded, false otherwise. static TemplateDeductionResult DeduceNonTypeTemplateArgument(Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, ValueDecl *D, + NonTypeOrVarTemplateParmDecl NTTP, ValueDecl *D, QualType T, TemplateDeductionInfo &Info, bool PartialOrdering, SmallVectorImpl<DeducedTemplateArgument> &Deduced, @@ -1930,14 +2008,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Determine the array bound is something we can deduce. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, DAP->getSizeExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, DAP->getSizeExpr()); if (!NTTP) return TemplateDeductionResult::Success; // We can perform template argument deduction for the given non-type // template parameter. - assert(NTTP->getDepth() == Info.getDeducedDepth() && + assert(NTTP.getDepth() == Info.getDeducedDepth() && "saw non-type template parameter with wrong depth"); if (const auto *CAA = dyn_cast<ConstantArrayType>(AA)) { llvm::APSInt Size(CAA->getSize()); @@ -1994,10 +2072,10 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // deducing through the noexcept-specifier if it's part of the canonical // type. libstdc++ relies on this. Expr *NoexceptExpr = FPP->getNoexceptExpr(); - if (const NonTypeTemplateParmDecl *NTTP = - NoexceptExpr ? getDeducedParameterFromExpr(Info, NoexceptExpr) + if (NonTypeOrVarTemplateParmDecl NTTP = + NoexceptExpr ? getDeducedNTTParameterFromExpr(Info, NoexceptExpr) : nullptr) { - assert(NTTP->getDepth() == Info.getDeducedDepth() && + assert(NTTP.getDepth() == Info.getDeducedDepth() && "saw non-type template parameter with wrong depth"); llvm::APSInt Noexcept(1); @@ -2191,8 +2269,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the vector size, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2217,8 +2295,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the vector size, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2246,8 +2324,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the vector size, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2271,8 +2349,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the vector size, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, VP->getSizeExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2348,8 +2426,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return TemplateDeductionResult::NonDeducedMismatch; } - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, ParamExpr); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, ParamExpr); if (!NTTP) return TemplateDeductionResult::Success; @@ -2395,8 +2473,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the address space, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2420,8 +2498,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return Result; // Perform deduction on the address space, if we can. - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, ASP->getAddrSpaceExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2440,8 +2518,8 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (IP->isUnsigned() != IA->isUnsigned()) return TemplateDeductionResult::NonDeducedMismatch; - const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, IP->getNumBitsExpr()); + NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, IP->getNumBitsExpr()); if (!NTTP) return TemplateDeductionResult::Success; @@ -2573,8 +2651,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, return TemplateDeductionResult::NonDeducedMismatch; case TemplateArgument::Expression: - if (const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, P.getAsExpr())) { + if (NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(Info, P.getAsExpr())) { switch (A.getKind()) { case TemplateArgument::Expression: { const Expr *E = A.getAsExpr(); @@ -2628,7 +2706,6 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, } llvm_unreachable("Unknown template argument kind"); } - // Can't deduce anything, but that's okay. return TemplateDeductionResult::Success; case TemplateArgument::Pack: @@ -4392,8 +4469,8 @@ static TemplateDeductionResult DeduceFromInitializerList( // from the length of the initializer list. if (auto *DependentArrTy = dyn_cast_or_null<DependentSizedArrayType>(ArrTy)) { // Determine the array bound is something we can deduce. - if (const NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(Info, DependentArrTy->getSizeExpr())) { + if (NonTypeOrVarTemplateParmDecl NTTP = getDeducedNTTParameterFromExpr( + Info, DependentArrTy->getSizeExpr())) { // We can perform template argument deduction for the given non-type // template parameter. // C++ [temp.deduct.type]p13: @@ -5098,7 +5175,7 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, AutoTypeLoc TypeLoc, QualType Deduced) { ConstraintSatisfaction Satisfaction; - ConceptDecl *Concept = Type.getTypeConstraintConcept(); + ConceptDecl *Concept = cast<ConceptDecl>(Type.getTypeConstraintConcept()); TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(), TypeLoc.getRAngleLoc()); TemplateArgs.addArgument( @@ -6654,6 +6731,18 @@ struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor { Used[NTTP->getIndex()] = true; return true; } + + bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *ULE) override { + if (ULE->isConceptReference() || ULE->isVarDeclReference()) { + if (auto *TTP = ULE->getTemplateTemplateDecl()) { + if (TTP->getDepth() == Depth) + Used[TTP->getIndex()] = true; + } + for (auto &TLoc : ULE->template_arguments()) + DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc(TLoc); + } + return true; + } }; } @@ -6675,17 +6764,28 @@ MarkUsedTemplateParameters(ASTContext &Ctx, if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E)) E = Expansion->getPattern(); - const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(E, Depth); - if (!NTTP) + E = unwrapExpressionForDeduction(E); + if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E); + ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) { + if (const auto *TTP = ULE->getTemplateTemplateDecl()) + Used[TTP->getIndex()] = true; + for (auto &TLoc : ULE->template_arguments()) + MarkUsedTemplateParameters(Ctx, TLoc.getArgument(), OnlyDeduced, Depth, + Used); return; + } - if (NTTP->getDepth() == Depth) - Used[NTTP->getIndex()] = true; + const NonTypeOrVarTemplateParmDecl NTTP = + getDeducedNTTParameterFromExpr(E, Depth); + if (!NTTP) + return; + if (NTTP.getDepth() == Depth) + Used[NTTP.getIndex()] = true; // In C++17 mode, additional arguments may be deduced from the type of a // non-type argument. if (Ctx.getLangOpts().CPlusPlus17) - MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used); + MarkUsedTemplateParameters(Ctx, NTTP.getType(), OnlyDeduced, Depth, Used); } /// Mark the template parameters that are used by the given diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index d84d0ca1..0d96d18 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1899,8 +1899,7 @@ namespace { private: ExprResult - transformNonTypeTemplateParmRef(Decl *AssociatedDecl, - const NonTypeTemplateParmDecl *parm, + transformNonTypeTemplateParmRef(Decl *AssociatedDecl, const NamedDecl *parm, SourceLocation loc, TemplateArgument arg, UnsignedOrNone PackIndex, bool Final); }; @@ -2338,22 +2337,25 @@ TemplateInstantiator::TransformOpenACCRoutineDeclAttr( } ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( - Decl *AssociatedDecl, const NonTypeTemplateParmDecl *parm, - SourceLocation loc, TemplateArgument arg, UnsignedOrNone PackIndex, - bool Final) { + Decl *AssociatedDecl, const NamedDecl *parm, SourceLocation loc, + TemplateArgument arg, UnsignedOrNone PackIndex, bool Final) { ExprResult result; // Determine the substituted parameter type. We can usually infer this from // the template argument, but not always. auto SubstParamType = [&] { - QualType T; - if (parm->isExpandedParameterPack()) - T = parm->getExpansionType(*SemaRef.ArgPackSubstIndex); - else - T = parm->getType(); - if (parm->isParameterPack() && isa<PackExpansionType>(T)) - T = cast<PackExpansionType>(T)->getPattern(); - return SemaRef.SubstType(T, TemplateArgs, loc, parm->getDeclName()); + if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(parm)) { + QualType T; + if (NTTP->isExpandedParameterPack()) + T = NTTP->getExpansionType(*SemaRef.ArgPackSubstIndex); + else + T = NTTP->getType(); + if (parm->isParameterPack() && isa<PackExpansionType>(T)) + T = cast<PackExpansionType>(T)->getPattern(); + return SemaRef.SubstType(T, TemplateArgs, loc, parm->getDeclName()); + } + return SemaRef.SubstType(arg.getAsExpr()->getType(), TemplateArgs, loc, + parm->getDeclName()); }; bool refParam = false; @@ -2408,7 +2410,9 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( Expr *resultExpr = result.get(); return new (SemaRef.Context) SubstNonTypeTemplateParmExpr( resultExpr->getType(), resultExpr->getValueKind(), loc, resultExpr, - AssociatedDecl, parm->getIndex(), PackIndex, refParam, Final); + AssociatedDecl, + clang::getDepthAndIndex(const_cast<NamedDecl *>(parm)).second, PackIndex, + refParam, Final); } ExprResult diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 233bb65..87ec4f7 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -3784,14 +3784,14 @@ TemplateDeclInstantiator::VisitTemplateTemplateParmDecl( Param = TemplateTemplateParmDecl::Create( SemaRef.Context, Owner, D->getLocation(), D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), - D->getPosition(), D->getIdentifier(), D->wasDeclaredWithTypename(), - InstParams, ExpandedParams); + D->getPosition(), D->getIdentifier(), D->templateParameterKind(), + D->wasDeclaredWithTypename(), InstParams, ExpandedParams); else Param = TemplateTemplateParmDecl::Create( SemaRef.Context, Owner, D->getLocation(), D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getPosition(), D->isParameterPack(), D->getIdentifier(), - D->wasDeclaredWithTypename(), InstParams); + D->templateParameterKind(), D->wasDeclaredWithTypename(), InstParams); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { NestedNameSpecifierLoc QualifierLoc = D->getDefaultArgument().getTemplateQualifierLoc(); diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index b0a673d..d2baa2e 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -310,6 +310,16 @@ class CollectUnexpandedParameterPacksVisitor return DynamicRecursiveASTVisitor::TraverseLambdaCapture(Lambda, C, Init); } + bool TraverseUnresolvedLookupExpr(UnresolvedLookupExpr *E) override { + if (E->getNumDecls() == 1) { + NamedDecl *ND = *E->decls_begin(); + if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND); + TTP && TTP->isParameterPack()) + addUnexpanded(ND, E->getBeginLoc()); + } + return DynamicRecursiveASTVisitor::TraverseUnresolvedLookupExpr(E); + } + #ifndef NDEBUG bool TraverseFunctionParmPackExpr(FunctionParmPackExpr *) override { ContainsIntermediatePacks = true; diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 7dbd4bb..1289bed 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1306,12 +1306,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { ? AutoTypeKeyword::DecltypeAuto : AutoTypeKeyword::Auto; - ConceptDecl *TypeConstraintConcept = nullptr; + TemplateDecl *TypeConstraintConcept = nullptr; llvm::SmallVector<TemplateArgument, 8> TemplateArgs; if (DS.isConstrainedAuto()) { if (TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId()) { TypeConstraintConcept = - cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()); + cast<TemplateDecl>(TemplateId->Template.get().getAsTemplateDecl()); TemplateArgumentListInfo TemplateArgsInfo; TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc); TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc); @@ -3090,15 +3090,13 @@ InventTemplateParameter(TypeProcessingState &state, QualType T, if (!Invalid) { UsingShadowDecl *USD = TemplateId->Template.get().getAsUsingShadowDecl(); - auto *CD = - cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()); + TemplateDecl *CD = TemplateId->Template.get().getAsTemplateDecl(); S.AttachTypeConstraint( D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context), DeclarationNameInfo(DeclarationName(TemplateId->Name), TemplateId->TemplateNameLoc), CD, - /*FoundDecl=*/ - USD ? cast<NamedDecl>(USD) : CD, + /*FoundDecl=*/USD ? cast<NamedDecl>(USD) : CD, TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr, InventedTemplateParam, D.getEllipsisLoc()); } diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index c7428d1..5ff5fbf5 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -610,6 +610,10 @@ public: TemplateArgumentLoc &Output, bool Uneval = false); + TemplateArgument + TransformNamedTemplateTemplateArgument(CXXScopeSpec &SS, TemplateName Name, + SourceLocation NameLoc); + /// Transform the given set of template arguments. /// /// By default, this operation transforms all of the template arguments @@ -4843,6 +4847,15 @@ TreeTransform<Derived>::TransformTemplateName(CXXScopeSpec &SS, llvm_unreachable("overloaded function decl survived to here"); } +template <typename Derived> +TemplateArgument TreeTransform<Derived>::TransformNamedTemplateTemplateArgument( + CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc) { + TemplateName TN = getDerived().TransformTemplateName(SS, Name, NameLoc); + if (TN.isNull()) + return TemplateArgument(); + return TemplateArgument(TN); +} + template<typename Derived> void TreeTransform<Derived>::InventTemplateArgumentLoc( const TemplateArgument &Arg, @@ -4927,13 +4940,13 @@ bool TreeTransform<Derived>::TransformTemplateArgument( CXXScopeSpec SS; SS.Adopt(QualifierLoc); - TemplateName Template = getDerived().TransformTemplateName( + + TemplateArgument Out = getDerived().TransformNamedTemplateTemplateArgument( SS, Arg.getAsTemplate(), Input.getTemplateNameLoc()); - if (Template.isNull()) + if (Out.isNull()) return true; - - Output = TemplateArgumentLoc(SemaRef.Context, TemplateArgument(Template), - QualifierLoc, Input.getTemplateNameLoc()); + Output = TemplateArgumentLoc(SemaRef.Context, Out, QualifierLoc, + Input.getTemplateNameLoc()); return false; } @@ -5029,10 +5042,8 @@ template<typename InputIterator> bool TreeTransform<Derived>::TransformTemplateArguments( InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs, bool Uneval) { - for (; First != Last; ++First) { + for (TemplateArgumentLoc In : llvm::make_range(First, Last)) { TemplateArgumentLoc Out; - TemplateArgumentLoc In = *First; - if (In.getArgument().getKind() == TemplateArgument::Pack) { // Unpack argument packs, which we translate them into separate // arguments. @@ -5042,11 +5053,10 @@ bool TreeTransform<Derived>::TransformTemplateArguments( typedef TemplateArgumentLocInventIterator<Derived, TemplateArgument::pack_iterator> PackLocIterator; - if (TransformTemplateArguments(PackLocIterator(*this, - In.getArgument().pack_begin()), - PackLocIterator(*this, - In.getArgument().pack_end()), - Outputs, Uneval)) + if (TransformTemplateArguments( + PackLocIterator(*this, In.getArgument().pack_begin()), + PackLocIterator(*this, In.getArgument().pack_end()), Outputs, + Uneval)) return true; continue; @@ -11730,20 +11740,26 @@ class OpenACCClauseTransform final SemaOpenACC::OpenACCParsedClause &ParsedClause; OpenACCClause *NewClause = nullptr; + ExprResult VisitVar(Expr *VarRef) { + ExprResult Res = Self.TransformExpr(VarRef); + + if (!Res.isUsable()) + return Res; + + Res = Self.getSema().OpenACC().ActOnVar(ParsedClause.getDirectiveKind(), + ParsedClause.getClauseKind(), + Res.get()); + + return Res; + } + llvm::SmallVector<Expr *> VisitVarList(ArrayRef<Expr *> VarList) { llvm::SmallVector<Expr *> InstantiatedVarList; for (Expr *CurVar : VarList) { - ExprResult Res = Self.TransformExpr(CurVar); + ExprResult VarRef = VisitVar(CurVar); - if (!Res.isUsable()) - continue; - - Res = Self.getSema().OpenACC().ActOnVar(ParsedClause.getDirectiveKind(), - ParsedClause.getClauseKind(), - Res.get()); - - if (Res.isUsable()) - InstantiatedVarList.push_back(Res.get()); + if (VarRef.isUsable()) + InstantiatedVarList.push_back(VarRef.get()); } return InstantiatedVarList; @@ -11870,12 +11886,31 @@ void OpenACCClauseTransform<Derived>::VisitNumGangsClause( template <typename Derived> void OpenACCClauseTransform<Derived>::VisitPrivateClause( const OpenACCPrivateClause &C) { - ParsedClause.setVarListDetails(VisitVarList(C.getVarList()), + llvm::SmallVector<Expr *> InstantiatedVarList; + llvm::SmallVector<VarDecl *> InitRecipes; + + for (const auto [RefExpr, InitRecipe] : + llvm::zip(C.getVarList(), C.getInitRecipes())) { + ExprResult VarRef = VisitVar(RefExpr); + + if (VarRef.isUsable()) { + InstantiatedVarList.push_back(VarRef.get()); + + // We only have to create a new one if it is dependent, and Sema won't + // make one of these unless the type is non-dependent. + if (InitRecipe) + InitRecipes.push_back(InitRecipe); + else + InitRecipes.push_back( + Self.getSema().OpenACC().CreateInitRecipe(VarRef.get())); + } + } + ParsedClause.setVarListDetails(InstantiatedVarList, OpenACCModifierKind::Invalid); NewClause = OpenACCPrivateClause::Create( Self.getSema().getASTContext(), ParsedClause.getBeginLoc(), - ParsedClause.getLParenLoc(), ParsedClause.getVarList(), + ParsedClause.getLParenLoc(), ParsedClause.getVarList(), InitRecipes, ParsedClause.getEndLoc()); } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 682d263..95e92cf 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -8317,6 +8317,9 @@ Decl *ASTReader::getPredefinedDecl(PredefinedDeclIDs ID) { NewLoaded = Context.getCFConstantStringTagDecl(); break; + case PREDEF_DECL_BUILTIN_MS_TYPE_INFO_TAG_ID: + return Context.getMSTypeInfoTagDecl(); + #define BuiltinTemplate(BTName) \ case PREDEF_DECL##BTName##_ID: \ if (Context.Decl##BTName) \ @@ -12851,8 +12854,13 @@ OpenACCClause *ASTRecordReader::readOpenACCClause() { case OpenACCClauseKind::Private: { SourceLocation LParenLoc = readSourceLocation(); llvm::SmallVector<Expr *> VarList = readOpenACCVarList(); + + llvm::SmallVector<VarDecl *> RecipeList; + for (unsigned I = 0; I < VarList.size(); ++I) + RecipeList.push_back(readDeclAs<VarDecl>()); + return OpenACCPrivateClause::Create(getContext(), BeginLoc, LParenLoc, - VarList, EndLoc); + VarList, RecipeList, EndLoc); } case OpenACCClauseKind::Host: { SourceLocation LParenLoc = readSourceLocation(); diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index cdaf38d..2c7beb4 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -2742,6 +2742,7 @@ void ASTDeclReader::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { VisitTemplateDecl(D); + D->ParameterKind = static_cast<TemplateNameKind>(Record.readInt()); D->setDeclaredWithTypename(Record.readBool()); // TemplateParmPosition. D->setDepth(Record.readInt()); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 0166e49..3f37dfb 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -2086,13 +2086,12 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) { assert((E->hasTemplateKWAndArgsInfo() == HasTemplateKWAndArgsInfo) && "Wrong HasTemplateKWAndArgsInfo!"); + unsigned NumTemplateArgs = 0; if (HasTemplateKWAndArgsInfo) { - unsigned NumTemplateArgs = Record.readInt(); + NumTemplateArgs = Record.readInt(); ReadTemplateKWAndArgsInfo(*E->getTrailingASTTemplateKWAndArgsInfo(), E->getTrailingTemplateArgumentLoc(), NumTemplateArgs); - assert((E->getNumTemplateArgs() == NumTemplateArgs) && - "Wrong NumTemplateArgs!"); } UnresolvedSet<8> Decls; @@ -2108,6 +2107,9 @@ void ASTStmtReader::VisitOverloadExpr(OverloadExpr *E) { Results[I] = (Iter + I).getPair(); } + assert((E->getNumTemplateArgs() == NumTemplateArgs) && + "Wrong NumTemplateArgs!"); + E->NameInfo = Record.readDeclarationNameInfo(); E->QualifierLoc = Record.readNestedNameSpecifierLoc(); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index a6957e5..955f7b9 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -5618,6 +5618,8 @@ void ASTWriter::PrepareWritingSpecialDecls(Sema &SemaRef) { PREDEF_DECL_BUILTIN_MS_VA_LIST_ID); RegisterPredefDecl(Context.MSGuidTagDecl, PREDEF_DECL_BUILTIN_MS_GUID_ID); + RegisterPredefDecl(Context.MSTypeInfoTagDecl, + PREDEF_DECL_BUILTIN_MS_TYPE_INFO_TAG_ID); RegisterPredefDecl(Context.ExternCContext, PREDEF_DECL_EXTERN_C_CONTEXT_ID); RegisterPredefDecl(Context.CFConstantStringTypeDecl, PREDEF_DECL_CF_CONSTANT_STRING_ID); @@ -8738,6 +8740,9 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) { const auto *PC = cast<OpenACCPrivateClause>(C); writeSourceLocation(PC->getLParenLoc()); writeOpenACCVarList(PC); + + for (VarDecl *VD : PC->getInitRecipes()) + AddDeclRef(VD); return; } case OpenACCClauseKind::Host: { diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index e414910..6fd25b9 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -2149,6 +2149,7 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { Record.push_back(D->getNumExpansionTemplateParameters()); VisitTemplateDecl(D); + Record.push_back(D->templateParameterKind()); Record.push_back(D->wasDeclaredWithTypename()); // TemplateParmPosition. Record.push_back(D->getDepth()); diff --git a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt index 22dd3f0..7836041 100644 --- a/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt +++ b/clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt @@ -104,6 +104,7 @@ add_clang_library(clangStaticAnalyzerCheckers SmartPtrChecker.cpp SmartPtrModeling.cpp StackAddrEscapeChecker.cpp + StoreToImmutableChecker.cpp StdLibraryFunctionsChecker.cpp StdVariantChecker.cpp STLAlgorithmModeling.cpp diff --git a/clang/lib/StaticAnalyzer/Checkers/StoreToImmutableChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StoreToImmutableChecker.cpp new file mode 100644 index 0000000..afad419 --- /dev/null +++ b/clang/lib/StaticAnalyzer/Checkers/StoreToImmutableChecker.cpp @@ -0,0 +1,188 @@ +//=== StoreToImmutableChecker.cpp - Store to immutable memory ---*- 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 file defines StoreToImmutableChecker, a checker that detects writes +// to immutable memory regions. This implements part of SEI CERT Rule ENV30-C. +// +//===----------------------------------------------------------------------===// + +#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/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/MemRegion.h" + +using namespace clang; +using namespace ento; + +namespace { +class StoreToImmutableChecker : public Checker<check::Bind> { + const BugType BT{this, "Write to immutable memory", "CERT Environment (ENV)"}; + +public: + void checkBind(SVal Loc, SVal Val, const Stmt *S, CheckerContext &C) const; +}; +} // end anonymous namespace + +static bool isInitializationContext(const Stmt *S, CheckerContext &C) { + // Check if this is a DeclStmt (variable declaration) + if (isa<DeclStmt>(S)) + return true; + + // This part is specific for initialization of const lambdas pre-C++17. + // Lets look at the AST of the statement: + // ``` + // const auto lambda = [](){}; + // ``` + // + // The relevant part of the AST for this case prior to C++17 is: + // ... + // `-DeclStmt + // `-VarDecl + // `-ExprWithCleanups + // `-CXXConstructExpr + // ... + // In C++17 and later, the AST is different: + // ... + // `-DeclStmt + // `-VarDecl + // `-ImplicitCastExpr + // `-LambdaExpr + // |-CXXRecordDecl + // `-CXXConstructExpr + // ... + // And even beside this, the statement `S` that is given to the checkBind + // callback is the VarDecl in C++17 and later, and the CXXConstructExpr in + // C++14 and before. So in order to support the C++14 we need the following + // ugly hack to detect whether this construction is used to initialize a + // variable. + // + // FIXME: This should be eliminated by improving the API of checkBind to + // ensure that it consistently passes the `VarDecl` (instead of the + // `CXXConstructExpr`) when the constructor call denotes the initialization + // of a variable with a lambda, or maybe less preferably, try the more + // invasive approach of passing the information forward to the checkers + // whether the current bind is an initialization or an assignment. + const auto *ConstructExp = dyn_cast<CXXConstructExpr>(S); + return ConstructExp && ConstructExp->isElidable(); +} + +static bool isEffectivelyConstRegion(const MemRegion *MR, CheckerContext &C) { + if (isa<GlobalImmutableSpaceRegion>(MR)) + return true; + + // Check if this is a TypedRegion with a const-qualified type + if (const auto *TR = dyn_cast<TypedRegion>(MR)) { + QualType LocationType = TR->getDesugaredLocationType(C.getASTContext()); + if (LocationType->isPointerOrReferenceType()) + LocationType = LocationType->getPointeeType(); + if (LocationType.isConstQualified()) + return true; + } + + // Check if this is a SymbolicRegion with a const-qualified pointee type + if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) { + QualType PointeeType = SR->getPointeeStaticType(); + if (PointeeType.isConstQualified()) + return true; + } + + // NOTE: The above branches do not cover AllocaRegion. We do not need to check + // AllocaRegion, as it models untyped memory, that is allocated on the stack. + + return false; +} + +static const MemRegion *getInnermostConstRegion(const MemRegion *MR, + CheckerContext &C) { + while (true) { + if (isEffectivelyConstRegion(MR, C)) + return MR; + if (auto *SR = dyn_cast<SubRegion>(MR)) + MR = SR->getSuperRegion(); + else + return nullptr; + } +} + +static const DeclRegion * +getInnermostEnclosingConstDeclRegion(const MemRegion *MR, CheckerContext &C) { + while (true) { + if (const auto *DR = dyn_cast<DeclRegion>(MR)) { + const ValueDecl *D = DR->getDecl(); + QualType DeclaredType = D->getType(); + if (DeclaredType.isConstQualified()) + return DR; + } + if (auto *SR = dyn_cast<SubRegion>(MR)) + MR = SR->getSuperRegion(); + else + return nullptr; + } +} + +void StoreToImmutableChecker::checkBind(SVal Loc, SVal Val, const Stmt *S, + CheckerContext &C) const { + // We are only interested in stores to memory regions + const MemRegion *MR = Loc.getAsRegion(); + if (!MR) + return; + + // Skip variable declarations and initializations - we only want to catch + // actual writes + // FIXME: If the API of checkBind would allow to distinguish between + // initialization and assignment, we could use that instead. + if (isInitializationContext(S, C)) + return; + + // Check if the region is in the global immutable space + const MemSpaceRegion *MS = MR->getMemorySpace(C.getState()); + const bool IsGlobalImmutableSpace = isa<GlobalImmutableSpaceRegion>(MS); + // Check if the region corresponds to a const variable + const MemRegion *InnermostConstRegion = getInnermostConstRegion(MR, C); + if (!IsGlobalImmutableSpace && !InnermostConstRegion) + return; + + SmallString<64> WarningMessage{"Trying to write to immutable memory"}; + if (IsGlobalImmutableSpace) + WarningMessage += " in global read-only storage"; + + // Generate the bug report + ExplodedNode *N = C.generateNonFatalErrorNode(); + if (!N) + return; + + auto R = std::make_unique<PathSensitiveBugReport>(BT, WarningMessage, N); + R->addRange(S->getSourceRange()); + + // Generate a note if the location that is being written to has a + // declaration or if it is a subregion of a const region with a declaration. + const DeclRegion *DR = + getInnermostEnclosingConstDeclRegion(InnermostConstRegion, C); + if (DR) { + const char *NoteMessage = + (DR != MR) ? "Enclosing memory region is declared as immutable here" + : "Memory region is declared as immutable here"; + R->addNote(NoteMessage, PathDiagnosticLocation::create( + DR->getDecl(), C.getSourceManager())); + } + + // For this checker, we are only interested in the value being written, no + // need to mark the value being assigned interesting. + + C.emitReport(std::move(R)); +} + +void ento::registerStoreToImmutableChecker(CheckerManager &mgr) { + mgr.registerChecker<StoreToImmutableChecker>(); +} + +bool ento::shouldRegisterStoreToImmutableChecker(const CheckerManager &mgr) { + return true; +} |