mirror of https://github.com/microsoft/clang.git
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:
parent
42b60551ef
commit
40b2e19cae
|
@ -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())
|
||||
|
|
|
@ -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'}}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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'}}
|
||||
|
|
|
@ -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'}}
|
||||
}
|
||||
|
|
|
@ -6,5 +6,5 @@
|
|||
@end
|
||||
|
||||
void f() {
|
||||
NSScriptClassDescription *f; // expected-error {{use of undeclared identifier 'NSScriptClassDescription'}}
|
||||
NSScriptClassDescription *f; // expected-error {{unknown type name 'NSScriptClassDescription'}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue