forked from OSchip/llvm-project
PR19339: Disambiguate lambdas with init-captures from designated initializers
properly. llvm-svn: 206128
This commit is contained in:
parent
0563ca1be8
commit
9e2f0a4f62
|
@ -837,8 +837,8 @@ Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro,
|
|||
// [..., x = expr
|
||||
//
|
||||
// We need to find the end of the following expression in order to
|
||||
// determine whether this is an Obj-C message send's receiver, or a
|
||||
// lambda init-capture.
|
||||
// determine whether this is an Obj-C message send's receiver, a
|
||||
// C99 designator, or a lambda init-capture.
|
||||
//
|
||||
// Parse the expression to find where it ends, and annotate it back
|
||||
// onto the tokens. We would have parsed this expression the same way
|
||||
|
|
|
@ -66,45 +66,29 @@ bool Parser::MayBeDesignationStart() {
|
|||
}
|
||||
|
||||
// Parse up to (at most) the token after the closing ']' to determine
|
||||
// whether this is a C99 designator or a lambda.
|
||||
// whether this is a C99 designator or a lambda.
|
||||
TentativeParsingAction Tentative(*this);
|
||||
ConsumeBracket();
|
||||
while (true) {
|
||||
switch (Tok.getKind()) {
|
||||
case tok::equal:
|
||||
case tok::amp:
|
||||
case tok::identifier:
|
||||
case tok::kw_this:
|
||||
// These tokens can occur in a capture list or a constant-expression.
|
||||
// Keep looking.
|
||||
ConsumeToken();
|
||||
continue;
|
||||
|
||||
case tok::comma:
|
||||
// Since a comma cannot occur in a constant-expression, this must
|
||||
// be a lambda.
|
||||
Tentative.Revert();
|
||||
return false;
|
||||
|
||||
case tok::r_square: {
|
||||
// Once we hit the closing square bracket, we look at the next
|
||||
// token. If it's an '=', this is a designator. Otherwise, it's a
|
||||
// lambda expression. This decision favors lambdas over the older
|
||||
// GNU designator syntax, which allows one to omit the '=', but is
|
||||
// consistent with GCC.
|
||||
ConsumeBracket();
|
||||
tok::TokenKind Kind = Tok.getKind();
|
||||
Tentative.Revert();
|
||||
return Kind == tok::equal;
|
||||
}
|
||||
|
||||
default:
|
||||
// Anything else cannot occur in a lambda capture list, so it
|
||||
// must be a designator.
|
||||
Tentative.Revert();
|
||||
return true;
|
||||
}
|
||||
|
||||
LambdaIntroducer Intro;
|
||||
bool SkippedInits = false;
|
||||
Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro, &SkippedInits));
|
||||
|
||||
if (DiagID) {
|
||||
// If this can't be a lambda capture list, it's a designator.
|
||||
Tentative.Revert();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Once we hit the closing square bracket, we look at the next
|
||||
// token. If it's an '=', this is a designator. Otherwise, it's a
|
||||
// lambda expression. This decision favors lambdas over the older
|
||||
// GNU designator syntax, which allows one to omit the '=', but is
|
||||
// consistent with GCC.
|
||||
tok::TokenKind Kind = Tok.getKind();
|
||||
// FIXME: If we didn't skip any inits, parse the lambda from here
|
||||
// rather than throwing away then reparsing the LambdaIntroducer.
|
||||
Tentative.Revert();
|
||||
return Kind == tok::equal;
|
||||
}
|
||||
|
||||
static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
enum E { e };
|
||||
|
||||
constexpr int id(int n) { return n; }
|
||||
|
||||
class C {
|
||||
|
||||
int f() {
|
||||
|
@ -34,12 +36,18 @@ class C {
|
|||
typedef int T;
|
||||
const int b = 0;
|
||||
const int c = 1;
|
||||
int d;
|
||||
int a1[1] = {[b] (T()) {}}; // expected-error{{no viable conversion from '(lambda}}
|
||||
int a2[1] = {[b] = 1 };
|
||||
int a3[1] = {[b,c] = 1 }; // expected-error{{expected body of lambda expression}}
|
||||
int a3[1] = {[b,c] = 1 }; // expected-error{{expected ']'}} expected-note {{to match}}
|
||||
int a4[1] = {[&b] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'const int *'}}
|
||||
int a5[3] = { []{return 0;}() };
|
||||
int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
|
||||
int a7[1] = {[d(0)] { return d; } ()}; // expected-warning{{extension}}
|
||||
int a8[1] = {[d = 0] { return d; } ()}; // expected-warning{{extension}}
|
||||
int a9[1] = {[d = 0] = 1}; // expected-error{{is not an integral constant expression}}
|
||||
int a10[1] = {[id(0)] { return id; } ()}; // expected-warning{{extension}}
|
||||
int a11[1] = {[id(0)] = 1};
|
||||
}
|
||||
|
||||
void delete_lambda(int *p) {
|
||||
|
|
Loading…
Reference in New Issue