From: Reid Kleckner Date: Mon, 14 Jul 2014 18:19:58 +0000 (+0000) Subject: Revert "Improve error recovery around colon." X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=a4ea60f7c008902fa21e79aa307930b52182d68a;p=clang Revert "Improve error recovery around colon." This reverts commit r212957. It broke the self-host on code like this from LLVM's option library: for (auto Arg: filtered(Id0, Id1, Id2)) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@212965 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 89f4fc9fb9..09f78e5a75 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2715,23 +2715,24 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // typedef-name case tok::kw_decltype: case tok::identifier: { - // This identifier can only be a typedef name if we haven't already seen - // a type-specifier. Without this check we misparse: - // typedef int X; struct Y { short X; }; as 'short int'. - if (DS.hasTypeSpecifier()) - goto DoneWithDeclSpec; - // In C++, check to see if this is a scope specifier like foo::bar::, if // so handle it as such. This is important for ctor parsing. if (getLangOpts().CPlusPlus) { if (TryAnnotateCXXScopeToken(EnteringContext)) { - DS.SetTypeSpecError(); + if (!DS.hasTypeSpecifier()) + DS.SetTypeSpecError(); goto DoneWithDeclSpec; } if (!Tok.is(tok::identifier)) continue; } + // This identifier can only be a typedef name if we haven't already seen + // a type-specifier. Without this check we misparse: + // typedef int X; struct Y { short X; }; as 'short int'. + if (DS.hasTypeSpecifier()) + goto DoneWithDeclSpec; + // Check for need to substitute AltiVec keyword tokens. if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid)) break; @@ -4528,9 +4529,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, // Member pointers get special handling, since there's no place for the // scope spec in the generic path below. if (getLangOpts().CPlusPlus && - (Tok.is(tok::coloncolon) || - (Tok.is(tok::identifier) && - (NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) || + (Tok.is(tok::coloncolon) || Tok.is(tok::identifier) || Tok.is(tok::annot_cxxscope))) { bool EnteringContext = D.getContext() == Declarator::FileContext || D.getContext() == Declarator::MemberContext; @@ -4723,11 +4722,6 @@ void Parser::ParseDirectDeclarator(Declarator &D) { DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { - // Don't parse FOO:BAR as if it were a typo for FOO::BAR inside a class, in - // this context it is a bitfield. - ColonProtectionRAIIObject X(*this, - D.getContext() == Declarator::MemberContext); - // ParseDeclaratorInternal might already have parsed the scope. if (D.getCXXScopeSpec().isEmpty()) { bool EnteringContext = D.getContext() == Declarator::FileContext || diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 6200363b3b..cd2e397188 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1239,8 +1239,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // Parse the (optional) nested-name-specifier. CXXScopeSpec &SS = DS.getTypeSpecScope(); if (getLangOpts().CPlusPlus) { - // "FOO : BAR" is not a potential typo for "FOO::BAR". In this context it - // is a base-specifier-list. + // "FOO : BAR" is not a potential typo for "FOO::BAR". ColonProtectionRAIIObject X(*this); if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) @@ -1927,8 +1926,14 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer( // declarator pure-specifier[opt] // declarator brace-or-equal-initializer[opt] // identifier[opt] ':' constant-expression - if (Tok.isNot(tok::colon)) + if (Tok.isNot(tok::colon)) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it + // is a bitfield. + // FIXME: This should only apply when parsing the id-expression (see + // PR18587). + ColonProtectionRAIIObject X(*this); ParseDeclarator(DeclaratorInfo); + } if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) { BitfieldSize = ParseConstantExpression(); @@ -2010,14 +2015,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, return; } - // Turn on colon protection early, while parsing declspec, although there is - // nothing to protect there. It prevents from false errors if error recovery - // incorrectly determines where the declspec ends, as in the example: - // struct A { enum class B { C }; }; - // const int C = 4; - // struct D { A::B : C; }; - ColonProtectionRAIIObject X(*this); - // Access declarations. bool MalformedTypeSpec = false; if (!TemplateInfo.Kind && @@ -2131,11 +2128,13 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, if (MalformedTypeSpec) DS.SetTypeSpecError(); - ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, - &CommonLateParsedAttrs); - - // Turn off colon protection that was set for declspec. - X.restore(); + { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it + // is a bitfield. + ColonProtectionRAIIObject X(*this); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class, + &CommonLateParsedAttrs); + } // If we had a free-standing type definition with a missing semicolon, we // may get this far before the problem becomes obvious. diff --git a/test/SemaCXX/enum-bitfield.cpp b/test/SemaCXX/enum-bitfield.cpp index ec849b79a7..63445ca058 100644 --- a/test/SemaCXX/enum-bitfield.cpp +++ b/test/SemaCXX/enum-bitfield.cpp @@ -16,15 +16,3 @@ struct Y { enum E : int(2); enum E : Z(); // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'Z'}} }; - -namespace pr18587 { -struct A { - enum class B { - C - }; -}; -const int C = 4; -struct D { - A::B : C; -}; -} diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index bdeb00d357..bfbf9c4135 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -311,102 +311,3 @@ namespace N { namespace TypedefNamespace { typedef int F; }; TypedefNamespace::F::NonexistentName BadNNSWithCXXScopeSpec; // expected-error {{'F' (aka 'int') is not a class, namespace, or scoped enumeration}} - -namespace PR18587 { - -struct C1 { - int a, b, c; - typedef int C2; - struct B1 { - struct B2 { - int a, b, c; - }; - }; -}; -struct C2 { static const unsigned N1 = 1; }; -struct B1 { - enum E1 { B2 = 2 }; - static const int B3 = 3; -}; -const int N1 = 2; - -// Function declarators -struct S1a { int f(C1::C2); }; -struct S1b { int f(C1:C2); }; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} - -struct S2a { - C1::C2 f(C1::C2); -}; -struct S2c { - C1::C2 f(C1:C2); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} -}; - -struct S3a { - int f(C1::C2), C2 : N1; - int g : B1::B2; -}; -struct S3b { - int g : B1:B2; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} -}; - -// Inside square brackets -struct S4a { - int f[C2::N1]; -}; -struct S4b { - int f[C2:N1]; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} -}; - -struct S5a { - int f(int xx[B1::B3 ? C2::N1 : B1::B2]); -}; -struct S5b { - int f(int xx[B1::B3 ? C2::N1 : B1:B2]); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} -}; -struct S5c { - int f(int xx[B1:B3 ? C2::N1 : B1::B2]); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} -}; - -// Bit fields -struct S6a { - C1::C2 m1 : B1::B2; -}; -struct S6c { - C1::C2 m1 : B1:B2; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} -}; -struct S6d { - int C2:N1; -}; -struct S6e { - static const int N = 3; - B1::E1 : N; -}; -struct S6g { - C1::C2 : B1:B2; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} - B1::E1 : B1:B2; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} -}; - -// Template parameters -template struct T1 { - int a,b,c; - static const unsigned N1 = N; - typedef unsigned C1; -}; -T1 var_1a; -T1 var_1b; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} -template int F() {} -int (*X1)() = (B1::B2 ? F<1> : F<2>); -int (*X2)() = (B1:B2 ? F<1> : F<2>); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} - -// Bit fields + templates -struct S7a { - T1::C1 m1 : T1::N1; -}; -struct S7b { - T1::C1 m1 : T1::N1; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} -}; -struct S7c { - T1::C1 m1 : T1::N1; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} -}; - -}