PR19339: Disambiguate lambdas with init-captures from designated initializers

properly.

llvm-svn: 206128
This commit is contained in:
Richard Smith 2014-04-13 04:31:48 +00:00
parent 0563ca1be8
commit 9e2f0a4f62
3 changed files with 32 additions and 40 deletions

View File

@ -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

View File

@ -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,

View File

@ -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) {