[clang] 5043962 - [Concepts] Fix parsing of scope specifier in compound-requirements, add more tests for scope specifiers in type-constraints

Saar Raz via cfe-commits cfe-commits at lists.llvm.org
Sun Jan 26 10:47:04 PST 2020


Author: Saar Raz
Date: 2020-01-26T20:46:53+02:00
New Revision: 5043962dd3150c6ac72b75174b9460a510d1b5c3

URL: https://github.com/llvm/llvm-project/commit/5043962dd3150c6ac72b75174b9460a510d1b5c3
DIFF: https://github.com/llvm/llvm-project/commit/5043962dd3150c6ac72b75174b9460a510d1b5c3.diff

LOG: [Concepts] Fix parsing of scope specifier in compound-requirements, add more tests for scope specifiers in type-constraints

The code for parsing of type-constraints in compound-requirements was not adapted for the new TryAnnotateTypeConstraint which
caused compound-requirements with scope specifiers to ignore them.

Also add regression tests for scope specifiers in type-constraints in more contexts.

Added: 
    clang/test/Parser/cxx2a-abbreviated-templates.cpp

Modified: 
    clang/lib/Parse/ParseExprCXX.cpp
    clang/test/Parser/cxx2a-concepts-requires-expr.cpp
    clang/test/Parser/cxx2a-placeholder-type-constraint.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 73d15cbc20c1..5b604f940ab8 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -3383,25 +3383,6 @@ ExprResult Parser::ParseRequiresExpression() {
           Diag(Tok, diag::err_requires_expr_missing_arrow)
               << FixItHint::CreateInsertion(Tok.getLocation(), "->");
         // Try to parse a 'type-constraint'
-        CXXScopeSpec SS;
-        if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
-                                           /*EnteringContext=*/false,
-                                           /*MayBePseudoDestructor=*/nullptr,
-                                           // If this is not a type-constraint,
-                                           // then this scope-spec is part of
-                                           // the typename of a non-type
-                                           // template parameter
-                                           /*IsTypename=*/true,
-                                           /*LastII=*/nullptr,
-                                           // We won't find concepts in
-                                           // non-namespaces anyway, so might as
-                                           // well parse this correctly for
-                                           // possible type names.
-                                           /*OnlyNamespace=*/false,
-                                           /*SuppressDiagnostic=*/true)) {
-          SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
-          break;
-        }
         if (TryAnnotateTypeConstraint()) {
           SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
           break;
@@ -3411,8 +3392,13 @@ ExprResult Parser::ParseRequiresExpression() {
           SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
           break;
         }
-        if (Tok.is(tok::annot_cxxscope))
+        CXXScopeSpec SS;
+        if (Tok.is(tok::annot_cxxscope)) {
+          Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
+                                                       Tok.getAnnotationRange(),
+                                                       SS);
           ConsumeAnnotationToken();
+        }
 
         Req = Actions.ActOnCompoundRequirement(
             Expression.get(), NoexceptLoc, SS, takeTemplateIdAnnotation(Tok),

diff  --git a/clang/test/Parser/cxx2a-abbreviated-templates.cpp b/clang/test/Parser/cxx2a-abbreviated-templates.cpp
new file mode 100644
index 000000000000..e2b3803c807e
--- /dev/null
+++ b/clang/test/Parser/cxx2a-abbreviated-templates.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
+// expected-no-diagnostics
+
+template<typename T, typename U=void>
+concept C = true;
+
+namespace ns {
+  template<typename T, typename U=void>
+  concept D = true;
+}
+
+void foo(C auto a,
+         C<int> auto b,
+         ns::D auto c,
+         ns::D<int> auto d,
+         const C auto e,
+         const C<int> auto f,
+         const ns::D auto g,
+         const ns::D<int> auto h);
\ No newline at end of file

diff  --git a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp
index 6b4a5d62b407..fa42b0633850 100644
--- a/clang/test/Parser/cxx2a-concepts-requires-expr.cpp
+++ b/clang/test/Parser/cxx2a-concepts-requires-expr.cpp
@@ -108,34 +108,38 @@ bool r29 = requires { { 0 } noexcept C1; };
 
 bool r30 = requires { { 0 } noexcept -> C2<int>; };
 
+namespace ns { template<typename T> concept C = true; }
+
+bool r31 = requires { { 0 } noexcept -> ns::C; };
+
 template<typename T>
 T i1 = 0;
 
-bool r31 = requires { requires false, 1; };
+bool r32 = requires { requires false, 1; };
 // expected-error at -1 {{expected ';' at end of requirement}}
 
-bool r32 = requires { 0 noexcept; };
+bool r33 = requires { 0 noexcept; };
 // expected-error at -1 {{'noexcept' can only be used in a compound requirement (with '{' '}' around the expression)}}
 
-bool r33 = requires { 0 int; };
+bool r34 = requires { 0 int; };
 // expected-error at -1 {{expected ';' at end of requirement}}
 
-bool r34 = requires { requires true };
+bool r35 = requires { requires true };
 // expected-error at -1 {{expected ';' at end of requirement}}
 
-bool r35 = requires (bool b) { requires sizeof(b) == 1; };
+bool r36 = requires (bool b) { requires sizeof(b) == 1; };
 
-void r36(bool b) requires requires { 1 } {}
+void r37(bool b) requires requires { 1 } {}
 // expected-error at -1 {{expected ';' at end of requirement}}
 
-bool r37 = requires { requires { 1; }; };
+bool r38 = requires { requires { 1; }; };
 // expected-warning at -1 {{this requires expression will only be checked for syntactic validity; did you intend to place it in a nested requirement? (add another 'requires' before the expression)}}
 
-bool r38 = requires { requires () { 1; }; };
+bool r39 = requires { requires () { 1; }; };
 // expected-warning at -1 {{this requires expression will only be checked for syntactic validity; did you intend to place it in a nested requirement? (add another 'requires' before the expression)}}
 
-bool r39 = requires { requires (int i) { i; }; };
+bool r40 = requires { requires (int i) { i; }; };
 // expected-warning at -1 {{this requires expression will only be checked for syntactic validity; did you intend to place it in a nested requirement? (add another 'requires' before the expression)}}
 
-bool r40 = requires { requires (); };
+bool r41 = requires { requires (); };
 // expected-error at -1 {{expected expression}}

diff  --git a/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp b/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp
index 7c94cd526340..dc1d75e1d960 100644
--- a/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp
+++ b/clang/test/Parser/cxx2a-placeholder-type-constraint.cpp
@@ -3,24 +3,33 @@
 template<typename T, typename U=void>
 concept C = true;
 
+namespace ns {
+  template<typename T, typename U=void>
+  concept D = true;
+}
+
 int foo() {
-  C auto a4 = 1;
-  C<> auto a5 = 1;
-  C<int> auto a6 = 1;
-  const C auto &a7 = 1;
-  const C<> auto &a8 = 1;
-  const C<int> auto &a9 = 1;
-  C decltype(auto) a10 = 1;
-  C<> decltype(auto) a11 = 1;
-  C<int> decltype(auto) a12 = 1;
-  const C<> decltype(auto) &a13 = 1; // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
+  {ns::D auto a = 1;}
+  {C auto a = 1;}
+  {C<> auto a = 1;}
+  {C<int> auto a = 1;}
+  {ns::D<int> auto a = 1;}
+  {const ns::D auto &a = 1;}
+  {const C auto &a = 1;}
+  {const C<> auto &a = 1;}
+  {const C<int> auto &a = 1;}
+  {const ns::D<int> auto &a = 1;}
+  {C decltype(auto) a = 1;}
+  {C<> decltype(auto) a = 1;}
+  {C<int> decltype(auto) a = 1;}
+  {const C<> decltype(auto) &a = 1;} // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
   // expected-error at -1{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
-  const C<int> decltype(auto) &a14 = 1; // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
+  {const C<int> decltype(auto) &a = 1;} // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
   // expected-error at -1{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
-  C a15 = 1;
+  {C a = 1;}
   // expected-error at -1{{expected 'auto' or 'decltype(auto)' after concept name}}
-  C decltype a19 = 1;
+  {C decltype a19 = 1;}
   // expected-error at -1{{expected '('}}
-  C decltype(1) a20 = 1;
+  {C decltype(1) a20 = 1;}
   // expected-error at -1{{expected 'auto' or 'decltype(auto)' after concept name}}
 }
\ No newline at end of file


        


More information about the cfe-commits mailing list