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@-1 {{partial specialization matches}} template <class T6, class T7> struct B<A<T6, T7>> {}; - // new-note@-1 {{partial specialization matches}} template struct B<A<int>>; - // new-error@-1 {{ambiguous partial specialization}} } // namespace class_template namespace type_pack1 { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits