[cfe-commits] r72260 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseTentative.cpp test/Parser/cxx-ambig-paren-expr.cpp

Argiris Kirtzidis akyrtzi at gmail.com
Fri May 22 03:24:43 PDT 2009


Author: akirtzidis
Date: Fri May 22 05:24:42 2009
New Revision: 72260

URL: http://llvm.org/viewvc/llvm-project?rev=72260&view=rev
Log:
Handle correctly a very ugly part of the C++ syntax. We cannot disambiguate between a parenthesized type-id and
a paren expression without considering the context past the parentheses.

Behold:
  (T())x;  - type-id
  (T())*x; - type-id
  (T())/x; - expression
  (T());   - expression

Added:
    cfe/trunk/test/Parser/cxx-ambig-paren-expr.cpp
Modified:
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/ParseTentative.cpp

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=72260&r1=72259&r2=72260&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri May 22 05:24:42 2009
@@ -661,6 +661,9 @@
   OwningExprResult ParseRHSOfBinaryExpression(OwningExprResult LHS,
                                               unsigned MinPrec);
   OwningExprResult ParseCastExpression(bool isUnaryExpression,
+                                       bool isAddressOfOperand,
+                                       bool &NotCastExpr);
+  OwningExprResult ParseCastExpression(bool isUnaryExpression,
                                        bool isAddressOfOperand = false);
   OwningExprResult ParsePostfixExpressionSuffix(OwningExprResult LHS);
   OwningExprResult ParseSizeofAlignofExpression();
@@ -690,6 +693,11 @@
                                         TypeTy *&CastTy,
                                         SourceLocation &RParenLoc);
   
+  OwningExprResult ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
+                                                    TypeTy *&CastTy,
+                                                    SourceLocation LParenLoc,
+                                                    SourceLocation &RParenLoc);
+  
   OwningExprResult ParseCompoundLiteralExpression(TypeTy *Ty,
                                                   SourceLocation LParenLoc,
                                                   SourceLocation RParenLoc);
@@ -918,11 +926,16 @@
   /// isTypeIdInParens - Assumes that a '(' was parsed and now we want to know
   /// whether the parens contain an expression or a type-id.
   /// Returns true for a type-id and false for an expression.
-  bool isTypeIdInParens() {
+  bool isTypeIdInParens(bool &isAmbiguous) {
     if (getLang().CPlusPlus)
-      return isCXXTypeId(TypeIdInParens);
+      return isCXXTypeId(TypeIdInParens, isAmbiguous);
+    isAmbiguous = false;
     return isTypeSpecifierQualifier();
   }
+  bool isTypeIdInParens() {
+    bool isAmbiguous;
+    return isTypeIdInParens(isAmbiguous);
+  }
 
   /// isCXXDeclarationStatement - C++-specialized function that disambiguates
   /// between a declaration or an expression statement, when parsing function
@@ -951,7 +964,11 @@
   /// the function returns true to let the declaration parsing code handle it.
   bool isCXXConditionDeclaration();
 
-  bool isCXXTypeId(TentativeCXXTypeIdContext Context);
+  bool isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous);
+  bool isCXXTypeId(TentativeCXXTypeIdContext Context) {
+    bool isAmbiguous;
+    return isCXXTypeId(Context, isAmbiguous);
+  }
 
   /// TPResult - Used as the result value for functions whose purpose is to
   /// disambiguate C++ constructs by "tentatively parsing" them.

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Fri May 22 05:24:42 2009
@@ -400,6 +400,23 @@
 /// id-expression that is the operand of address-of gets special treatment
 /// due to member pointers.
 ///
+Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
+                                                     bool isAddressOfOperand) {
+  bool NotCastExpr;
+  OwningExprResult Res = ParseCastExpression(isUnaryExpression,
+                                             isAddressOfOperand,
+                                             NotCastExpr);
+  if (NotCastExpr)
+    Diag(Tok, diag::err_expected_expression);
+  return move(Res);
+}
+
+/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
+/// true, parse a unary-expression. isAddressOfOperand exists because an
+/// id-expression that is the operand of address-of gets special treatment
+/// due to member pointers. NotCastExpr is set to true if the token is not the
+/// start of a cast-expression, and no diagnostic is emitted in this case.
+///
 ///       cast-expression: [C99 6.5.4]
 ///         unary-expression
 ///         '(' type-name ')' cast-expression
@@ -506,9 +523,11 @@
 ///                   '__is_base_of'                          [TODO]
 ///
 Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression,
-                                                     bool isAddressOfOperand) {
+                                                     bool isAddressOfOperand,
+                                                     bool &NotCastExpr) {
   OwningExprResult Res(Actions);
   tok::TokenKind SavedKind = Tok.getKind();
+  NotCastExpr = false;
   
   // This handles all of cast-expression, unary-expression, postfix-expression,
   // and primary-expression.  We handle them together like this for efficiency
@@ -797,7 +816,7 @@
       return ParsePostfixExpressionSuffix(ParseObjCMessageExpression());
     // FALL THROUGH.      
   default:
-    Diag(Tok, diag::err_expected_expression);
+    NotCastExpr = true;
     return ExprError();
   }
 
@@ -1216,6 +1235,7 @@
   GreaterThanIsOperatorScope G(GreaterThanIsOperator, true);
   SourceLocation OpenLoc = ConsumeParen();
   OwningExprResult Result(Actions, true);
