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

Reply via email to