erichkeane updated this revision to Diff 376257.
erichkeane added a comment.
Change the skip-until code after a requires-clause failed parse.
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::comma, tok::greater, tok::greatergreater,
+ StopAtSemi | StopBeforeMatch);
+ 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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits