[Lldb-commits] [clang] [lldb] [Clang] Initial support for P2841 (Variable template and concept template parameters) (PR #150823)
Corentin Jabot via lldb-commits
lldb-commits at lists.llvm.org
Tue Jul 29 01:37:12 PDT 2025
https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/150823
>From ef82ffb4300c301b19965b421dc52ba524ea7bd3 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Sun, 27 Jul 2025 12:16:12 +0200
Subject: [PATCH 01/10] [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 <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;
@@ -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<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;
@@ -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;
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<TemplateTemplateParmDecl, TemplateArgumentLoc *>;
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<TemplateParameterList *> 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<TemplateParameterList *> Expansions);
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
@@ -1746,6 +1754,16 @@ class TemplateTemplateParmDecl final
return SourceRange(getTemplateParameters()->getTemplateLoc(), End);
}
+ TemplateNameKind kind() const {
+ 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; }
@@ -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 =
+ dyn_cast<TemplateTemplateParmDecl>(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<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())
@@ -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<ConceptDecl>(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<TemplateArgument> 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<TemplateArgument> 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<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() }];
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<LocalTypeTemplateArgs>;
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 <new>
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<Expr*>(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<Expr *>(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 <template \<typename> class T> class array)
/// has been parsed. S is the current scope.
NamedDecl *ActOnTemplateTemplateParameter(
- Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params,
- bool Typename, SourceLocation EllipsisLoc, IdentifierInfo *ParamName,
+ Scope *S, SourceLocation TmpLoc, TemplateNameKind Kind,
+ bool TypenameKeyword, TemplateParameterList *Params,
+ SourceLocation EllipsisLoc, IdentifierInfo *ParamName,
SourceLocation ParamNameLoc, unsigned Depth, unsigned Position,
SourceLocation EqualLoc, ParsedTemplateArgument DefaultArg);
@@ -11646,6 +11647,11 @@ class Sema final : public SemaBase {
SourceLocation TemplateLoc,
const TemplateArgumentListInfo *TemplateArgs);
+ ExprResult CheckVarOrConceptTemplateTemplateId(
+ const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
+ TemplateTemplateParmDecl *Template, SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs);
+
ExprResult
CheckConceptTemplateId(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc,
const DeclarationNameInfo &ConceptNameInfo,
@@ -11982,7 +11988,7 @@ class Sema final : public SemaBase {
/// 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 CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
+ ExprResult CheckTemplateArgument(NamedDecl *Param,
QualType InstantiatedParamType, Expr *Arg,
TemplateArgument &SugaredConverted,
TemplateArgument &CanonicalConverted,
@@ -12000,6 +12006,10 @@ class Sema final : public SemaBase {
bool PartialOrdering,
bool *StrictPackMatch);
+ bool CheckDeclCompatibleWithTemplateTemplate(TemplateDecl *Template,
+ TemplateTemplateParmDecl *Param,
+ const TemplateArgumentLoc &Arg);
+
void NoteTemplateLocation(const NamedDecl &Decl,
std::optional<SourceRange> ParamRange = {});
void NoteTemplateParameterLocation(const NamedDecl &Decl);
@@ -12276,7 +12286,7 @@ class Sema final : public SemaBase {
void CheckConceptRedefinition(ConceptDecl *NewDecl, LookupResult &Previous,
bool &AddToScope);
- bool CheckConceptUseInDefinition(ConceptDecl *Concept, SourceLocation Loc);
+ bool CheckConceptUseInDefinition(NamedDecl *Concept, SourceLocation Loc);
TypeResult ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
const CXXScopeSpec &SS,
diff --git a/clang/include/clang/Sema/SemaInternal.h b/clang/include/clang/Sema/SemaInternal.h
index 4d0da1102bb59..42c9469e44e53 100644
--- a/clang/include/clang/Sema/SemaInternal.h
+++ b/clang/include/clang/Sema/SemaInternal.h
@@ -15,6 +15,7 @@
#define LLVM_CLANG_SEMA_SEMAINTERNAL_H
#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
diff --git a/clang/lib/AST/ASTConcept.cpp b/clang/lib/AST/ASTConcept.cpp
index 91ab66f4639fc..2243ac035115f 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 16cf114981824..6e6572d5cd31a 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->kind());
TemplateParameterList *Params = Parm->getTemplateParameters();
ID.AddInteger(Params->size());
@@ -829,7 +830,8 @@ ASTContext::getCanonicalTemplateTemplateParmDecl(
TemplateTemplateParmDecl *CanonTTP = TemplateTemplateParmDecl::Create(
*this, getTranslationUnitDecl(), SourceLocation(), TTP->getDepth(),
- TTP->getPosition(), TTP->isParameterPack(), nullptr, /*Typename=*/false,
+ TTP->getPosition(), TTP->isParameterPack(), nullptr, TTP->kind(),
+ /*Typename=*/false,
TemplateParameterList::Create(*this, SourceLocation(), SourceLocation(),
CanonParams, SourceLocation(),
/*RequiresClause=*/nullptr));
@@ -6643,7 +6645,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 +6654,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 +6668,8 @@ QualType ASTContext::getAutoTypeInternal(
Canon = DeducedType.getCanonicalType();
} else if (TypeConstraintConcept) {
bool AnyNonCanonArgs = false;
- ConceptDecl *CanonicalConcept = TypeConstraintConcept->getCanonicalDecl();
+ TemplateDecl *CanonicalConcept =
+ cast<TemplateDecl>(TypeConstraintConcept->getCanonicalDecl());
auto CanonicalConceptArgs = ::getCanonicalTemplateArguments(
*this, TypeConstraintArgs, AnyNonCanonArgs);
if (CanonicalConcept != TypeConstraintConcept || AnyNonCanonArgs) {
@@ -6701,7 +6705,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 +14391,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 b9bdabe0b8c06..e8cc5b8cda72a 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->kind(),
+ 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 0f2762d5c0f14..b3b9e47b2787f 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -2249,7 +2249,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
}
// Check template parameter lists.
- return IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
+ return D1->kind() == D2->kind() &&
+ IsStructurallyEquivalent(Context, D1->getTemplateParameters(),
D2->getTemplateParameters());
}
diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp
index 14ec93eb1d166..87334d98413e6 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 83fcd87aec2f8..d8899e9e1f725 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/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 5035f2d33b0a1..70b12c9d3bb64 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->kind());
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;
@@ -235,7 +237,7 @@ void TemplateParameterList::getAssociatedConstraints(
ACs.emplace_back(E);
}
}
- if (HasRequiresClause)
+ if (HasRequiresClause && getRequiresClause())
ACs.emplace_back(getRequiresClause());
}
@@ -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 5833a6405125d..ac55f23bbea07 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 (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/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index 2a667934dba42..5233648d8f9c8 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -529,7 +529,7 @@ class CXXNameMangler {
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/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index 7c89dea4629cc..4207fea3764ab 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -339,6 +339,18 @@ bool TemplateArgument::isPackExpansion() const {
llvm_unreachable("Invalid TemplateArgument Kind!");
}
+bool TemplateArgument::isConceptOrConceptTemplateParameter() const {
+ bool isConcept = false;
+ if (getKind() == TemplateArgument::Template) {
+ if (isa<ConceptDecl>(getAsTemplate().getAsTemplateDecl()))
+ isConcept = true;
+ else if (auto *TTP = dyn_cast_if_present<TemplateTemplateParmDecl>(
+ getAsTemplate().getAsTemplateDecl()))
+ isConcept = TTP->kind() == TNK_Concept_template;
+ }
+ return isConcept;
+}
+
bool TemplateArgument::containsUnexpandedParameterPack() const {
return getDependence() & TemplateArgumentDependence::UnexpandedPack;
}
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 7444a2f90c5dd..141edc881d683 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/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index e47caeb855d0c..5fb3f92b2e7ce 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 9a04bf298c0ac..f08361ced6379 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -711,41 +711,59 @@ 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().CPlusPlus23 &&
+ Kind != TemplateNameKind::TNK_Type_template) {
+ // Diag older language mods
+ }
+
// Parse the ellipsis, if given.
- SourceLocation EllipsisLoc;
if (TryConsumeToken(tok::ellipsis, EllipsisLoc))
Diag(EllipsisLoc,
getLangOpts().CPlusPlus11
@@ -753,8 +771,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 +809,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 +1218,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 +1263,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 +1294,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 +1335,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 b58100c635677..2a731a18ea82a 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 ff50b3f83908c..a8cfe202c5214 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/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index c74b67106ad74..6e97cd08584b4 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/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 45c7178c6965d..af8f5ca185c59 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2903,9 +2903,11 @@ 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>() &&
- "There should only be one declaration found.");
+ (Id.TemplateId->Kind == TNK_Var_template ||
+ Id.TemplateId->Kind == TNK_Concept_template)) {
+ // TODO CORENTIN
+ // assert(R.getAsSingle<VarTemplateDecl>() &&
+ // "There should only be one declaration found.");
}
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, ADL, TemplateArgs);
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 1c6f292454ed6..95aa60ed64a82 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/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 698d1270be634..4a985bf37a49c 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>
@@ -305,10 +307,11 @@ TemplateNameKind Sema::isTemplateName(Scope *S,
assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) ||
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;
+ TemplateKind = isa<TemplateTemplateParmDecl>(TD)
+ ? dyn_cast<TemplateTemplateParmDecl>(TD)->kind()
+ : isa<VarTemplateDecl>(TD) ? TNK_Var_template
+ : isa<ConceptDecl>(TD) ? TNK_Concept_template
+ : TNK_Type_template;
}
}
@@ -1071,12 +1074,27 @@ 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 (TemplateTemplateParmDecl *TTP =
+ llvm::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,12 +1179,32 @@ 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);
- if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
- return ImmediatelyDeclaredConstraint;
+ ExprResult ImmediatelyDeclaredConstraint;
+ if (auto *CD = dyn_cast<ConceptDecl>(NamedConcept)) {
+ ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId(
+ SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
+ /*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, CD,
+ &ConstraintArgs);
+ if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
+ return ImmediatelyDeclaredConstraint;
+ }
+ // We have a template template parameter
+ else {
+ auto *CDT = dyn_cast<TemplateTemplateParmDecl>(NamedConcept);
+ ImmediatelyDeclaredConstraint = S.CheckVarOrConceptTemplateTemplateId(
+ SS, NameInfo, CDT, SourceLocation(), &ConstraintArgs);
+ if (ImmediatelyDeclaredConstraint.isInvalid())
+ return ImmediatelyDeclaredConstraint;
+ UnresolvedSet<1> R;
+ R.addDecl(CDT);
+ ImmediatelyDeclaredConstraint = UnresolvedLookupExpr::Create(
+ S.getASTContext(), nullptr, SS.getWithLocInContext(S.getASTContext()),
+ SourceLocation(), NameInfo, false, &ConstraintArgs, R.begin(), R.end(),
+ /*KnownDependent=*/false,
+ /*KnownInstantiationDependent=*/false);
+ if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
+ return ImmediatelyDeclaredConstraint;
+ }
// C++2a [temp.param]p4:
// [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
@@ -1191,7 +1228,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 +1626,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 +1651,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 +1700,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 +2717,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 +4109,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 +4168,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 +4759,28 @@ ExprResult Sema::CheckVarTemplateId(
return BuildDeclarationNameExpr(SS, NameInfo, Var, FoundD, TemplateArgs);
}
+ExprResult Sema::CheckVarOrConceptTemplateTemplateId(
+ const CXXScopeSpec &, const DeclarationNameInfo &,
+ TemplateTemplateParmDecl *Template, SourceLocation TemplateLoc,
+ const TemplateArgumentListInfo *TemplateArgs) {
+ assert(Template && "A variable template id without template?");
+
+ if (Template->kind() != TemplateNameKind::TNK_Var_template &&
+ Template->kind() != TemplateNameKind::TNK_Concept_template)
+ return ExprResult();
+
+ // Check that the template argument list is well-formed for this template.
+ CheckTemplateArgumentInfo CTAI;
+ if (CheckTemplateArgumentList(
+ Template, TemplateLoc,
+ const_cast<TemplateArgumentListInfo &>(*TemplateArgs),
+ /*DefaultArgs=*/{}, /*PartialTemplateArgs=*/false, CTAI,
+ /*UpdateArgsWithConversions=*/true))
+ return true;
+
+ return ExprResult();
+}
+
void Sema::diagnoseMissingTemplateArguments(TemplateName Name,
SourceLocation Loc) {
Diag(Loc, diag::err_template_missing_args)
@@ -4812,6 +4899,16 @@ ExprResult Sema::BuildTemplateIdExpr(const CXXScopeSpec &SS,
R.getAsSingle<ConceptDecl>(), TemplateArgs);
}
+ // In C++1y, check variable template ids.
+ if (R.getAsSingle<TemplateTemplateParmDecl>()) {
+ ExprResult Res = CheckVarOrConceptTemplateTemplateId(
+ SS, R.getLookupNameInfo(), R.getAsSingle<TemplateTemplateParmDecl>(),
+ TemplateKWLoc, TemplateArgs);
+ if (Res.isInvalid() || Res.isUsable())
+ return Res;
+ // Result is dependent. Carry on to build an UnresolvedLookupEpxr.
+ }
+
// We don't want lookup warnings at this point.
R.suppressDiagnostics();
@@ -5611,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->kind()) {
+ 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:
@@ -6361,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())
@@ -6466,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() &&
@@ -6524,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;
@@ -6786,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;
@@ -6921,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,
@@ -6976,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,
@@ -6988,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();
}
@@ -7389,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);
}
@@ -7404,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);
}
@@ -7583,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->kind()) {
+ case TemplateNameKind::TNK_Concept_template:
+ DiagFoundKind = 3;
+ break;
+ case TemplateNameKind::TNK_Var_template:
+ DiagFoundKind = 2;
+ break;
+ default:
+ DiagFoundKind = 1;
+ break;
+ }
+ Kind = TTP->kind();
+ } 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->kind()) {
+ return true;
+ }
+
+ unsigned DiagKind = 0;
+ switch (Param->kind()) {
+ 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,
@@ -7599,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)
@@ -7691,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) {
@@ -8011,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.
@@ -8047,6 +8230,8 @@ static bool MatchTemplateParameterKind(
else if (TemplateTemplateParmDecl *OldTTP =
dyn_cast<TemplateTemplateParmDecl>(Old)) {
TemplateTemplateParmDecl *NewTTP = cast<TemplateTemplateParmDecl>(New);
+ if (OldTTP->kind() != NewTTP->kind())
+ return false;
if (!S.TemplateParameterListsAreEqual(
NewInstFrom, NewTTP->getTemplateParameters(), OldInstFrom,
OldTTP->getTemplateParameters(), Complain,
@@ -8058,6 +8243,7 @@ static bool MatchTemplateParameterKind(
}
if (Kind != Sema::TPL_TemplateParamsEquivalent &&
+ Kind != Sema::TPL_TemplateTemplateParmMatch &&
!isa<TemplateTemplateParmDecl>(Old)) {
const Expr *NewC = nullptr, *OldC = nullptr;
@@ -8423,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:
@@ -9034,11 +9225,11 @@ 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;
}
return false;
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 9e56e6978ef7f..c36aac906af3a 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,107 @@ 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)->kind() ==
+ TNK_Var_template ||
+ cast<TemplateTemplateParmDecl>(Template)->kind() ==
+ TNK_Concept_template)));
+ }
+
+ /*NonTypeOrVarTemplateParmDecl(const NonTypeTemplateParmDecl* NTTP)
+ : Template(NTTP) {}
+ NonTypeOrVarTemplateParmDecl(const TemplateTemplateParmDecl* TTP)
+ : Template(TTP) {
+ assert(TTP->kind() == TNK_Var_template || TTP->kind() ==
+ clang::TNK_Concept_template);
+ }*/
+
+ QualType getType() const {
+ if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
+ return NTTP->getType();
+ return getTemplate()->kind() == 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 +472,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 +502,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 +529,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 +544,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 +567,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 +582,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 +2015,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 +2079,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 +2276,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 +2302,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 +2331,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 +2356,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 +2433,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 +2480,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 +2505,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 +2525,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 +2658,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 +2713,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 +4476,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 +5182,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 +6738,19 @@ struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor {
Used[NTTP->getIndex()] = true;
return true;
}
+
+ /*bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *ULE) {
+ if (ULE->isConceptReference() || ULE->isVarDeclReference()) {
+ if (auto *TTP = ULE->getTemplateTemplateDecl()) {
+ if (TTP->getDepth() == Depth)
+ Used[TTP->getIndex()] = true;
+ }
+ for (auto &TLoc : ULE->template_arguments())
+ RecursiveASTVisitor<MarkUsedTemplateParameterVisitor>::
+ TraverseTemplateArgumentLoc(TLoc);
+ }
+ return true;
+ }*/
};
}
@@ -6675,17 +6772,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 20bac0e56b195..7a4ff53573ebf 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1608,6 +1608,9 @@ namespace {
QualType ObjectType = QualType(),
NamedDecl *FirstQualifierInScope = nullptr,
bool AllowInjectedClassName = false);
+ TemplateArgument
+ TransformNamedTemplateTemplateArgument(CXXScopeSpec &SS, TemplateName Name,
+ SourceLocation NameLoc);
const AnnotateAttr *TransformAnnotateAttr(const AnnotateAttr *AA);
const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
@@ -1899,8 +1902,7 @@ namespace {
private:
ExprResult
- transformNonTypeTemplateParmRef(Decl *AssociatedDecl,
- const NonTypeTemplateParmDecl *parm,
+ transformNonTypeTemplateParmRef(Decl *AssociatedDecl, const NamedDecl *parm,
SourceLocation loc, TemplateArgument arg,
UnsignedOrNone PackIndex, bool Final);
};
@@ -2187,6 +2189,27 @@ TemplateName TemplateInstantiator::TransformTemplateName(
AllowInjectedClassName);
}
+TemplateArgument TemplateInstantiator::TransformNamedTemplateTemplateArgument(
+ CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc) {
+ if (TemplateTemplateParmDecl *TTP =
+ dyn_cast_or_null<TemplateTemplateParmDecl>(
+ Name.getAsTemplateDecl())) {
+ if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
+ // If the corresponding template argument is NULL or non-existent, it's
+ // because we are performing instantiation from explicitly-specified
+ // template arguments in a function template, but there were some
+ // arguments left unspecified.
+ if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
+ TTP->getPosition()))
+ return TemplateArgument(Name);
+ }
+ }
+ TemplateName TN = getDerived().TransformTemplateName(SS, Name, NameLoc);
+ if (!TN.isNull())
+ return TN;
+ return TemplateArgument();
+}
+
ExprResult
TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
if (!E->isTypeDependent())
@@ -2343,22 +2366,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 (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;
@@ -2413,7 +2439,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 e2c3cdcd536bc..509222e135e21 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3784,13 +3784,13 @@ 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->kind(),
+ D->wasDeclaredWithTypename(), InstParams, ExpandedParams);
else
Param = TemplateTemplateParmDecl::Create(
SemaRef.Context, Owner, D->getLocation(),
D->getDepth() - TemplateArgs.getNumSubstitutedLevels(),
- D->getPosition(), D->isParameterPack(), D->getIdentifier(),
+ D->getPosition(), D->isParameterPack(), D->getIdentifier(), D->kind(),
D->wasDeclaredWithTypename(), InstParams);
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
NestedNameSpecifierLoc QualifierLoc =
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 572dbf2e7393f..8e44accc0e3d5 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 (auto *TTP = llvm::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 7dbd4bb0ed125..1289bede3f192 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 c7428d1a02345..d3c90b0508234 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -610,6 +610,10 @@ class TreeTransform {
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
@@ -656,6 +660,12 @@ class TreeTransform {
TemplateArgumentListInfo &Outputs,
bool Uneval = false);
+ template <typename InputIterator>
+ bool TransformConceptTemplateArguments(InputIterator First,
+ InputIterator Last,
+ TemplateArgumentListInfo &Outputs,
+ bool Uneval = false);
+
/// Fakes up a TemplateArgumentLoc for a given TemplateArgument.
void InventTemplateArgumentLoc(const TemplateArgument &Arg,
TemplateArgumentLoc &ArgLoc);
@@ -4843,6 +4853,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 +4946,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;
}
@@ -5144,6 +5163,56 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
}
+template <typename Derived>
+template <typename InputIterator>
+bool TreeTransform<Derived>::TransformConceptTemplateArguments(
+ InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs,
+ bool Uneval) {
+
+ auto isConcept = [](const TemplateArgument &Arg) {
+ bool isConcept = false;
+ if (Arg.getKind() == TemplateArgument::Template)
+ if (auto *TTP = dyn_cast_if_present<TemplateTemplateParmDecl>(
+ Arg.getAsTemplate().getAsTemplateDecl()))
+ isConcept = TTP->kind() == TNK_Concept_template;
+ return isConcept;
+ };
+
+ for (; First != Last; ++First) {
+ TemplateArgumentLoc Out;
+ TemplateArgumentLoc In = *First;
+
+ if (In.getArgument().getKind() == TemplateArgument::Pack) {
+ // if(In.getArgument().pack_size() == 00 ||
+ // !isConcept(In.getArgument().pack_elements()[0])) {
+ // Outputs.addArgument(In);
+ // continue;
+ // }
+ typedef TemplateArgumentLocInventIterator<Derived,
+ TemplateArgument::pack_iterator>
+ PackLocIterator;
+ if (TransformConceptTemplateArguments(
+ PackLocIterator(*this, In.getArgument().pack_begin()),
+ PackLocIterator(*this, In.getArgument().pack_end()), Outputs,
+ Uneval))
+ return true;
+ continue;
+ }
+
+ if (!isConcept(In.getArgument())) {
+ Outputs.addArgument(In);
+ continue;
+ }
+
+ if (getDerived().TransformTemplateArgument(In, Out, Uneval))
+ return true;
+
+ Outputs.addArgument(Out);
+ }
+
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Type transformation
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index bd84a9741d01b..ef526ae92a43c 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -2741,6 +2741,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 0166e493bf03f..3f37dfbc3dea9 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/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp
index e414910469a64..2881ff8cf5ecf 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->kind());
Record.push_back(D->wasDeclaredWithTypename());
// TemplateParmPosition.
Record.push_back(D->getDepth());
diff --git a/clang/test/CodeGenCXX/mangle-concept.cpp b/clang/test/CodeGenCXX/mangle-concept.cpp
index aa0940c35b237..63e819bb4f8f0 100644
--- a/clang/test/CodeGenCXX/mangle-concept.cpp
+++ b/clang/test/CodeGenCXX/mangle-concept.cpp
@@ -6,7 +6,8 @@
namespace test1 {
template <bool> struct S {};
template <typename> concept C = true;
-template <typename T = int> S<C<T>> f0() { return S<C<T>>{}; }
+template <typename T = int>
+S<C<T>> f0() { return S<C<T>>{}; }
template S<C<int>> f0<>();
// CHECK: @_ZN5test12f0IiEENS_1SIX1CIT_EEEEv(
// CLANG17: @_ZN5test12f0IiEENS_1SIL_ZNS_1CIT_EEEEEv(
diff --git a/clang/test/Parser/cxx-template-template-recovery.cpp b/clang/test/Parser/cxx-template-template-recovery.cpp
index 5700b160cd364..61ef82dd06ec4 100644
--- a/clang/test/Parser/cxx-template-template-recovery.cpp
+++ b/clang/test/Parser/cxx-template-template-recovery.cpp
@@ -22,18 +22,18 @@ auto V3 = true; // #V3
template <template <typename T> typename C>
constexpr bool test = true;
-static_assert(test<a::C1>); // expected-error {{too few template arguments for concept 'C1'}} \
+static_assert(test<a::C1>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#C1 {{here}}
-static_assert(test<a::b::C2>); // expected-error {{too few template arguments for concept 'C2'}} \
+static_assert(test<a::b::C2>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#C2 {{here}}
-static_assert(test<C3>); // expected-error {{too few template arguments for concept 'C3'}} \
+static_assert(test<C3>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#C3 {{here}}
-static_assert(test<a::V1>); // expected-error {{use of variable template 'a::V1' requires template arguments}} \
+static_assert(test<a::V1>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#V1 {{here}}
-static_assert(test<a::b::V2>); // expected-error {{use of variable template 'a::b::V2' requires template arguments}} \
+static_assert(test<a::b::V2>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#V2 {{here}}
-static_assert(test<V3>); // expected-error {{use of variable template 'V3' requires template arguments}} \
+static_assert(test<V3>); // expected-error {{template argument does not refer to a class or alias template, or template template parameter}} \
// expected-note@#V3 {{here}}
diff --git a/clang/test/Parser/cxx2a-concept-declaration.cpp b/clang/test/Parser/cxx2a-concept-declaration.cpp
index 0a7af847112de..fea6084d58f3a 100644
--- a/clang/test/Parser/cxx2a-concept-declaration.cpp
+++ b/clang/test/Parser/cxx2a-concept-declaration.cpp
@@ -9,11 +9,6 @@ template<concept T> concept D1 = true;
// expected-error at -1{{expected template parameter}}
// expected-error at -2{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}}
-template<template<typename> concept T> concept D2 = true;
-// expected-error at -1{{expected identifier}}
-// expected-error at -2{{template template parameter requires 'class' or 'typename' after the parameter list}}
-// expected-error at -3{{concept template parameter list must have at least one parameter; explicit specialization of concepts is not allowed}}
-
struct S1 {
template<typename T> concept C1 = true; // expected-error {{concept declarations may only appear in global or namespace scope}}
};
diff --git a/clang/test/Parser/cxx2c-template-template-param.cpp b/clang/test/Parser/cxx2c-template-template-param.cpp
new file mode 100644
index 0000000000000..aa9e2393cf106
--- /dev/null
+++ b/clang/test/Parser/cxx2c-template-template-param.cpp
@@ -0,0 +1,79 @@
+// RUN: %clang_cc1 -std=c++2b -verify %s
+
+template<template<typename> auto Var>
+struct A{};
+template<template<auto> auto Var>
+struct B{};
+template<template<typename> auto Var>
+struct C{};
+template<template<typename> concept C>
+struct D{};
+template<template<auto> concept C>
+struct E{};
+
+template<template<typename> auto Var>
+int V1;
+template<template<auto> auto Var>
+int V2;
+template<template<typename> auto Var>
+int V3;
+template<template<typename> concept C>
+int V4;
+template<template<auto> concept C>
+int V5;
+
+namespace packs {
+
+template<template<typename> auto... Var>
+struct A{};
+template<template<auto> auto... Var>
+struct B{};
+template<template<typename> auto... Var>
+struct C{};
+template<template<typename> concept... C>
+struct D{};
+template<template<auto> concept... C>
+struct E{};
+
+template<template<typename> auto... Var>
+int V1;
+template<template<auto> auto... Var>
+int V2;
+template<template<typename> auto... Var>
+int V3;
+template<template<typename> concept... C>
+int V4;
+template<template<auto> concept... C>
+int V5;
+
+}
+
+namespace concepts {
+template<template<auto> concept...>
+struct A{};
+template<template<auto> concept... C>
+struct B{};
+template<template<auto> concept& C> // expected-error{{expected identifier}} \
+ // expected-error {{in declaration of struct 'C'}}
+struct C{};
+}
+
+namespace vars {
+template<template<auto> auto...>
+struct A{};
+template<template<auto> auto & C> // expected-error {{expected identifier}} \
+ // expected-error {{extraneous 'template<>'}}
+struct B{};
+template<template<auto> const auto> // expected-error {{expected identifier}} \
+ // expected-error {{extraneous 'template<>'}}
+struct C{};
+}
+
+namespace errors {
+template<concept> // expected-error {{expected template parameter}} \
+ // expected-error {{extraneous 'template<>' in declaration of struct 'A'}}
+struct A{};
+template<template<concept> auto> // expected-error {{expected template parameter}} \
+ // expected-error {{template template parameter must have its own template parameters}}
+struct B{};
+}
diff --git a/clang/test/SemaCXX/cxx2c-template-template-param.cpp b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
new file mode 100644
index 0000000000000..b96ce733eabe0
--- /dev/null
+++ b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
@@ -0,0 +1,372 @@
+// RUN: %clang_cc1 -std=c++2b -verify %s
+
+namespace Errors {
+
+template <template<typename T> auto>
+struct S1;
+template <template<auto T> auto>
+struct S2;
+template <template<typename T> concept>
+struct S3;
+template <template<auto T> concept>
+struct S4;
+int a;
+
+template <typename T>
+concept C = true; // expected-note 2{{template argument refers to a concept 'C', here}}
+template <typename T>
+auto Var = 0; // expected-note 2{{template argument refers to a variable template 'Var', here}}
+
+S1<1> t1; // expected-error {{template argument for template template parameter must be a variable template}}
+S1<a> t2; // expected-error {{template argument for template template parameter must be a variable template}}
+S1<int> t3; // expected-error {{template argument for template template parameter must be a variable template}}
+S1<C> t4; // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+S2<1> t5; // expected-error {{template argument for template template parameter must be a variable template}}
+S2<a> t6; // expected-error {{template argument for template template parameter must be a variable template}}
+S2<int> t7; // expected-error {{template argument for template template parameter must be a variable template}}
+S2<C> t8; // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+S3<1> t9; // expected-error {{template argument for template template parameter must be a concept}}
+S3<a> t10; // expected-error {{template argument for template template parameter must be a concept}}
+S3<int> t11; // expected-error {{template argument for template template parameter must be a concept}}
+S3<Var> t12; // expected-error {{template argument does not refer to a concept, or template template parameter}}
+S4<1> t13; // expected-error {{template argument for template template parameter must be a concept}}
+S4<a> t14; // expected-error {{template argument for template template parameter must be a concept}}
+S4<int> t15; // expected-error {{template argument for template template parameter must be a concept}}
+S4<Var> t16; // expected-error {{template argument does not refer to a concept, or template template parameter}}
+
+}
+
+template <template<typename T> auto V> // expected-note {{previous template template parameter is here}}
+struct S1 {
+ static_assert(V<int> == 42);
+ static_assert(V<const int> == 84);
+ static_assert(V<double> == 0);
+};
+template <template<auto T> auto V> // expected-note {{previous template template parameter is here}}
+struct S2 {
+ static_assert(V<0> == 1);
+ static_assert(V<1> == 0);
+};
+template <template<typename T> concept C > // expected-note {{previous template template parameter is here}}
+struct S3 {
+ static_assert(C<int>);
+};
+template <template<auto> concept C> // expected-note {{previous template template parameter is here}}
+struct S4 {
+ static_assert(C<0>);
+};
+
+template <typename T> // expected-note {{template parameter has a different kind in template argument}}
+concept C = true;
+
+template <auto I> // expected-note {{template parameter has a different kind in template argument}}
+concept CI = true;
+
+template <typename T> // expected-note {{template parameter has a different kind in template argument}}
+constexpr auto Var = 42;
+template <typename T>
+constexpr auto Var<const T> = 84;
+template <>
+constexpr auto Var<double> = 0;
+
+template <auto N> // expected-note {{template parameter has a different kind in template argument}}
+constexpr auto Var2 = 0;
+template <auto N>
+requires (N%2 == 0)
+constexpr auto Var2<N> = 1;
+
+void test () {
+ S1<Var2> sE; // expected-error {{template template argument has different template parameters than its corresponding template template parameter}}
+ S2<Var> sE; // expected-error {{template template argument has different template parameters than its corresponding template template parameter}}
+ S1<Var> s1;
+ S2<Var2> s2;
+ S3<C> s3;
+ S4<C> sE; // expected-error {{template template argument has different template parameters than its corresponding template template parameter}}
+ S4<CI> s4;
+ S3<CI> sE; // expected-error {{template template argument has different template parameters than its corresponding template template parameter}}
+}
+
+namespace subsumption {
+
+template <typename T>
+concept A = true;
+
+template <typename T>
+concept B = A<T> && true;
+
+template <typename T>
+concept C = true;
+
+template <typename T>
+concept D = C<T> && true;
+
+template <typename ABC, template <typename> concept... C>
+concept Apply = (C<ABC> && ...);
+
+constexpr int f(Apply<A, C> auto) {return 1;}
+constexpr int f(Apply<B, D> auto) {return 2;}
+
+int test() {
+ static_assert(f(1) == 2);
+}
+
+}
+
+namespace template_type_constraints {
+
+
+template <typename T>
+concept Unary = true;
+template <typename T, typename = int>
+concept BinaryDefaulted = true;
+
+template <typename T>
+concept UnaryFalse = false; // expected-note 3{{because 'false' evaluated to false}}
+template <typename T, typename = int>
+concept BinaryDefaultedFalse = false;
+
+template <template <typename...> concept C, typename T>
+struct S {
+ template <C TT> // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
+ void f(TT); // expected-note {{ignored}}
+ void g(C auto); // expected-note {{ignored}} \
+ // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
+
+ auto h() -> C auto { // expected-error {{deduced type 'int' does not satisfy 'UnaryFalse'}}
+ return 0;
+ };
+
+ void test() {
+ C auto a = 0;
+ }
+};
+
+template <template <typename...> concept C, typename T>
+struct SArg {
+ template <C<int> TT>
+ void f(TT);
+ void g(C<int> auto);
+
+ auto h() -> C<int> auto {
+ return 0;
+ };
+ void test() {
+ C<int> auto a = 0;
+ }
+};
+
+void test() {
+ S<Unary, int> s;
+ s.f(0);
+ s.g(0);
+ s.h();
+ S<BinaryDefaulted, int> s2;
+ s2.f(0);
+ s2.g(0);
+ s2.h();
+
+ SArg<BinaryDefaulted, int> s3;
+ s3.f(0);
+ s3.g(0);
+ s3.h();
+}
+
+void test_errors() {
+ S<UnaryFalse, int> s;
+ s.f(0); // expected-error {{no matching member function for call to 'f'}}
+ s.g(0); // expected-error {{no matching member function for call to 'g'}}
+ s.h(); // expected-note {{in instantiation of member function 'template_type_constraints::S<template_type_constraints::UnaryFalse, int>::h'}}
+}
+
+}
+
+template <typename T>
+concept Unary = true;
+template <typename T, typename = int>
+concept BinaryDefaulted = true;
+
+template <typename T>
+concept UnaryFalse = false; // expected-note 3{{because 'false' evaluated to false}}
+template <typename T, typename = int>
+concept BinaryDefaultedFalse = false;
+
+template <template <typename...> concept C, typename T>
+struct S {
+ template <C TT> // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
+ void f(TT); // expected-note {{ignored}}
+ void g(C auto); // expected-note {{ignored}} \
+ // expected-note {{because 'int' does not satisfy 'UnaryFalse'}}
+
+ auto h() -> C auto { // expected-error {{deduced type 'int' does not satisfy 'UnaryFalse'}}
+ return 0;
+ };
+
+ void test() {
+ C auto a = 0;
+ }
+};
+
+template <template <typename...> concept C, typename T>
+struct SArg {
+ template <C<int> TT>
+ void f(TT);
+ void g(C<int> auto);
+
+ auto h() -> C<int> auto {
+ return 0;
+ };
+ void test() {
+ C<int> auto a = 0;
+ }
+};
+
+void test_args() {
+ S<Unary, int> s;
+ s.f(0);
+ s.g(0);
+ s.h();
+ S<BinaryDefaulted, int> s2;
+ s2.f(0);
+ s2.g(0);
+ s2.h();
+
+ SArg<BinaryDefaulted, int> s3;
+ s3.f(0);
+ s3.g(0);
+ s3.h();
+}
+
+void test_errors() {
+ S<UnaryFalse, int> s;
+ s.f(0); // expected-error {{no matching member function for call to 'f'}}
+ s.g(0); // expected-error {{no matching member function for call to 'g'}}
+ s.h(); // expected-note {{in instantiation of member function 'S<UnaryFalse, int>::h'}}
+}
+
+namespace non_type {
+
+template <auto>
+concept Unary = true;
+
+template <template <auto> concept C>
+struct S {
+ template <C Foo> // expected-error {{concept named in type constraint is not a type concept}}
+ void f();
+ // FIXME, bad diagnostic
+ void g(C auto); // expected-error{{concept named in type constraint is not a type concept}}
+ auto h() -> C auto { // expected-error{{concept named in type constraint is not a type concept}}
+ }
+ void i() {
+ C auto a = 0; // expected-error{{concept named in type constraint is not a type concept}}
+ }
+};
+
+}
+
+namespace default_args {
+
+template <typename T>
+concept Concept = false; // expected-note 2{{template argument refers to a concept 'Concept', here}} \
+ // expected-note 2{{because 'false' evaluated to false}}
+
+template <typename T>
+constexpr auto Var = false; // expected-note 2{{template argument refers to a variable template 'Var', here}}
+
+template <typename T>
+struct Type; // expected-note 2{{template argument refers to a class template 'Type', here}}
+
+
+template <template <typename> auto = Concept> // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+struct E1;
+
+template <template <typename> auto = Type> // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+struct E2;
+
+template <template <typename> typename = Concept> // expected-error {{template argument does not refer to a class or alias template, or template template parameter}}
+struct E3;
+
+template <template <typename> typename = Var> // expected-error {{template argument does not refer to a class or alias template, or template template parameter}}
+struct E4;
+
+template <template <typename> concept = Var> // expected-error {{template argument does not refer to a concept, or template template parameter}}
+struct E4;
+
+template <template <typename> concept = Type> // expected-error {{template argument does not refer to a concept, or template template parameter}}
+struct E4;
+
+template <
+ template <typename> concept TConcept, // expected-note 2{{template argument refers to a concept 'TConcept', here}}
+ template <typename> auto TVar, // expected-note 2{{template argument refers to a variable template 'TVar', here}}
+ template <typename> typename TType // expected-note 2{{template argument refers to a class template 'TType', here}}
+>
+struct Nested {
+ template <template <typename> auto = TConcept> // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+ struct E1;
+
+ template <template <typename> auto = TType> // expected-error {{template argument does not refer to a variable template, or template template parameter}}
+ struct E2;
+
+ template <template <typename> typename = TConcept> // expected-error {{template argument does not refer to a class or alias template, or template template parameter}}
+ struct E3;
+
+ template <template <typename> typename = TVar> // expected-error {{template argument does not refer to a class or alias template, or template template parameter}}
+ struct E4;
+
+ template <template <typename> concept = TVar> // expected-error {{template argument does not refer to a concept, or template template parameter}}
+ struct E4;
+
+ template <template <typename> concept = TType> // expected-error {{template argument does not refer to a concept, or template template parameter}}
+ struct E4;
+};
+
+
+template <template <typename> concept C = Concept>
+struct TestDefaultConcept {
+ template <template <typename> concept CC = C>
+ void f() {
+ static_assert(C<int>); // expected-error {{static assertion failed}} \
+ // expected-note {{because 'int' does not satisfy 'Concept'}}
+ static_assert(CC<int>); // expected-error {{static assertion failed}} \
+ // expected-note {{because 'int' does not satisfy 'Concept'}}
+ }
+};
+void do_test_concept() {
+ TestDefaultConcept<>{}.f(); // expected-note {{in instantiation}}
+}
+
+template <template <typename> auto V = Var>
+struct TestDefaultVar {
+ template <template <typename> auto VV = V>
+ void f() {
+ static_assert(V<int>); // expected-error {{static assertion failed}}
+ static_assert(VV<int>); // expected-error {{static assertion failed}}
+ }
+};
+void do_test_var() {
+ TestDefaultVar<>{}.f(); // expected-note {{in instantiation}}
+}
+
+}
+
+namespace TTPDependence {
+template <template <typename... > concept C>
+concept A = C<>;
+template <template <typename... > concept C>
+concept B = C<int>;
+
+template <template <typename... > auto Var>
+concept C = Var<>;
+template <template <typename... > auto Var>
+concept D = Var<int>;
+
+}
+
+namespace InvalidName {
+// FIXME corentin: improve diagnostics
+template <typename T, template <typename> concept C>
+concept A = C<T>; // expected-note {{here}}
+
+template <A<concept missing<int>> T> // expected-error {{expected expression}} \
+ // expected-error {{too few template arguments for concept 'A'}}
+auto f();
+}
diff --git a/clang/utils/TableGen/ClangBuiltinTemplatesEmitter.cpp b/clang/utils/TableGen/ClangBuiltinTemplatesEmitter.cpp
index 310ae89835e00..7c0cda044ee78 100644
--- a/clang/utils/TableGen/ClangBuiltinTemplatesEmitter.cpp
+++ b/clang/utils/TableGen/ClangBuiltinTemplatesEmitter.cpp
@@ -52,7 +52,8 @@ ParseTemplateParameterList(ParserState &PS,
Code << TemplateCode << " auto *" << ParmName
<< " = TemplateTemplateParmDecl::Create(C, DC, SourceLocation(), "
<< PS.CurrentDepth << ", " << Position++
- << ", /*ParameterPack=*/false, /*Id=*/nullptr, /*Typename=*/false, "
+ << ", /*ParameterPack=*/false, /*Id=*/nullptr, "
+ "/*Kind=*/TNK_Type_template, /*Typename=*/false, "
<< TPLName << ");\n";
} else if (Arg->isSubClassOf("Class")) {
Code << " auto *" << ParmName
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 256952dcf9085..8f0decbf3dcd7 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -1631,11 +1631,11 @@ TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) {
// type that includes a template template argument. Only the name matters for
// this purpose, so we use dummy values for the other characteristics of the
// type.
- return TemplateTemplateParmDecl::Create(ast, decl_ctx, SourceLocation(),
- /*Depth=*/0, /*Position=*/0,
- /*IsParameterPack=*/false,
- &identifier_info, /*Typename=*/false,
- template_param_list);
+ return TemplateTemplateParmDecl::Create(
+ ast, decl_ctx, SourceLocation(),
+ /*Depth*/ 0, /*Position*/ 0,
+ /*IsParameterPack*/ false, &identifier_info,
+ TemplateNameKind::TNK_Type_template, template_param_list);
}
ClassTemplateSpecializationDecl *
>From 7948dc0eb1a69e50d02c514bd5e9dd162febd9d4 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 28 Jul 2025 14:55:10 +0200
Subject: [PATCH 02/10] fix tests
---
.../SemaCXX/cxx2c-template-template-param.cpp | 58 ++++++-------------
1 file changed, 19 insertions(+), 39 deletions(-)
diff --git a/clang/test/SemaCXX/cxx2c-template-template-param.cpp b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
index b96ce733eabe0..303e5ef9c6276 100644
--- a/clang/test/SemaCXX/cxx2c-template-template-param.cpp
+++ b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
@@ -36,81 +36,60 @@ S4<Var> t16; // expected-error {{template argument does not refer to a concept,
}
-template <template<typename T> auto V> // expected-note {{previous template template parameter is here}}
+template <template<typename T> auto V> // expected-note {{previous template template parameter is here}} \
+ // expected-error{{template argument for non-type template parameter must be an expression}}
struct S1 {
static_assert(V<int> == 42);
static_assert(V<const int> == 84);
static_assert(V<double> == 0);
};
-template <template<auto T> auto V> // expected-note {{previous template template parameter is here}}
+template <template<auto T> auto V> // expected-error {{template argument for template type parameter must be a type}} \
+ // expected-note {{previous template template parameter is here}}
struct S2 {
static_assert(V<0> == 1);
static_assert(V<1> == 0);
};
-template <template<typename T> concept C > // expected-note {{previous template template parameter is here}}
+template <template<typename T> concept C > // expected-error {{template argument for non-type template parameter must be an expression}} \
+ // expected-note {{previous template template parameter is here}}
struct S3 {
static_assert(C<int>);
};
-template <template<auto> concept C> // expected-note {{previous template template parameter is here}}
+template <template<auto> concept C> // expected-error {{template argument for template type parameter must be a type}} \
+ // expected-note {{previous template template parameter is here}}
struct S4 {
static_assert(C<0>);
};
-template <typename T> // expected-note {{template parameter has a different kind in template argument}}
+template <typename T> // expected-note {{template parameter is declared here}}
concept C = true;
-template <auto I> // expected-note {{template parameter has a different kind in template argument}}
+template <auto I> // expected-note {{template parameter is declared here}}
concept CI = true;
-template <typename T> // expected-note {{template parameter has a different kind in template argument}}
+template <typename T> // expected-note {{template parameter is declared here}}
constexpr auto Var = 42;
template <typename T>
constexpr auto Var<const T> = 84;
template <>
constexpr auto Var<double> = 0;
-template <auto N> // expected-note {{template parameter has a different kind in template argument}}
+template <auto N> // expected-note {{template parameter is declared here}}
constexpr auto Var2 = 0;
template <auto N>
requires (N%2 == 0)
constexpr auto Var2<N> = 1;
void test () {
- S1<Var2> sE; // expected-error {{template template argument has different template parameters than its corresponding template template parameter}}
- S2<Var> sE; // expected-error {{template template argument has different template parameters than its corresponding template template parameter}}
+ S1<Var2> sE; // expected-note {{template template argument has different template parameters than its corresponding template template parameter}}
+ S2<Var> sE; // expected-note {{template template argument has different template parameters than its corresponding template template parameter}}
S1<Var> s1;
S2<Var2> s2;
S3<C> s3;
- S4<C> sE; // expected-error {{template template argument has different template parameters than its corresponding template template parameter}}
+ S4<C> sE; // expected-note {{template template argument has different template parameters than its corresponding template template parameter}}
S4<CI> s4;
- S3<CI> sE; // expected-error {{template template argument has different template parameters than its corresponding template template parameter}}
+ S3<CI> sE; // expected-note {{template template argument has different template parameters than its corresponding template template parameter}}
}
-namespace subsumption {
-
-template <typename T>
-concept A = true;
-
-template <typename T>
-concept B = A<T> && true;
-
-template <typename T>
-concept C = true;
-
-template <typename T>
-concept D = C<T> && true;
-
-template <typename ABC, template <typename> concept... C>
-concept Apply = (C<ABC> && ...);
-
-constexpr int f(Apply<A, C> auto) {return 1;}
-constexpr int f(Apply<B, D> auto) {return 2;}
-
-int test() {
- static_assert(f(1) == 2);
-}
-
-}
namespace template_type_constraints {
@@ -362,11 +341,12 @@ concept D = Var<int>;
}
namespace InvalidName {
-// FIXME corentin: improve diagnostics
template <typename T, template <typename> concept C>
concept A = C<T>; // expected-note {{here}}
template <A<concept missing<int>> T> // expected-error {{expected expression}} \
- // expected-error {{too few template arguments for concept 'A'}}
+ // expected-error {{too few template arguments for concept 'A'}} \
+ // expected-error {{unknown type name 'T'}} \
+ // expected-error {{expected unqualified-id}}
auto f();
}
>From 8fedefe2b768121fe17e96b50c865514f611bc17 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 28 Jul 2025 15:12:11 +0200
Subject: [PATCH 03/10] Make it an error in older language modes
---
clang/include/clang/Basic/DiagnosticParseKinds.td | 4 ++++
clang/lib/Parse/ParseTemplate.cpp | 8 +++++---
clang/test/Parser/cxx2c-template-template-param.cpp | 2 +-
clang/test/SemaCXX/cxx2c-template-template-param.cpp | 2 +-
4 files changed, 11 insertions(+), 5 deletions(-)
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<CXX11>;
def warn_cxx98_compat_extern_template : Warning<
diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp
index f08361ced6379..0277dfb5aac13 100644
--- a/clang/lib/Parse/ParseTemplate.cpp
+++ b/clang/lib/Parse/ParseTemplate.cpp
@@ -758,9 +758,11 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth,
ConsumeToken();
}
- if (!getLangOpts().CPlusPlus23 &&
- Kind != TemplateNameKind::TNK_Type_template) {
- // Diag older language mods
+ 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.
diff --git a/clang/test/Parser/cxx2c-template-template-param.cpp b/clang/test/Parser/cxx2c-template-template-param.cpp
index aa9e2393cf106..e8c7621404766 100644
--- a/clang/test/Parser/cxx2c-template-template-param.cpp
+++ b/clang/test/Parser/cxx2c-template-template-param.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++2b -verify %s
+// RUN: %clang_cc1 -std=c++2c -verify %s
template<template<typename> auto Var>
struct A{};
diff --git a/clang/test/SemaCXX/cxx2c-template-template-param.cpp b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
index 303e5ef9c6276..ed55a059bb53c 100644
--- a/clang/test/SemaCXX/cxx2c-template-template-param.cpp
+++ b/clang/test/SemaCXX/cxx2c-template-template-param.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -std=c++2b -verify %s
+// RUN: %clang_cc1 -std=c++2c -verify %s
namespace Errors {
>From 352b44a7f3ded99beb47ebd4c5178edb733cd084 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 28 Jul 2025 16:07:15 +0200
Subject: [PATCH 04/10] fixc lldb
---
lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 8f0decbf3dcd7..0988343709442 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -1634,8 +1634,9 @@ TypeSystemClang::CreateTemplateTemplateParmDecl(const char *template_name) {
return TemplateTemplateParmDecl::Create(
ast, decl_ctx, SourceLocation(),
/*Depth*/ 0, /*Position*/ 0,
- /*IsParameterPack*/ false, &identifier_info,
- TemplateNameKind::TNK_Type_template, template_param_list);
+ /*IsParameterPack=*/false, &identifier_info,
+ TemplateNameKind::TNK_Type_template, /*DeclaredWithTypename=*/true,
+ template_param_list);
}
ClassTemplateSpecializationDecl *
>From db90ccc9c46cbd8b9414a5fb4a5e94bae8d81e8e Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 28 Jul 2025 16:34:46 +0200
Subject: [PATCH 05/10] cleanups
---
clang/include/clang/AST/ExprCXX.h | 2 +-
clang/lib/Sema/SemaExpr.cpp | 5 ++---
clang/lib/Sema/SemaTemplateDeduction.cpp | 19 +++++--------------
clang/lib/Sema/TreeTransform.h | 10 +++++-----
4 files changed, 13 insertions(+), 23 deletions(-)
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index a78ad0999d198..1979aa8a97b26 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -3261,7 +3261,7 @@ class OverloadExpr : public Expr {
bool hasExplicitTemplateArgs() const {
if (!hasTemplateKWAndArgsInfo())
return false;
- // FIXME corentin: deduced function types can have "hidden" args and no <
+ // 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())
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index af8f5ca185c59..0b524cd0b3493 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2905,9 +2905,8 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS,
if (Id.getKind() == UnqualifiedIdKind::IK_TemplateId && Id.TemplateId &&
(Id.TemplateId->Kind == TNK_Var_template ||
Id.TemplateId->Kind == TNK_Concept_template)) {
- // TODO CORENTIN
- // assert(R.getAsSingle<VarTemplateDecl>() &&
- // "There should only be one declaration found.");
+ assert(R.getAsSingle<TemplateDecl>() &&
+ "There should only be one declaration found.");
}
return BuildTemplateIdExpr(SS, TemplateKWLoc, R, ADL, TemplateArgs);
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index c36aac906af3a..df96ff6ebca05 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -181,14 +181,6 @@ class NonTypeOrVarTemplateParmDecl {
TNK_Concept_template)));
}
- /*NonTypeOrVarTemplateParmDecl(const NonTypeTemplateParmDecl* NTTP)
- : Template(NTTP) {}
- NonTypeOrVarTemplateParmDecl(const TemplateTemplateParmDecl* TTP)
- : Template(TTP) {
- assert(TTP->kind() == TNK_Var_template || TTP->kind() ==
- clang::TNK_Concept_template);
- }*/
-
QualType getType() const {
if (const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Template))
return NTTP->getType();
@@ -6739,18 +6731,17 @@ struct MarkUsedTemplateParameterVisitor : DynamicRecursiveASTVisitor {
return true;
}
- /*bool VisitUnresolvedLookupExpr(UnresolvedLookupExpr *ULE) {
+ 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())
- RecursiveASTVisitor<MarkUsedTemplateParameterVisitor>::
- TraverseTemplateArgumentLoc(TLoc);
+ DynamicRecursiveASTVisitor::TraverseTemplateArgumentLoc(TLoc);
}
return true;
- }*/
+ }
};
}
@@ -6773,7 +6764,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
E = Expansion->getPattern();
E = unwrapExpressionForDeduction(E);
- /*if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E);
+ if (const auto *ULE = dyn_cast<UnresolvedLookupExpr>(E);
ULE && (ULE->isConceptReference() || ULE->isVarDeclReference())) {
if (const auto *TTP = ULE->getTemplateTemplateDecl())
Used[TTP->getIndex()] = true;
@@ -6781,7 +6772,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx,
MarkUsedTemplateParameters(Ctx, TLoc.getArgument(), OnlyDeduced, Depth,
Used);
return;
- }*/
+ }
const NonTypeOrVarTemplateParmDecl NTTP =
getDeducedNTTParameterFromExpr(E, Depth);
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index d3c90b0508234..a955ee7f7987c 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -5183,11 +5183,11 @@ bool TreeTransform<Derived>::TransformConceptTemplateArguments(
TemplateArgumentLoc In = *First;
if (In.getArgument().getKind() == TemplateArgument::Pack) {
- // if(In.getArgument().pack_size() == 00 ||
- // !isConcept(In.getArgument().pack_elements()[0])) {
- // Outputs.addArgument(In);
- // continue;
- // }
+ if (In.getArgument().pack_size() == 0 ||
+ !isConcept(In.getArgument().pack_elements()[0])) {
+ Outputs.addArgument(In);
+ continue;
+ }
typedef TemplateArgumentLocInventIterator<Derived,
TemplateArgument::pack_iterator>
PackLocIterator;
>From 031ca840bca44642e690ee8ef7df104fde0b35e9 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 29 Jul 2025 09:08:13 +0200
Subject: [PATCH 06/10] Address Erich's feedback
---
clang/lib/AST/DeclTemplate.cpp | 2 +-
clang/lib/AST/TemplateBase.cpp | 7 ++--
clang/lib/Sema/TreeTransform.h | 69 +++-------------------------------
3 files changed, 9 insertions(+), 69 deletions(-)
diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp
index 70b12c9d3bb64..f084af7f4832e 100644
--- a/clang/lib/AST/DeclTemplate.cpp
+++ b/clang/lib/AST/DeclTemplate.cpp
@@ -237,7 +237,7 @@ void TemplateParameterList::getAssociatedConstraints(
ACs.emplace_back(E);
}
}
- if (HasRequiresClause && getRequiresClause())
+ if (HasRequiresClause)
ACs.emplace_back(getRequiresClause());
}
diff --git a/clang/lib/AST/TemplateBase.cpp b/clang/lib/AST/TemplateBase.cpp
index 4207fea3764ab..93d5611ff34bd 100644
--- a/clang/lib/AST/TemplateBase.cpp
+++ b/clang/lib/AST/TemplateBase.cpp
@@ -340,15 +340,14 @@ bool TemplateArgument::isPackExpansion() const {
}
bool TemplateArgument::isConceptOrConceptTemplateParameter() const {
- bool isConcept = false;
if (getKind() == TemplateArgument::Template) {
if (isa<ConceptDecl>(getAsTemplate().getAsTemplateDecl()))
- isConcept = true;
+ return true;
else if (auto *TTP = dyn_cast_if_present<TemplateTemplateParmDecl>(
getAsTemplate().getAsTemplateDecl()))
- isConcept = TTP->kind() == TNK_Concept_template;
+ return TTP->kind() == TNK_Concept_template;
}
- return isConcept;
+ return false;
}
bool TemplateArgument::containsUnexpandedParameterPack() const {
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index a955ee7f7987c..f2e800ad17dd3 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -660,12 +660,6 @@ class TreeTransform {
TemplateArgumentListInfo &Outputs,
bool Uneval = false);
- template <typename InputIterator>
- bool TransformConceptTemplateArguments(InputIterator First,
- InputIterator Last,
- TemplateArgumentListInfo &Outputs,
- bool Uneval = false);
-
/// Fakes up a TemplateArgumentLoc for a given TemplateArgument.
void InventTemplateArgumentLoc(const TemplateArgument &Arg,
TemplateArgumentLoc &ArgLoc);
@@ -5048,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.
@@ -5061,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;
@@ -5163,56 +5154,6 @@ bool TreeTransform<Derived>::TransformTemplateArguments(
}
-template <typename Derived>
-template <typename InputIterator>
-bool TreeTransform<Derived>::TransformConceptTemplateArguments(
- InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs,
- bool Uneval) {
-
- auto isConcept = [](const TemplateArgument &Arg) {
- bool isConcept = false;
- if (Arg.getKind() == TemplateArgument::Template)
- if (auto *TTP = dyn_cast_if_present<TemplateTemplateParmDecl>(
- Arg.getAsTemplate().getAsTemplateDecl()))
- isConcept = TTP->kind() == TNK_Concept_template;
- return isConcept;
- };
-
- for (; First != Last; ++First) {
- TemplateArgumentLoc Out;
- TemplateArgumentLoc In = *First;
-
- if (In.getArgument().getKind() == TemplateArgument::Pack) {
- if (In.getArgument().pack_size() == 0 ||
- !isConcept(In.getArgument().pack_elements()[0])) {
- Outputs.addArgument(In);
- continue;
- }
- typedef TemplateArgumentLocInventIterator<Derived,
- TemplateArgument::pack_iterator>
- PackLocIterator;
- if (TransformConceptTemplateArguments(
- PackLocIterator(*this, In.getArgument().pack_begin()),
- PackLocIterator(*this, In.getArgument().pack_end()), Outputs,
- Uneval))
- return true;
- continue;
- }
-
- if (!isConcept(In.getArgument())) {
- Outputs.addArgument(In);
- continue;
- }
-
- if (getDerived().TransformTemplateArgument(In, Out, Uneval))
- return true;
-
- Outputs.addArgument(Out);
- }
-
- return false;
-}
-
//===----------------------------------------------------------------------===//
// Type transformation
//===----------------------------------------------------------------------===//
>From 01f651f330ce0820691ad515f872b09a2185a5f9 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 29 Jul 2025 09:48:10 +0200
Subject: [PATCH 07/10] Address some of Younan's feedback
---
clang/lib/Sema/SemaTemplate.cpp | 52 +++++++++++++++------------------
1 file changed, 24 insertions(+), 28 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 4a985bf37a49c..d15253662aea6 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1185,26 +1185,15 @@ static ExprResult formImmediatelyDeclaredConstraint(
SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo,
/*FoundDecl=*/FoundDecl ? FoundDecl : NamedConcept, CD,
&ConstraintArgs);
- if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
- return ImmediatelyDeclaredConstraint;
}
// We have a template template parameter
else {
auto *CDT = dyn_cast<TemplateTemplateParmDecl>(NamedConcept);
ImmediatelyDeclaredConstraint = S.CheckVarOrConceptTemplateTemplateId(
SS, NameInfo, CDT, SourceLocation(), &ConstraintArgs);
- if (ImmediatelyDeclaredConstraint.isInvalid())
- return ImmediatelyDeclaredConstraint;
- UnresolvedSet<1> R;
- R.addDecl(CDT);
- ImmediatelyDeclaredConstraint = UnresolvedLookupExpr::Create(
- S.getASTContext(), nullptr, SS.getWithLocInContext(S.getASTContext()),
- SourceLocation(), NameInfo, false, &ConstraintArgs, R.begin(), R.end(),
- /*KnownDependent=*/false,
- /*KnownInstantiationDependent=*/false);
- if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
- return ImmediatelyDeclaredConstraint;
}
+ if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid())
+ return ImmediatelyDeclaredConstraint;
// C++2a [temp.param]p4:
// [...] If T is not a pack, then E is E', otherwise E is (E' && ...).
@@ -4760,7 +4749,7 @@ ExprResult Sema::CheckVarTemplateId(
}
ExprResult Sema::CheckVarOrConceptTemplateTemplateId(
- const CXXScopeSpec &, const DeclarationNameInfo &,
+ const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo,
TemplateTemplateParmDecl *Template, SourceLocation TemplateLoc,
const TemplateArgumentListInfo *TemplateArgs) {
assert(Template && "A variable template id without template?");
@@ -4773,12 +4762,21 @@ ExprResult Sema::CheckVarOrConceptTemplateTemplateId(
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=*/true))
+ /*UpdateArgsWithConversions=*/false))
return true;
- return ExprResult();
+ UnresolvedSet<1> R;
+ R.addDecl(Template);
+ 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,
@@ -4893,31 +4891,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);
}
- // In C++1y, check variable template ids.
- if (R.getAsSingle<TemplateTemplateParmDecl>()) {
- ExprResult Res = CheckVarOrConceptTemplateTemplateId(
+ // 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);
- if (Res.isInvalid() || Res.isUsable())
- return Res;
- // Result is dependent. Carry on to build an UnresolvedLookupEpxr.
- }
- // We don't want lookup warnings at this point.
- R.suppressDiagnostics();
-
- 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.
>From c8464a0cb521707ed9324aa134500e8f9a803db2 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 29 Jul 2025 10:18:39 +0200
Subject: [PATCH 08/10] add comment
---
clang/include/clang/Sema/Initialization.h | 3 ++-
clang/lib/Sema/SemaTemplate.cpp | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h
index e5ee4b4e48ccc..d7675ea153afb 100644
--- a/clang/include/clang/Sema/Initialization.h
+++ b/clang/include/clang/Sema/Initialization.h
@@ -159,7 +159,8 @@ class alignas(8) InitializedEntity {
};
struct VD {
- /// The VarDecl, FieldDecl, or BindingDecl being initialized.
+ /// The VarDecl, FieldDecl, TemplateParmDecl, or BindingDecl being
+ /// initialized.
NamedDecl *VariableOrMember;
/// When Kind == EK_Member, whether this is an implicit member
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index d15253662aea6..631bfc7558c16 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -9228,6 +9228,8 @@ bool Sema::CheckConceptUseInDefinition(NamedDecl *Concept, SourceLocation Loc) {
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;
}
>From 83d6873908742672811c77e3704cef49bb1df083 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 29 Jul 2025 10:25:23 +0200
Subject: [PATCH 09/10] revert ParsedTemplate.h changes
---
clang/include/clang/Sema/ParsedTemplate.h | 212 +++++++++++-----------
1 file changed, 105 insertions(+), 107 deletions(-)
diff --git a/clang/include/clang/Sema/ParsedTemplate.h b/clang/include/clang/Sema/ParsedTemplate.h
index 6628bb88a81b9..3a8050f9a0a3d 100644
--- a/clang/include/clang/Sema/ParsedTemplate.h
+++ b/clang/include/clang/Sema/ParsedTemplate.h
@@ -14,7 +14,6 @@
#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"
@@ -27,116 +26,115 @@
#include <new>
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);
+ }
-/// 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,
- };
+ /// Retrieve the non-type template argument's expression.
+ Expr *getAsExpr() const {
+ assert(Kind == NonType && "Not a non-type template argument");
+ return static_cast<Expr*>(Arg);
+ }
- /// Build an empty template argument.
- ///
- /// This template argument is invalid.
- ParsedTemplateArgument() : Kind(Type), Arg(nullptr) {}
+ /// Retrieve the template template argument's template name.
+ ParsedTemplateTy getAsTemplate() const {
+ assert(Kind == Template && "Not a template template argument");
+ return ParsedTemplateTy::getFromOpaquePtr(Arg);
+ }
- /// 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) {}
+ /// Retrieve the location of the template argument.
+ SourceLocation getLocation() const { return 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<Expr *>(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;
-};
+ /// 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;
+
+ /// 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 template
+ /// argument (turning it into a template template argument expansion).
+ SourceLocation EllipsisLoc;
+ };
/// Information about a template-id annotation
/// token.
>From 0cb6d19c703e584d2d531034aaf959b9a75f7725 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Tue, 29 Jul 2025 10:36:44 +0200
Subject: [PATCH 10/10] remove more uneeded/redundant code
---
clang/lib/Sema/SemaTemplateInstantiate.cpp | 24 ----------------------
1 file changed, 24 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp
index 7a4ff53573ebf..6ed46fdd46531 100644
--- a/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -1608,9 +1608,6 @@ namespace {
QualType ObjectType = QualType(),
NamedDecl *FirstQualifierInScope = nullptr,
bool AllowInjectedClassName = false);
- TemplateArgument
- TransformNamedTemplateTemplateArgument(CXXScopeSpec &SS, TemplateName Name,
- SourceLocation NameLoc);
const AnnotateAttr *TransformAnnotateAttr(const AnnotateAttr *AA);
const CXXAssumeAttr *TransformCXXAssumeAttr(const CXXAssumeAttr *AA);
@@ -2189,27 +2186,6 @@ TemplateName TemplateInstantiator::TransformTemplateName(
AllowInjectedClassName);
}
-TemplateArgument TemplateInstantiator::TransformNamedTemplateTemplateArgument(
- CXXScopeSpec &SS, TemplateName Name, SourceLocation NameLoc) {
- if (TemplateTemplateParmDecl *TTP =
- dyn_cast_or_null<TemplateTemplateParmDecl>(
- Name.getAsTemplateDecl())) {
- if (TTP->getDepth() < TemplateArgs.getNumLevels()) {
- // If the corresponding template argument is NULL or non-existent, it's
- // because we are performing instantiation from explicitly-specified
- // template arguments in a function template, but there were some
- // arguments left unspecified.
- if (!TemplateArgs.hasTemplateArgument(TTP->getDepth(),
- TTP->getPosition()))
- return TemplateArgument(Name);
- }
- }
- TemplateName TN = getDerived().TransformTemplateName(SS, Name, NameLoc);
- if (!TN.isNull())
- return TN;
- return TemplateArgument();
-}
-
ExprResult
TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) {
if (!E->isTypeDependent())
More information about the lldb-commits
mailing list