]> granicus.if.org Git - clang/commitdiff
Remove special error recovery for ::(id)
authorReid Kleckner <rnk@google.com>
Fri, 9 Dec 2016 21:10:43 +0000 (21:10 +0000)
committerReid Kleckner <rnk@google.com>
Fri, 9 Dec 2016 21:10:43 +0000 (21:10 +0000)
The code pattern used to implement the token rewriting hack doesn't
interact well with token caching in the pre-processor. As a result,
clang would crash on 'int f(::(id));' while doing a tenative parse of
the contents of the outer parentheses. The original code from PR11852
still doesn't crash the compiler.

This error recovery also often does the wrong thing with member function
pointers. The test case from the original PR doesn't recover the right
way either:
  void S::(*pf)() = S::f; // should be 'void (S::*pf)()'

Instead we were recovering as 'void S::*pf()', which is still wrong.

If we still think that users mistakenly parenthesize identifiers in
nested name specifiers, we should change clang to intentionally parse
that form with an error, rather than doing a token rewrite.

Fixes PR26623, but I think there will be many more bugs like this around
token rewriting in the parser.

Reviewers: rsmith, rtrieu

Differential Revision: https://reviews.llvm.org/D25882

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@289273 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

index ecebda9924244edb75a48c88f7a3d520d387a0f5..8aa3e1ccb318e7ce6441b26288142824fdb0778e 100644 (file)
@@ -347,8 +347,6 @@ 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 parenthesis after '::'">;
 def err_function_definition_not_allowed : Error<
   "function definition is not allowed here">;
 def err_expected_end_of_enumerator : Error<
index 40eb579be4652a8b2b3678e03a6b48df3c5ed3b3..c956aaeffcfdc525866b8023681a9551157ed735 100644 (file)
@@ -1530,8 +1530,6 @@ private:
                                       bool IsTypename = false,
                                       IdentifierInfo **LastII = nullptr);
 
-  void CheckForLParenAfterColonColon();
-
   //===--------------------------------------------------------------------===//
   // C++0x 5.1.2: Lambda expressions
 
index cabc7b5266dfcc4c5638754f7e082dff88af5d10..3f335747a4ae95684663370b706a77cd8cda6d2e 100644 (file)
@@ -100,48 +100,6 @@ 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 found.
-void Parser::CheckForLParenAfterColonColon() {
-  if (!Tok.is(tok::l_paren))
-    return;
-
-  Token LParen = Tok;
-  Token NextTok = GetLookAheadToken(1);
-  Token StarTok = NextTok;
-  // Check for (identifier or (*identifier
-  Token IdentifierTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : StarTok;
-  if (IdentifierTok.isNot(tok::identifier))
-    return;
-  // Eat the '('.
-  ConsumeParen();
-  Token RParen;
-  RParen.setLocation(SourceLocation());
-  // Do we have a ')' ?
-  NextTok = StarTok.is(tok::star) ? GetLookAheadToken(2) : GetLookAheadToken(1);
-  if (NextTok.is(tok::r_paren)) {
-    RParen = NextTok;
-    // Eat the '*' if it is present.
-    if (StarTok.is(tok::star))
-      ConsumeToken();
-    // Eat the identifier.
-    ConsumeToken();
-    // Add the identifier token back.
-    PP.EnterToken(IdentifierTok);
-    // Add the '*' back if it was present.
-    if (StarTok.is(tok::star))
-      PP.EnterToken(StarTok);
-    // Eat the ')'.
-    ConsumeParen();
-  }
-
-  Diag(LParen.getLocation(), diag::err_paren_after_colon_colon)
-      << FixItHint::CreateRemoval(LParen.getLocation())
-      << FixItHint::CreateRemoval(RParen.getLocation());
-}
-
 /// \brief Parse global scope or nested-name-specifier if present.
 ///
 /// Parses a C++ global scope specifier ('::') or nested-name-specifier (which
@@ -237,8 +195,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
       if (Actions.ActOnCXXGlobalScopeSpecifier(ConsumeToken(), SS))
         return true;
 
-      CheckForLParenAfterColonColon();
-
       HasScopeSpecifier = true;
     }
   }
@@ -491,8 +447,6 @@ bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS,
       Token ColonColon = Tok;
       SourceLocation CCLoc = ConsumeToken();
 
-      CheckForLParenAfterColonColon();
-
       bool IsCorrectedToColon = false;
       bool *CorrectionFlagPtr = ColonIsSacred ? &IsCorrectedToColon : nullptr;
       if (Actions.ActOnCXXNestedNameSpecifier(getCurScope(), IdInfo,
index b3db4fbed2f11e28aa7af84308966ea764356fde..804e4f785ee635127ccb8381335fc8f383a57299 100644 (file)
@@ -1,30 +1,36 @@
-// RUN: %clang_cc1 %s -fsyntax-only -verify -DPR21815
-// RUN: cp %s %t
-// RUN: not %clang_cc1 -x c++ -fixit %t
-// RUN: %clang_cc1 -x c++ %t
+// RUN: %clang_cc1 %s -verify -fno-spell-checking
 
 struct S { static int a,b,c;};
-int S::(a);  // expected-error{{unexpected parenthesis after '::'}}
-int S::(b;  // expected-error{{unexpected parenthesis after '::'}}
+int S::(a);  // expected-error{{expected unqualified-id}}
+int S::(b;  // expected-error{{expected unqualified-id}}
+        );
 int S::c;
-int S::(*d);  // expected-error{{unexpected parenthesis after '::'}}
-int S::(*e;  // expected-error{{unexpected parenthesis after '::'}}
+int S::(*d);  // expected-error{{expected unqualified-id}}
+int S::(*e;  // expected-error{{expected unqualified-id}}
+        );
 int S::*f;
-int g = S::(a);  // expected-error{{unexpected parenthesis after '::'}}
-int h = S::(b;  // expected-error{{unexpected parenthesis after '::'}}
+int g = S::(a);  // expected-error {{expected unqualified-id}} expected-error {{use of undeclared identifier 'a'}}
+int h = S::(b;  // expected-error {{expected unqualified-id}} expected-error {{use of undeclared identifier 'b'}}
+            );
 int i = S::c;
 
 void foo() {
   int a;
-  a = ::(g);  // expected-error{{unexpected parenthesis after '::'}}
-  a = ::(h;  // expected-error{{unexpected parenthesis after '::'}}
+  a = ::(g);  // expected-error{{expected unqualified-id}}
+  a = ::(h;  // expected-error{{expected unqualified-id}}
   a = ::i;
 }
 
-#ifdef PR21815
+// The following tests used to be crash bugs.
+
+// PR21815
 // expected-error@+2{{C++ requires a type specifier for all declarations}}
 // expected-error@+1{{expected unqualified-id}}
 a (::( ));
 
 ::((c )); // expected-error{{expected unqualified-id}}
-#endif
+
+// PR26623
+int f1(::(B) p); // expected-error {{expected unqualified-id}} expected-error {{use of undeclared identifier 'B'}}
+
+int f2(::S::(C) p); // expected-error {{expected unqualified-id}} expected-error {{use of undeclared identifier 'C'}}