Skip to content

[Clang] Handle default template arguments for alias CTAD guides #134807

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 4 commits into from
Apr 17, 2025
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
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ Bug Fixes to C++ Support
- Clang no longer crashes when trying to unify the types of arrays with
certain differences in qualifiers (this could happen during template argument
deduction or when building a ternary operator). (#GH97005)
- Fixed type alias CTAD issues involving default template arguments. (#GH134471)
- The initialization kind of elements of structured bindings
direct-list-initialized from an array is corrected to direct-initialization.
- Clang no longer crashes when a coroutine is declared ``[[noreturn]]``. (#GH127327)
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/Sema/SemaTemplateDeductionGuide.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,26 @@ SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
SemaRef.MarkUsedTemplateParameters(
DeducedArgs, TemplateParamsList->getDepth(), ReferencedTemplateParams);

auto MarkDefaultArgs = [&](auto *Param) {
if (!Param->hasDefaultArgument())
return;
SemaRef.MarkUsedTemplateParameters(
Param->getDefaultArgument().getArgument(),
TemplateParamsList->getDepth(), ReferencedTemplateParams);
};

for (unsigned Index = 0; Index < TemplateParamsList->size(); ++Index) {
if (!ReferencedTemplateParams[Index])
continue;
auto *Param = TemplateParamsList->getParam(Index);
if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Param))
MarkDefaultArgs(TTPD);
else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(Param))
MarkDefaultArgs(NTTPD);
else
MarkDefaultArgs(cast<TemplateTemplateParmDecl>(Param));
}

SmallVector<unsigned> Results;
for (unsigned Index = 0; Index < TemplateParamsList->size(); ++Index) {
if (ReferencedTemplateParams[Index])
Expand Down
117 changes: 116 additions & 1 deletion clang/test/SemaTemplate/deduction-guide.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -std=c++2a -verify -ast-dump -ast-dump-decl-types -ast-dump-filter "deduction guide" %s | FileCheck %s --strict-whitespace
// RUN: %clang_cc1 -std=c++2a -verify -ast-dump -ast-dump-decl-types -ast-dump-filter "deduction guide" %s | FileCheck %s --strict-whitespace -dump-input=always

template<auto ...> struct X {};
template<template<typename X, X> typename> struct Y {};
Expand Down Expand Up @@ -771,3 +771,118 @@ D d(24);
// CHECK-NEXT: `-ParmVarDecl {{.+}} 'U'

} // namespace GH132616_DeductionGuide

namespace GH133132 {

template <class _Ty>
struct A {};

template <class T = int, class U = T>
using AA = A<U>;

AA a{};

// CHECK-LABEL: Dumping GH133132::<deduction guide for AA>:
// CHECK-NEXT: FunctionTemplateDecl {{.+}} implicit <deduction guide for AA>
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} class depth 0 index 0 T
// CHECK-NEXT: | `-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType {{.+}} 'int'
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} class depth 0 index 1 U
// CHECK-NEXT: | `-TemplateArgument type 'T':'type-parameter-0-0'
// CHECK-NEXT: | `-TemplateTypeParmType {{.+}} 'T' dependent depth 0 index 0
// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'T'
// CHECK-NEXT: |-TypeTraitExpr {{.+}} 'bool' __is_deducible
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.+}} 'GH133132::AA' dependent
// CHECK-NEXT: | | `-name: 'GH133132::AA'
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.+}} AA
// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'A<U>' dependent
// CHECK-NEXT: | |-name: 'A':'GH133132::A' qualified
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} A
// CHECK-NEXT: | `-TemplateArgument type 'U':'type-parameter-0-1'
// CHECK-NEXT: | `-SubstTemplateTypeParmType {{.+}} 'U' sugar dependent class depth 0 index 0 _Ty
// CHECK-NEXT: | |-FunctionTemplate {{.+}} '<deduction guide for A>'
// CHECK-NEXT: | `-TemplateTypeParmType {{.+}} 'U' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'U'
// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for AA> 'auto () -> A<U>'
// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for AA> 'auto () -> A<int>' implicit_instantiation
// CHECK-NEXT: |-TemplateArgument type 'int'
// CHECK-NEXT: | `-BuiltinType {{.+}} 'int'
// CHECK-NEXT: `-TemplateArgument type 'int'
// CHECK-NEXT: `-BuiltinType {{.+}} 'int'

template <template <class> class _X>
struct B {};

template <template <class> class _X = A, template <class> class _Y = _X>
using BB = B<_Y>;

BB b{};

