[cfe-commits] r72279 - /cfe/trunk/lib/Parse/ParseExprCXX.cpp

Argiris Kirtzidis akyrtzi at gmail.com
Fri May 22 14:09:48 PDT 2009


Author: akirtzidis
Date: Fri May 22 16:09:47 2009
New Revision: 72279

URL: http://llvm.org/viewvc/llvm-project?rev=72279&view=rev
Log:
The disambiguation process for ambiguous paren expressions is not "side effects free", e.g:

  (T(*)(int[x+y]));

is an (invalid) paren expression, but "x+y" will be parsed as part of the (rejected) type-id,
so unnecessary Action calls are made for an unused (and possibly leaked) "x+y".

Use a different scheme, similar to parsing inline methods. The parenthesized tokens are cached,
the context that follows is determined (possibly by parsing a cast-expression),
and then we re-introduce the cached tokens into the token stream and parse them appropriately.

Modified:
    cfe/trunk/lib/Parse/ParseExprCXX.cpp

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=72279&r1=72278&r2=72279&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Fri May 22 16:09:47 2009
@@ -1067,68 +1067,82 @@
   //
   // The good news is that the parser can disambiguate this part without
   // making any unnecessary Action calls.
-
-  // Start tentantive parsing.
-  TentativeParsingAction PA(*this);
-
-  // Parse the type-id but don't create a type with ActOnTypeName yet.
-  DeclSpec DS;
-  ParseSpecifierQualifierList(DS);
-
-  // Parse the abstract-declarator, if present.
-  Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
-  ParseDeclarator(DeclaratorInfo);
-
-  if (!Tok.is(tok::r_paren)) {
-    PA.Commit();
+  //
+  // It uses a scheme similar to parsing inline methods. The parenthesized
+  // tokens are cached, the context that follows is determined (possibly by
+  // parsing a cast-expression), and then we re-introduce the cached tokens
+  // into the token stream and parse them appropriately.
+
+  ParenParseOption ParseAs;  
+  CachedTokens Toks;
+
+  // Store the tokens of the parentheses. We will parse them after we determine
+  // the context that follows them.
+  if (!ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks, tok::semi)) {
+    // We didn't find the ')' we expected.
     MatchRHSPunctuation(tok::r_paren, LParenLoc);
     return ExprError();
   }
 
-  RParenLoc = ConsumeParen();
-
   if (Tok.is(tok::l_brace)) {
-    // Compound literal. Ok, we can commit the parsed tokens and continue
-    // normal parsing.
-    ExprType = CompoundLiteral;
-    PA.Commit();
-    TypeResult Ty = true;
-    if (!DeclaratorInfo.isInvalidType())
-      Ty = Actions.ActOnTypeName(CurScope, DeclaratorInfo);
-    return ParseCompoundLiteralExpression(Ty.get(), LParenLoc, RParenLoc);
+    ParseAs = CompoundLiteral;
+  } else {
+    bool NotCastExpr;
+    // Try parsing the cast-expression that may follow.
+    // If it is not a cast-expression, NotCastExpr will be true and no token
+    // will be consumed.
+    Result = ParseCastExpression(false/*isUnaryExpression*/,
+                                 false/*isAddressofOperand*/,
+                                 NotCastExpr);
+
+    // If we parsed a cast-expression, it's really a type-id, otherwise it's
+    // an expression.
+    ParseAs = NotCastExpr ? SimpleExpr : CastExpr;
   }
 
-  // We parsed '(' type-name ')' and the thing after it wasn't a '{'.
+  // The current token should go after the cached tokens. 
+  Toks.push_back(Tok);
+  // Re-enter the stored parenthesized tokens into the token stream, so we may
+  // parse them now.
+  PP.EnterTokenStream(Toks.data(), Toks.size(),
+                      true/*DisableMacroExpansion*/, false/*OwnsTokens*/);
+  // Drop the current token and bring the first cached one. It's the same token
+  // as when we entered this function.
+  ConsumeAnyToken();
+
+  if (ParseAs >= CompoundLiteral) {
+    TypeResult Ty = ParseTypeName();
+
+    // Match the ')'.
+    if (Tok.is(tok::r_paren))
+      RParenLoc = ConsumeParen();
+    else
+      MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+    if (ParseAs == CompoundLiteral) {
+      ExprType = CompoundLiteral;
+      return ParseCompoundLiteralExpression(Ty.get(), LParenLoc, RParenLoc);
+    }
+    
+    // We parsed '(' type-id ')' and the thing after it wasn't a '{'.
+    assert(ParseAs == CastExpr);
 
-  if (DeclaratorInfo.isInvalidType()) {
-    PA.Commit();
-    return ExprError();
-  }
+    if (Ty.isInvalid())
+      return ExprError();
 
-  bool NotCastExpr;
-  // Parse the cast-expression that follows it next.
-  Result = ParseCastExpression(false/*isUnaryExpression*/,
-                               false/*isAddressofOperand*/,
-                               NotCastExpr);
-
-  if (NotCastExpr == false) {
-    // We parsed a cast-expression. That means it's really a type-id, so commit
-    // the parsed tokens and continue normal parsing.
-    PA.Commit();
-    TypeResult Ty = Actions.ActOnTypeName(CurScope, DeclaratorInfo);
     CastTy = Ty.get();
+
+    // Result is what ParseCastExpression returned earlier.
     if (!Result.isInvalid())
       Result = Actions.ActOnCastExpr(LParenLoc, CastTy, RParenLoc,move(Result));
     return move(Result);
   }
+  
+  // Not a compound literal, and not followed by a cast-expression.
+  assert(ParseAs == SimpleExpr);
 
-  // If we get here, the things after the parens are not the start of
-  // a cast-expression. This means we must actually parse the tokens inside
-  // the parens as an expression.
-  PA.Revert();
-
-  Result = ParseExpression();
   ExprType = SimpleExpr;
+  Result = ParseExpression();
   if (!Result.isInvalid() && Tok.is(tok::r_paren))
     Result = Actions.ActOnParenExpr(LParenLoc, Tok.getLocation(), move(Result));
 
@@ -1137,7 +1151,7 @@
     SkipUntil(tok::r_paren);
     return ExprError();
   }
-
+  
   if (Tok.is(tok::r_paren))
     RParenLoc = ConsumeParen();
   else





More information about the cfe-commits mailing list