]> granicus.if.org Git - clang/commitdiff
When finding a '(' after '::', emit error with hint to remove '(' and matching
authorRichard Trieu <rtrieu@google.com>
Fri, 2 Nov 2012 01:08:58 +0000 (01:08 +0000)
committerRichard Trieu <rtrieu@google.com>
Fri, 2 Nov 2012 01:08:58 +0000 (01:08 +0000)
')', 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
include/clang/Parse/Parser.h
lib/Parse/ParseExprCXX.cpp
test/Parser/colon-colon-parentheses.cpp [new file with mode: 0644]

index 846f37ab406338358e33912567605bc3043ce910..235b2da62f299e849832627328285dd57ddfbe2b 100644 (file)
@@ -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<CXX98Compat>, DefaultIgnore;
+def err_paren_after_colon_colon : Error<
+  "unexpected parentheses after '::'">;
 
 /// Objective-C parser diagnostics
 def err_expected_minus_or_plus : Error<
index 20b13baf69ba8d427947f6f22a56ff8645095fd7..e16aeadb08657f184223bc5f3ad9b1b167c0305f 100644 (file)
@@ -1327,6 +1327,8 @@ private:
                                       bool *MayBePseudoDestructor = 0,
                                       bool IsTypename = false);
 
+  void CheckForLParenAfterColonColon();
+
   //===--------------------------------------------------------------------===//
   // C++0x 5.1.2: Lambda expressions
 
index 63fcf34be393d47b2e1ffa578b386180e9cd1be3..2f615e150aada0d6ffb6c07b7a619d70ab75dc47 100644 (file)
@@ -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 (file)
index 0000000..e837bd9
--- /dev/null
@@ -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;
+}