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..32de203f2d831 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 templateParameterKind() const { + return static_cast(ParameterKind); + } + + bool isTypeConceptTemplateParam() const { + return templateParameterKind() == 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,11 @@ inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) { return TD && (isa(TD) || isa(TD) || isa(TD) || - isa(TD)) + [&]() { + if (const auto *TTP = dyn_cast(TD)) + return TTP->templateParameterKind() == 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..7a26934de6259 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: 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->templateParameterKind() == 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->templateParameterKind() == 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/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 165f01514e2b1..0042afccba2c8 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -931,6 +931,10 @@ def err_missing_dependent_template_keyword : Error< def warn_missing_dependent_template_keyword : ExtWarn< "use 'template' keyword to treat '%0' as a dependent template name">; +def err_cxx26_template_template_params + : Error<"%select{variable template|concept}0 template parameter is a C++2c " + "extension">; + def ext_extern_template : Extension< "extern templates are a C++11 extension">, InGroup; def warn_cxx98_compat_extern_template : Warning< 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..d7675ea153afb 100644 --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/include/clang/Sema/Initialization.h @@ -159,8 +159,9 @@ class alignas(8) InitializedEntity { }; struct VD { - /// The VarDecl, FieldDecl, or BindingDecl being initialized. - ValueDecl *VariableOrMember; + /// The VarDecl, FieldDecl, TemplateParmDecl, or BindingDecl being + /// initialized. + 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 +292,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/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