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;