summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Parse/Parser.h6
-rw-r--r--clang/lib/Parse/ParseDecl.cpp12
-rw-r--r--clang/lib/Parse/ParseTentative.cpp32
-rw-r--r--clang/test/Parser/cxx0x-ambig.cpp92
-rw-r--r--clang/test/Parser/cxx0x-condition.cpp8
5 files changed, 137 insertions, 13 deletions
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index 27e86ebab69..079a93fb5b8 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -1828,9 +1828,11 @@ private:
/// declaration specifier, TPResult::False() if it is not,
/// TPResult::Ambiguous() if it could be either a decl-specifier or a
/// function-style cast, and TPResult::Error() if a parsing error was
- /// encountered.
+ /// encountered. If it could be a braced C++11 function-style cast, returns
+ /// BracedCastResult.
/// Doesn't consume tokens.
- TPResult isCXXDeclarationSpecifier();
+ TPResult
+ isCXXDeclarationSpecifier(TPResult BracedCastResult = TPResult::False());
// "Tentative parsing" functions, used for disambiguation. If a parsing error
// is encountered they will return TPResult::Error().
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 41938900210..4d93eaf85d5 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3000,9 +3000,15 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
// 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/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp
index 987ae65d066..35c418cb7ef 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -233,6 +233,8 @@ Parser::TPResult Parser::TryParseInitDeclaratorList() {
/// 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 @@ bool Parser::isCXXConditionDeclaration() {
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 @@ Parser::isExpressionOrTypeSpecifierSimple(tok::TokenKind Kind) {
/// '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 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
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 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
// 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 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
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 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
TPResult TPR = TryParseProtocolQualifiers();
bool isFollowedByParen = Tok.is(tok::l_paren);
+ bool isFollowedByBrace = Tok.is(tok::l_brace);
PA.Revert();
@@ -1013,6 +1019,9 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
if (isFollowedByParen)
return TPResult::Ambiguous();
+
+ if (getLang().CPlusPlus0x && isFollowedByBrace)
+ return BracedCastResult;
return TPResult::True();
}
@@ -1036,6 +1045,15 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
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 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
TPResult TPR = TryParseTypeofSpecifier();
bool isFollowedByParen = Tok.is(tok::l_paren);
+ bool isFollowedByBrace = Tok.is(tok::l_brace);
PA.Revert();
@@ -1059,6 +1078,9 @@ Parser::TPResult Parser::isCXXDeclarationSpecifier() {
if (isFollowedByParen)
return TPResult::Ambiguous();
+ if (getLang().CPlusPlus0x && isFollowedByBrace)
+ return BracedCastResult;
+
return TPResult::True();
}
@@ -1219,6 +1241,8 @@ Parser::TPResult Parser::TryParseParameterDeclarationClause() {
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;
diff --git a/clang/test/Parser/cxx0x-ambig.cpp b/clang/test/Parser/cxx0x-ambig.cpp
new file mode 100644
index 00000000000..c955dc16909
--- /dev/null
+++ b/clang/test/Parser/cxx0x-ambig.cpp
@@ -0,0 +1,92 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+
+// New exciting ambiguities in C++11
+
+// final 'context sensitive' mess.
+namespace final {
+ struct S { int n; };
+ namespace N {
+ int n;
+ // This defines a class, not a variable, even though it would successfully
+ // parse as a variable but not as a class. DR1318's wording suggests that
+ // this disambiguation is only performed on an ambiguity, but that was not
+ // the intent.
+ struct S final {
+ int(n) // expected-error {{expected ';'}}
+ };
+ }
+}
+
+// enum versus bitfield mess.
+namespace bitfield {
+ enum E {};
+
+ struct T {
+ constexpr T() {}
+ constexpr T(int) {}
+ constexpr T(T, T, T, T) {}
+ constexpr T operator=(T) { return *this; }
+ constexpr operator int() { return 4; }
+ };
+ constexpr T a, b, c, d;
+
+ struct S1 {
+ enum E : T ( a = 1, b = 2, c = 3, 4 ); // ok, declares a bitfield
+ };
+ // This could be a bit-field.
+ struct S2 {
+ enum E : T { a = 1, b = 2, c = 3, 4 }; // expected-error {{non-integral type}} expected-error {{expected '}'}} expected-note {{to match}}
+ };
+ struct S3 {
+ enum E : int { a = 1, b = 2, c = 3, d }; // ok, defines an enum
+ };
+ // Ambiguous.
+ struct S4 {
+ enum E : int { a = 1 }; // ok, defines an enum
+ };
+ // This could be a bit-field, but would be ill-formed due to the anonymous
+ // member being initialized.
+ struct S5 {
+ enum E : int { a = 1 } { b = 2 }; // expected-error {{expected member name}}
+ };
+ // This could be a bit-field.
+ struct S6 {
+ enum E : int { 1 }; // expected-error {{expected '}'}} expected-note {{to match}}
+ };
+
+ struct U {
+ constexpr operator T() { return T(); } // expected-note 2{{candidate}}
+ };
+ // This could be a bit-field.
+ struct S7 {
+ enum E : int { a = U() }; // expected-error {{no viable conversion}}
+ };
+ // This could be a bit-field, and does not conform to the grammar of an
+ // enum definition, because 'id(U())' is not a constant-expression.
+ constexpr const U &id(const U &u) { return u; }
+ struct S8 {
+ enum E : int { a = id(U()) }; // expected-error {{no viable conversion}}
+ };
+}
+
+namespace trailing_return {
+ typedef int n;
+ int a;
+
+ struct S {
+ S(int);
+ S *operator()() const;
+ int n;
+ };
+
+ namespace N {
+ void f() {
+ // This parses as a function declaration, but DR1223 makes the presence of
+ // 'auto' be used for disambiguation.
+ S(a)()->n; // ok, expression; expected-warning{{expression result unused}}
+ auto(a)()->n; // ok, function declaration
+ using T = decltype(a);
+ using T = auto() -> n;
+ }
+ }
+}
diff --git a/clang/test/Parser/cxx0x-condition.cpp b/clang/test/Parser/cxx0x-condition.cpp
index ce7d1a8aefd..e45cd866ff2 100644
--- a/clang/test/Parser/cxx0x-condition.cpp
+++ b/clang/test/Parser/cxx0x-condition.cpp
@@ -27,11 +27,11 @@ void f() {
if (S b(n) = 0) {} // expected-error {{a function type is not allowed here}}
if (S b(n) == 0) {} // expected-error {{a function type is not allowed here}} expected-error {{did you mean '='?}}
- // FIXME: this is legal, and incorrectly rejected, because tentative parsing
- // does not yet know about braced function-style casts.
- if (S{a}) {} // unexpected-error{{unqualified-id}}
-
+ if (S{a}) {} // ok
if (S a{a}) {} // ok
if (S a = {a}) {} // ok
if (S a == {a}) {} // expected-error {{did you mean '='?}}
+
+ if (S(b){a}) {} // ok
+ if (S(b) = {a}) {} // ok
}
OpenPOWER on IntegriCloud