forked from OSchip/llvm-project
[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.
This commit is contained in:
parent
f29204d388
commit
5043962dd3
|
@ -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),
|
||||
|
|
|
@ -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);
|
|
@ -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@-1 {{expected ';' at end of requirement}}
|
||||
|
||||
bool r32 = requires { 0 noexcept; };
|
||||
bool r33 = requires { 0 noexcept; };
|
||||
// expected-error@-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@-1 {{expected ';' at end of requirement}}
|
||||
|
||||
bool r34 = requires { requires true };
|
||||
bool r35 = requires { requires true };
|
||||
// expected-error@-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@-1 {{expected ';' at end of requirement}}
|
||||
|
||||
bool r37 = requires { requires { 1; }; };
|
||||
bool r38 = requires { requires { 1; }; };
|
||||
// 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)}}
|
||||
|
||||
bool r38 = requires { requires () { 1; }; };
|
||||
bool r39 = requires { requires () { 1; }; };
|
||||
// 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)}}
|
||||
|
||||
bool r39 = requires { requires (int i) { i; }; };
|
||||
bool r40 = requires { requires (int i) { i; }; };
|
||||
// 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)}}
|
||||
|
||||
bool r40 = requires { requires (); };
|
||||
bool r41 = requires { requires (); };
|
||||
// expected-error@-1 {{expected expression}}
|
||||
|
|
|
@ -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@-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@-1{{non-const lvalue reference to type 'int' cannot bind to a temporary of type 'int'}}
|
||||
C a15 = 1;
|
||||
{C a = 1;}
|
||||
// expected-error@-1{{expected 'auto' or 'decltype(auto)' after concept name}}
|
||||
C decltype a19 = 1;
|
||||
{C decltype a19 = 1;}
|
||||
// expected-error@-1{{expected '('}}
|
||||
C decltype(1) a20 = 1;
|
||||
{C decltype(1) a20 = 1;}
|
||||
// expected-error@-1{{expected 'auto' or 'decltype(auto)' after concept name}}
|
||||
}
|
Loading…
Reference in New Issue