From ef82ffb4300c301b19965b421dc52ba524ea7bd3 Mon Sep 17 00:00:00 2001 From: Corentin Jabot Date: Sun, 27 Jul 2025 12:16:12 +0200 Subject: [PATCH 01/13] [WIP] Variable and concept template parameters --- clang/include/clang/AST/ASTConcept.h | 16 +- clang/include/clang/AST/ASTContext.h | 11 +- clang/include/clang/AST/DeclTemplate.h | 47 ++- clang/include/clang/AST/ExprCXX.h | 47 ++- clang/include/clang/AST/ExprConcepts.h | 4 +- clang/include/clang/AST/TemplateBase.h | 2 + clang/include/clang/AST/Type.h | 8 +- clang/include/clang/AST/TypeLoc.h | 2 +- clang/include/clang/AST/TypeProperties.td | 4 +- .../clang/Basic/DiagnosticSemaKinds.td | 19 +- clang/include/clang/Sema/Initialization.h | 6 +- clang/include/clang/Sema/Ownership.h | 1 + clang/include/clang/Sema/ParsedTemplate.h | 212 +++++----- clang/include/clang/Sema/Sema.h | 20 +- clang/include/clang/Sema/SemaInternal.h | 1 + clang/lib/AST/ASTConcept.cpp | 2 +- clang/lib/AST/ASTContext.cpp | 26 +- clang/lib/AST/ASTImporter.cpp | 4 +- clang/lib/AST/ASTStructuralEquivalence.cpp | 3 +- clang/lib/AST/ComputeDependence.cpp | 2 +- clang/lib/AST/Decl.cpp | 3 + clang/lib/AST/DeclTemplate.cpp | 41 +- clang/lib/AST/ExprCXX.cpp | 36 +- clang/lib/AST/ItaniumMangle.cpp | 4 +- clang/lib/AST/TemplateBase.cpp | 12 + clang/lib/AST/Type.cpp | 7 +- clang/lib/Parse/ParseDecl.cpp | 2 +- clang/lib/Parse/ParseTemplate.cpp | 83 ++-- clang/lib/Parse/ParseTentative.cpp | 2 +- clang/lib/Parse/Parser.cpp | 7 +- clang/lib/Sema/SemaChecking.cpp | 3 +- clang/lib/Sema/SemaExpr.cpp | 8 +- clang/lib/Sema/SemaInit.cpp | 2 +- clang/lib/Sema/SemaTemplate.cpp | 385 +++++++++++++----- clang/lib/Sema/SemaTemplateDeduction.cpp | 218 +++++++--- clang/lib/Sema/SemaTemplateInstantiate.cpp | 56 ++- .../lib/Sema/SemaTemplateInstantiateDecl.cpp | 6 +- clang/lib/Sema/SemaTemplateVariadic.cpp | 10 + clang/lib/Sema/SemaType.cpp | 10 +- clang/lib/Sema/TreeTransform.h | 79 +++- clang/lib/Serialization/ASTReaderDecl.cpp | 1 + clang/lib/Serialization/ASTReaderStmt.cpp | 8 +- clang/lib/Serialization/ASTWriterDecl.cpp | 1 + clang/test/CodeGenCXX/mangle-concept.cpp | 3 +- .../Parser/cxx-template-template-recovery.cpp | 12 +- .../test/Parser/cxx2a-concept-declaration.cpp | 5 - .../Parser/cxx2c-template-template-param.cpp | 79 ++++ .../SemaCXX/cxx2c-template-template-param.cpp | 372 +++++++++++++++++ .../TableGen/ClangBuiltinTemplatesEmitter.cpp | 3 +- .../TypeSystem/Clang/TypeSystemClang.cpp | 10 +- 50 files changed, 1467 insertions(+), 438 deletions(-) create mode 100644 clang/test/Parser/cxx2c-template-template-param.cpp create mode 100644 clang/test/SemaCXX/cxx2c-template-template-param.cpp diff --git a/clang/include/clang/AST/ASTConcept.h b/clang/include/clang/AST/ASTConcept.h index c8f6330a73bb1..7ccac4481b14c 100644 --- a/clang/include/clang/AST/ASTConcept.h +++ b/clang/include/clang/AST/ASTConcept.h @@ -27,6 +27,7 @@ namespace clang { class ConceptDecl; +class TemplateDecl; class Expr; class NamedDecl; struct PrintingPolicy; @@ -123,6 +124,7 @@ struct ASTConstraintSatisfaction final : /// template T> void dump(); /// ~~~~~~~~~~~~~~~~~~~~~~~ (in TemplateTypeParmDecl) class ConceptReference { +protected: // \brief The optional nested name specifier used when naming the concept. NestedNameSpecifierLoc NestedNameSpec; @@ -140,7 +142,7 @@ class ConceptReference { NamedDecl *FoundDecl; /// \brief The concept named. - ConceptDecl *NamedConcept; + TemplateDecl *NamedConcept; /// \brief The template argument list source info used to specialize the /// concept. @@ -148,7 +150,7 @@ class ConceptReference { ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, - ConceptDecl *NamedConcept, + TemplateDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten) : NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc), ConceptName(ConceptNameInfo), FoundDecl(FoundDecl), @@ -158,7 +160,7 @@ class ConceptReference { static ConceptReference * Create(const ASTContext &C, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, - NamedDecl *FoundDecl, ConceptDecl *NamedConcept, + NamedDecl *FoundDecl, TemplateDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten); const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const { @@ -197,9 +199,7 @@ class ConceptReference { return FoundDecl; } - ConceptDecl *getNamedConcept() const { - return NamedConcept; - } + TemplateDecl *getNamedConcept() const { return NamedConcept; } const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const { return ArgsAsWritten; @@ -252,7 +252,9 @@ class TypeConstraint { // FIXME: Instead of using these concept related functions the callers should // directly work with the corresponding ConceptReference. - ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); } + TemplateDecl *getNamedConcept() const { + return ConceptRef->getNamedConcept(); + } SourceLocation getConceptNameLoc() const { return ConceptRef->getConceptNameLoc(); diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 0273109f8a698..8bdcff8b17fda 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -1753,7 +1753,7 @@ class ASTContext : public RefCountedBase { QualType getAutoTypeInternal(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent, bool IsPack = false, - ConceptDecl *TypeConstraintConcept = nullptr, + TemplateDecl *TypeConstraintConcept = nullptr, ArrayRef TypeConstraintArgs = {}, bool IsCanon = false) const; @@ -1973,10 +1973,11 @@ class ASTContext : public RefCountedBase { UnaryTransformType::UTTKind UKind) const; /// C++11 deduced auto type. - QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, - bool IsDependent, bool IsPack = false, - ConceptDecl *TypeConstraintConcept = nullptr, - ArrayRef TypeConstraintArgs ={}) const; + QualType + getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent, + bool IsPack = false, + TemplateDecl *TypeConstraintConcept = nullptr, + ArrayRef TypeConstraintArgs = {}) const; /// C++11 deduction pattern for 'auto' type. QualType getAutoDeductType() const; diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index 1ff6cc6fcb7d1..8e25f239fb97f 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -26,6 +26,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TemplateKinds.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerIntPair.h" @@ -1585,6 +1586,9 @@ class TemplateTemplateParmDecl final DefaultArgStorage; DefArgStorage DefaultArgument; + LLVM_PREFERRED_TYPE(TemplateNameKind) + unsigned ParameterKind : 3; + /// Whether this template template parameter was declaration with /// the 'typename' keyword. /// @@ -1607,13 +1611,16 @@ class TemplateTemplateParmDecl final TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, bool ParameterPack, IdentifierInfo *Id, - bool Typename, TemplateParameterList *Params) + TemplateNameKind ParameterKind, bool Typename, + TemplateParameterList *Params) : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), - TemplateParmPosition(D, P), Typename(Typename), - ParameterPack(ParameterPack), ExpandedParameterPack(false) {} + TemplateParmPosition(D, P), ParameterKind(ParameterKind), + Typename(Typename), ParameterPack(ParameterPack), + ExpandedParameterPack(false) {} TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, - unsigned P, IdentifierInfo *Id, bool Typename, + unsigned P, IdentifierInfo *Id, + TemplateNameKind ParameterKind, bool Typename, TemplateParameterList *Params, ArrayRef Expansions); @@ -1624,15 +1631,16 @@ class TemplateTemplateParmDecl final friend class ASTDeclWriter; friend TrailingObjects; - static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC, - SourceLocation L, unsigned D, - unsigned P, bool ParameterPack, - IdentifierInfo *Id, bool Typename, - TemplateParameterList *Params); static TemplateTemplateParmDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, - unsigned P, IdentifierInfo *Id, bool Typename, - TemplateParameterList *Params, + unsigned P, bool ParameterPack, IdentifierInfo *Id, + TemplateNameKind ParameterKind, bool Typename, + TemplateParameterList *Params); + + static TemplateTemplateParmDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, TemplateNameKind ParameterKind, + bool Typename, TemplateParameterList *Params, ArrayRef Expansions); static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C, @@ -1746,6 +1754,16 @@ class TemplateTemplateParmDecl final return SourceRange(getTemplateParameters()->getTemplateLoc(), End); } + TemplateNameKind kind() const { + return static_cast(ParameterKind); + } + + bool isTypeConceptTemplateParam() const { + return kind() == TemplateNameKind::TNK_Concept_template && + getTemplateParameters()->size() > 0 && + isa(getTemplateParameters()->getParam(0)); + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K == TemplateTemplateParm; } @@ -3341,7 +3359,12 @@ inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) { return TD && (isa(TD) || isa(TD) || isa(TD) || - isa(TD)) + [&]() { + if (TemplateTemplateParmDecl *TTP = + dyn_cast(TD)) + return TTP->kind() == TNK_Type_template; + return false; + }()) ? TD : nullptr; } diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index a22c32241ac61..a78ad0999d198 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -38,6 +38,7 @@ #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Basic/TemplateKinds.h" #include "clang/Basic/TypeTraits.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerUnion.h" @@ -3257,7 +3258,49 @@ class OverloadExpr : public Expr { bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); } /// Determines whether this expression had explicit template arguments. - bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); } + bool hasExplicitTemplateArgs() const { + if (!hasTemplateKWAndArgsInfo()) + return false; + // FIXME corentin: deduced function types can have "hidden" args and no < + // investigate that further, but ultimately maybe we want to model concepts + // reference with another kind of expression. + return (isConceptReference() || isVarDeclReference()) + ? getTrailingASTTemplateKWAndArgsInfo()->NumTemplateArgs + : getLAngleLoc().isValid(); + } + + bool isConceptReference() const { + return getNumDecls() == 1 && [&]() { + if (auto *TTP = dyn_cast_or_null( + getTrailingResults()->getDecl())) + return TTP->kind() == TNK_Concept_template; + if (isa(getTrailingResults()->getDecl())) + return true; + return false; + }(); + } + + bool isVarDeclReference() const { + return getNumDecls() == 1 && [&]() { + if (auto *TTP = dyn_cast_or_null( + getTrailingResults()->getDecl())) + return TTP->kind() == TNK_Var_template; + if (isa(getTrailingResults()->getDecl())) + return true; + return false; + }(); + } + + TemplateDecl *getTemplateDecl() const { + assert(getNumDecls() == 1); + return dyn_cast_or_null(getTrailingResults()->getDecl()); + } + + TemplateTemplateParmDecl *getTemplateTemplateDecl() const { + assert(getNumDecls() == 1); + return dyn_cast_or_null( + getTrailingResults()->getDecl()); + } TemplateArgumentLoc const *getTemplateArgs() const { if (!hasExplicitTemplateArgs()) @@ -4658,7 +4701,7 @@ class SubstNonTypeTemplateParmExpr : public Expr { // sugared: it doesn't need to be resugared later. bool getFinal() const { return Final; } - NonTypeTemplateParmDecl *getParameter() const; + NamedDecl *getParameter() const; bool isReferenceParameter() const { return AssociatedDeclAndRef.getInt(); } diff --git a/clang/include/clang/AST/ExprConcepts.h b/clang/include/clang/AST/ExprConcepts.h index 7ab0c3e0b2769..4f162b6ffc8af 100644 --- a/clang/include/clang/AST/ExprConcepts.h +++ b/clang/include/clang/AST/ExprConcepts.h @@ -84,7 +84,9 @@ class ConceptSpecializationExpr final : public Expr { ConceptReference *getConceptReference() const { return ConceptRef; } - ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); } + ConceptDecl *getNamedConcept() const { + return cast(ConceptRef->getNamedConcept()); + } // FIXME: Several of the following functions can be removed. Instead the // caller can directly work with the ConceptReference. diff --git a/clang/include/clang/AST/TemplateBase.h b/clang/include/clang/AST/TemplateBase.h index b67036cae4261..eb384eae3faa7 100644 --- a/clang/include/clang/AST/TemplateBase.h +++ b/clang/include/clang/AST/TemplateBase.h @@ -316,6 +316,8 @@ class TemplateArgument { /// Determine whether this template argument is a pack expansion. bool isPackExpansion() const; + bool isConceptOrConceptTemplateParameter() const; + /// Retrieve the type for a type template argument. QualType getAsType() const { assert(getKind() == Type && "Unexpected kind"); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 98810fbea726e..12dce309127e5 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -6762,10 +6762,10 @@ class DeducedType : public Type { class AutoType : public DeducedType { friend class ASTContext; // ASTContext creates these - ConceptDecl *TypeConstraintConcept; + TemplateDecl *TypeConstraintConcept; AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword, - TypeDependence ExtraDependence, QualType Canon, ConceptDecl *CD, + TypeDependence ExtraDependence, QualType Canon, TemplateDecl *CD, ArrayRef TypeConstraintArgs); public: @@ -6774,7 +6774,7 @@ class AutoType : public DeducedType { AutoTypeBits.NumArgs}; } - ConceptDecl *getTypeConstraintConcept() const { + TemplateDecl *getTypeConstraintConcept() const { return TypeConstraintConcept; } @@ -6797,7 +6797,7 @@ class AutoType : public DeducedType { void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context); static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType Deduced, AutoTypeKeyword Keyword, - bool IsDependent, ConceptDecl *CD, + bool IsDependent, TemplateDecl *CD, ArrayRef Arguments); static bool classof(const Type *T) { diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index be0bc896de3ea..52ef7ac54145e 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -2284,7 +2284,7 @@ class AutoTypeLoc return nullptr; } - ConceptDecl *getNamedConcept() const { + TemplateDecl *getNamedConcept() const { if (const auto *CR = getConceptReference()) return CR->getNamedConcept(); return nullptr; diff --git a/clang/include/clang/AST/TypeProperties.td b/clang/include/clang/AST/TypeProperties.td index 3114d1180319a..3373e963038f1 100644 --- a/clang/include/clang/AST/TypeProperties.td +++ b/clang/include/clang/AST/TypeProperties.td @@ -495,9 +495,9 @@ let Class = AutoType in { def : Property<"keyword", AutoTypeKeyword> { let Read = [{ node->getKeyword() }]; } - def : Property<"typeConstraintConcept", Optional> { + def : Property<"typeConstraintConcept", Optional> { let Read = [{ makeOptionalFromPointer( - const_cast(node->getTypeConstraintConcept())) }]; + node->getTypeConstraintConcept()) }]; } def : Property<"typeConstraintArguments", Array> { let Read = [{ node->getTypeConstraintArguments() }]; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 81cbd38d5cd24..7cfe145120ea4 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5441,8 +5441,10 @@ def err_template_arg_must_be_expr : Error< "template argument for non-type template parameter must be an expression">; def err_template_arg_nontype_ambig : Error< "template argument for non-type template parameter is treated as function type %0">; -def err_template_arg_must_be_template : Error< - "template argument for template template parameter must be a class template%select{| or type alias template}0">; +def err_template_arg_must_be_template + : Error<"template argument for template template parameter must be a " + "%select{class template%select{| or type alias template}1|variable " + "template|concept}0">; def ext_template_arg_local_type : ExtWarn< "template argument uses local type %0">, InGroup; def ext_template_arg_unnamed_type : ExtWarn< @@ -5457,11 +5459,14 @@ def note_template_unnamed_type_here : Note< "unnamed type used in template argument was declared here">; def err_template_arg_overload_type : Error< "template argument is the type of an unresolved overloaded function">; -def err_template_arg_not_valid_template : Error< - "template argument does not refer to a class or alias template, or template " - "template parameter">; -def note_template_arg_refers_here_func : Note< - "template argument refers to function template %0, here">; +def err_template_arg_not_valid_template + : Error<"template argument does not refer to a %select{class or alias " + "template|variable template|concept}0, or template " + "template parameter">; + +def note_template_arg_refers_to_template_here + : Note<"template argument refers to a %select{function template|class " + "template|variable template|concept}0 %1, here">; def err_template_arg_template_params_mismatch : Error< "template template argument has different template parameters than its " "corresponding template template parameter">; diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h index a1c156eed5394..e5ee4b4e48ccc 100644 --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/include/clang/Sema/Initialization.h @@ -160,7 +160,7 @@ class alignas(8) InitializedEntity { struct VD { /// The VarDecl, FieldDecl, or BindingDecl being initialized. - ValueDecl *VariableOrMember; + NamedDecl *VariableOrMember; /// When Kind == EK_Member, whether this is an implicit member /// initialization in a copy or move constructor. These can perform array @@ -291,8 +291,8 @@ class alignas(8) InitializedEntity { } /// Create the initialization entity for a template parameter. - static InitializedEntity - InitializeTemplateParameter(QualType T, NonTypeTemplateParmDecl *Param) { + static InitializedEntity InitializeTemplateParameter(QualType T, + NamedDecl *Param) { InitializedEntity Entity; Entity.Kind = EK_TemplateParameter; Entity.Type = T; diff --git a/clang/include/clang/Sema/Ownership.h b/clang/include/clang/Sema/Ownership.h index 0752f5de7e334..b1520837f2f9d 100644 --- a/clang/include/clang/Sema/Ownership.h +++ b/clang/include/clang/Sema/Ownership.h @@ -13,6 +13,7 @@ #ifndef LLVM_CLANG_SEMA_OWNERSHIP_H #define LLVM_CLANG_SEMA_OWNERSHIP_H +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/Basic/LLVM.h" #include "llvm/ADT/ArrayRef.h" diff --git a/clang/include/clang/Sema/ParsedTemplate.h b/clang/include/clang/Sema/ParsedTemplate.h index 3a8050f9a0a3d..6628bb88a81b9 100644 --- a/clang/include/clang/Sema/ParsedTemplate.h +++ b/clang/include/clang/Sema/ParsedTemplate.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_SEMA_PARSEDTEMPLATE_H #define LLVM_CLANG_SEMA_PARSEDTEMPLATE_H +#include "clang/AST/DeclTemplate.h" #include "clang/Basic/OperatorKinds.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/TemplateKinds.h" @@ -26,115 +27,116 @@ #include namespace clang { - /// Represents the parsed form of a C++ template argument. - class ParsedTemplateArgument { - public: - /// Describes the kind of template argument that was parsed. - enum KindType { - /// A template type parameter, stored as a type. - Type, - /// A non-type template parameter, stored as an expression. - NonType, - /// A template template argument, stored as a template name. - Template - }; - - /// Build an empty template argument. - /// - /// This template argument is invalid. - ParsedTemplateArgument() : Kind(Type), Arg(nullptr) { } - - /// Create a template type argument or non-type template argument. - /// - /// \param Arg the template type argument or non-type template argument. - /// \param Loc the location of the type. - ParsedTemplateArgument(KindType Kind, void *Arg, SourceLocation Loc) - : Kind(Kind), Arg(Arg), Loc(Loc) { } - - /// Create a template template argument. - /// - /// \param SS the C++ scope specifier that precedes the template name, if - /// any. - /// - /// \param Template the template to which this template template - /// argument refers. - /// - /// \param TemplateLoc the location of the template name. - ParsedTemplateArgument(const CXXScopeSpec &SS, - ParsedTemplateTy Template, - SourceLocation TemplateLoc) - : Kind(ParsedTemplateArgument::Template), - Arg(Template.getAsOpaquePtr()), SS(SS), Loc(TemplateLoc) {} - - /// Determine whether the given template argument is invalid. - bool isInvalid() const { return Arg == nullptr; } - - /// Determine what kind of template argument we have. - KindType getKind() const { return Kind; } - - /// Retrieve the template type argument's type. - ParsedType getAsType() const { - assert(Kind == Type && "Not a template type argument"); - return ParsedType::getFromOpaquePtr(Arg); - } - - /// Retrieve the non-type template argument's expression. - Expr *getAsExpr() const { - assert(Kind == NonType && "Not a non-type template argument"); - return static_cast(Arg); - } - - /// Retrieve the template template argument's template name. - ParsedTemplateTy getAsTemplate() const { - assert(Kind == Template && "Not a template template argument"); - return ParsedTemplateTy::getFromOpaquePtr(Arg); - } - - /// Retrieve the location of the template argument. - SourceLocation getLocation() const { return Loc; } - - /// Retrieve the nested-name-specifier that precedes the template - /// name in a template template argument. - const CXXScopeSpec &getScopeSpec() const { - assert(Kind == Template && - "Only template template arguments can have a scope specifier"); - return SS; - } - - /// Retrieve the location of the ellipsis that makes a template - /// template argument into a pack expansion. - SourceLocation getEllipsisLoc() const { - assert(Kind == Template && - "Only template template arguments can have an ellipsis"); - return EllipsisLoc; - } - - /// Retrieve a pack expansion of the given template template - /// argument. - /// - /// \param EllipsisLoc The location of the ellipsis. - ParsedTemplateArgument getTemplatePackExpansion( - SourceLocation EllipsisLoc) const; - private: - KindType Kind; - - /// The actual template argument representation, which may be - /// an \c Sema::TypeTy* (for a type), an Expr* (for an - /// expression), or an Sema::TemplateTy (for a template). - void *Arg; +/// Represents the parsed form of a C++ template argument. +class ParsedTemplateArgument { +public: + /// Describes the kind of template argument that was parsed. + enum KindType { + /// A template type parameter, stored as a type. + Type, + /// A non-type template parameter, stored as an expression. + NonType, + /// A template template argument, stored as a template name. + Template, + }; - /// The nested-name-specifier that can accompany a template template - /// argument. - CXXScopeSpec SS; + /// Build an empty template argument. + /// + /// This template argument is invalid. + ParsedTemplateArgument() : Kind(Type), Arg(nullptr) {} - /// the location of the template argument. - SourceLocation Loc; + /// Create a template type argument or non-type template argument. + /// + /// \param Arg the template type argument or non-type template argument. + /// \param Loc the location of the type. + ParsedTemplateArgument(KindType Kind, void *Arg, SourceLocation Loc) + : Kind(Kind), Arg(Arg), Loc(Loc) {} - /// The ellipsis location that can accompany a template template - /// argument (turning it into a template template argument expansion). - SourceLocation EllipsisLoc; - }; + /// Create a template template argument. + /// + /// \param SS the C++ scope specifier that precedes the template name, if + /// any. + /// + /// \param Template the template to which this template template + /// argument refers. + /// + /// \param TemplateLoc the location of the template name. + ParsedTemplateArgument(const CXXScopeSpec &SS, ParsedTemplateTy Template, + SourceLocation TemplateLoc) + : Kind(ParsedTemplateArgument::Template), Arg(Template.getAsOpaquePtr()), + SS(SS), Loc(TemplateLoc) {} + + /// Determine whether the given template argument is invalid. + bool isInvalid() const { return Arg == nullptr; } + + /// Determine what kind of template argument we have. + KindType getKind() const { return Kind; } + + /// Retrieve the template type argument's type. + ParsedType getAsType() const { + assert(Kind == Type && "Not a template type argument"); + return ParsedType::getFromOpaquePtr(Arg); + } + + /// Retrieve the non-type template argument's expression. + Expr *getAsExpr() const { + assert(Kind == NonType && "Not a non-type template argument"); + return static_cast(Arg); + } + + /// Retrieve the template template argument's template name. + ParsedTemplateTy getAsTemplate() const { + assert(Kind == Template && "Not a template template argument"); + return ParsedTemplateTy::getFromOpaquePtr(Arg); + } + + /// Retrieve the location of the template argument. + SourceLocation getLocation() const { return Loc; } + + /// Retrieve the nested-name-specifier that precedes the template + /// name in a template template argument. + const CXXScopeSpec &getScopeSpec() const { + assert((Kind == Template) && + "Only template template arguments can have a scope specifier"); + return SS; + } + + /// Retrieve the location of the ellipsis that makes a template + /// template argument into a pack expansion. + SourceLocation getEllipsisLoc() const { + assert((Kind == Template) && + "Only template arguments can have an ellipsis"); + return EllipsisLoc; + } + + /// Retrieve a pack expansion of the given template template + /// argument. + /// + /// \param EllipsisLoc The location of the ellipsis. + ParsedTemplateArgument + getTemplatePackExpansion(SourceLocation EllipsisLoc) const; + +private: + KindType Kind; + + /// The actual template argument representation, which may be + /// an \c Sema::TypeTy* (for a type), an Expr* (for an + /// expression), or an Sema::TemplateTy (for a template). + void *Arg; + + /// The nested-name-specifier that can accompany a template template + /// argument. + CXXScopeSpec SS; + + /// the location of the template argument. + SourceLocation Loc; + + /// The ellipsis location that can accompany a template/universal template + /// argument (turning it into a template/universal template argument + /// expansion). + SourceLocation EllipsisLoc; +}; /// Information about a template-id annotation /// token. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 73eb730ca555b..7853c9d649f77 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -11444,7 +11444,7 @@ class Sema final : public SemaBase { /// of arguments for the named concept). bool AttachTypeConstraint(NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, - ConceptDecl *NamedConcept, NamedDecl *FoundDecl, + TemplateDecl *NamedConcept, NamedDecl *FoundDecl, const TemplateArgumentListInfo *TemplateArgs, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc); @@ -11477,8 +11477,9 @@ class Sema final : public SemaBase { /// parameter (e.g. T in template