diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 3526ffb40f350..7107293abffd8 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -737,6 +737,8 @@ Crash and bug fixes ``[[assume(expr)]]`` attribute was enclosed in parentheses. (#GH151529) - Fixed a crash when parsing ``#embed`` parameters with unmatched closing brackets. (#GH152829) - Fixed a crash when compiling ``__real__`` or ``__imag__`` unary operator on scalar value with type promotion. (#GH160583) +- Fixed a crash when parsing invalid nested name specifier sequences + containing a single colon. (#GH167905) Improvements ^^^^^^^^^^^^ diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h index d9dc5a562d802..43091a6f3a8c6 100644 --- a/clang/include/clang/Lex/Token.h +++ b/clang/include/clang/Lex/Token.h @@ -100,13 +100,19 @@ class Token { /// is/isNot - Predicates to check if this token is a specific kind, as in /// "if (Tok.is(tok::l_brace)) {...}". bool is(tok::TokenKind K) const { return Kind == K; } - bool isNot(tok::TokenKind K) const { return Kind != K; } template bool isOneOf(Ts... Ks) const { static_assert(sizeof...(Ts) > 0, "requires at least one tok::TokenKind specified"); return (is(Ks) || ...); } + bool isNot(tok::TokenKind K) const { return Kind != K; } + template bool isNoneOf(Ts... Ks) const { + static_assert(sizeof...(Ts) > 0, + "requires at least one tok::TokenKind specified"); + return (isNot(Ks) && ...); + } + /// Return true if this is a raw identifier (when lexing /// in raw mode) or a non-keyword identifier (when lexing in non-raw mode). bool isAnyIdentifier() const { diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index 82f2294ff5bb7..9622a00687ca5 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1063,7 +1063,7 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, return TPResult::False; } - if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) { + if (Next.isNoneOf(tok::coloncolon, tok::less, tok::colon)) { // Determine whether this is a valid expression. If not, we will hit // a parse error one way or another. In that case, tell the caller that // this is ambiguous. Typo-correct to type and expression keywords and diff --git a/clang/test/Parser/cxx-nested-name-spec.cpp b/clang/test/Parser/cxx-nested-name-spec.cpp new file mode 100644 index 0000000000000..3a551a4f2221f --- /dev/null +++ b/clang/test/Parser/cxx-nested-name-spec.cpp @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +namespace a { b c ( a:c:: +// expected-error@-1 {{unknown type name 'b'}} +// expected-error@-2 {{unexpected ':' in nested name specifier; did you mean '::'?}} +// expected-error@-3 {{no member named 'c' in namespace 'a'}} +// expected-error@-4 {{expected ';' after top level declarator}} +// expected-note@-5 {{to match this '{'}} +// expected-error@+1 {{expected unqualified-id}} \ +// expected-error@+1 {{expected '}'}}