erichkeane updated this revision to Diff 375680. erichkeane added a comment.
Moments after my last comment, i figured out the scope issue, which makes the names in the template-template-parameter parameter-list in scope for this requires clause. I don't think it makes SENSE that this is the case, but I suspect thats what the standard says based on the other compiler's behavior. This fixes the exmaple in the concepts.cpp test. CHANGES SINCE LAST ACTION https://reviews.llvm.org/D110641/new/ https://reviews.llvm.org/D110641 Files: clang/lib/Parse/ParseTemplate.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,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/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 { 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"); @@ -879,12 +904,26 @@ 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; } + + // Parse optional requires-clause. + 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. @@ -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