Skip to content

Commit 040e7ad

Browse files
authored
[Clang] Consider default template arguments when synthesizing CTAD guides (#147675)
We copy arguments from different template parameter lists depending on the deducibility of the template parameters. In particular, we may lose the default template argument from the original alias declaration, and this patch helps preserve that. Fixes #133132
1 parent 8983b22 commit 040e7ad

File tree

3 files changed

+76
-10
lines changed

3 files changed

+76
-10
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,7 @@ Bug Fixes to C++ Support
875875
- Clang no longer crashes when trying to unify the types of arrays with
876876
certain differences in qualifiers (this could happen during template argument
877877
deduction or when building a ternary operator). (#GH97005)
878-
- Fixed type alias CTAD issues involving default template arguments. (#GH134471)
878+
- Fixed type alias CTAD issues involving default template arguments. (#GH133132), (#GH134471)
879879
- Fixed CTAD issues when initializing anonymous fields with designated initializers. (#GH67173)
880880
- The initialization kind of elements of structured bindings
881881
direct-list-initialized from an array is corrected to direct-initialization.

clang/lib/Sema/SemaTemplateDeductionGuide.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,7 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef,
949949
ReturnType = SemaRef.SubstType(
950950
ReturnType, Args, AliasTemplate->getLocation(),
951951
Context.DeclarationNames.getCXXDeductionGuideName(AliasTemplate));
952-
};
952+
}
953953

954954
SmallVector<TypeSourceInfo *> IsDeducibleTypeTraitArgs = {
955955
Context.getTrivialTypeSourceInfo(
@@ -981,7 +981,8 @@ getRHSTemplateDeclAndArgs(Sema &SemaRef, TypeAliasTemplateDecl *AliasTemplate) {
981981
// template<typename T>
982982
// using AliasFoo1 = Foo<T>; // a class/type alias template specialization
983983
Template = TST->getTemplateName().getAsTemplateDecl();
984-
AliasRhsTemplateArgs = TST->template_arguments();
984+
AliasRhsTemplateArgs =
985+
TST->getAsNonAliasTemplateSpecializationType()->template_arguments();
985986
} else if (const auto *RT = RhsType->getAs<RecordType>()) {
986987
// Cases where template arguments in the RHS of the alias are not
987988
// dependent. e.g.
@@ -1025,6 +1026,24 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
10251026
auto [Template, AliasRhsTemplateArgs] =
10261027
getRHSTemplateDeclAndArgs(SemaRef, AliasTemplate);
10271028

1029+
// We need both types desugared, before we continue to perform type deduction.
1030+
// The intent is to get the template argument list 'matched', e.g. in the
1031+
// following case:
1032+
//
1033+
//
1034+
// template <class T>
1035+
// struct A {};
1036+
// template <class T>
1037+
// using Foo = A<A<T>>;
1038+
// template <class U = int>
1039+
// using Bar = Foo<U>;
1040+
//
1041+
// In terms of Bar, we want U (which has the default argument) to appear in
1042+
// the synthesized deduction guide, but U would remain undeduced if we deduced
1043+
// A<A<T>> using Foo<U> directly.
1044+
//
1045+
// Instead, we need to canonicalize both against A, i.e. A<A<T>> and A<A<U>>,
1046+
// such that T can be deduced as U.
10281047
auto RType = F->getTemplatedDecl()->getReturnType();
10291048
// The (trailing) return type of the deduction guide.
10301049
const TemplateSpecializationType *FReturnType =
@@ -1034,7 +1053,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
10341053
FReturnType = InjectedCNT->getInjectedTST();
10351054
else if (const auto *ET = RType->getAs<ElaboratedType>())
10361055
// explicit deduction guide.
1037-
FReturnType = ET->getNamedType()->getAs<TemplateSpecializationType>();
1056+
FReturnType = ET->getNamedType()->getAsNonAliasTemplateSpecializationType();
10381057
assert(FReturnType && "expected to see a return type");
10391058
// Deduce template arguments of the deduction guide f from the RHS of
10401059
// the alias.

clang/test/SemaCXX/cxx20-ctad-type-alias.cpp

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,13 +207,14 @@ namespace test15 {
207207
template <class T> struct Foo { Foo(T); };
208208

209209
template<class V> using AFoo = Foo<V *>;
210-
template<typename> concept False = false;
210+
template<typename> concept False = false; // #test15_False
211211
template<False W>
212-
using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with V = int]}} \
213-
// expected-note {{cannot deduce template arguments for 'BFoo' from 'Foo<int *>'}} \
214-
// expected-note {{implicit deduction guide declared as 'template <class V> requires __is_deducible(AFoo, Foo<V *>) && __is_deducible(test15::BFoo, Foo<V *>) BFoo(V *) -> Foo<V *>}} \
215-
// expected-note {{candidate template ignored: could not match 'Foo<V *>' against 'int *'}} \
216-
// expected-note {{template <class V> requires __is_deducible(AFoo, Foo<V *>) && __is_deducible(test15::BFoo, Foo<V *>) BFoo(Foo<V *>) -> Foo<V *>}}
212+
using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with W = int]}} \
213+
// expected-note@-1 {{because 'int' does not satisfy 'False'}} \
214+
// expected-note@#test15_False {{because 'false' evaluated to false}} \
215+
// expected-note {{implicit deduction guide declared as 'template <False<> W> requires __is_deducible(AFoo, Foo<W *>) && __is_deducible(test15::BFoo, Foo<W *>) BFoo(W *) -> Foo<W *>}} \
216+
// expected-note {{candidate template ignored: could not match 'Foo<W *>' against 'int *'}} \
217+
// expected-note {{template <False<> W> requires __is_deducible(AFoo, Foo<W *>) && __is_deducible(test15::BFoo, Foo<W *>) BFoo(Foo<W *>) -> Foo<W *>}}
217218
int i = 0;
218219
AFoo a1(&i); // OK, deduce Foo<int *>
219220

@@ -441,6 +442,32 @@ ACase4 case4{0, 1};
441442

442443
} // namespace test24
443444

