erichkeane created this revision. erichkeane added reviewers: rsmith, hubert.reinterpretcast, saar.raz, arthur.j.odwyer. erichkeane requested review of this revision.
P0857R0 part-b allows a 'requires' clause on template-template parameters. This patch adds this in. However, no part of the standard seems to require checking of these constraints, nor do any of the 3 major implementations (EDG, GCC, MSVC) that implement this feature. Additionally, Part A of the document allows requires clauses on lambdas which appears to already be implemented, so update cxx_status.html to mark this paper as implemented. https://reviews.llvm.org/D110641 Files: clang/lib/Parse/ParseTemplate.cpp clang/test/CXX/temp/temp.arg/temp.arg.template/p3-2a.cpp clang/www/cxx_status.html
Index: clang/www/cxx_status.html =================================================================== --- clang/www/cxx_status.html +++ clang/www/cxx_status.html @@ -912,7 +912,7 @@ </tr> <tr> <!-- from Albuquerque --> <td><a href="https://wg21.link/p0857r0">P0857R0</a></td> - <td class="partial" align="center">Partial</td> + <td class="unreleased" align="center">Clang 14</td> </tr> <tr> <!-- from San Diego --> <td><a href="https://wg21.link/p1084r2">P1084R2</a></td> 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 @@ -32,3 +32,35 @@ using s31 = S3<N>; using s32 = S3<Z>; + +template<typename T> +struct Evals { + bool f() { return true; } +}; + +template<> +struct Evals<float> { + bool f() { return false; } +}; + +template <typename T, template <typename> requires C<T> typename P> +struct S4 {}; + +template <typename T, template <typename> +requires requires { requires T::f(); } +typename P > + void func(const P<T> &p){}; + +template <typename T, template <typename> requires false typename P> +void func_always_requires_false(const P<T> &p) {}; + +void use() { + S4<int, Evals> s4; + func(Evals<int>{}); + // A naive individual might expect the following to all fail concept checking, + // but there does not seem to be any requirement to check these in the + // standard, and none of the other implementations do so either. + S4<float, Evals> s4b; + func(Evals<float>{}); + func_always_requires_false(Evals<int>{}); +} Index: clang/lib/Parse/ParseTemplate.cpp =================================================================== --- clang/lib/Parse/ParseTemplate.cpp +++ clang/lib/Parse/ParseTemplate.cpp @@ -871,6 +871,31 @@ /// type-parameter-key: /// 'class' /// 'typename' [C++1z] +/// +/// In C++20: +/// template-head: [C++ temp.pre] +/// template '<' template-parameter-list '>' requires-clause[opt] +/// +/// template-parameter: [C++ temp.param] +/// type-parameter +/// parameter-declaration +/// +/// type-parameter: +/// type-parameter-key ...[opt] identifier[opt] +/// type-parameter-key identifier[opt] = type-id +/// type-constraint ...[opt] identifier[opt] +/// type-constraint identifier[opt] = type-id +/// template-head type-parameter-key ...[opt] identifier[opt] +/// template-head type-parameter-key identifier[opt] = id-expression +/// +/// type-parameter-key: +/// 'class' +/// 'typename' +/// +/// type-constraint: +/// nested-name-specifier[opt] concept-name +/// nested-name-specifier[opt] concept-name '<' +/// template-argument-list[opt] '>' NamedDecl * Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { assert(Tok.is(tok::kw_template) && "Expected 'template' keyword"); @@ -887,6 +912,20 @@ } } + // Parse optional requires-clause. + ExprResult OptionalRequiresClauseConstraintER; + if (getLangOpts().CPlusPlus20 && TryConsumeToken(tok::kw_requires)) { + OptionalRequiresClauseConstraintER = + Actions.ActOnRequiresClause(ParseConstraintLogicalOrExpression( + /*IsTrailingRequiresClause=*/false)); + if (!OptionalRequiresClauseConstraintER.isUsable()) { + // Skip until the semi-colon or a '}'. + SkipUntil(tok::r_brace, StopAtSemi | StopBeforeMatch); + TryConsumeToken(tok::semi); + return nullptr; + } + } + // Provide an ExtWarn if the C++1z feature of using 'typename' here is used. // Generate a meaningful error if the user forgot to put class before the // identifier, comma, or greater. Provide a fixit if the identifier, comma, @@ -946,11 +985,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
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits