Skip to content

Commit 28ed57e

Browse files
authored
[Clang] Initial support for P2841 (Variable template and concept template parameters) (#150823)
This is a first pass at implementing [P2841R7](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2841r7.pdf). The implementation is far from complete; however, I'm aiming to do that in chunks, to make our lives easier. In particular, this does not implement - Subsumption - Mangling - Satisfaction checking is minimal as we should focus on #141776 first (note that I'm currently very stuck) FTM, release notes, status page, etc, will be updated once the feature is more mature. Given the state of the feature, it is not yet allowed in older language modes. Of note: - Mismatches between template template arguments and template template parameters are a bit wonky. This is addressed by #130603 - We use `UnresolvedLookupExpr` to model template-id. While this is pre-existing, I have been wondering if we want to introduce a different OverloadExpr subclass for that. I did not make the change in this patch.
1 parent 342f212 commit 28ed57e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1267
-341
lines changed

clang/include/clang/AST/ASTConcept.h

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
namespace clang {
2828

2929
class ConceptDecl;
30+
class TemplateDecl;
3031
class Expr;
3132
class NamedDecl;
3233
struct PrintingPolicy;
@@ -123,6 +124,7 @@ struct ASTConstraintSatisfaction final :
123124
/// template <std::derives_from<Expr> T> void dump();
124125
/// ~~~~~~~~~~~~~~~~~~~~~~~ (in TemplateTypeParmDecl)
125126
class ConceptReference {
127+
protected:
126128
// \brief The optional nested name specifier used when naming the concept.
127129
NestedNameSpecifierLoc NestedNameSpec;
128130

@@ -140,15 +142,15 @@ class ConceptReference {
140142
NamedDecl *FoundDecl;
141143

142144
/// \brief The concept named.
143-
ConceptDecl *NamedConcept;
145+
TemplateDecl *NamedConcept;
144146

145147
/// \brief The template argument list source info used to specialize the
146148
/// concept.
147149
const ASTTemplateArgumentListInfo *ArgsAsWritten;
148150

149151
ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
150152
DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
151-
ConceptDecl *NamedConcept,
153+
TemplateDecl *NamedConcept,
152154
const ASTTemplateArgumentListInfo *ArgsAsWritten)
153155
: NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
154156
ConceptName(ConceptNameInfo), FoundDecl(FoundDecl),
@@ -158,7 +160,7 @@ class ConceptReference {
158160
static ConceptReference *
159161
Create(const ASTContext &C, NestedNameSpecifierLoc NNS,
160162
SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo,
161-
NamedDecl *FoundDecl, ConceptDecl *NamedConcept,
163+
NamedDecl *FoundDecl, TemplateDecl *NamedConcept,
162164
const ASTTemplateArgumentListInfo *ArgsAsWritten);
163165

164166
const NestedNameSpecifierLoc &getNestedNameSpecifierLoc() const {
@@ -197,9 +199,7 @@ class ConceptReference {
197199
return FoundDecl;
198200
}
199201

200-
ConceptDecl *getNamedConcept() const {
201-
return NamedConcept;
202-
}
202+
TemplateDecl *getNamedConcept() const { return NamedConcept; }
203203

204204
const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
205205
return ArgsAsWritten;
@@ -252,7 +252,9 @@ class TypeConstraint {
252252

253253
// FIXME: Instead of using these concept related functions the callers should
254254
// directly work with the corresponding ConceptReference.
255-
ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); }
255+
TemplateDecl *getNamedConcept() const {
256+
return ConceptRef->getNamedConcept();
257+
}
256258

257259
SourceLocation getConceptNameLoc() const {
258260
return ConceptRef->getConceptNameLoc();

clang/include/clang/AST/ASTContext.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1759,7 +1759,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
17591759
QualType
17601760
getAutoTypeInternal(QualType DeducedType, AutoTypeKeyword Keyword,
17611761
bool IsDependent, bool IsPack = false,
1762-
ConceptDecl *TypeConstraintConcept = nullptr,
1762+
TemplateDecl *TypeConstraintConcept = nullptr,
17631763
ArrayRef<TemplateArgument> TypeConstraintArgs = {},
17641764
bool IsCanon = false) const;
17651765

@@ -1979,10 +1979,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
19791979
UnaryTransformType::UTTKind UKind) const;
19801980

19811981
/// C++11 deduced auto type.
1982-
QualType getAutoType(QualType DeducedType, AutoTypeKeyword Keyword,
1983-
bool IsDependent, bool IsPack = false,
1984-
ConceptDecl *TypeConstraintConcept = nullptr,
1985-
ArrayRef<TemplateArgument> TypeConstraintArgs ={}) const;
1982+
QualType
1983+
getAutoType(QualType DeducedType, AutoTypeKeyword Keyword, bool IsDependent,
1984+
bool IsPack = false,
1985+
TemplateDecl *TypeConstraintConcept = nullptr,
1986+
ArrayRef<TemplateArgument> TypeConstraintArgs = {}) const;
19861987

19871988
/// C++11 deduction pattern for 'auto' type.
19881989
QualType getAutoDeductType() const;

clang/include/clang/AST/DeclTemplate.h

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "clang/Basic/LLVM.h"
2727
#include "clang/Basic/SourceLocation.h"
2828
#include "clang/Basic/Specifiers.h"
29+
#include "clang/Basic/TemplateKinds.h"
2930
#include "llvm/ADT/ArrayRef.h"
3031
#include "llvm/ADT/FoldingSet.h"
3132
#include "llvm/ADT/PointerIntPair.h"
@@ -1585,6 +1586,9 @@ class TemplateTemplateParmDecl final
15851586
DefaultArgStorage<TemplateTemplateParmDecl, TemplateArgumentLoc *>;
15861587
DefArgStorage DefaultArgument;
15871588

1589+
LLVM_PREFERRED_TYPE(TemplateNameKind)
1590+
unsigned ParameterKind : 3;
1591+
15881592
/// Whether this template template parameter was declaration with
15891593
/// the 'typename' keyword.
15901594
///
@@ -1607,13 +1611,16 @@ class TemplateTemplateParmDecl final
16071611

16081612
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
16091613
unsigned P, bool ParameterPack, IdentifierInfo *Id,
1610-
bool Typename, TemplateParameterList *Params)
1614+
TemplateNameKind ParameterKind, bool Typename,
1615+
TemplateParameterList *Params)
16111616
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
1612-
TemplateParmPosition(D, P), Typename(Typename),
1613-
ParameterPack(ParameterPack), ExpandedParameterPack(false) {}
1617+
TemplateParmPosition(D, P), ParameterKind(ParameterKind),
1618+
Typename(Typename), ParameterPack(ParameterPack),
1619+
ExpandedParameterPack(false) {}
16141620

16151621
TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
1616-
unsigned P, IdentifierInfo *Id, bool Typename,
1622+
unsigned P, IdentifierInfo *Id,
1623+
TemplateNameKind ParameterKind, bool Typename,
16171624
TemplateParameterList *Params,
16181625
ArrayRef<TemplateParameterList *> Expansions);
16191626

