diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -251,6 +251,7 @@ - Address the thread identification problems in coroutines. `Issue 47177 `_ `Issue 47179 `_ +- Fix a crash upon stray coloncolon token in C2x mode. Improvements to Clang's diagnostics ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -866,10 +866,11 @@ bool TryAnnotateCXXScopeToken(bool EnteringContext = false); bool MightBeCXXScopeToken() { - return Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || - (Tok.is(tok::annot_template_id) && - NextToken().is(tok::coloncolon)) || - Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super); + return getLangOpts().CPlusPlus && + (Tok.is(tok::identifier) || Tok.is(tok::coloncolon) || + (Tok.is(tok::annot_template_id) && + NextToken().is(tok::coloncolon)) || + Tok.is(tok::kw_decltype) || Tok.is(tok::kw___super)); } bool TryAnnotateOptionalCXXScopeToken(bool EnteringContext = false) { return MightBeCXXScopeToken() && TryAnnotateCXXScopeToken(EnteringContext); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -5411,6 +5411,8 @@ return isDeclarationSpecifier(AllowImplicitTypename); case tok::coloncolon: // ::foo::bar + if (!getLangOpts().CPlusPlus) + return false; if (NextToken().is(tok::kw_new) || // ::new NextToken().is(tok::kw_delete)) // ::delete return false; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2080,9 +2080,9 @@ } if (!getLangOpts().CPlusPlus) { - // If we're in C, we can't have :: tokens at all (the lexer won't return - // them). If the identifier is not a type, then it can't be scope either, - // just early exit. + // If we're in C, the only place we can have :: tokens is C2x + // attribute which is parsed elsewhere. If the identifier is not a type, + // then it can't be scope either, just early exit. return false; } diff --git a/clang/test/Parser/c2x-attributes.c b/clang/test/Parser/c2x-attributes.c --- a/clang/test/Parser/c2x-attributes.c +++ b/clang/test/Parser/c2x-attributes.c @@ -141,3 +141,6 @@ struct [[]] S4 *s; // expected-error {{an attribute list cannot appear here}} struct S5 {}; int c = sizeof(struct [[]] S5); // expected-error {{an attribute list cannot appear here}} + +// Ensure that '::' outside of attributes does not crash and is not treated as scope +double n::v; // expected-error {{expected ';' after top level declarator}}