Skip to content
16 changes: 9 additions & 7 deletions clang/include/clang/AST/ASTConcept.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
namespace clang {

class ConceptDecl;
class TemplateDecl;
class Expr;
class NamedDecl;
struct PrintingPolicy;
Expand Down Expand Up @@ -123,6 +124,7 @@ struct ASTConstraintSatisfaction final :
/// template <std::derives_from<Expr> T> void dump();
/// ~~~~~~~~~~~~~~~~~~~~~~~ (in TemplateTypeParmDecl)
class ConceptReference {
protected:
// \brief The optional nested name specifier used when naming the concept.
NestedNameSpecifierLoc NestedNameSpec;

Expand All @@ -140,15 +142,15 @@ class ConceptReference {
NamedDecl *FoundDecl;

/// \brief The concept named.
ConceptDecl *NamedConcept;
TemplateDecl *NamedConcept;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems weird for a type named ConceptReference to not refer to a ConceptDecl anymore


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

ConceptReference(NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc,
DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl,
ConceptDecl *NamedConcept,
TemplateDecl *NamedConcept,
const ASTTemplateArgumentListInfo *ArgsAsWritten)
: NestedNameSpec(NNS), TemplateKWLoc(TemplateKWLoc),
ConceptName(ConceptNameInfo), FoundDecl(FoundDecl),
Expand All @@ -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 {
Expand Down Expand Up @@ -197,9 +199,7 @@ class ConceptReference {
return FoundDecl;
}

ConceptDecl *getNamedConcept() const {
return NamedConcept;
}
TemplateDecl *getNamedConcept() const { return NamedConcept; }

const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
return ArgsAsWritten;
Expand Down Expand Up @@ -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();
Expand Down
11 changes: 6 additions & 5 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1753,7 +1753,7 @@ class ASTContext : public RefCountedBase<ASTContext> {
QualType
getAutoTypeInternal(QualType DeducedType, AutoTypeKeyword Keyword,
bool IsDependent, bool IsPack = false,
ConceptDecl *TypeConstraintConcept = nullptr,
TemplateDecl *TypeConstraintConcept = nullptr,
ArrayRef<TemplateArgument> TypeConstraintArgs = {},
bool IsCanon = false) const;

Expand Down Expand Up @@ -1973,10 +1973,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
UnaryTransformType::UTTKind UKind) const;

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

/// C++11 deduction pattern for 'auto' type.
QualType getAutoDeductType() const;
Expand Down
47 changes: 35 additions & 12 deletions clang/include/clang/AST/DeclTemplate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1585,6 +1586,9 @@ class TemplateTemplateParmDecl final
DefaultArgStorage<TemplateTemplateParmDecl, TemplateArgumentLoc *>;
DefArgStorage DefaultArgument;

LLVM_PREFERRED_TYPE(TemplateNameKind)
unsigned ParameterKind : 3;

/// Whether this template template parameter was declaration with
/// the 'typename' keyword.
///
Expand All @@ -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<TemplateParameterList *> Expansions);

Expand All @@ -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<TemplateParameterList *> Expansions);

static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
Expand Down Expand Up @@ -1746,6 +1754,16 @@ class TemplateTemplateParmDecl final
return SourceRange(getTemplateParameters()->getTemplateLoc(), End);
}

TemplateNameKind kind() const {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mild preference for templateKind or something like that (perhaps something more accurate? nameKind seems wrong toot hough)? We use kind to mean sooooo many different things, it makes reading later not particularly descriptive.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TemplateNameKind is pre-existing. It's the kind of a TemplateName.
Note that I did consider using a new enum type, as we don't need all the values of TemplateNameKind, but reusing the same enums avoids having to convert back and forth.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, i wasn't suggesting changing the num name, just that kind isn't really descriptive here. and nameKind is a bad alternative, and templateKind is perhaps not a great name either. So if you have a better name than kind for the function, it would be appreciated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I somehow completely misread your point. I will think about it.
Note that core failed to come up with something better https://eel.is/c++draft/temp#param-2

return static_cast<TemplateNameKind>(ParameterKind);
}

bool isTypeConceptTemplateParam() const {
return kind() == TemplateNameKind::TNK_Concept_template &&
getTemplateParameters()->size() > 0 &&
isa<TemplateTypeParmDecl>(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; }
Expand Down Expand Up @@ -3341,7 +3359,12 @@ inline TemplateDecl *getAsTypeTemplateDecl(Decl *D) {
return TD && (isa<ClassTemplateDecl>(TD) ||
isa<ClassTemplatePartialSpecializationDecl>(TD) ||
isa<TypeAliasTemplateDecl>(TD) ||
isa<TemplateTemplateParmDecl>(TD))
[&]() {
if (TemplateTemplateParmDecl *TTP =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (TemplateTemplateParmDecl *TTP =
if (const auto *TTP =

dyn_cast<TemplateTemplateParmDecl>(TD))
return TTP->kind() == TNK_Type_template;
return false;
}())
? TD
: nullptr;
}
Expand Down
47 changes: 45 additions & 2 deletions clang/include/clang/AST/ExprCXX.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<TemplateTemplateParmDecl>(
getTrailingResults()->getDecl()))
return TTP->kind() == TNK_Concept_template;
if (isa<ConceptDecl>(getTrailingResults()->getDecl()))
return true;
return false;
}();
}

