Handle ambiguities between expressions and type-ids that occur inside parentheses, e.g.:

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
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 2f1130a..9bd35dd 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -282,6 +282,58 @@
   return TPR == TPResult::True();
 }
 
+/// 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.

+///

+/// type-id:

+///   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 @@
 ///           '~' 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 @@
   // 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 @@
       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))