This revision was not accepted when it landed; it landed in state "Needs Review". This revision was automatically updated to reflect the committed changes. Closed by commit rGae48d1c76a6c: [P0857R0 Part-B] Allows `require' clauses appearing in (authored by lime, committed by erichkeane).
Changed prior to commit: https://reviews.llvm.org/D134128?vs=471046&id=471153#toc Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D134128/new/ https://reviews.llvm.org/D134128 Files: clang/docs/ReleaseNotes.rst clang/include/clang/Sema/Sema.h clang/lib/Parse/ParseTemplate.cpp clang/lib/Sema/SemaConcept.cpp clang/lib/Sema/SemaOverload.cpp clang/lib/Sema/SemaTemplate.cpp clang/lib/Sema/SemaTemplateInstantiate.cpp clang/lib/Sema/SemaTemplateInstantiateDecl.cpp clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp clang/test/SemaTemplate/concepts.cpp clang/www/cxx_status.html
Index: clang/www/cxx_status.html =================================================================== --- clang/www/cxx_status.html +++ clang/www/cxx_status.html @@ -912,11 +912,7 @@ </tr> <tr> <!-- from Albuquerque --> <td><a href="https://wg21.link/p0857r0">P0857R0</a></td> - <td class="partial" align="center"> - <details><summary>Partial</summary> - Constraining template template parameters is not yet supported. - </details> - </td> + <td rowspan="1" class="unreleased" align="center">Clang 16</td> </tr> <tr> <!-- from San Diego --> <td><a href="https://wg21.link/p1084r2">P1084R2</a></td> Index: clang/test/SemaTemplate/concepts.cpp =================================================================== --- clang/test/SemaTemplate/concepts.cpp +++ clang/test/SemaTemplate/concepts.cpp @@ -59,11 +59,10 @@ x.operator()<false>(); // expected-error {{no matching member function}} } - // FIXME: This is valid under P0857R0. template<typename T> concept C = true; - template<template<typename T> requires C<T> typename U> struct X {}; // expected-error {{requires 'class'}} expected-error 0+{{}} + template<template<typename T> requires C<T> typename U> struct X {}; template<typename T> requires C<T> struct Y {}; - X<Y> xy; // expected-error {{no template named 'X'}} + X<Y> xy; } namespace PR50306 { @@ -706,7 +705,7 @@ Container<5>::var_templ<int> inst_fail; // expected-error@-1{{constraints not satisfied for alias template 'var_templ'}} // expected-note@#CMVT_REQ{{because 'sizeof(int) == arity' (4 == 5) evaluated to false}} -} // namespace ConstrainedMemberVarTemplate +} // namespace ConstrainedMemberVarTemplate // These should not diagnose, where we were unintentionally doing so before by // checking trailing requires clause twice, yet not having the ability to the @@ -764,4 +763,4 @@ void use2() { __iterator_traits_member_pointer_or_arrow_or_void<counted_iterator<int>> f; } -}// namespace InheritedFromPartialSpec +}// namespace InheritedFromPartialSpec Index: clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp =================================================================== --- clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp +++ clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp @@ -1,22 +1,27 @@ // RUN: %clang_cc1 -std=c++2a -frelaxed-template-template-args -verify %s -template<typename T> concept C = T::f(); -// expected-note@-1{{similar constraint}} +template<typename T> concept C = T::f(); // #C template<typename T> concept D = C<T> && T::g(); -template<typename T> concept F = T::f(); -// expected-note@-1{{similar constraint expressions not considered equivalent}} -template<template<C> class P> struct S1 { }; // expected-note 2{{'P' declared here}} +template<typename T> concept F = T::f(); // #F +template<template<C> class P> struct S1 { }; // #S1 template<C> struct X { }; -template<D> struct Y { }; // expected-note{{'Y' declared here}} +template<D> struct Y { }; // #Y template<typename T> struct Z { }; -template<F> struct W { }; // expected-note{{'W' declared here}} - +template<F> struct W { }; // #W S1<X> s11; -S1<Y> s12; // expected-error{{template template argument 'Y' is more constrained than template template parameter 'P'}} +S1<Y> s12; +// expected-error@-1 {{template template argument 'Y' is more constrained than template template parameter 'P'}} +// expected-note@#S1 {{'P' declared here}} +// expected-note@#Y {{'Y' declared here}} S1<Z> s13; -S1<W> s14; // expected-error{{template template argument 'W' is more constrained than template template parameter 'P'}} +S1<W> s14; +// expected-error@-1 {{template template argument 'W' is more constrained than template template parameter 'P'}} +// expected-note@#S1 {{'P' declared here}} +// expected-note@#W {{'W' declared here}} +// expected-note@#F 1-2{{similar constraint expressions not considered equivalent}} +// expected-note@#C 1-2{{similar constraint}} template<template<typename> class P> struct S2 { }; @@ -32,3 +37,25 @@ using s31 = S3<N>; using s32 = S3<Z>; + +template<template<typename T> requires C<T> class P> struct S4 { }; // #S4 + +S4<X> s41; +S4<Y> s42; +// expected-error@-1 {{template template argument 'Y' is more constrained than template template parameter 'P'}} +// expected-note@#S4 {{'P' declared here}} +// expected-note@#Y {{'Y' declared here}} +S4<Z> s43; +S4<W> s44; +// expected-error@-1 {{template template argument 'W' is more constrained than template template parameter 'P'}} +// expected-note@#S4 {{'P' declared here}} +// expected-note@#W {{'W' declared here}} + +template<template<typename T> requires C<T> typename U> struct S5 { + template<typename T> static U<T> V; +}; + +struct Nothing {}; + +// FIXME: Wait the standard to clarify the intent. +template<> template<> Z<Nothing> S5<Z>::V<Nothing>; Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -4097,8 +4097,10 @@ TemplateParameterList * Sema::SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner, - const MultiLevelTemplateArgumentList &TemplateArgs) { + const MultiLevelTemplateArgumentList &TemplateArgs, + bool EvaluateConstraints) { TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs); + Instantiator.setEvaluateConstraints(EvaluateConstraints); return Instantiator.SubstTemplateParams(Params); } Index: clang/lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiate.cpp +++ clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -75,7 +75,8 @@ // Add template arguments from a variable template instantiation. Response HandleVarTemplateSpec(const VarTemplateSpecializationDecl *VarTemplSpec, - MultiLevelTemplateArgumentList &Result) { + MultiLevelTemplateArgumentList &Result, + bool SkipForSpecialization) { // For a class-scope explicit specialization, there are no template arguments // at this level, but there may be enclosing template arguments. if (VarTemplSpec->isClassScopeExplicitSpecialization()) @@ -93,16 +94,18 @@ Specialized = VarTemplSpec->getSpecializedTemplateOrPartial(); if (VarTemplatePartialSpecializationDecl *Partial = Specialized.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { - Result.addOuterTemplateArguments( - Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(), - /*Final=*/false); + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + Partial, VarTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); if (Partial->isMemberSpecialization()) return Response::Done(); } else { VarTemplateDecl *Tmpl = Specialized.get<VarTemplateDecl *>(); - Result.addOuterTemplateArguments( - Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(), - /*Final=*/false); + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + Tmpl, VarTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); if (Tmpl->isMemberSpecialization()) return Response::Done(); } @@ -126,17 +129,19 @@ // Add template arguments from a class template instantiation. Response HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec, - MultiLevelTemplateArgumentList &Result) { + MultiLevelTemplateArgumentList &Result, + bool SkipForSpecialization) { if (!ClassTemplSpec->isClassScopeExplicitSpecialization()) { // We're done when we hit an explicit specialization. if (ClassTemplSpec->getSpecializationKind() == TSK_ExplicitSpecialization && !isa<ClassTemplatePartialSpecializationDecl>(ClassTemplSpec)) return Response::Done(); - Result.addOuterTemplateArguments( - const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec), - ClassTemplSpec->getTemplateInstantiationArgs().asArray(), - /*Final=*/false); + if (!SkipForSpecialization) + Result.addOuterTemplateArguments( + const_cast<ClassTemplateSpecializationDecl *>(ClassTemplSpec), + ClassTemplSpec->getTemplateInstantiationArgs().asArray(), + /*Final=*/false); // If this class template specialization was instantiated from a // specialized member that is a class template, we're done. @@ -279,7 +284,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs( const NamedDecl *ND, bool Final, const TemplateArgumentList *Innermost, bool RelativeToPrimary, const FunctionDecl *Pattern, - bool ForConstraintInstantiation) { + bool ForConstraintInstantiation, bool SkipForSpecialization) { assert(ND && "Can't find arguments for a decl if one isn't provided"); // Accumulate the set of template argument lists in this structure. MultiLevelTemplateArgumentList Result; @@ -295,10 +300,11 @@ Response R; if (const auto *VarTemplSpec = dyn_cast<VarTemplateSpecializationDecl>(CurDecl)) { - R = HandleVarTemplateSpec(VarTemplSpec, Result); + R = HandleVarTemplateSpec(VarTemplSpec, Result, SkipForSpecialization); } else if (const auto *ClassTemplSpec = dyn_cast<ClassTemplateSpecializationDecl>(CurDecl)) { - R = HandleClassTemplateSpec(ClassTemplSpec, Result); + R = HandleClassTemplateSpec(ClassTemplSpec, Result, + SkipForSpecialization); } else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) { R = HandleFunction(Function, Result, Pattern, RelativeToPrimary, ForConstraintInstantiation); Index: clang/lib/Sema/SemaTemplate.cpp =================================================================== --- clang/lib/Sema/SemaTemplate.cpp +++ clang/lib/Sema/SemaTemplate.cpp @@ -5717,7 +5717,8 @@ Params = SubstTemplateParams(Params, CurContext, MultiLevelTemplateArgumentList( - Template, SugaredConverted, /*Final=*/true)); + Template, SugaredConverted, /*Final=*/true), + /*EvaluateConstraints=*/false); if (!Params) return true; } Index: clang/lib/Sema/SemaOverload.cpp =================================================================== --- clang/lib/Sema/SemaOverload.cpp +++ clang/lib/Sema/SemaOverload.cpp @@ -10049,13 +10049,13 @@ // parameter-type-lists, and F1 is more constrained than F2 [...], if (!Cand1IsSpecialization && !Cand2IsSpecialization && sameFunctionParameterTypeLists(S, Cand1, Cand2)) { - Expr *RC1 = Cand1.Function->getTrailingRequiresClause(); - Expr *RC2 = Cand2.Function->getTrailingRequiresClause(); + const Expr *RC1 = Cand1.Function->getTrailingRequiresClause(); + const Expr *RC2 = Cand2.Function->getTrailingRequiresClause(); if (RC1 && RC2) { bool AtLeastAsConstrained1, AtLeastAsConstrained2; - if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function, {RC2}, + if (S.IsAtLeastAsConstrained(Cand1.Function, RC1, Cand2.Function, RC2, AtLeastAsConstrained1) || - S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function, {RC1}, + S.IsAtLeastAsConstrained(Cand2.Function, RC2, Cand1.Function, RC1, AtLeastAsConstrained2)) return false; if (AtLeastAsConstrained1 != AtLeastAsConstrained2) Index: clang/lib/Sema/SemaConcept.cpp =================================================================== --- clang/lib/Sema/SemaConcept.cpp +++ clang/lib/Sema/SemaConcept.cpp @@ -586,12 +586,13 @@ // Figure out the to-translation-unit depth for this function declaration for // the purpose of seeing if they differ by constraints. This isn't the same as // getTemplateDepth, because it includes already instantiated parents. -static unsigned CalculateTemplateDepthForConstraints(Sema &S, - const NamedDecl *ND) { +static unsigned +CalculateTemplateDepthForConstraints(Sema &S, const NamedDecl *ND, + bool SkipForSpecialization = false) { MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( ND, /*Final=*/false, /*Innermost=*/nullptr, /*RelativeToPrimary=*/true, /*Pattern=*/nullptr, - /*ForConstraintInstantiation=*/true); + /*ForConstraintInstantiation=*/true, SkipForSpecialization); return MLTAL.getNumSubstitutedLevels(); } @@ -1278,8 +1279,10 @@ return false; } -bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1, - NamedDecl *D2, ArrayRef<const Expr *> AC2, +bool Sema::IsAtLeastAsConstrained(NamedDecl *D1, + MutableArrayRef<const Expr *> AC1, + NamedDecl *D2, + MutableArrayRef<const Expr *> AC2, bool &Result) { if (AC1.empty()) { Result = AC2.empty(); @@ -1298,6 +1301,21 @@ return false; } + unsigned Depth1 = CalculateTemplateDepthForConstraints(*this, D1, true); + unsigned Depth2 = CalculateTemplateDepthForConstraints(*this, D2, true); + + for (size_t I = 0; I != AC1.size() && I != AC2.size(); ++I) { + if (Depth2 > Depth1) { + AC1[I] = AdjustConstraintDepth(*this, Depth2 - Depth1) + .TransformExpr(const_cast<Expr *>(AC1[I])) + .get(); + } else if (Depth1 > Depth2) { + AC2[I] = AdjustConstraintDepth(*this, Depth1 - Depth2) + .TransformExpr(const_cast<Expr *>(AC2[I])) + .get(); + } + } + if (subsumes(*this, D1, AC1, D2, AC2, Result, [this] (const AtomicConstraint &A, const AtomicConstraint &B) { return A.subsumes(Context, B); Index: clang/lib/Parse/ParseTemplate.cpp =================================================================== --- clang/lib/Parse/ParseTemplate.cpp +++ clang/lib/Parse/ParseTemplate.cpp @@ -874,27 +874,39 @@ /// template parameters. /// /// type-parameter: [C++ temp.param] -/// 'template' '<' template-parameter-list '>' type-parameter-key -/// ...[opt] identifier[opt] -/// 'template' '<' template-parameter-list '>' type-parameter-key -/// identifier[opt] = id-expression +/// template-head type-parameter-key ...[opt] identifier[opt] +/// template-head type-parameter-key identifier[opt] = id-expression /// type-parameter-key: /// 'class' /// 'typename' [C++1z] -NamedDecl * -Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { +/// template-head: [C++2a] +/// 'template' '<' template-parameter-list '>' +/// requires-clause[opt] +NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth, + unsigned Position) { assert(Tok.is(tok::kw_template) && "Expected 'template' keyword"); // Handle the template <...> part. SourceLocation TemplateLoc = ConsumeToken(); SmallVector<NamedDecl*,8> TemplateParams; SourceLocation LAngleLoc, RAngleLoc; + ExprResult OptionalRequiresClauseConstraintER; { MultiParseScope TemplateParmScope(*this); if (ParseTemplateParameters(TemplateParmScope, Depth + 1, TemplateParams, LAngleLoc, RAngleLoc)) { return nullptr; } + if (TryConsumeToken(tok::kw_requires)) { + OptionalRequiresClauseConstraintER = + Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression( + /*IsTrailingRequiresClause=*/false)); + if (!OptionalRequiresClauseConstraintER.isUsable()) { + SkipUntil(tok::comma, tok::greater, tok::greatergreater, + StopAtSemi | StopBeforeMatch); + return nullptr; + } + } } // Provide an ExtWarn if the C++1z feature of using 'typename' here is used. @@ -956,11 +968,9 @@ if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) DiagnoseMisplacedEllipsis(EllipsisLoc, NameLoc, AlreadyHasEllipsis, true); - TemplateParameterList *ParamList = - Actions.ActOnTemplateParameterList(Depth, SourceLocation(), - TemplateLoc, LAngleLoc, - TemplateParams, - RAngleLoc, nullptr); + TemplateParameterList *ParamList = Actions.ActOnTemplateParameterList( + Depth, SourceLocation(), TemplateLoc, LAngleLoc, TemplateParams, + RAngleLoc, OptionalRequiresClauseConstraintER.get()); // Grab a default argument (if available). // Per C++0x [basic.scope.pdecl]p9, we parse the default argument before Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -7232,8 +7232,8 @@ /// at least constrained than D2, and false otherwise. /// /// \returns true if an error occurred, false otherwise. - bool IsAtLeastAsConstrained(NamedDecl *D1, ArrayRef<const Expr *> AC1, - NamedDecl *D2, ArrayRef<const Expr *> AC2, + bool IsAtLeastAsConstrained(NamedDecl *D1, MutableArrayRef<const Expr *> AC1, + NamedDecl *D2, MutableArrayRef<const Expr *> AC2, bool &Result); /// If D1 was not at least as constrained as D2, but would've been if a pair @@ -9076,7 +9076,8 @@ const TemplateArgumentList *Innermost = nullptr, bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr, - bool ForConstraintInstantiation = false); + bool ForConstraintInstantiation = false, + bool SkipForSpecialization = false); /// A context in which code is being synthesized (where a source location /// alone is not sufficient to identify the context). This covers template @@ -9860,7 +9861,8 @@ TemplateParameterList * SubstTemplateParams(TemplateParameterList *Params, DeclContext *Owner, - const MultiLevelTemplateArgumentList &TemplateArgs); + const MultiLevelTemplateArgumentList &TemplateArgs, + bool EvaluateConstraints = true); bool SubstTemplateArguments(ArrayRef<TemplateArgumentLoc> Args, Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -556,9 +556,10 @@ - Implemented `P0634r3 <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0634r3.html>`_, which removes the requirement for the ``typename`` keyword in certain contexts. - Implemented The Equality Operator You Are Looking For (`P2468 <http://wg21.link/p2468r2>`_). - - Implemented `P2113R0: Proposed resolution for 2019 comment CA 112 <https://wg21.link/P2113R0>`_ ([temp.func.order]p6.2.1 is not implemented, matching GCC). +- Implemented `P0857R0 <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0857r0.html>`_, + which specifies constrained lambdas and constrained template *template-parameter*\s. - Do not hide templated base members introduced via using-decl in derived class (useful specially for constrained members). Fixes `GH50886 <https://github.com/llvm/llvm-project/issues/50886>`_.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits