Skip to content

Commit de528d6

Browse files
authored
[Clang] Handle default template arguments for alias CTAD guides (#134807)
It's possible that some deduced template arguments come from default arguments, not just from the return type. So we need to recursively visit the default arguments of the parameter if it's referenced, thereby the template parameter referenced by the defualt arguments could come along to the synthesized deduction guide. Fixes #134471
1 parent 9bd0c87 commit de528d6

File tree

3 files changed

+137
-1
lines changed

3 files changed

+137
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ Bug Fixes to C++ Support
471471
- Clang no longer crashes when trying to unify the types of arrays with
472472
certain differences in qualifiers (this could happen during template argument
473473
deduction or when building a ternary operator). (#GH97005)
474+
- Fixed type alias CTAD issues involving default template arguments. (#GH134471)
474475
- The initialization kind of elements of structured bindings
475476
direct-list-initialized from an array is corrected to direct-initialization.
476477
- Clang no longer crashes when a coroutine is declared ``[[noreturn]]``. (#GH127327)

clang/lib/Sema/SemaTemplateDeductionGuide.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,26 @@ SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
690690
SemaRef.MarkUsedTemplateParameters(
691691
DeducedArgs, TemplateParamsList->getDepth(), ReferencedTemplateParams);
692692

693+
auto MarkDefaultArgs = [&](auto *Param) {
694+
if (!Param->hasDefaultArgument())
695+
return;
696+
SemaRef.MarkUsedTemplateParameters(
697+
Param->getDefaultArgument().getArgument(),
698+
TemplateParamsList->getDepth(), ReferencedTemplateParams);
699+
};
700+
701+
for (unsigned Index = 0; Index < TemplateParamsList->size(); ++Index) {
702+
if (!ReferencedTemplateParams[Index])
703+
continue;
704+
auto *Param = TemplateParamsList->getParam(Index);
705+
if (auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Param))
706+
MarkDefaultArgs(TTPD);
707+
else if (auto *NTTPD = dyn_cast<NonTypeTemplateParmDecl>(Param))
708+
MarkDefaultArgs(NTTPD);
709+
else
710+
MarkDefaultArgs(cast<TemplateTemplateParmDecl>(Param));
711+
}
712+
693713
SmallVector<unsigned> Results;
694714
for (unsigned Index = 0; Index < TemplateParamsList->size(); ++Index) {
695715
if (ReferencedTemplateParams[Index])

clang/test/SemaTemplate/deduction-guide.cpp

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -std=c++2a -verify -ast-dump -ast-dump-decl-types -ast-dump-filter "deduction guide" %s | FileCheck %s --strict-whitespace
1+
// 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
22

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

773773
} // namespace GH132616_DeductionGuide
774+
775+
namespace GH133132 {
776+
777+
template <class _Ty>
778+
struct A {};
779+
780+
template <class T = int, class U = T>
781+
using AA = A<U>;
782+
783+
AA a{};
784+
785+
// CHECK-LABEL: Dumping GH133132::<deduction guide for AA>:
786+
// CHECK-NEXT: FunctionTemplateDecl {{.+}} implicit <deduction guide for AA>
787+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} class depth 0 index 0 T
788+
// CHECK-NEXT: | `-TemplateArgument type 'int'
789+
// CHECK-NEXT: | `-BuiltinType {{.+}} 'int'
790+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} class depth 0 index 1 U
791+
// CHECK-NEXT: | `-TemplateArgument type 'T':'type-parameter-0-0'
792+
// CHECK-NEXT: | `-TemplateTypeParmType {{.+}} 'T' dependent depth 0 index 0
793+
// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'T'
794+
// CHECK-NEXT: |-TypeTraitExpr {{.+}} 'bool' __is_deducible
795+
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.+}} 'GH133132::AA' dependent
796+
// CHECK-NEXT: | | `-name: 'GH133132::AA'
797+
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.+}} AA
798+
// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'A<U>' dependent
799+
// CHECK-NEXT: | |-name: 'A':'GH133132::A' qualified
800+
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} A
801+
// CHECK-NEXT: | `-TemplateArgument type 'U':'type-parameter-0-1'
802+
// CHECK-NEXT: | `-SubstTemplateTypeParmType {{.+}} 'U' sugar dependent class depth 0 index 0 _Ty
803+
// CHECK-NEXT: | |-FunctionTemplate {{.+}} '<deduction guide for A>'
804+
// CHECK-NEXT: | `-TemplateTypeParmType {{.+}} 'U' dependent depth 0 index 1
805+
// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'U'
806+
// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for AA> 'auto () -> A<U>'
807+
// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for AA> 'auto () -> A<int>' implicit_instantiation
808+
// CHECK-NEXT: |-TemplateArgument type 'int'
809+
// CHECK-NEXT: | `-BuiltinType {{.+}} 'int'
810+
// CHECK-NEXT: `-TemplateArgument type 'int'
811+
// CHECK-NEXT: `-BuiltinType {{.+}} 'int'
812+
813+
template <template <class> class _X>
814+
struct B {};
815+
816+
template <template <class> class _X = A, template <class> class _Y = _X>
817+
using BB = B<_Y>;
818+
819+
BB b{};
820+
821+
// CHECK-LABEL: Dumping GH133132::<deduction guide for BB>:
822+
// CHECK-NEXT: FunctionTemplateDecl {{.+}} implicit <deduction guide for BB>
823+
// CHECK-NEXT: |-TemplateTemplateParmDecl {{.+}} depth 0 index 0 _X
824+
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.+}} class depth 0 index 0
825+
// CHECK-NEXT: | `-TemplateArgument {{.+}} template 'A':'GH133132::A' qualified
826+
// CHECK-NEXT: | `-ClassTemplateDecl {{.+}} A
827+
// CHECK-NEXT: |-TemplateTemplateParmDecl {{.+}} depth 0 index 1 _Y
828+
// CHECK-NEXT: | |-TemplateTypeParmDecl {{.+}} class depth 0 index 0
829+
// CHECK-NEXT: | `-TemplateArgument {{.+}} template '_X':'template-parameter-0-0' qualified
830+
// CHECK-NEXT: | `-TemplateTemplateParmDecl {{.+}} depth 0 index 0 _X
831+
// CHECK-NEXT: |-TypeTraitExpr {{.+}} 'bool' __is_deducible
832+
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.+}} 'GH133132::BB' dependent
833+
// CHECK-NEXT: | | `-name: 'GH133132::BB'
834+
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.+}} BB
835+
// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'B<_Y>' dependent
836+
// CHECK-NEXT: | |-name: 'B':'GH133132::B' qualified
837+
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} B
838+
// CHECK-NEXT: | `-TemplateArgument template '_Y':'template-parameter-0-1' subst index 0
839+
// CHECK-NEXT: | |-parameter: TemplateTemplateParmDecl {{.+}} depth 0 index 0 _X
840+
// CHECK-NEXT: | |-associated FunctionTemplate {{.+}} '<deduction guide for B>'
841+
// CHECK-NEXT: | `-replacement: '_Y':'template-parameter-0-1' qualified
842+
// CHECK-NEXT: | `-TemplateTemplateParmDecl {{.+}} depth 0 index 1 _Y
843+
// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for BB> 'auto () -> B<_Y>'
844+
// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for BB> 'auto () -> B<GH133132::A>' implicit_instantiation
845+
// CHECK-NEXT: |-TemplateArgument template 'GH133132::A'
846+
// CHECK-NEXT: | `-ClassTemplateDecl {{.+}} A
847+
// CHECK-NEXT: `-TemplateArgument template 'GH133132::A'
848+
// CHECK-NEXT: `-ClassTemplateDecl {{.+}} A
849+
850+
template <int N = 42, class U = A<decltype(N)>>
851+
using CC = A<U>;
852+
853+
CC c{};
854+
855+
// CHECK-LABEL: Dumping GH133132::<deduction guide for CC>:
856+
// CHECK-NEXT: FunctionTemplateDecl {{.+}} implicit <deduction guide for CC>
857+
// CHECK-NEXT: |-NonTypeTemplateParmDecl {{.+}} 'int' depth 0 index 0 N
858+
// CHECK-NEXT: | `-TemplateArgument {{.+}} expr '42'
859+
// CHECK-NEXT: | `-IntegerLiteral {{.+}} 'int' 42
860+
// CHECK-NEXT: |-TemplateTypeParmDecl {{.+}} class depth 0 index 1 U
861+
// CHECK-NEXT: | `-TemplateArgument type 'A<decltype(N)>'
862+
// CHECK-NEXT: | `-ElaboratedType {{.+}} 'A<decltype(N)>' sugar dependent
863+
// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'A<decltype(N)>' dependent
864+
// CHECK-NEXT: | |-name: 'A':'GH133132::A' qualified
865+
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} A
866+
// CHECK-NEXT: | `-TemplateArgument type 'decltype(N)'
867+
// CHECK-NEXT: | `-DecltypeType {{.+}} 'decltype(N)' dependent
868+
// CHECK-NEXT: | `-DeclRefExpr {{.+}} 'int' NonTypeTemplateParm {{.+}} 'N' 'int'
869+
// CHECK-NEXT: |-TypeTraitExpr {{.+}} 'bool' __is_deducible
870+
// CHECK-NEXT: | |-DeducedTemplateSpecializationType {{.+}} 'GH133132::CC' dependent
871+
// CHECK-NEXT: | | `-name: 'GH133132::CC'
872+
// CHECK-NEXT: | | `-TypeAliasTemplateDecl {{.+}} CC
873+
// CHECK-NEXT: | `-TemplateSpecializationType {{.+}} 'A<U>' dependent
874+
// CHECK-NEXT: | |-name: 'A':'GH133132::A' qualified
875+
// CHECK-NEXT: | | `-ClassTemplateDecl {{.+}} A
876+
// CHECK-NEXT: | `-TemplateArgument type 'U':'type-parameter-0-1'
877+
// CHECK-NEXT: | `-SubstTemplateTypeParmType {{.+}} 'U' sugar dependent class depth 0 index 0 _Ty
878+
// CHECK-NEXT: | |-FunctionTemplate {{.+}} '<deduction guide for A>'
879+
// CHECK-NEXT: | `-TemplateTypeParmType {{.+}} 'U' dependent depth 0 index 1
880+
// CHECK-NEXT: | `-TemplateTypeParm {{.+}} 'U'
881+
// CHECK-NEXT: |-CXXDeductionGuideDecl {{.+}} implicit <deduction guide for CC> 'auto () -> A<U>'
882+
// CHECK-NEXT: `-CXXDeductionGuideDecl {{.+}} implicit used <deduction guide for CC> 'auto () -> A<GH133132::A<int>>' implicit_instantiation
883+
// CHECK-NEXT: |-TemplateArgument integral '42'
884+
// CHECK-NEXT: `-TemplateArgument type 'GH133132::A<int>'
885+
// CHECK-NEXT: `-RecordType {{.+}} 'GH133132::A<int>'
886+
// CHECK-NEXT: `-ClassTemplateSpecialization {{.+}} 'A'
887+
888+
}

0 commit comments

Comments
 (0)