+  bool isAmbiguousTypeId;
   CastTy = 0;
 
   if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) {
@@ -1227,9 +1247,20 @@
     if (!Stmt.isInvalid() && Tok.is(tok::r_paren))
       Result = Actions.ActOnStmtExpr(OpenLoc, move(Stmt), Tok.getLocation());
 
-  } else if (ExprType >= CompoundLiteral && isTypeIdInParens()) {
+  } else if (ExprType >= CompoundLiteral &&
+             isTypeIdInParens(isAmbiguousTypeId)) {
     
     // Otherwise, this is a compound literal expression or cast expression.
+    
+    // In C++, if the type-id is ambiguous we disambiguate based on context.
+    // If stopIfCastExpr is true the context is a typeof/sizeof/alignof
+    // in which case we should treat it as type-id.
+    // if stopIfCastExpr is false, we need to determine the context past the
+    // parens, so we defer to ParseCXXAmbiguousParenExpression for that.
+    if (isAmbiguousTypeId && !stopIfCastExpr)
+      return ParseCXXAmbiguousParenExpression(ExprType, CastTy,
+                                              OpenLoc, RParenLoc);
+    
     TypeResult Ty = ParseTypeName();
 
     // Match the ')'.

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Fri May 22 05:24:42 2009
@@ -1038,3 +1038,110 @@
 
   return Actions.ActOnUnaryTypeTrait(UTT, Loc, LParen, Ty.get(), RParen);
 }
+
+/// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a
+/// parenthesized ambiguous type-id. This uses tentative parsing to disambiguate
+/// based on the context past the parens.
+Parser::OwningExprResult
+Parser::ParseCXXAmbiguousParenExpression(ParenParseOption &ExprType,
+                                         TypeTy *&CastTy,
+                                         SourceLocation LParenLoc,
+                                         SourceLocation &RParenLoc) {
+  assert(getLang().CPlusPlus && "Should only be called for C++!");
+  assert(ExprType == CastExpr && "Compound literals are not ambiguous!");
+  assert(isTypeIdInParens() && "Not a type-id!");
+
+  OwningExprResult Result(Actions, true);
+  CastTy = 0;
+
+  // We need to disambiguate a very ugly part of the C++ syntax:
+  //
+  // (T())x;  - type-id
+  // (T())*x; - type-id
+  // (T())/x; - expression
+  // (T());   - expression
+  //
+  // The bad news is that we cannot use the specialized tentative parser, since
+  // it can only verify that the thing inside the parens can be parsed as
+  // type-id, it is not useful for determining the context past the parens.
+  //
+  // The good news is that the parser can disambiguate this part without
+  // making any unnecessary Action calls (apart from isTypeName).
+
+  // 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();
+    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);
+  }
+
+  // We parsed '(' type-name ')' and the thing after it wasn't a '{'.
+
+  if (DeclaratorInfo.isInvalidType()) {
+    PA.Commit();
+    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();
+    if (!Result.isInvalid())
+      Result = Actions.ActOnCastExpr(LParenLoc, CastTy, RParenLoc,move(Result));
+    return move(Result);
+  }
+
+  // If we get here, it means 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;
+  if (!Result.isInvalid() && Tok.is(tok::r_paren))
+    Result = Actions.ActOnParenExpr(LParenLoc, Tok.getLocation(), move(Result));
+
+  // Match the ')'.
+  if (Result.isInvalid()) {
+    SkipUntil(tok::r_paren);
+    return ExprError();
+  }
+
+  if (Tok.is(tok::r_paren))
+    RParenLoc = ConsumeParen();
+  else
+    MatchRHSPunctuation(tok::r_paren, LParenLoc);
+
+  return move(Result);
+}

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseTentative.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTentative.cpp Fri May 22 05:24:42 2009
@@ -287,7 +287,9 @@
   /// type-id:
   ///   type-specifier-seq abstract-declarator[opt]
   ///
-bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context) {
+bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
+  
+  isAmbiguous = false;
 
   // C++ 8.2p2:
   // The ambiguity arising from the similarity between a function-style cast and
@@ -326,16 +328,20 @@
   if (TPR == TPResult::Ambiguous()) {
     // We are supposed to be inside parens, so if after the abstract declarator
     // we encounter a ')' this is a type-id, otherwise it's an expression.
-    if (Context == TypeIdInParens && Tok.is(tok::r_paren))
+    if (Context == TypeIdInParens && Tok.is(tok::r_paren)) {
       TPR = TPResult::True();
+      isAmbiguous = true;
+
     // We are supposed to be inside a template argument, so if after
     // the abstract declarator we encounter a '>', '>>' (in C++0x), or
     // ',', this is a type-id. Otherwise, it's an expression.
-    else if (Context == TypeIdAsTemplateArgument &&
-             (Tok.is(tok::greater) || Tok.is(tok::comma) ||
-              (getLang().CPlusPlus0x && Tok.is(tok::greatergreater))))
+    } else if (Context == TypeIdAsTemplateArgument &&
+               (Tok.is(tok::greater) || Tok.is(tok::comma) ||
+                (getLang().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
       TPR = TPResult::True();
-    else
+      isAmbiguous = true;
+
+    } else
       TPR = TPResult::False();
   }
 

Added: cfe/trunk/test/Parser/cxx-ambig-paren-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-ambig-paren-expr.cpp?rev=72260&view=auto

==============================================================================
--- cfe/trunk/test/Parser/cxx-ambig-paren-expr.cpp (added)
+++ cfe/trunk/test/Parser/cxx-ambig-paren-expr.cpp Fri May 22 05:24:42 2009
@@ -0,0 +1,15 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f() {
+  typedef int T;
+  int x, *px;
+  
+  // Type id.
+  (T())x;    // expected-error {{used type 'T (void)'}}
+  (T())+x;   // expected-error {{used type 'T (void)'}}
+  (T())*px;  // expected-error {{used type 'T (void)'}}
+  
+  // Expression.
+  x = (T());
+  x = (T())/x;
+}





More information about the cfe-commits mailing list