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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits