Skip to content

[clang] Implement CTAD for type alias template. #77890

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,10 @@ C++20 Feature Support
current module units.
Fixes `#84002 <https://github.com/llvm/llvm-project/issues/84002>`_.

- Initial support for class template argument deduction (CTAD) for type alias
templates (`P1814R0 <https://wg21.link/p1814r0>`_).
(#GH54051).

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^

Expand Down
10 changes: 8 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2515,10 +2515,11 @@ def err_deduced_class_template_compound_type : Error<
"cannot %select{form pointer to|form reference to|form array of|"
"form function returning|use parentheses when declaring variable with}0 "
"deduced class template specialization type">;
def err_deduced_non_class_template_specialization_type : Error<
def err_deduced_non_class_or_alias_template_specialization_type : Error<
"%select{<error>|function template|variable template|alias template|"
"template template parameter|concept|template}0 %1 requires template "
"arguments; argument deduction only allowed for class templates">;
"arguments; argument deduction only allowed for class templates or alias "
"templates">;
def err_deduced_class_template_ctor_ambiguous : Error<
"ambiguous deduction for template arguments of %0">;
def err_deduced_class_template_ctor_no_viable : Error<
Expand Down Expand Up @@ -8199,6 +8200,11 @@ let CategoryName = "Lambda Issue" in {
def warn_cxx17_compat_lambda_def_ctor_assign : Warning<
"%select{default construction|assignment}0 of lambda is incompatible with "
"C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;

// C++20 class template argument deduction for alias templates.
def warn_cxx17_compat_ctad_for_alias_templates : Warning<
"class template argument deduction for alias templates is incompatible with "
"C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
}

def err_return_in_captured_stmt : Error<
Expand Down
17 changes: 14 additions & 3 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -9826,6 +9826,12 @@ class Sema final {
ArrayRef<TemplateArgument> TemplateArgs,
sema::TemplateDeductionInfo &Info);

TemplateDeductionResult DeduceTemplateArguments(
TemplateParameterList *TemplateParams, ArrayRef<TemplateArgument> Ps,
ArrayRef<TemplateArgument> As, sema::TemplateDeductionInfo &Info,
SmallVectorImpl<DeducedTemplateArgument> &Deduced,
bool NumberOfArgumentsMustMatch);

TemplateDeductionResult SubstituteExplicitTemplateArguments(
FunctionTemplateDecl *FunctionTemplate,
TemplateArgumentListInfo &ExplicitTemplateArgs,
Expand Down Expand Up @@ -10377,6 +10383,9 @@ class Sema final {
InstantiatingTemplate &operator=(const InstantiatingTemplate &) = delete;
};

bool SubstTemplateArgument(const TemplateArgumentLoc &Input,
const MultiLevelTemplateArgumentList &TemplateArgs,
TemplateArgumentLoc &Output);
bool
SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args,
const MultiLevelTemplateArgumentList &TemplateArgs,
Expand Down Expand Up @@ -10861,9 +10870,11 @@ class Sema final {
ParmVarDecl *Param);
void InstantiateExceptionSpec(SourceLocation PointOfInstantiation,
FunctionDecl *Function);
FunctionDecl *InstantiateFunctionDeclaration(FunctionTemplateDecl *FTD,
const TemplateArgumentList *Args,
SourceLocation Loc);
FunctionDecl *InstantiateFunctionDeclaration(
FunctionTemplateDecl *FTD, const TemplateArgumentList *Args,
SourceLocation Loc,
CodeSynthesisContext::SynthesisKind CSC =
CodeSynthesisContext::ExplicitTemplateArgumentSubstitution);
void InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,
bool Recursive = false,
Expand Down
37 changes: 32 additions & 5 deletions clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10720,13 +10720,40 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
if (TemplateName.isDependent())
return SubstAutoTypeDependent(TSInfo->getType());

// We can only perform deduction for class templates.
// We can only perform deduction for class templates or alias templates.
auto *Template =
dyn_cast_or_null<ClassTemplateDecl>(TemplateName.getAsTemplateDecl());
TemplateDecl *LookupTemplateDecl = Template;
if (!Template) {
if (auto *AliasTemplate = dyn_cast_or_null<TypeAliasTemplateDecl>(
TemplateName.getAsTemplateDecl())) {
Diag(Kind.getLocation(),
diag::warn_cxx17_compat_ctad_for_alias_templates);
LookupTemplateDecl = AliasTemplate;
auto UnderlyingType = AliasTemplate->getTemplatedDecl()
->getUnderlyingType()
.getCanonicalType();
// C++ [over.match.class.deduct#3]: ..., the defining-type-id of A must be
// of the form
// [typename] [nested-name-specifier] [template] simple-template-id
if (const auto *TST =
UnderlyingType->getAs<TemplateSpecializationType>()) {
Template = dyn_cast_or_null<ClassTemplateDecl>(
TST->getTemplateName().getAsTemplateDecl());
} else if (const auto *RT = UnderlyingType->getAs<RecordType>()) {
// Cases where template arguments in the RHS of the alias are not
// dependent. e.g.
// using AliasFoo = Foo<bool>;
if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(
RT->getAsCXXRecordDecl()))
Template = CTSD->getSpecializedTemplate();
}
}
}
if (!Template) {
Diag(Kind.getLocation(),
diag::err_deduced_non_class_template_specialization_type)
<< (int)getTemplateNameKindForDiagnostics(TemplateName) << TemplateName;
diag::err_deduced_non_class_or_alias_template_specialization_type)
<< (int)getTemplateNameKindForDiagnostics(TemplateName) << TemplateName;
if (auto *TD = TemplateName.getAsTemplateDecl())
NoteTemplateLocation(*TD);
return QualType();
Expand All @@ -10753,10 +10780,10 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// template-name, a function template [...]
// - For each deduction-guide, a function or function template [...]
DeclarationNameInfo NameInfo(
Context.DeclarationNames.getCXXDeductionGuideName(Template),
Context.DeclarationNames.getCXXDeductionGuideName(LookupTemplateDecl),
TSInfo->getTypeLoc().getEndLoc());
LookupResult Guides(*this, NameInfo, LookupOrdinaryName);
LookupQualifiedName(Guides, Template->getDeclContext());
LookupQualifiedName(Guides, LookupTemplateDecl->getDeclContext());

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