From 919b9557b4f0155dfaaea309493ff2a702fca676 Mon Sep 17 00:00:00 2001 From: Richard Trieu Date: Fri, 2 Nov 2012 01:08:58 +0000 Subject: [PATCH] When finding a '(' after '::', emit error with hint to remove '(' and matching ')', if found. Don't crash. Fixes PR11852. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@167268 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/DiagnosticParseKinds.td | 2 + include/clang/Parse/Parser.h | 2 + lib/Parse/ParseExprCXX.cpp | 45 ++++++++++++++++++++- test/Parser/colon-colon-parentheses.cpp | 22 ++++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 test/Parser/colon-colon-parentheses.cpp diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index 846f37ab40..235b2da62f 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -348,6 +348,8 @@ def ext_c11_static_assert : Extension< def warn_cxx98_compat_static_assert : Warning< "static_assert declarations are incompatible with C++98">, InGroup, DefaultIgnore; +def err_paren_after_colon_colon : Error< + "unexpected parentheses after '::'">; /// Objective-C parser diagnostics def err_expected_minus_or_plus : Error< diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 20b13baf69..e16aeadb08 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -1327,6 +1327,8 @@ private: bool *MayBePseudoDestructor = 0, bool IsTypename = false); + void CheckForLParenAfterColonColon(); + //===--------------------------------------------------------------------===// // C++0x 5.1.2: Lambda expressions diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 63fcf34be3..2f615e150a 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -96,6 +96,45 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, /*AtDigraph*/false); } +/// \brief Emits an error for a left parentheses after a double colon. +/// +/// When a '(' is found after a '::', emit an error. Attempt to fix the token +/// stream by removing the '(', and the matching ')' if it found. +void Parser::CheckForLParenAfterColonColon() { + if (!Tok.is(tok::l_paren)) + return; + + SourceLocation l_parenLoc = ConsumeParen(), r_parenLoc; + Token Tok1 = getCurToken(); + if (!Tok1.is(tok::identifier) && !Tok1.is(tok::star)) + return; + + if (Tok1.is(tok::identifier)) { + Token Tok2 = GetLookAheadToken(1); + if (Tok2.is(tok::r_paren)) { + ConsumeToken(); + PP.EnterToken(Tok1); + r_parenLoc = ConsumeParen(); + } + } else if (Tok1.is(tok::star)) { + Token Tok2 = GetLookAheadToken(1); + if (Tok2.is(tok::identifier)) { + Token Tok3 = GetLookAheadToken(2); + if (Tok3.is(tok::r_paren)) { + ConsumeToken(); + ConsumeToken(); + PP.EnterToken(Tok2); + PP.EnterToken(Tok1); + r_parenLoc = ConsumeParen(); + } + } + } + + Diag(l_parenLoc, diag::err_paren_after_colon_colon) + << FixItHint::CreateRemoval(l_parenLoc) + << FixItHint::CreateRemoval(r_parenLoc); +} + /// \brief Parse global scope or nested-name-specifier if present. /// /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which @@ -160,7 +199,9 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, // '::' - Global scope qualifier. if (Actions.ActOnCXXGlobalScopeSpecifier(getCurScope(), ConsumeToken(), SS)) return true; - + + CheckForLParenAfterColonColon(); + HasScopeSpecifier = true; } @@ -371,6 +412,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, "NextToken() not working properly!"); SourceLocation CCLoc = ConsumeToken(); + CheckForLParenAfterColonColon(); + HasScopeSpecifier = true; if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), II, IdLoc, CCLoc, ObjectType, EnteringContext, SS)) diff --git a/test/Parser/colon-colon-parentheses.cpp b/test/Parser/colon-colon-parentheses.cpp new file mode 100644 index 0000000000..e837bd9f43 --- /dev/null +++ b/test/Parser/colon-colon-parentheses.cpp @@ -0,0 +1,22 @@ +// RUN: %clang_cc1 %s -fsyntax-only -verify +// RUN: cp %s %t +// RUN: not %clang_cc1 -x c++ -fixit %t +// RUN: %clang_cc1 -x c++ %t + +struct S { static int a,b,c;}; +int S::(a); // expected-error{{unexpected parentheses after '::'}} +int S::(b; // expected-error{{unexpected parentheses after '::'}} +int S::c; +int S::(*d); // expected-error{{unexpected parentheses after '::'}} +int S::(*e; // expected-error{{unexpected parentheses after '::'}} +int S::*f; +int g = S::(a); // expected-error{{unexpected parentheses after '::'}} +int h = S::(b; // expected-error{{unexpected parentheses after '::'}} +int i = S::c; + +void foo() { + int a; + a = ::(g); // expected-error{{unexpected parentheses after '::'}} + a = ::(h; // expected-error{{unexpected parentheses after '::'}} + a = ::i; +}