@@ -1624,15 +1631,16 @@ class TemplateTemplateParmDecl final
16241631
friend class ASTDeclWriter;
16251632
friend TrailingObjects;
16261633

1627-
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
1628-
SourceLocation L, unsigned D,
1629-
unsigned P, bool ParameterPack,
1630-
IdentifierInfo *Id, bool Typename,
1631-
TemplateParameterList *Params);
16321634
static TemplateTemplateParmDecl *
16331635
Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
1634-
unsigned P, IdentifierInfo *Id, bool Typename,
1635-
TemplateParameterList *Params,
1636+
unsigned P, bool ParameterPack, IdentifierInfo *Id,
1637+
TemplateNameKind ParameterKind, bool Typename,
1638+
TemplateParameterList *Params);
1639+
1640+
static TemplateTemplateParmDecl *
1641+
Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
1642+
unsigned P, IdentifierInfo *Id, TemplateNameKind ParameterKind,
1643+
bool Typename, TemplateParameterList *Params,
16361644
ArrayRef<TemplateParameterList *> Expansions);
16371645

16381646
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
@@ -1746,6 +1754,16 @@ class TemplateTemplateParmDecl final
17461754
return SourceRange(getTemplateParameters()->getTemplateLoc(), End);
17471755
}
17481756

1757+
TemplateNameKind templateParameterKind() const {
1758+
return static_cast<TemplateNameKind>(ParameterKind);
1759+
}
1760+
1761+
bool isTypeConceptTemplateParam() const {
1762+
return templateParameterKind() == TemplateNameKind::TNK_Concept_template &&
1763+
getTemplateParameters()->size() > 0 &&
1764+
isa<TemplateTypeParmDecl>(getTemplateParameters()->getParam(0));
1765+
}
1766+
17491767
// Implement isa/cast/dyncast/etc.
17501768
static bool classof(const Decl *D) { return classofKind(D->getKind()); }
17511769
static bool classofKind(Kind K) { return K == TemplateTemplateParm; }
@@ -3341,7 +3359,11 @@ inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) {
33413359
return TD && (isa<ClassTemplateDecl>(TD) ||
33423360
isa<ClassTemplatePartialSpecializationDecl>(TD) ||
33433361
isa<TypeAliasTemplateDecl>(TD) ||
3344-
isa<TemplateTemplateParmDecl>(TD))
3362+
[&]() {
3363+
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TD))
3364+
return TTP->templateParameterKind() == TNK_Type_template;
3365+
return false;
3366+
}())
33453367
? TD
33463368
: nullptr;
33473369
}

