]> granicus.if.org Git - clang/commitdiff
PR19339: Disambiguate lambdas with init-captures from designated initializers
authorRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 13 Apr 2014 04:31:48 +0000 (04:31 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Sun, 13 Apr 2014 04:31:48 +0000 (04:31 +0000)
properly.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@206128 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Parse/ParseExprCXX.cpp
lib/Parse/ParseInit.cpp
test/Parser/cxx0x-lambda-expressions.cpp

index f10ca6ab784ed0ef8727daa4063623a5e6c17884..6495d193f7c81d54ee2a75ff0f01461f6829992c 100644 (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
index 44053f193bd42c334e922ee0926982613ef8e1eb..bdd45131676c90f66c57d3d297909ea94d75124c 100644 (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.\13
+  // 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,
index 53ea05ea8609456f3575b8ae67e0cb0aee15cb4f..8cfe7f3b02da09e32abb3d9edcd78315fbc2f76f 100644 (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) {