bool isVarDeclReference() const {
return getNumDecls() == 1 && [&]() {
if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(
getTrailingResults()->getDecl()))
return TTP->kind() == TNK_Var_template;
if (isa<VarTemplateDecl>(getTrailingResults()->getDecl()))
return true;
return false;
}();
}

TemplateDecl *getTemplateDecl() const {
assert(getNumDecls() == 1);
return dyn_cast_or_null<TemplateDecl>(getTrailingResults()->getDecl());
}

TemplateTemplateParmDecl *getTemplateTemplateDecl() const {
assert(getNumDecls() == 1);
return dyn_cast_or_null<TemplateTemplateParmDecl>(
getTrailingResults()->getDecl());
}

TemplateArgumentLoc const *getTemplateArgs() const {
if (!hasExplicitTemplateArgs())
Expand Down Expand Up @@ -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(); }

Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/AST/ExprConcepts.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<ConceptDecl>(ConceptRef->getNamedConcept());
}

// FIXME: Several of the following functions can be removed. Instead the
// caller can directly work with the ConceptReference.
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/TemplateBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<TemplateArgument> TypeConstraintArgs);

public:
Expand All @@ -6774,7 +6774,7 @@ class AutoType : public DeducedType {
AutoTypeBits.NumArgs};
}

ConceptDecl *getTypeConstraintConcept() const {
TemplateDecl *getTypeConstraintConcept() const {
return TypeConstraintConcept;
}

Expand All @@ -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<TemplateArgument> Arguments);

static bool classof(const Type *T) {
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/AST/TypeLoc.h
Original file line number Diff line number Diff line change
Expand Up @@ -2284,7 +2284,7 @@ class AutoTypeLoc
return nullptr;
}

ConceptDecl *getNamedConcept() const {
TemplateDecl *getNamedConcept() const {
if (const auto *CR = getConceptReference())
return CR->getNamedConcept();
return nullptr;
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/AST/TypeProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -495,9 +495,9 @@ let Class = AutoType in {
def : Property<"keyword", AutoTypeKeyword> {
let Read = [{ node->getKeyword() }];
}
def : Property<"typeConstraintConcept", Optional<ConceptDeclRef>> {
def : Property<"typeConstraintConcept", Optional<TemplateDeclRef>> {
let Read = [{ makeOptionalFromPointer(
const_cast<const ConceptDecl*>(node->getTypeConstraintConcept())) }];
node->getTypeConstraintConcept()) }];
}
def : Property<"typeConstraintArguments", Array<TemplateArgument>> {
let Read = [{ node->getTypeConstraintArguments() }];
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<CXX11>;
def warn_cxx98_compat_extern_template : Warning<
Expand Down
19 changes: 12 additions & 7 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -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<LocalTypeTemplateArgs>;
def ext_template_arg_unnamed_type : ExtWarn<
Expand All @@ -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">;
Expand Down
9 changes: 5 additions & 4 deletions clang/include/clang/Sema/Initialization.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Sema/Ownership.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Loading