clang/include/clang/AST/ExprCXX.h

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "clang/Basic/OperatorKinds.h"
3939
#include "clang/Basic/SourceLocation.h"
4040
#include "clang/Basic/Specifiers.h"
41+
#include "clang/Basic/TemplateKinds.h"
4142
#include "clang/Basic/TypeTraits.h"
4243
#include "llvm/ADT/ArrayRef.h"
4344
#include "llvm/ADT/PointerUnion.h"
@@ -3257,7 +3258,49 @@ class OverloadExpr : public Expr {
32573258
bool hasTemplateKeyword() const { return getTemplateKeywordLoc().isValid(); }
32583259

32593260
/// Determines whether this expression had explicit template arguments.
3260-
bool hasExplicitTemplateArgs() const { return getLAngleLoc().isValid(); }
3261+
bool hasExplicitTemplateArgs() const {
3262+
if (!hasTemplateKWAndArgsInfo())
3263+
return false;
3264+
// FIXME: deduced function types can have "hidden" args and no <
3265+
// investigate that further, but ultimately maybe we want to model concepts
3266+
// reference with another kind of expression.
3267+
return (isConceptReference() || isVarDeclReference())
3268+
? getTrailingASTTemplateKWAndArgsInfo()->NumTemplateArgs
3269+
: getLAngleLoc().isValid();
3270+
}
3271+
3272+
bool isConceptReference() const {
3273+
return getNumDecls() == 1 && [&]() {
3274+
if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(
3275+
getTrailingResults()->getDecl()))
3276+
return TTP->templateParameterKind() == TNK_Concept_template;
3277+
if (isa<ConceptDecl>(getTrailingResults()->getDecl()))
3278+
return true;
3279+
return false;
3280+
}();
3281+
}
3282+
3283+
bool isVarDeclReference() const {
3284+
return getNumDecls() == 1 && [&]() {
3285+
if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(
3286+
getTrailingResults()->getDecl()))
3287+
return TTP->templateParameterKind() == TNK_Var_template;
3288+
if (isa<VarTemplateDecl>(getTrailingResults()->getDecl()))
3289+
return true;
3290+
return false;
3291+
}();
3292+
}
3293+
3294+
TemplateDecl *getTemplateDecl() const {
3295+
assert(getNumDecls() == 1);
3296+
return dyn_cast_or_null<TemplateDecl>(getTrailingResults()->getDecl());
3297+
}
3298+
3299+
TemplateTemplateParmDecl *getTemplateTemplateDecl() const {
3300+
assert(getNumDecls() == 1);
3301+
return dyn_cast_or_null<TemplateTemplateParmDecl>(
3302+
getTrailingResults()->getDecl());
3303+
}
32613304