// CHECK-LABEL: Dumping GH133132::<deduction guide for BB>:
// CHECK-NEXT: FunctionTemplateDecl {{.+}} implicit <deduction guide for BB>
// CHECK-NEXT: |-TemplateTemplateParmDecl {{.+}} depth 0 index 0 _X
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.+}} class depth 0 index 0
// CHECK-NEXT: | `-TemplateArgument {{.+}} template 'A':'GH133132::A' qualified
// CHECK-NEXT: | `-ClassTemplateDecl {{.+}} A
// CHECK-NEXT: |-TemplateTemplateParmDecl {{.+}} depth 0 index 1 _Y
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.+}} class depth 0 index 0
// CHECK-NEXT: | `-TemplateArgument {{.+}} template '_X':'template-parameter-0-0' qualified
// CHECK-NEXT: | `-TemplateTemplateParmDecl {{.+}} depth 0 index 0 _X
// CHECK-NEXT: |-TypeTraitExpr {{.+}} 'bool' __is_deducible
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.+}} 'GH133132::BB' dependent
// CHECK-NEXT: | | `-name: 'GH133132::BB'
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.+}} BB
// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'B<_Y>' dependent
// CHECK-NEXT: | |-name: 'B':'GH133132::B' qualified
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} B
// CHECK-NEXT: | `-TemplateArgument template '_Y':'template-parameter-0-1' subst index 0
// CHECK-NEXT: | |-parameter: TemplateTemplateParmDecl {{.+}} depth 0 index 0 _X
// CHECK-NEXT: | |-associated FunctionTemplate {{.+}} '<deduction guide for B>'
// CHECK-NEXT: | `-replacement: '_Y':'template-parameter-0-1' qualified
// CHECK-NEXT: | `-TemplateTemplateParmDecl {{.+}} depth 0 index 1 _Y
// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for BB> 'auto () -> B<_Y>'
// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for BB> 'auto () -> B<GH133132::A>' implicit_instantiation
// CHECK-NEXT: |-TemplateArgument template 'GH133132::A'
// CHECK-NEXT: | `-ClassTemplateDecl {{.+}} A
// CHECK-NEXT: `-TemplateArgument template 'GH133132::A'
// CHECK-NEXT: `-ClassTemplateDecl {{.+}} A

template <int N = 42, class U = A<decltype(N)>>
using CC = A<U>;

CC c{};

// CHECK-LABEL: Dumping GH133132::<deduction guide for CC>:
// CHECK-NEXT: FunctionTemplateDecl {{.+}} implicit <deduction guide for CC>
// CHECK-NEXT: |-NonTypeTemplateParmDecl {{.+}} 'int' depth 0 index 0 N
// CHECK-NEXT: | `-TemplateArgument {{.+}} expr '42'
// CHECK-NEXT: | `-IntegerLiteral {{.+}} 'int' 42
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} class depth 0 index 1 U
// CHECK-NEXT: | `-TemplateArgument type 'A<decltype(N)>'
// CHECK-NEXT: | `-ElaboratedType {{.+}} 'A<decltype(N)>' sugar dependent
// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'A<decltype(N)>' dependent
// CHECK-NEXT: | |-name: 'A':'GH133132::A' qualified
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} A
// CHECK-NEXT: | `-TemplateArgument type 'decltype(N)'
// CHECK-NEXT: | `-DecltypeType {{.+}} 'decltype(N)' dependent
// CHECK-NEXT: | `-DeclRefExpr {{.+}} 'int' NonTypeTemplateParm {{.+}} 'N' 'int'
// CHECK-NEXT: |-TypeTraitExpr {{.+}} 'bool' __is_deducible
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.+}} 'GH133132::CC' dependent
// CHECK-NEXT: | | `-name: 'GH133132::CC'
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.+}} CC
// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'A<U>' dependent
// CHECK-NEXT: | |-name: 'A':'GH133132::A' qualified
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} A
// CHECK-NEXT: | `-TemplateArgument type 'U':'type-parameter-0-1'
// CHECK-NEXT: | `-SubstTemplateTypeParmType {{.+}} 'U' sugar dependent class depth 0 index 0 _Ty
// CHECK-NEXT: | |-FunctionTemplate {{.+}} '<deduction guide for A>'
// CHECK-NEXT: | `-TemplateTypeParmType {{.+}} 'U' dependent depth 0 index 1
// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'U'
// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for CC> 'auto () -> A<U>'
// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for CC> 'auto () -> A<GH133132::A<int>>' implicit_instantiation
// CHECK-NEXT: |-TemplateArgument integral '42'
// CHECK-NEXT: `-TemplateArgument type 'GH133132::A<int>'
// CHECK-NEXT: `-RecordType {{.+}} 'GH133132::A<int>'
// CHECK-NEXT: `-ClassTemplateSpecialization {{.+}} 'A'

}
Loading