Update parser's disambiguation to cope with braced function-style casts in
C++11, and with braced-init-list initializers in conditions. This exposed an
ambiguity with enum underlying types versus bitfields, which we resolve by
treating 'enum E : T {' as always defining an enumeration (even if it would
only successfully parse as a bitfield). This appears to be g++ compatible.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@151227 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 4193890..4d93eaf 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -3000,9 +3000,15 @@
 
         // Consume the ':'.
         ConsumeToken();
-      
-        if ((getLang().CPlusPlus && 
-             isCXXDeclarationSpecifier() != TPResult::True()) ||
+
+        // If we see a type specifier followed by an open-brace, we have an
+        // ambiguity between an underlying type and a C++11 braced
+        // function-style cast. Resolve this by always treating it as an
+        // underlying type.
+        // FIXME: The standard is not entirely clear on how to disambiguate in
+        // this case.
+        if ((getLang().CPlusPlus &&
+             isCXXDeclarationSpecifier(TPResult::True()) != TPResult::True()) ||
             (!getLang().CPlusPlus && !isDeclarationSpecifier(true))) {
           // We'll parse this as a bitfield later.
           PossibleBitfield = true;
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 987ae65..35c418c 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -233,6 +233,8 @@
 ///       condition:
 ///         expression
 ///         type-specifier-seq declarator '=' assignment-expression
+/// [C++11] type-specifier-seq declarator '=' initializer-clause
+/// [C++11] type-specifier-seq declarator braced-init-list
 /// [GNU]   type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
 ///             '=' assignment-expression
 ///
@@ -274,6 +276,8 @@
     if (Tok.is(tok::equal)  ||
         Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
       TPR = TPResult::True();
+    else if (getLang().CPlusPlus0x && Tok.is(tok::l_brace))
+      TPR = TPResult::True();
     else
       TPR = TPResult::False();
   }
@@ -834,7 +838,8 @@
 ///           'volatile'
 /// [GNU]     restrict
 ///
-Parser::TPResult Parser::isCXXDeclarationSpecifier() {
+Parser::TPResult
+Parser::isCXXDeclarationSpecifier(Parser::TPResult BracedCastResult) {
   switch (Tok.getKind()) {
   case tok::identifier:   // foo::bar
     // Check for need to substitute AltiVec __vector keyword
@@ -849,7 +854,7 @@
       return TPResult::Error();
     if (Tok.is(tok::identifier))
       return TPResult::False();
-    return isCXXDeclarationSpecifier();
+    return isCXXDeclarationSpecifier(BracedCastResult);
 
   case tok::coloncolon: {    // ::foo::bar
     const Token &Next = NextToken();
@@ -863,7 +868,7 @@
     // recurse to handle whatever we get.
     if (TryAnnotateTypeOrScopeToken())
       return TPResult::Error();
-    return isCXXDeclarationSpecifier();
+    return isCXXDeclarationSpecifier(BracedCastResult);
 
     // decl-specifier:
     //   storage-class-specifier
@@ -965,7 +970,7 @@
           bool isIdentifier = Tok.is(tok::identifier);
           TPResult TPR = TPResult::False();
           if (!isIdentifier)
-            TPR = isCXXDeclarationSpecifier();
+            TPR = isCXXDeclarationSpecifier(BracedCastResult);
           PA.Revert();
 
           if (isIdentifier ||
@@ -1005,6 +1010,7 @@
       
       TPResult TPR = TryParseProtocolQualifiers();
       bool isFollowedByParen = Tok.is(tok::l_paren);
+      bool isFollowedByBrace = Tok.is(tok::l_brace);
       
       PA.Revert();
       
@@ -1013,6 +1019,9 @@
       
       if (isFollowedByParen)
         return TPResult::Ambiguous();
+
+      if (getLang().CPlusPlus0x && isFollowedByBrace)
+        return BracedCastResult;
       
       return TPResult::True();
     }
@@ -1036,6 +1045,15 @@
     if (NextToken().is(tok::l_paren))
       return TPResult::Ambiguous();
 
+    // This is a function-style cast in all cases we disambiguate other than
+    // one:
+    //   struct S {
+    //     enum E : int { a = 4 }; // enum
+    //     enum E : int { 4 };     // bit-field
+    //   };
+    if (getLang().CPlusPlus0x && NextToken().is(tok::l_brace))
+      return BracedCastResult;
+
     if (isStartOfObjCClassMessageMissingOpenBracket())
       return TPResult::False();
       
@@ -1050,6 +1068,7 @@
 
     TPResult TPR = TryParseTypeofSpecifier();
     bool isFollowedByParen = Tok.is(tok::l_paren);
+    bool isFollowedByBrace = Tok.is(tok::l_brace);
 
     PA.Revert();
 
@@ -1059,6 +1078,9 @@
     if (isFollowedByParen)
       return TPResult::Ambiguous();
 
+    if (getLang().CPlusPlus0x && isFollowedByBrace)
+      return BracedCastResult;
+
     return TPResult::True();
   }
 
@@ -1219,6 +1241,8 @@
     MaybeParseMicrosoftAttributes(attrs);
 
     // decl-specifier-seq
+    // A parameter-declaration's initializer must be preceded by an '=', so
+    // decl-specifier-seq '{' is not a parameter in C++11.
     TPResult TPR = TryParseDeclarationSpecifier();
     if (TPR != TPResult::Ambiguous())
       return TPR;