32623305
TemplateArgumentLoc const *getTemplateArgs() const {
32633306
if (!hasExplicitTemplateArgs())
@@ -4658,7 +4701,7 @@ class SubstNonTypeTemplateParmExpr : public Expr {
46584701
// sugared: it doesn't need to be resugared later.
46594702
bool getFinal() const { return Final; }
46604703

4661-
NonTypeTemplateParmDecl *getParameter() const;
4704+
NamedDecl *getParameter() const;
46624705

46634706
bool isReferenceParameter() const { return AssociatedDeclAndRef.getInt(); }
46644707

clang/include/clang/AST/ExprConcepts.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,9 @@ class ConceptSpecializationExpr final : public Expr {
8484

8585
ConceptReference *getConceptReference() const { return ConceptRef; }
8686

87-
ConceptDecl *getNamedConcept() const { return ConceptRef->getNamedConcept(); }
87+
ConceptDecl *getNamedConcept() const {
88+
return cast<ConceptDecl>(ConceptRef->getNamedConcept());
89+
}
8890

8991
// FIXME: Several of the following functions can be removed. Instead the
9092
// caller can directly work with the ConceptReference.

clang/include/clang/AST/TemplateBase.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,8 @@ class TemplateArgument {
316316
/// Determine whether this template argument is a pack expansion.
317317
bool isPackExpansion() const;
318318

319+
bool isConceptOrConceptTemplateParameter() const;
320+
319321
/// Retrieve the type for a type template argument.
320322
QualType getAsType() const {
321323
assert(getKind() == Type && "Unexpected kind");

clang/include/clang/AST/Type.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6762,10 +6762,10 @@ class DeducedType : public Type {
67626762
class AutoType : public DeducedType {
67636763
friend class ASTContext; // ASTContext creates these
67646764

6765-
ConceptDecl *TypeConstraintConcept;
6765+
TemplateDecl *TypeConstraintConcept;
67666766

67676767
AutoType(QualType DeducedAsType, AutoTypeKeyword Keyword,
6768-
TypeDependence ExtraDependence, QualType Canon, ConceptDecl *CD,
6768+
TypeDependence ExtraDependence, QualType Canon, TemplateDecl *CD,
67696769
ArrayRef<TemplateArgument> TypeConstraintArgs);
67706770

67716771
public:
@@ -6774,7 +6774,7 @@ class AutoType : public DeducedType {
67746774
AutoTypeBits.NumArgs};
67756775
}
67766776

6777-
ConceptDecl *getTypeConstraintConcept() const {
6777+
TemplateDecl *getTypeConstraintConcept() const {
67786778
return TypeConstraintConcept;
67796779
}
67806780

@@ -6797,7 +6797,7 @@ class AutoType : public DeducedType {
67976797
void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context);
67986798
static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
67996799
QualType Deduced, AutoTypeKeyword Keyword,
6800-
bool IsDependent, ConceptDecl *CD,
6800+
bool IsDependent, TemplateDecl *CD,
68016801
ArrayRef<TemplateArgument> Arguments);
68026802

68036803
static bool classof(const Type *T) {

clang/include/clang/AST/TypeLoc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2284,7 +2284,7 @@ class AutoTypeLoc
22842284
return nullptr;
22852285
}
22862286

2287-
ConceptDecl *getNamedConcept() const {
2287+
TemplateDecl *getNamedConcept() const {
22882288
if (const auto *CR = getConceptReference())
22892289
return CR->getNamedConcept();
22902290
return nullptr;

clang/include/clang/AST/TypeProperties.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -495,9 +495,9 @@ let Class = AutoType in {
495495
def : Property<"keyword", AutoTypeKeyword> {
496496
let Read = [{ node->getKeyword() }];
497497
}
498-
def : Property<"typeConstraintConcept", Optional<ConceptDeclRef>> {
498+
def : Property<"typeConstraintConcept", Optional<TemplateDeclRef>> {
499499
let Read = [{ makeOptionalFromPointer(
500-
const_cast<const ConceptDecl*>(node->getTypeConstraintConcept())) }];
500+
node->getTypeConstraintConcept()) }];
501501
}
502502
def : Property<"typeConstraintArguments", Array<TemplateArgument>> {
503503
let Read = [{ node->getTypeConstraintArguments() }];

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -931,6 +931,10 @@ def err_missing_dependent_template_keyword : Error<
931931
def warn_missing_dependent_template_keyword : ExtWarn<
932932
"use 'template' keyword to treat '%0' as a dependent template name">;
933933

934+
def err_cxx26_template_template_params
935+
: Error<"%select{variable template|concept}0 template parameter is a C++2c "
936+
"extension">;
937+
934938
def ext_extern_template : Extension<
935939
"extern templates are a C++11 extension">, InGroup<CXX11>;
936940
def warn_cxx98_compat_extern_template : Warning<

0 commit comments

Comments
 (0)