Index: lib/Parse/ParseDecl.cpp =================================================================== --- lib/Parse/ParseDecl.cpp +++ lib/Parse/ParseDecl.cpp @@ -2706,7 +2706,7 @@ case tok::identifier: { // 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 (getLangOpts().CPlusPlus && !DS.hasTypeSpecifier()) { if (TryAnnotateCXXScopeToken(EnteringContext)) { if (!DS.hasTypeSpecifier()) DS.SetTypeSpecError(); @@ -4508,8 +4508,10 @@ // 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::annot_cxxscope))) { + (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; CXXScopeSpec SS; @@ -4701,6 +4703,11 @@ DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec()); if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) { + // Don't parse FOO:BAR as if it were a typo for FOO::BAR, 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 || Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -1228,7 +1228,8 @@ // 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 base-specifier-list. ColonProtectionRAIIObject X(*this); if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext)) @@ -1913,14 +1914,8 @@ // 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(); @@ -2115,13 +2110,8 @@ 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); // If we had a free-standing type definition with a missing semicolon, we // may get this far before the problem becomes obvious. Index: test/SemaCXX/nested-name-spec.cpp =================================================================== --- test/SemaCXX/nested-name-spec.cpp +++ test/SemaCXX/nested-name-spec.cpp @@ -311,3 +311,116 @@ 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 { 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 S2b { + C1:C2 f(C1::C2); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} +}; +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 S6b { + C1:C2 m1 : B1::B2; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} +}; +struct S6c { + C1::C2 m1 : B1:B2; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} +}; +struct S6d { + int C2:N1; +}; + +// 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 '::'?}} +}; + +// Member pointers +struct S8a { + C1::C2 C1::*m1; +}; +struct S8b { + C1:C2 C1::*m1; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} +}; + +// nested types +struct S9a { + typedef C1::C2 t1; +}; +struct S9b { + typedef C1:C2 t1; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} +}; + +}