-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[Clang] Consider default template arguments when synthesizing CTAD guides #147675
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
base: main
Are you sure you want to change the base?
Conversation
…ides 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.
@llvm/pr-subscribers-clang Author: Younan Zhang (zyn0217) ChangesWe 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 Full diff: https://github.com/llvm/llvm-project/pull/147675.diff 3 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 96477ef6ddc9a..2562650fcc622 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -803,7 +803,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)
+- Fixed type alias CTAD issues involving default template arguments. (#GH133132), (#GH134471)
- Fixed CTAD issues when initializing anonymous fields with designated initializers. (#GH67173)
- The initialization kind of elements of structured bindings
direct-list-initialized from an array is corrected to direct-initialization.
diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
index bdc46a0115a45..9eea2cc1dad4a 100644
--- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
+++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp
@@ -1061,15 +1061,36 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
SmallVector<DeducedTemplateArgument> DeduceResults(
F->getTemplateParameters()->size());
+ // We don't have to deduce against the alias template specialization,
+ // if the source template is a synthesized alias deduction guide. This allows
+ // us to utilize the default template arguments from alias declaration.
+ //
+ // template <class T>
+ // using Foo = A<A<T>>;
+ //
+ // template <class U = int>
+ // using Bar = Foo<U>;
+ //
+ // In terms of Bar, we want U to appear in the synthesized deduction guide,
+ // but U would remain undeduced if we deduce against A<T> instead of T.
+ // Also note that since the deduced results are only used for synthesizing
+ // template parameters, they should not introduce unintended behavior in
+ // theory.
+ ArrayRef<TemplateArgument> Ps = FReturnType->template_arguments();
+ if (auto *DG = dyn_cast<CXXDeductionGuideDecl>(F->getTemplatedDecl());
+ DG && DG->getSourceDeductionGuideKind() ==
+ CXXDeductionGuideDecl::SourceDeductionGuideKind::Alias)
+ Ps = F->getInjectedTemplateArgs(Context);
+
// FIXME: DeduceTemplateArguments stops immediately at the first
// non-deducible template argument. However, this doesn't seem to cause
// issues for practice cases, we probably need to extend it to continue
// performing deduction for rest of arguments to align with the C++
// standard.
- SemaRef.DeduceTemplateArguments(
- F->getTemplateParameters(), FReturnType->template_arguments(),
- AliasRhsTemplateArgs, TDeduceInfo, DeduceResults,
- /*NumberOfArgumentsMustMatch=*/false);
+ SemaRef.DeduceTemplateArguments(F->getTemplateParameters(), Ps,
+ AliasRhsTemplateArgs, TDeduceInfo,
+ DeduceResults,
+ /*NumberOfArgumentsMustMatch=*/false);
SmallVector<TemplateArgument> DeducedArgs;
SmallVector<unsigned> NonDeducedTemplateParamsInFIndex;
diff --git a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
index aeb02c9e4898e..6d027130ce741 100644
--- a/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
+++ b/clang/test/SemaCXX/cxx20-ctad-type-alias.cpp
@@ -207,13 +207,14 @@ namespace test15 {
template <class T> struct Foo { Foo(T); };
template<class V> using AFoo = Foo<V *>;
-template<typename> concept False = false;
+template<typename> concept False = false; // #test15_False
template<False W>
-using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with V = int]}} \
- // expected-note {{cannot deduce template arguments for 'BFoo' from 'Foo<int *>'}} \
- // 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 *>}} \
- // expected-note {{candidate template ignored: could not match 'Foo<V *>' against 'int *'}} \
- // expected-note {{template <class V> requires __is_deducible(AFoo, Foo<V *>) && __is_deducible(test15::BFoo, Foo<V *>) BFoo(Foo<V *>) -> Foo<V *>}}
+using BFoo = AFoo<W>; // expected-note {{candidate template ignored: constraints not satisfied [with W = int]}} \
+ // expected-note@-1 {{because 'int' does not satisfy 'False'}} \
+ // expected-note@#test15_False {{because 'false' evaluated to false}} \
+ // 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 *>}} \
+ // expected-note {{candidate template ignored: could not match 'Foo<W *>' against 'int *'}} \
+ // expected-note {{template <False<> W> requires __is_deducible(AFoo, Foo<W *>) && __is_deducible(test15::BFoo, Foo<W *>) BFoo(Foo<W *>) -> Foo<W *>}}
int i = 0;
AFoo a1(&i); // OK, deduce Foo<int *>
@@ -539,3 +540,23 @@ using C = Proxy< A<T> >;
C test{ 42 }; // expected-error {{no viable constructor or deduction guide for deduction of template arguments}}
} // namespace GH125821
+
+namespace GH133132 {
+
+template <class T>
+struct A {};
+
+template <class T>
+using Foo = A<A<T>>;
+
+template <class T = int>
+using Bar = Foo<T>;
+
+template <class T = int, class U = int>
+using Baz = Bar<T>;
+
+Bar a{};
+
+Baz b{};
+
+} // namespace GH133132
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems reasonable/right to me, but please give @mizvekov a chance to double-check, he's more familiar with deduction than I am.
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