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
|
// [..., x = expr
|
||||||
//
|
//
|
||||||
// We need to find the end of the following expression in order to
|
// 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
|
// determine whether this is an Obj-C message send's receiver, a
|
||||||
// lambda init-capture.
|
// C99 designator, or a lambda init-capture.
|
||||||
//
|
//
|
||||||
// Parse the expression to find where it ends, and annotate it back
|
// Parse the expression to find where it ends, and annotate it back
|
||||||
// onto the tokens. We would have parsed this expression the same way
|
// 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
|
// 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);
|
TentativeParsingAction Tentative(*this);
|
||||||
ConsumeBracket();
|
|
||||||
while (true) {
|
LambdaIntroducer Intro;
|
||||||
switch (Tok.getKind()) {
|
bool SkippedInits = false;
|
||||||
case tok::equal:
|
Optional<unsigned> DiagID(ParseLambdaIntroducer(Intro, &SkippedInits));
|
||||||
case tok::amp:
|
|
||||||
case tok::identifier:
|
if (DiagID) {
|
||||||
case tok::kw_this:
|
// If this can't be a lambda capture list, it's a designator.
|
||||||
// These tokens can occur in a capture list or a constant-expression.
|
Tentative.Revert();
|
||||||
// Keep looking.
|
return true;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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,
|
static void CheckArrayDesignatorSyntax(Parser &P, SourceLocation Loc,
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
enum E { e };
|
enum E { e };
|
||||||
|
|
||||||
|
constexpr int id(int n) { return n; }
|
||||||
|
|
||||||
class C {
|
class C {
|
||||||
|
|
||||||
int f() {
|
int f() {
|
||||||
|
@ -34,12 +36,18 @@ class C {
|
||||||
typedef int T;
|
typedef int T;
|
||||||
const int b = 0;
|
const int b = 0;
|
||||||
const int c = 1;
|
const int c = 1;
|
||||||
|
int d;
|
||||||
int a1[1] = {[b] (T()) {}}; // expected-error{{no viable conversion from '(lambda}}
|
int a1[1] = {[b] (T()) {}}; // expected-error{{no viable conversion from '(lambda}}
|
||||||
int a2[1] = {[b] = 1 };
|
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 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 a5[3] = { []{return 0;}() };
|
||||||
int a6[1] = {[this] = 1 }; // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'C *'}}
|
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) {
|
void delete_lambda(int *p) {
|
||||||
|
|
Loading…
Reference in New Issue