]> granicus.if.org Git - clang/commitdiff
Handle ambiguities between expressions and type-ids that occur inside parentheses...
authorArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sun, 5 Oct 2008 19:56:22 +0000 (19:56 +0000)
committerArgyrios Kyrtzidis <akyrtzi@gmail.com>
Sun, 5 Oct 2008 19:56:22 +0000 (19:56 +0000)
sizeof(int()) -> "int()" is type-id
sizeof(int()+1) -> "int()+1" is expression.

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

include/clang/Parse/Parser.h
lib/Parse/ParseDecl.cpp
lib/Parse/ParseExpr.cpp
lib/Parse/ParseTentative.cpp
test/SemaCXX/decl-expr-ambiguity.cpp

index 7510219e3afc5c151340475ef133993fd15215e4..c1259c69654fa6a990ee7a7724fcb2af6de9bc6f 100644 (file)
@@ -591,6 +591,15 @@ private:
     return isDeclarationSpecifier();
   }
 
+  /// 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() {
+    if (getLang().CPlusPlus)
+      return isCXXTypeIdInParens();
+    return isTypeSpecifierQualifier();
+  }
+
   /// isCXXDeclarationStatement - C++-specialized function that disambiguates
   /// between a declaration or an expression statement, when parsing function
   /// bodies. Returns true for declaration, false for expression.
@@ -617,6 +626,13 @@ private:
   /// the function returns true to let the declaration parsing code handle it.
   bool isCXXConditionDeclaration();
 
+  /// isCXXTypeIdInParens - 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.
+  /// If during the disambiguation process a parsing error is encountered,
+  /// the function returns true to let the declaration parsing code handle it.
+  bool isCXXTypeIdInParens();
+
   /// TPResult - Used as the result value for functions whose purpose is to
   /// disambiguate C++ constructs by "tentatively parsing" them.
   /// This is a class instead of a simple enum because the implicit enum-to-bool
@@ -659,7 +675,7 @@ private:
   TPResult TryParseSimpleDeclaration();
   TPResult TryParseTypeofSpecifier();
   TPResult TryParseInitDeclaratorList();
-  TPResult TryParseDeclarator(bool mayBeAbstract);
+  TPResult TryParseDeclarator(bool mayBeAbstract, bool mayHaveIdentifier=true);
   TPResult TryParseParameterDeclarationClause();
   TPResult TryParseFunctionDeclarator();
   TPResult TryParseBracketDeclarator();
index eef071fd407b7ea2e4facd67af78c4acb8081d31..c22d9e871b0cbee7ad048f3769b98a4c775261d8 100644 (file)
@@ -1581,7 +1581,7 @@ void Parser::ParseTypeofSpecifier(DeclSpec &DS) {
 
   SourceLocation LParenLoc = ConsumeParen(), RParenLoc;
   
-  if (isTypeSpecifierQualifier()) {
+  if (isTypeIdInParens()) {
     TypeTy *Ty = ParseTypeName();
 
     assert(Ty && "Parser::ParseTypeofSpecifier(): missing type");
index 64f31ddbc80638a4e05f645ee0f093d83e610930..c8d95cf053c8830172e084844e2ede7aea3b3328 100644 (file)
@@ -981,7 +981,7 @@ Parser::ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType,
     if (!Stmt.isInvalid && Tok.is(tok::r_paren))
       Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.Val, Tok.getLocation());
     
-  } else if (ExprType >= CompoundLiteral && isTypeSpecifierQualifier()) {
+  } else if (ExprType >= CompoundLiteral && isTypeIdInParens()) {
     // Otherwise, this is a compound literal expression or cast expression.
     TypeTy *Ty = ParseTypeName();
 
index 2f1130ad742caa2ac7372691283f80bffaf2aa6a..9bd35dd11005d867237e32180abe02c4f938c69e 100644 (file)
@@ -282,6 +282,58 @@ bool Parser::isCXXConditionDeclaration() {
   return TPR == TPResult::True();
 }
 
+/// isCXXTypeIdInParens - Assumes that a '(' was parsed and now we want to\r
+/// know whether the parens contain an expression or a type-id.\r
+/// Returns true for a type-id and false for an expression.\r
+/// If during the disambiguation process a parsing error is encountered,\r
+/// the function returns true to let the declaration parsing code handle it.\r
+///\r
+/// type-id:\r
+///   type-specifier-seq abstract-declarator[opt]
+///
+bool Parser::isCXXTypeIdInParens() {
+  TPResult TPR = isCXXDeclarationSpecifier();
+  if (TPR != TPResult::Ambiguous())
+    return TPR != TPResult::False(); // Returns true for TPResult::True() or
+                                     // TPResult::Error().
+
+  // FIXME: Add statistics about the number of ambiguous statements encountered
+  // and how they were resolved (number of declarations+number of expressions).
+
+  // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
+  // We need tentative parsing...
+
+  TentativeParsingAction PA(*this);
+
+  // type-specifier-seq
+  if (Tok.is(tok::kw_typeof))
+    TryParseTypeofSpecifier();
+  else
+    ConsumeToken();
+  assert(Tok.is(tok::l_paren) && "Expected '('");
+
+  // declarator
+  TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/);
+
+  // In case of an error, let the declaration parsing code handle it.
+  if (TPR == TPResult::Error())
+    TPR = TPResult::True();
+
+  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 (Tok.is(tok::r_paren))
+      TPR = TPResult::True();
+    else
+      TPR = TPResult::False();
+  }
+
+  PA.Revert();
+
+  assert(TPR == TPResult::True() || TPR == TPResult::False());
+  return TPR == TPResult::True();
+}
+
 ///         declarator:
 ///           direct-declarator
 ///           ptr-operator declarator
@@ -332,7 +384,8 @@ bool Parser::isCXXConditionDeclaration() {
 ///           '~' class-name                                              [TODO]
 ///           template-id                                                 [TODO]
 ///
-Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract) {
+Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
+                                            bool mayHaveIdentifier) {
   // declarator:
   //   direct-declarator
   //   ptr-operator declarator
@@ -353,7 +406,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract) {
   // direct-declarator:
   // direct-abstract-declarator:
 
-  if (Tok.is(tok::identifier)) {
+  if (Tok.is(tok::identifier) && mayHaveIdentifier) {
     // declarator-id
     ConsumeToken();
   } else if (Tok.is(tok::l_paren)) {
@@ -370,7 +423,7 @@ Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract) {
       ConsumeParen();
       if (Tok.is(tok::kw___attribute))
         return TPResult::True(); // attributes indicate declaration
-      TPResult TPR = TryParseDeclarator(mayBeAbstract);
+      TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
       if (TPR != TPResult::Ambiguous())
         return TPR;
       if (Tok.isNot(tok::r_paren))
index 63f744a2c476b0a19f8422e73a4a32a6d4f2fad0..35805abac57b6dce70f465f01ab7fffa50938caa 100644 (file)
@@ -13,6 +13,8 @@ void f() {
   void(a), ++a; // expected-warning {{statement was disambiguated as expression}} expected-warning {{expression result unused}}
   if (int(a)+1) {}
   for (int(a)+1;;) {}
+  a = sizeof(int()+1);
+  typeof(int()+1) a2;
 
   // Declarations.
   T(*d)(int(p)); // expected-warning {{statement was disambiguated as declaration}} expected-error {{previous definition is here}}