]> granicus.if.org Git - clang/commitdiff
When disambiguating an expression-statement from a declaraton-statement, if the
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 23 Aug 2012 20:19:14 +0000 (20:19 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 23 Aug 2012 20:19:14 +0000 (20:19 +0000)
statement starts with an identifier for which name lookup will fail either way,
look at later tokens to disambiguate in order to improve error recovery.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162464 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Parse/ParseTentative.cpp
test/CXX/class.access/class.friend/p1.cpp
test/Modules/module-private.cpp
test/Parser/cxx-ambig-decl-expr.cpp
test/SemaObjCXX/category-lookup.mm

index 653f6c26ae7756bba548e2ebbbe9b8897517c4ad..01ab0e4eeaabe5ac491d55f6591859e86f3ded31 100644 (file)
@@ -104,16 +104,27 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
   // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such
   // a case.
 
-  TPResult TPR = isCXXDeclarationSpecifier();
+  bool InvalidAsDeclaration = false;
+  TPResult TPR = isCXXDeclarationSpecifier(TPResult::False(),
+                                           &InvalidAsDeclaration);
   if (TPR != TPResult::Ambiguous())
     return TPR != TPResult::False(); // Returns true for TPResult::True() or
                                      // TPResult::Error().
 
+  // FIXME: TryParseSimpleDeclaration doesn't look past the first initializer,
+  // and so gets some cases wrong. We can't carry on if we've already seen
+  // something which makes this statement invalid as a declaration in this case,
+  // since it can cause us to misparse valid code. Revisit this once
+  // TryParseInitDeclaratorList is fixed.
+  if (InvalidAsDeclaration)
+    return false;
+
   // FIXME: Add statistics about the number of ambiguous statements encountered
   // and how they were resolved (number of declarations+number of expressions).
 
-  // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
-  // We need tentative parsing...
+  // Ok, we have a simple-type-specifier/typename-specifier followed by a '(',
+  // or an identifier which doesn't resolve as anything. We need tentative
+  // parsing...
 
   TentativeParsingAction PA(*this);
   TPR = TryParseSimpleDeclaration(AllowForRangeDecl);
@@ -140,20 +151,28 @@ bool Parser::isCXXSimpleDeclaration(bool AllowForRangeDecl) {
 ///    attribute-specifier-seqopt type-specifier-seq declarator
 ///
 Parser::TPResult Parser::TryParseSimpleDeclaration(bool AllowForRangeDecl) {
-  // We know that we have a simple-type-specifier/typename-specifier followed
-  // by a '('.
-  assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous());
-
   if (Tok.is(tok::kw_typeof))
     TryParseTypeofSpecifier();
   else {
+    if (Tok.is(tok::annot_cxxscope))
+      ConsumeToken();
     ConsumeToken();
-    
+
     if (getLangOpts().ObjC1 && Tok.is(tok::less))
       TryParseProtocolQualifiers();
   }
-  
-  assert(Tok.is(tok::l_paren) && "Expected '('");
+
+  // Two decl-specifiers in a row conclusively disambiguate this as being a
+  // simple-declaration. Don't bother calling isCXXDeclarationSpecifier in the
+  // overwhelmingly common case that the next token is a '('.
+  if (Tok.isNot(tok::l_paren)) {
+    TPResult TPR = isCXXDeclarationSpecifier();
+    if (TPR == TPResult::Ambiguous())
+      return TPResult::True();
+    if (TPR == TPResult::True() || TPR == TPResult::Error())
+      return TPR;
+    assert(TPR == TPResult::False());
+  }
 
   TPResult TPR = TryParseInitDeclaratorList();
   if (TPR != TPResult::Ambiguous())
index 7cb192b5a1f3faa773ba4a77c8fb3970dba3d2e3..3d3c5f789acc3c600da474e29d85b8fa076d4675 100644 (file)
@@ -20,7 +20,7 @@ void test1() {
   g()->f();
   S::f();
   X::g(); // expected-error{{no member named 'g' in 'X'}}
-  X::S x_s; // expected-error{{no member named 'S' in 'X'}}
+  X::S x_s; // expected-error{{no type named 'S' in 'X'}}
   X x;
   x.g(); // expected-error{{no member named 'g' in 'X'}}
 }
@@ -44,16 +44,16 @@ namespace N {
     S s;
     S::f();
     X::g(); // expected-error{{no member named 'g' in 'N::X'}}
-    X::S x_s; // expected-error{{no member named 'S' in 'N::X'}}
+    X::S x_s; // expected-error{{no type named 'S' in 'N::X'}}
     X x;
     x.g(); // expected-error{{no member named 'g' in 'N::X'}}
 
     g2();
     S2 s2;
     ::g2(); // expected-error{{no member named 'g2' in the global namespace}}
-    ::S2 g_s2; // expected-error{{no member named 'S2' in the global namespace}}
+    ::S2 g_s2; // expected-error{{no type named 'S2' in the global namespace}}
     X::g2(); // expected-error{{no member named 'g2' in 'N::X'}}
-    X::S2 x_s2; // expected-error{{no member named 'S2' in 'N::X'}}
+    X::S2 x_s2; // expected-error{{no type named 'S2' in 'N::X'}}
     x.g2(); // expected-error{{no member named 'g2' in 'N::X'}}
   }
 }
index 246dcaf80e2497e4783a2dba93af07c5cb1e78f1..31a3410a03f80eda21cbf9f31c34826edb828123 100644 (file)
@@ -12,9 +12,12 @@ void test() {
 }
 
 int test_broken() {
-  HiddenStruct hidden; // expected-error{{use of undeclared identifier 'HiddenStruct'}}
+  HiddenStruct hidden; // \
+  // expected-error{{must use 'struct' tag to refer to type 'HiddenStruct' in this scope}} \
+  // expected-error{{definition of 'struct HiddenStruct' must be imported}}
+  // expected-note@3 {{previous definition is here}}
 
-  Integer i; // expected-error{{use of undeclared identifier 'Integer'}}
+  Integer i; // expected-error{{unknown type name 'Integer'}}
 
   int *ip = 0;
   f1(ip); // expected-error{{use of undeclared identifier 'f1'}}
index b5ff728b47c921b80f1862831627fac2256cc461..feb185fbe3f282b8d23b599cfce29782b3822686 100644 (file)
@@ -7,4 +7,7 @@ struct X {
 
 void f() {
   void (*ptr)(int, int) = &X::f<int, int>;
+
+  unknown *p = 0; // expected-error {{unknown type name 'unknown'}}
+  unknown * p + 0; // expected-error {{undeclared identifier 'unknown'}}
 }
index 0e870259b73505f8bfd2b7b679442f010aa39b37..7ac4d1c5009e9ac2412bb3b14dc262c553be5633 100644 (file)
@@ -6,5 +6,5 @@
 @end
 
 void f() {
-  NSScriptClassDescription *f; // expected-error {{use of undeclared identifier 'NSScriptClassDescription'}}
+  NSScriptClassDescription *f; // expected-error {{unknown type name 'NSScriptClassDescription'}}
 }