[clang] ff3f41d - [clang] Implement CWG2398 provisional TTP matching to class templates (#92855)
via cfe-commits
cfe-commits at lists.llvm.org
Wed May 22 11:59:59 PDT 2024
Author: Matheus Izvekov
Date: 2024-05-22T15:59:55-03:00
New Revision: ff3f41deb04c03ba57658776e4e0dc26ef01187d
URL: https://github.com/llvm/llvm-project/commit/ff3f41deb04c03ba57658776e4e0dc26ef01187d
DIFF: https://github.com/llvm/llvm-project/commit/ff3f41deb04c03ba57658776e4e0dc26ef01187d.diff
LOG: [clang] Implement CWG2398 provisional TTP matching to class templates (#92855)
This solves some ambuguity introduced in P0522 regarding how template
template parameters are partially ordered, and should reduce the
negative impact of enabling `-frelaxed-template-template-args` by
default.
When performing template argument deduction, we extend the provisional
wording introduced in https://github.com/llvm/llvm-project/pull/89807 so
it also covers deduction of class templates.
Given the following example:
```C++
template <class T1, class T2 = float> struct A;
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>; // #1
template <class T6, class T7> struct B<A<T6, T7>>; // #2
template struct B<A<int>>;
```
Prior to P0522, `#2` was picked. Afterwards, this became ambiguous. This
patch restores the pre-P0522 behavior, `#2` is picked again.
This has the beneficial side effect of making the following code valid:
```C++
template<class T, class U> struct A {};
A<int, float> v;
template<template<class> class TT> void f(TT<int>);
// OK: TT picks 'float' as the default argument for the second parameter.
void g() { f(v); }
```
---
Since this changes provisional implementation of CWG2398 which has not
been released yet, and already contains a changelog entry, we don't
provide a changelog entry here.
Added:
Modified:
clang/lib/Sema/SemaTemplate.cpp
clang/lib/Sema/SemaTemplateDeduction.cpp
clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp
clang/test/SemaTemplate/cwg2398.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 39e9dbed0c3e0..268f079980a6c 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -1807,6 +1807,8 @@ static void SetNestedNameSpecifier(Sema &S, TagDecl *T,
// Returns the template parameter list with all default template argument
// information.
static TemplateParameterList *GetTemplateParameterList(TemplateDecl *TD) {
+ if (TD->isImplicit())
+ return TD->getTemplateParameters();
// Make sure we get the template parameter list from the most
// recent declaration, since that is the only one that is guaranteed to
// have all the default template argument information.
@@ -1827,7 +1829,8 @@ static TemplateParameterList *GetTemplateParameterList(TemplateDecl *TD) {
// template <class = void> friend struct C;
// };
// template struct S<int>;
- while (D->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None &&
+ while ((D->isImplicit() ||
+ D->getFriendObjectKind() != Decl::FriendObjectKind::FOK_None) &&
D->getPreviousDecl())
D = D->getPreviousDecl();
return cast<TemplateDecl>(D)->getTemplateParameters();
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index f16a07e1a1b34..76f47e9cb2560 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -527,8 +527,8 @@ static NamedDecl *getTemplateParameterWithDefault(Sema &S, NamedDecl *A,
R->setDefaultArgument(
S.Context,
S.getTrivialTemplateArgumentLoc(Default, QualType(), SourceLocation()));
- if (R->hasTypeConstraint()) {
- auto *C = R->getTypeConstraint();
+ if (T->hasTypeConstraint()) {
+ auto *C = T->getTypeConstraint();
R->setTypeConstraint(C->getConceptReference(),
C->getImmediatelyDeclaredConstraint());
}
@@ -583,37 +583,53 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
return TemplateDeductionResult::Success;
auto NewDeduced = DeducedTemplateArgument(Arg);
- // Provisional resolution for CWG2398: If Arg is also a template template
- // param, and it names a template specialization, then we deduce a
- // synthesized template template parameter based on A, but using the TS's
- // arguments as defaults.
- if (auto *TempArg = dyn_cast_or_null<TemplateTemplateParmDecl>(
- Arg.getAsTemplateDecl())) {
+ // Provisional resolution for CWG2398: If Arg names a template
+ // specialization, then we deduce a synthesized template template parameter
+ // based on A, but using the TS's arguments as defaults.
+ if (DefaultArguments.size() != 0) {
assert(Arg.getKind() == TemplateName::Template);
- assert(!TempArg->isExpandedParameterPack());
-
+ TemplateDecl *TempArg = Arg.getAsTemplateDecl();
TemplateParameterList *As = TempArg->getTemplateParameters();
- if (DefaultArguments.size() != 0) {
- assert(DefaultArguments.size() <= As->size());
- SmallVector<NamedDecl *, 4> Params(As->size());
- for (unsigned I = 0; I < DefaultArguments.size(); ++I)
- Params[I] = getTemplateParameterWithDefault(S, As->getParam(I),
- DefaultArguments[I]);
- for (unsigned I = DefaultArguments.size(); I < As->size(); ++I)
- Params[I] = As->getParam(I);
- // FIXME: We could unique these, and also the parameters, but we don't
- // expect programs to contain a large enough amount of these deductions
- // for that to be worthwhile.
- auto *TPL = TemplateParameterList::Create(
- S.Context, SourceLocation(), SourceLocation(), Params,
- SourceLocation(), As->getRequiresClause());
- NewDeduced = DeducedTemplateArgument(
- TemplateName(TemplateTemplateParmDecl::Create(
- S.Context, TempArg->getDeclContext(), SourceLocation(),
- TempArg->getDepth(), TempArg->getPosition(),
- TempArg->isParameterPack(), TempArg->getIdentifier(),
- TempArg->wasDeclaredWithTypename(), TPL)));
+ assert(DefaultArguments.size() <= As->size());
+
+ SmallVector<NamedDecl *, 4> Params(As->size());
+ for (unsigned I = 0; I < DefaultArguments.size(); ++I)
+ Params[I] = getTemplateParameterWithDefault(S, As->getParam(I),
+ DefaultArguments[I]);
+ for (unsigned I = DefaultArguments.size(); I < As->size(); ++I)
+ Params[I] = As->getParam(I);
+ // FIXME: We could unique these, and also the parameters, but we don't
+ // expect programs to contain a large enough amount of these deductions
+ // for that to be worthwhile.
+ auto *TPL = TemplateParameterList::Create(
+ S.Context, SourceLocation(), SourceLocation(), Params,
+ SourceLocation(), As->getRequiresClause());
+
+ TemplateDecl *TD;
+ switch (TempArg->getKind()) {
+ case Decl::TemplateTemplateParm: {
+ auto *A = cast<TemplateTemplateParmDecl>(TempArg);
+ assert(!A->isExpandedParameterPack());
+ TD = TemplateTemplateParmDecl::Create(
+ S.Context, A->getDeclContext(), SourceLocation(), A->getDepth(),
+ A->getPosition(), A->isParameterPack(), A->getIdentifier(),
+ A->wasDeclaredWithTypename(), TPL);
+ break;
+ }
+ case Decl::ClassTemplate: {
+ auto *A = cast<ClassTemplateDecl>(TempArg);
+ auto *CT = ClassTemplateDecl::Create(S.Context, A->getDeclContext(),
+ SourceLocation(), A->getDeclName(),
+ TPL, A->getTemplatedDecl());
+ CT->setPreviousDecl(A);
+ TD = CT;
+ break;
+ }
+ default:
+ llvm_unreachable("Unexpected Template Kind");
}
+ TD->setImplicit(true);
+ NewDeduced = DeducedTemplateArgument(TemplateName(TD));
}
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
diff --git a/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp b/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp
index a5b39fe5c51f7..bc39431253880 100644
--- a/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp
+++ b/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp
@@ -28,13 +28,14 @@ namespace StdExample {
{ /* ... */ }
template<template<class> class TT>
- void f(TT<int>); // expected-note {{candidate template ignored}}
+ void f(TT<int>);
template<template<class,class> class TT>
void g(TT<int, Alloc<int>>);
int h() {
- f(v); // expected-error {{no matching function for call to 'f'}}
+ f(v); // OK: TT = vector, Alloc<int> is used as the default argument for the
+ // second parameter.
g(v); // OK: TT = vector
}
diff --git a/clang/test/SemaTemplate/cwg2398.cpp b/clang/test/SemaTemplate/cwg2398.cpp
index e3b5e575374d3..4cc946735a1e2 100644
--- a/clang/test/SemaTemplate/cwg2398.cpp
+++ b/clang/test/SemaTemplate/cwg2398.cpp
@@ -65,13 +65,10 @@ namespace class_template {
template <class T3> struct B;
template <template <class T4> class TT1, class T5> struct B<TT1<T5>>;
- // new-note at -1 {{partial specialization matches}}
template <class T6, class T7> struct B<A<T6, T7>> {};
- // new-note at -1 {{partial specialization matches}}
template struct B<A<int>>;
- // new-error at -1 {{ambiguous partial specialization}}
} // namespace class_template
namespace type_pack1 {
More information about the cfe-commits
mailing list