Skip to content

Commit 458ea76

Browse files
committedJul 16, 2014
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 Review is tracked by http://reviews.llvm.org/D3653. This is an attempt to recommit the fix, initially committed as r212957 but then reverted in r212965 as it broke self-build. In the updated patch ParseDirectDeclarator turns on colon protection in for context as well. llvm-svn: 213120
1 parent c68237b commit 458ea76

File tree

5 files changed

+157
-24
lines changed

5 files changed

+157
-24
lines changed
 

‎clang/lib/Parse/ParseDecl.cpp

+18-9
Original file line numberDiff line numberDiff line change
@@ -2715,24 +2715,23 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS,
27152715
// typedef-name
27162716
case tok::kw_decltype:
27172717
case tok::identifier: {
2718+
// This identifier can only be a typedef name if we haven't already seen
2719+
// a type-specifier. Without this check we misparse:
2720+
// typedef int X; struct Y { short X; }; as 'short int'.
2721+
if (DS.hasTypeSpecifier())
2722+
goto DoneWithDeclSpec;
2723+
27182724
// In C++, check to see if this is a scope specifier like foo::bar::, if
27192725
// so handle it as such. This is important for ctor parsing.
27202726
if (getLangOpts().CPlusPlus) {
27212727
if (TryAnnotateCXXScopeToken(EnteringContext)) {
2722-
if (!DS.hasTypeSpecifier())
2723-
DS.SetTypeSpecError();
2728+
DS.SetTypeSpecError();
27242729
goto DoneWithDeclSpec;
27252730
}
27262731
if (!Tok.is(tok::identifier))
27272732
continue;
27282733
}
27292734

2730-
// This identifier can only be a typedef name if we haven't already seen
2731-
// a type-specifier. Without this check we misparse:
2732-
// typedef int X; struct Y { short X; }; as 'short int'.
2733-
if (DS.hasTypeSpecifier())
2734-
goto DoneWithDeclSpec;
2735-
27362735
// Check for need to substitute AltiVec keyword tokens.
27372736
if (TryAltiVecToken(DS, Loc, PrevSpec, DiagID, isInvalid))
27382737
break;
@@ -4529,7 +4528,9 @@ void Parser::ParseDeclaratorInternal(Declarator &D,
45294528
// Member pointers get special handling, since there's no place for the
45304529
// scope spec in the generic path below.
45314530
if (getLangOpts().CPlusPlus &&
4532-
(Tok.is(tok::coloncolon) || Tok.is(tok::identifier) ||
4531+
(Tok.is(tok::coloncolon) ||
4532+
(Tok.is(tok::identifier) &&
4533+
(NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) ||
45334534
Tok.is(tok::annot_cxxscope))) {
45344535
bool EnteringContext = D.getContext() == Declarator::FileContext ||
45354536
D.getContext() == Declarator::MemberContext;
@@ -4722,6 +4723,14 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
47224723
DeclaratorScopeObj DeclScopeObj(*this, D.getCXXScopeSpec());
47234724

47244725
if (getLangOpts().CPlusPlus && D.mayHaveIdentifier()) {
4726+
// Don't parse FOO:BAR as if it were a typo for FOO::BAR inside a class, in
4727+
// this context it is a bitfield. Also in range-based for statement colon
4728+
// may delimit for-range-declaration.
4729+
ColonProtectionRAIIObject X(*this,
4730+
D.getContext() == Declarator::MemberContext ||
4731+
(D.getContext() == Declarator::ForContext &&
4732+
getLangOpts().CPlusPlus11));
4733+
47254734
// ParseDeclaratorInternal might already have parsed the scope.
47264735
if (D.getCXXScopeSpec().isEmpty()) {
47274736
bool EnteringContext = D.getContext() == Declarator::FileContext ||

‎clang/lib/Parse/ParseDeclCXX.cpp

+16-15
Original file line numberDiff line numberDiff line change
@@ -1239,7 +1239,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
12391239
// Parse the (optional) nested-name-specifier.
12401240
CXXScopeSpec &SS = DS.getTypeSpecScope();
12411241
if (getLangOpts().CPlusPlus) {
1242-
// "FOO : BAR" is not a potential typo for "FOO::BAR".
1242+
// "FOO : BAR" is not a potential typo for "FOO::BAR". In this context it
1243+
// is a base-specifier-list.
12431244
ColonProtectionRAIIObject X(*this);
12441245

12451246
if (ParseOptionalCXXScopeSpecifier(SS, ParsedType(), EnteringContext))
@@ -1926,14 +1927,8 @@ void Parser::ParseCXXMemberDeclaratorBeforeInitializer(
19261927
// declarator pure-specifier[opt]
19271928
// declarator brace-or-equal-initializer[opt]
19281929
// identifier[opt] ':' constant-expression
1929-
if (Tok.isNot(tok::colon)) {
1930-
// Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
1931-
// is a bitfield.
1932-
// FIXME: This should only apply when parsing the id-expression (see
1933-
// PR18587).
1934-
ColonProtectionRAIIObject X(*this);
1930+
if (Tok.isNot(tok::colon))
19351931
ParseDeclarator(DeclaratorInfo);
1936-
}
19371932

19381933
if (!DeclaratorInfo.isFunctionDeclarator() && TryConsumeToken(tok::colon)) {
19391934
BitfieldSize = ParseConstantExpression();
@@ -2015,6 +2010,14 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
20152010
return;
20162011
}
20172012

2013+
// Turn on colon protection early, while parsing declspec, although there is
2014+
// nothing to protect there. It prevents from false errors if error recovery
2015+
// incorrectly determines where the declspec ends, as in the example:
2016+
// struct A { enum class B { C }; };
2017+
// const int C = 4;
2018+
// struct D { A::B : C; };
2019+
ColonProtectionRAIIObject X(*this);
2020+
20182021
// Access declarations.
20192022
bool MalformedTypeSpec = false;
20202023
if (!TemplateInfo.Kind &&
@@ -2128,13 +2131,11 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
21282131
if (MalformedTypeSpec)
21292132
DS.SetTypeSpecError();
21302133

2131-
{
2132-
// Don't parse FOO:BAR as if it were a typo for FOO::BAR, in this context it
2133-
// is a bitfield.
2134-
ColonProtectionRAIIObject X(*this);
2135-
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
2136-
&CommonLateParsedAttrs);
2137-
}
2134+
ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class,
2135+
&CommonLateParsedAttrs);
2136+
2137+
// Turn off colon protection that was set for declspec.
2138+
X.restore();
21382139

21392140
// If we had a free-standing type definition with a missing semicolon, we
21402141
// may get this far before the problem becomes obvious.

‎clang/test/SemaCXX/enum-bitfield.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,15 @@ struct Y {
1616
enum E : int(2);
1717
enum E : Z(); // expected-error{{integral constant expression must have integral or unscoped enumeration type, not 'Z'}}
1818
};
19+
20+
namespace pr18587 {
21+
struct A {
22+
enum class B {
23+
C
24+
};
25+
};
26+
const int C = 4;
27+
struct D {
28+
A::B : C;
29+
};
30+
}

‎clang/test/SemaCXX/for-range-examples.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,15 @@ namespace test7 {
227227
for (e [[deprecated]] : arr) { e = 0; } // expected-warning {{deprecated}} expected-note {{here}} expected-warning {{extension}}
228228
}
229229
}
230+
231+
namespace pr18587 {
232+
class Arg {};
233+
struct Cont {
234+
int *begin();
235+
int *end();
236+
};
237+
void AddAllArgs(Cont &x) {
238+
for (auto Arg: x) {
239+
}
240+
}
241+
}

‎clang/test/SemaCXX/nested-name-spec.cpp

+99
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,102 @@ namespace N {
311311

312312
namespace TypedefNamespace { typedef int F; };
313313
TypedefNamespace::F::NonexistentName BadNNSWithCXXScopeSpec; // expected-error {{'F' (aka 'int') is not a class, namespace, or scoped enumeration}}
314+
315+
namespace PR18587 {
316+
317+
struct C1 {
318+
int a, b, c;
319+
typedef int C2;
320+
struct B1 {
321+
struct B2 {
322+
int a, b, c;
323+
};
324+
};
325+
};
326+
struct C2 { static const unsigned N1 = 1; };
327+
struct B1 {
328+
enum E1 { B2 = 2 };
329+
static const int B3 = 3;
330+
};
331+
const int N1 = 2;
332+
333+
// Function declarators
334+
struct S1a { int f(C1::C2); };
335+
struct S1b { int f(C1:C2); }; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
336+
337+
struct S2a {
338+
C1::C2 f(C1::C2);
339+
};
340+
struct S2c {
341+
C1::C2 f(C1:C2); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
342+
};
343+
344+
struct S3a {
345+
int f(C1::C2), C2 : N1;
346+
int g : B1::B2;
347+
};
348+
struct S3b {
349+
int g : B1:B2; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
350+
};
351+
352+
// Inside square brackets
353+
struct S4a {
354+
int f[C2::N1];
355+
};
356+
struct S4b {
357+
int f[C2:N1]; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
358+
};
359+
360+
struct S5a {
361+
int f(int xx[B1::B3 ? C2::N1 : B1::B2]);
362+
};
363+
struct S5b {
364+
int f(int xx[B1::B3 ? C2::N1 : B1:B2]); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
365+
};
366+
struct S5c {
367+
int f(int xx[B1:B3 ? C2::N1 : B1::B2]); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
368+
};
369+
370+
// Bit fields
371+
struct S6a {
372+
C1::C2 m1 : B1::B2;
373+
};
374+
struct S6c {
375+
C1::C2 m1 : B1:B2; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
376+
};
377+
struct S6d {
378+
int C2:N1;
379+
};
380+
struct S6e {
381+
static const int N = 3;
382+
B1::E1 : N;
383+
};
384+
struct S6g {
385+
C1::C2 : B1:B2; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
386+
B1::E1 : B1:B2; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
387+
};
388+
389+
// Template parameters
390+
template <int N> struct T1 {
391+
int a,b,c;
392+
static const unsigned N1 = N;
393+
typedef unsigned C1;
394+
};
395+
T1<C2::N1> var_1a;
396+
T1<C2:N1> var_1b; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
397+
template<int N> int F() {}
398+
int (*X1)() = (B1::B2 ? F<1> : F<2>);
399+
int (*X2)() = (B1:B2 ? F<1> : F<2>); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
400+
401+
// Bit fields + templates
402+
struct S7a {
403+
T1<B1::B2>::C1 m1 : T1<B1::B2>::N1;
404+
};
405+
struct S7b {
406+
T1<B1:B2>::C1 m1 : T1<B1::B2>::N1; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
407+
};
408+
struct S7c {
409+
T1<B1::B2>::C1 m1 : T1<B1:B2>::N1; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}}
410+
};
411+
412+
}

0 commit comments

Comments
 (0)
Please sign in to comment.