[llvm-branch-commits] [clang] 73a9147 - [Concepts] Fix parsing of scope specifier in compound-requirements, add more tests for scope specifiers in type-constraints
Saar Raz via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Jan 26 10:50:44 PST 2020
Author: Saar Raz
Date: 2020-01-26T20:49:23+02:00
New Revision: 73a91477f7045d1325570f28e349dd87d9bff49c
URL: https://github.com/llvm/llvm-project/commit/73a91477f7045d1325570f28e349dd87d9bff49c
DIFF: https://github.com/llvm/llvm-project/commit/73a91477f7045d1325570f28e349dd87d9bff49c.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.
(cherry picked from commit 5043962dd3150c6ac72b75174b9460a510d1b5c3)
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 036eabb94dd7..9f94e0dde3bd 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -3374,25 +3374,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;
@@ -3402,8 +3383,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 llvm-branch-commits
mailing list