From: Richard Smith Date: Sun, 13 Apr 2014 04:31:48 +0000 (+0000) Subject: PR19339: Disambiguate lambdas with init-captures from designated initializers X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0446558506ede662c42d7ff2e3db5b21a5db2c02;p=clang PR19339: Disambiguate lambdas with init-captures from designated initializers properly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206128 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index f10ca6ab78..6495d193f7 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -837,8 +837,8 @@ Optional 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 diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index 44053f193b..bdd4513167 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -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 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, diff --git a/test/Parser/cxx0x-lambda-expressions.cpp b/test/Parser/cxx0x-lambda-expressions.cpp index 53ea05ea86..8cfe7f3b02 100644 --- a/test/Parser/cxx0x-lambda-expressions.cpp +++ b/test/Parser/cxx0x-lambda-expressions.cpp @@ -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) {