Skip to content

Commit 73a9147

Browse files
committed
[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 5043962)
1 parent 27f9351 commit 73a9147

File tree

4 files changed

+62
-44
lines changed

4 files changed

+62
-44
lines changed

clang/lib/Parse/ParseExprCXX.cpp

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3374,25 +3374,6 @@ ExprResult Parser::ParseRequiresExpression() {
33743374
Diag(Tok, diag::err_requires_expr_missing_arrow)
33753375
<< FixItHint::CreateInsertion(Tok.getLocation(), "->");
33763376
// Try to parse a 'type-constraint'
3377-
CXXScopeSpec SS;
3378-
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(),
3379-
/*EnteringContext=*/false,
3380-
/*MayBePseudoDestructor=*/nullptr,
3381-
// If this is not a type-constraint,
3382-
// then this scope-spec is part of
3383-
// the typename of a non-type
3384-
// template parameter
3385-
/*IsTypename=*/true,
3386-
/*LastII=*/nullptr,
3387-
// We won't find concepts in
3388-
// non-namespaces anyway, so might as
3389-
// well parse this correctly for
3390-
// possible type names.
3391-
/*OnlyNamespace=*/false,
3392-
/*SuppressDiagnostic=*/true)) {
3393-
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
3394-
break;
3395-
}
33963377
if (TryAnnotateTypeConstraint()) {
33973378
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
33983379
break;
@@ -3402,8 +3383,13 @@ ExprResult Parser::ParseRequiresExpression() {
34023383
SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch);
34033384
break;
34043385
}
3405-
if (Tok.is(tok::annot_cxxscope))
3386+
CXXScopeSpec SS;
3387+
if (Tok.is(tok::annot_cxxscope)) {
3388+
Actions.RestoreNestedNameSpecifierAnnotation(Tok.getAnnotationValue(),
3389+
Tok.getAnnotationRange(),
3390+
SS);
34063391
ConsumeAnnotationToken();
3392+
}
34073393

34083394
Req = Actions.ActOnCompoundRequirement(
34093395
Expression.get(), NoexceptLoc, SS, takeTemplateIdAnnotation(Tok),
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// RUN: %clang_cc1 -std=c++2a -x c++ %s -verify
2+
// expected-no-diagnostics
3+
4+
template<typename T, typename U=void>
5+
concept C = true;
6+
7+
namespace ns {
8+
template<typename T, typename U=void>
9+
concept D = true;
10+
}
11+
12+
void foo(C auto a,
13+
C<int> auto b,
14+
ns::D auto c,
15+
ns::D<int> auto d,
16+
const C auto e,
17+
const C<int> auto f,
18+
const ns::D auto g,
19+
const ns::D<int> auto h);

clang/test/Parser/cxx2a-concepts-requires-expr.cpp

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -108,34 +108,38 @@ bool r29 = requires { { 0 } noexcept C1; };
108108

109109
bool r30 = requires { { 0 } noexcept -> C2<int>; };
110110

111+
namespace ns { template<typename T> concept C = true; }
112+
113+
bool r31 = requires { { 0 } noexcept -> ns::C; };
114+
111115
template<typename T>
112116
T i1 = 0;
113117

114-
bool r31 = requires { requires false, 1; };
118+
bool r32 = requires { requires false, 1; };
115119
// expected-error@-1 {{expected ';' at end of requirement}}
116120

117-
bool r32 = requires { 0 noexcept; };
121+
bool r33 = requires { 0 noexcept; };
118122
// expected-error@-1 {{'noexcept' can only be used in a compound requirement (with '{' '}' around the expression)}}
119123

120-
bool r33 = requires { 0 int; };
124+
bool r34 = requires { 0 int; };
121125
// expected-error@-1 {{expected ';' at end of requirement}}
122126

123-
bool r34 = requires { requires true };
127+
bool r35 = requires { requires true };
124128
// expected-error@-1 {{expected ';' at end of requirement}}
125129

126-
bool r35 = requires (bool b) { requires sizeof(b) == 1; };
130+
bool r36 = requires (bool b) { requires sizeof(b) == 1; };
127131

128-
void r36(bool b) requires requires { 1 } {}
132+
void r37(bool b) requires requires { 1 } {}
129133
// expected-error@-1 {{expected ';' at end of requirement}}
130134

131-
bool r37 = requires { requires { 1; }; };
135+
bool r38 = requires { requires { 1; }; };
132136
// expected-warning@-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)}}
133137

134-
bool r38 = requires { requires () { 1; }; };
138+
bool r39 = requires { requires () { 1; }; };
135139
// expected-warning@-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)}}
136140

137-
bool r39 = requires { requires (int i) { i; }; };
141+
bool r40 = requires { requires (int i) { i; }; };
138142
// expected-warning@-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)}}
139143

140-
bool r40 = requires { requires (); };
144+
bool r41 = requires { requires (); };
141145
// expected-error@-1 {{expected expression}}

clang/test/Parser/cxx2a-placeholder-type-constraint.cpp

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,33 @@
33
template<typename T, typename U=void>
44
concept C = true;
55

6+
namespace ns {
7+
template<typename T, typename U=void>
8+
concept D = true;
9+
}
10+
611
int foo() {
7-
C auto a4 = 1;
8-
C<> auto a5 = 1;
9-
C<int> auto a6 = 1;
10-
const C auto &a7 = 1;
11-
const C<> auto &a8 = 1;
12-
const C<int> auto &a9 = 1;
13-
C decltype(auto) a10 = 1;
14-
C<> decltype(auto) a11 = 1;
15-
C<int> decltype(auto) a12 = 1;
16-
const C<> decltype(auto) &a13 = 1; // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
12+
{ns::D auto a = 1;}
13+
{C auto a = 1;}
14+
{C<> auto a = 1;}
15+
{C<int> auto a = 1;}
16+
{ns::D<int> auto a = 1;}
17+
{const ns::D auto &a = 1;}
18+
{const C auto &a = 1;}
19+
{const C<> auto &a = 1;}
20+
{const C<int> auto &a = 1;}
21+
{const ns::D<int> auto &a = 1;}
22+
{C decltype(auto) a = 1;}
23+
{C<> decltype(auto) a = 1;}
24+
{C<int> decltype(auto) a = 1;}
25+
{const C<> decltype(auto) &a = 1;} // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
1726
// expected-error@-1{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
18-
const C<int> decltype(auto) &a14 = 1; // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
27+
{const C<int> decltype(auto) &a = 1;} // expected-error{{'decltype(auto)' cannot be combined with other type specifiers}}
1928
// expected-error@-1{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
20-
C a15 = 1;
29+
{C a = 1;}
2130
// expected-error@-1{{expected 'auto' or 'decltype(auto)' after concept name}}
22-
C decltype a19 = 1;
31+
{C decltype a19 = 1;}
2332
// expected-error@-1{{expected '('}}
24-
C decltype(1) a20 = 1;
33+
{C decltype(1) a20 = 1;}
2534
// expected-error@-1{{expected 'auto' or 'decltype(auto)' after concept name}}
2635
}

0 commit comments

Comments
 (0)