Skip to content

Commit 7415524

Browse files
authored
[clang] Implement CTAD for type alias template. (#77890)
Fixes #54051 This patch implements the C++20 feature -- CTAD for alias templates (P1814R0, specified in https://eel.is/c++draft/over.match.class.deduct#3). It is an initial patch: - it cover major pieces, thus it works for most cases; - the big missing piece is to implement the associated constraints (over.match.class.deduct#3.3) for the synthesized deduction guides, see the FIXME in code and tests; - Some enhancements on the TreeTransform&TemplateInstantiator to allow performing instantiation on `BuildingDeductionGuides` mode;
1 parent 141ebdd commit 7415524

13 files changed

+827
-111
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,10 @@ C++20 Feature Support
9191
current module units.
9292
Fixes `#84002 <https://github.com/llvm/llvm-project/issues/84002>`_.
9393

94+
- Initial support for class template argument deduction (CTAD) for type alias
95+
templates (`P1814R0 <https://wg21.link/p1814r0>`_).
96+
(#GH54051).
97+
9498
C++23 Feature Support
9599
^^^^^^^^^^^^^^^^^^^^^
96100

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2515,10 +2515,11 @@ def err_deduced_class_template_compound_type : Error<
25152515
"cannot %select{form pointer to|form reference to|form array of|"
25162516
"form function returning|use parentheses when declaring variable with}0 "
25172517
"deduced class template specialization type">;
2518-
def err_deduced_non_class_template_specialization_type : Error<
2518+
def err_deduced_non_class_or_alias_template_specialization_type : Error<
25192519
"%select{<error>|function template|variable template|alias template|"
25202520
"template template parameter|concept|template}0 %1 requires template "
2521-
"arguments; argument deduction only allowed for class templates">;
2521+
"arguments; argument deduction only allowed for class templates or alias "
2522+
"templates">;
25222523
def err_deduced_class_template_ctor_ambiguous : Error<
25232524
"ambiguous deduction for template arguments of %0">;
25242525
def err_deduced_class_template_ctor_no_viable : Error<
@@ -8201,6 +8202,11 @@ let CategoryName = "Lambda Issue" in {
82018202
def warn_cxx17_compat_lambda_def_ctor_assign : Warning<
82028203
"%select{default construction|assignment}0 of lambda is incompatible with "
82038204
"C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
8205+
8206+
// C++20 class template argument deduction for alias templates.
8207+
def warn_cxx17_compat_ctad_for_alias_templates : Warning<
8208+
"class template argument deduction for alias templates is incompatible with "
8209+
"C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
82048210
}
82058211

82068212
def err_return_in_captured_stmt : Error<

clang/include/clang/Sema/Sema.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9827,6 +9827,12 @@ class Sema final {
98279827
ArrayRef<TemplateArgument> TemplateArgs,
98289828
sema::TemplateDeductionInfo &Info);
98299829

9830+
TemplateDeductionResult DeduceTemplateArguments(
9831+
TemplateParameterList *TemplateParams, ArrayRef<TemplateArgument> Ps,
9832+
ArrayRef<TemplateArgument> As, sema::TemplateDeductionInfo &Info,
9833+
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
9834+
bool NumberOfArgumentsMustMatch);
9835+
98309836
TemplateDeductionResult SubstituteExplicitTemplateArguments(
98319837
FunctionTemplateDecl *FunctionTemplate,
98329838
TemplateArgumentListInfo &ExplicitTemplateArgs,
@@ -10378,6 +10384,9 @@ class Sema final {
1037810384
InstantiatingTemplate &operator=(const InstantiatingTemplate &) = delete;
1037910385
};
1038010386

10387+
bool SubstTemplateArgument(const TemplateArgumentLoc &Input,
10388+
const MultiLevelTemplateArgumentList &TemplateArgs,
10389+
TemplateArgumentLoc &Output);
1038110390
bool
1038210391
SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
1038310392
const MultiLevelTemplateArgumentList &TemplateArgs,
@@ -10862,9 +10871,11 @@ class Sema final {
1086210871
ParmVarDecl *Param);
1086310872
void InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
1086410873
FunctionDecl *Function);
10865-
FunctionDecl *InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD,
10866-
const TemplateArgumentList *Args,
10867-
SourceLocation Loc);
10874+
FunctionDecl *InstantiateFunctionDeclaration(
10875+
FunctionTemplateDecl *FTD, const TemplateArgumentList *Args,
10876+
SourceLocation Loc,
10877+
CodeSynthesisContext::SynthesisKind CSC =
10878+
CodeSynthesisContext::ExplicitTemplateArgumentSubstitution);
1086810879
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
1086910880
FunctionDecl *Function,
1087010881
bool Recursive = false,

clang/lib/Sema/SemaInit.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10720,13 +10720,40 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
1072010720
if (TemplateName.isDependent())
1072110721
return SubstAutoTypeDependent(TSInfo->getType());
1072210722

10723-
// We can only perform deduction for class templates.
10723+
// We can only perform deduction for class templates or alias templates.
1072410724
auto *Template =
1072510725
dyn_cast_or_null<ClassTemplateDecl>(TemplateName.getAsTemplateDecl());
10726+
TemplateDecl *LookupTemplateDecl = Template;
10727+
if (!Template) {
10728+
if (auto *AliasTemplate = dyn_cast_or_null<TypeAliasTemplateDecl>(
10729+
TemplateName.getAsTemplateDecl())) {
10730+
Diag(Kind.getLocation(),
10731+
diag::warn_cxx17_compat_ctad_for_alias_templates);
10732+
LookupTemplateDecl = AliasTemplate;
10733+
auto UnderlyingType = AliasTemplate->getTemplatedDecl()
10734+
->getUnderlyingType()
10735+
.getCanonicalType();
10736+
// C++ [over.match.class.deduct#3]: ..., the defining-type-id of A must be
10737+
// of the form
10738+
// [typename] [nested-name-specifier] [template] simple-template-id
10739+
if (const auto *TST =
10740+
UnderlyingType->getAs<TemplateSpecializationType>()) {
10741+
Template = dyn_cast_or_null<ClassTemplateDecl>(
10742+
TST->getTemplateName().getAsTemplateDecl());
10743+
} else if (const auto *RT = UnderlyingType->getAs<RecordType>()) {
10744+
// Cases where template arguments in the RHS of the alias are not
10745+
// dependent. e.g.
10746+
// using AliasFoo = Foo<bool>;
10747+
if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(
10748+
RT->getAsCXXRecordDecl()))
10749+
Template = CTSD->getSpecializedTemplate();
10750+
}
10751+
}
10752+
}
1072610753
if (!Template) {
1072710754
Diag(Kind.getLocation(),
10728-
diag::err_deduced_non_class_template_specialization_type)
10729-
<< (int)getTemplateNameKindForDiagnostics(TemplateName) << TemplateName;
10755+
diag::err_deduced_non_class_or_alias_template_specialization_type)
10756+
<< (int)getTemplateNameKindForDiagnostics(TemplateName) << TemplateName;
1073010757
if (auto *TD = TemplateName.getAsTemplateDecl())
1073110758
NoteTemplateLocation(*TD);
1073210759
return QualType();
@@ -10753,10 +10780,10 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
1075310780
// template-name, a function template [...]
1075410781
// - For each deduction-guide, a function or function template [...]
1075510782
DeclarationNameInfo NameInfo(
10756-
Context.DeclarationNames.getCXXDeductionGuideName(Template),
10783+
Context.DeclarationNames.getCXXDeductionGuideName(LookupTemplateDecl),
1075710784
TSInfo->getTypeLoc().getEndLoc());
1075810785
LookupResult Guides(*this, NameInfo, LookupOrdinaryName);
10759-
LookupQualifiedName(Guides, Template->getDeclContext());
10786+
LookupQualifiedName(Guides, LookupTemplateDecl->getDeclContext());
1076010787

1076110788
// FIXME: Do not diagnose inaccessible deduction guides. The standard isn't
1076210789
// clear on this, but they're not found by name so access does not apply.

0 commit comments

Comments
 (0)