r212957 - Improve error recovery around colon.
Reid Kleckner
rnk at google.com
Mon Jul 14 11:28:45 PDT 2014
This broke the self-host on llvm/lib/Option/ArgList.cpp, so I reverted it
in r212965.
On Mon, Jul 14, 2014 at 9:42 AM, Serge Pavlov <sepavloff at gmail.com> wrote:
> Author: sepavloff
> Date: Mon Jul 14 11:42:20 2014
> New Revision: 212957
>
> URL: http://llvm.org/viewvc/llvm-project?rev=212957&view=rev
> Log:
> Improve error recovery around colon.
>
> Recognize additional cases, when '::' is mistyped as ':'.
> This is a fix to RP18587 - colons have too much protection in
> member-declarations.
>
> Differential Revision: http://reviews.llvm.org/D3653
>
> Modified:
> cfe/trunk/lib/Parse/ParseDecl.cpp
> cfe/trunk/lib/Parse/ParseDeclCXX.cpp
> cfe/trunk/test/SemaCXX/enum-bitfield.cpp
> cfe/trunk/test/SemaCXX/nested-name-spec.cpp
>
> Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=212957&r1=212956&r2=212957&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseDecl.cpp Mon Jul 14 11:42:20 2014
> @@ -2715,24 +2715,23 @@ void Parser::ParseDeclarationSpecifiers(
> // 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)) {
> - if (!DS.hasTypeSpecifier())
> - DS.SetTypeSpecError();
> + 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;
> @@ -4529,7 +4528,9 @@ void Parser::ParseDeclaratorInternal(Dec
> // 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) ||
> + (Tok.is(tok::coloncolon) ||
> + (Tok.is(tok::identifier) &&
> + (NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) ||
> Tok.is(tok::annot_cxxscope))) {
> bool EnteringContext = D.getContext() == Declarator::FileContext ||
> D.getContext() == Declarator::MemberContext;
> @@ -4722,6 +4723,11 @@ void Parser::ParseDirectDeclarator(Decla
> 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 ||
>
> Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=212957&r1=212956&r2=212957&view=diff
>
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Jul 14 11:42:20 2014
> @@ -1239,7 +1239,8 @@ void Parser::ParseClassSpecifier(tok::To
> // Parse the (optional) nested-name-specifier.
> CXXScopeSpec &SS = DS.getTypeSpecScope();
> if (getLangOpts().CPlusPlus) {
> - // "FOO : BAR" is not a potential typo for "FOO::BAR".
> + // "FOO : BAR" is not a potential typo for "FOO::BAR". In this
> context it
> + // is a base-specifier-list.
> ColonProtectionRAIIObject X(*this);
>
> if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
> @@ -1926,14 +1927,8 @@ void Parser::ParseCXXMemberDeclaratorBef
> // declarator pure-specifier[opt]
> // declarator brace-or-equal-initializer[opt]
> // identifier[opt] ':' constant-expression
> - 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);
> + if (Tok.isNot(tok::colon))
> ParseDeclarator(DeclaratorInfo);
> - }
>
> if (!DeclaratorInfo.isFunctionDeclarator() &&
> TryConsumeToken(tok::colon)) {
> BitfieldSize = ParseConstantExpression();
> @@ -2015,6 +2010,14 @@ void Parser::ParseCXXClassMemberDeclarat
> 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 &&
> @@ -2128,13 +2131,11 @@ void Parser::ParseCXXClassMemberDeclarat
> if (MalformedTypeSpec)
> DS.SetTypeSpecError();
>
> - {
> - // 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);
> - }
> + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
> + &CommonLateParsedAttrs);
> +
> + // Turn off colon protection that was set for declspec.
> + X.restore();
>
> // If we had a free-standing type definition with a missing semicolon,
> we
> // may get this far before the problem becomes obvious.
>
> Modified: cfe/trunk/test/SemaCXX/enum-bitfield.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/enum-bitfield.cpp?rev=212957&r1=212956&r2=212957&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/enum-bitfield.cpp (original)
> +++ cfe/trunk/test/SemaCXX/enum-bitfield.cpp Mon Jul 14 11:42:20 2014
> @@ -16,3 +16,15 @@ 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;
> +};
> +}
>
> Modified: cfe/trunk/test/SemaCXX/nested-name-spec.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nested-name-spec.cpp?rev=212957&r1=212956&r2=212957&view=diff
>
> ==============================================================================
> --- cfe/trunk/test/SemaCXX/nested-name-spec.cpp (original)
> +++ cfe/trunk/test/SemaCXX/nested-name-spec.cpp Mon Jul 14 11:42:20 2014
> @@ -311,3 +311,102 @@ 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 <int N> struct T1 {
> + int a,b,c;
> + static const unsigned N1 = N;
> + typedef unsigned C1;
> +};
> +T1<C2::N1> var_1a;
> +T1<C2:N1> var_1b; // expected-error{{unexpected ':' in nested name
> specifier; did you mean '::'?}}
> +template<int N> 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<B1::B2>::C1 m1 : T1<B1::B2>::N1;
> +};
> +struct S7b {
> + T1<B1:B2>::C1 m1 : T1<B1::B2>::N1; // expected-error{{unexpected ':'
> in nested name specifier; did you mean '::'?}}
> +};
> +struct S7c {
> + T1<B1::B2>::C1 m1 : T1<B1:B2>::N1; // expected-error{{unexpected ':'
> in nested name specifier; did you mean '::'?}}
> +};
> +
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140714/4806de10/attachment.html>
More information about the cfe-commits
mailing list