aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-08-23 20:19:14 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-08-23 20:19:14 +0000
commit40b2e19cae6ab85407856c70f76278f9efbeeb7c (patch)
tree33b64a284db290fe463964aaccecf55beff1026c
parent42b60551eff3a424e191b293bfd606559dc96bff (diff)
When disambiguating an expression-statement from a declaraton-statement, if the
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
-rw-r--r--lib/Parse/ParseTentative.cpp39
-rw-r--r--test/CXX/class.access/class.friend/p1.cpp8
-rw-r--r--test/Modules/module-private.cpp7
-rw-r--r--test/Parser/cxx-ambig-decl-expr.cpp3
-rw-r--r--test/SemaObjCXX/category-lookup.mm2
5 files changed, 42 insertions, 17 deletions
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 653f6c26ae..01ab0e4eea 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -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())
diff --git a/test/CXX/class.access/class.friend/p1.cpp b/test/CXX/class.access/class.friend/p1.cpp
index 7cb192b5a1..3d3c5f789a 100644
--- a/test/CXX/class.access/class.friend/p1.cpp
+++ b/test/CXX/class.access/class.friend/p1.cpp
@@ -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'}}
}
}
diff --git a/test/Modules/module-private.cpp b/test/Modules/module-private.cpp
index 246dcaf80e..31a3410a03 100644
--- a/test/Modules/module-private.cpp
+++ b/test/Modules/module-private.cpp
@@ -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'}}
diff --git a/test/Parser/cxx-ambig-decl-expr.cpp b/test/Parser/cxx-ambig-decl-expr.cpp
index b5ff728b47..feb185fbe3 100644
--- a/test/Parser/cxx-ambig-decl-expr.cpp
+++ b/test/Parser/cxx-ambig-decl-expr.cpp
@@ -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'}}
}
diff --git a/test/SemaObjCXX/category-lookup.mm b/test/SemaObjCXX/category-lookup.mm
index 0e870259b7..7ac4d1c500 100644
--- a/test/SemaObjCXX/category-lookup.mm
+++ b/test/SemaObjCXX/category-lookup.mm
@@ -6,5 +6,5 @@
@end
void f() {
- NSScriptClassDescription *f; // expected-error {{use of undeclared identifier 'NSScriptClassDescription'}}
+ NSScriptClassDescription *f; // expected-error {{unknown type name 'NSScriptClassDescription'}}
}