445+
namespace test25 {
446+
447+
template<typename T, typename...Us>
448+
struct A{
449+
template<typename V> requires __is_same(V, int)
450+
A(V);
451+
};
452+
453+
template<typename...TS>
454+
using AA = A<int, TS...>;
455+
456+
template<typename...US>
457+
using BB = AA<US...>; // #test25_BB
458+
459+
BB a{0};
460+
static_assert(__is_same(decltype(a), A<int>));
461+
// FIXME: The template parameter list of generated deduction guide is not strictly conforming,
462+
// as the pack occurs prior to the non-packs.
463+
BB b{0, 1};
464+
// expected-error@-1 {{no viable}}
465+
// expected-note@#test25_BB 2{{not viable}}
466+
// expected-note@#test25_BB {{template <typename ...US, typename V> requires __is_same(V, int) && __is_deducible(AA, A<int, US...>) && __is_deducible(test25::BB, A<int, US...>) BB(V) -> A<int, US...>}}
467+
// expected-note@#test25_BB {{implicit deduction guide}}
468+
469+
}
470+
444471
namespace GH92212 {
445472
template<typename T, typename...Us>
446473
struct A{
@@ -526,6 +553,7 @@ void foo() { test<{1, 2, 3}>(); }
526553

527554
} // namespace GH113518
528555

556+
// FIXME: This is accepted by GCC: https://gcc.godbolt.org/z/f3rMfbacz
529557
namespace GH125821 {
530558
template<typename T>
531559
struct A { A(T){} };
@@ -539,3 +567,22 @@ using C = Proxy< A<T> >;
539567
C test{ 42 }; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
540568

541569
} // namespace GH125821
570+
571+
namespace GH133132 {
572+
573+
template <class T>
574+
struct A {};
575+
576+
template <class T>
577+
using Foo = A<A<T>>;
578+
579+
template <class T>
580+
using Bar = Foo<T>;
581+
582+
template <class T = int>
583+
using Baz = Bar<T>;
584+
585+
Baz a{};
586+
static_assert(__is_same(decltype(a), A<A<int>>));
587+
588+
} // namespace GH133132

0 commit comments

Comments
 (0)