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; + + 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'}} }