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
This commit is contained in:
Richard Smith 2012-08-23 20:19:14 +00:00
parent 42b60551ef
commit 40b2e19cae
5 changed files with 42 additions and 17 deletions

View 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())

View 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'}}
}
}

View 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'}}

View 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'}}
}

View 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'}}
}