Fix miscompile and rejects-valids when disambiguating after an ambiguous
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 3 Feb 2016 02:58:20 +0000 (02:58 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 3 Feb 2016 02:58:20 +0000 (02:58 +0000)
C-style-cast to function/array type or parenthesized function-style cast/array
indexing.

llvm-svn: 259622

clang/lib/Parse/ParseExpr.cpp
clang/test/Parser/cxx-ambig-paren-expr.cpp

index ad23804..13b7722 100644 (file)
@@ -1010,15 +1010,24 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
     //   unary-expression:
     //     ++ cast-expression
     //     -- cast-expression
-    SourceLocation SavedLoc = ConsumeToken();
+    Token SavedTok = Tok;
+    ConsumeToken();
     // One special case is implicitly handled here: if the preceding tokens are
     // an ambiguous cast expression, such as "(T())++", then we recurse to
     // determine whether the '++' is prefix or postfix.
     Res = ParseCastExpression(!getLangOpts().CPlusPlus,
                               /*isAddressOfOperand*/false, NotCastExpr,
-                              NotTypeCast);
+                              isTypeCast);
+    if (NotCastExpr) {
+      // If we return with NotCastExpr = true, we must not consume any tokens,
+      // so put the token back where we found it.
+      assert(Res.isInvalid());
+      UnconsumeToken(SavedTok);
+      return ExprError();
+    }
     if (!Res.isInvalid())
-      Res = Actions.ActOnUnaryOp(getCurScope(), SavedLoc, SavedKind, Res.get());
+      Res = Actions.ActOnUnaryOp(getCurScope(), SavedTok.getLocation(),
+                                 SavedKind, Res.get());
     return Res;
   }
   case tok::amp: {         // unary-expression: '&' cast-expression
index 3988205..1535b00 100644 (file)
@@ -21,8 +21,13 @@ void f() {
   struct S{int operator()();};
   (S())();
 
-  // FIXME: Special case: "++" is postfix here, not prefix
-  // (S())++;
+  // Special case: "++" is postfix here, not prefix
+  (S())++; // expected-error {{cannot increment value of type 'S'}}
+
+  struct X { int &operator++(int); X operator[](int); int &operator++(); };
+  int &postfix_incr = (X()[3])++;
+  (X())++ ++; // ok, not a C-style cast
+  (X())++ ++X(); // expected-error {{C-style cast from 'int' to 'X ()'}}
 }
 
 // Make sure we do tentative parsing correctly in conditions.