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

Reply via email to