diff options
author | Chris Lattner <sabre@nondot.org> | 2009-04-14 22:17:06 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2009-04-14 22:17:06 +0000 |
commit | f4382f50b7ab9f445c3f5b3ddaa59e6da25ea3bb (patch) | |
tree | c40a54645a3b931b525d2f33f0a8ff0903b4f014 | |
parent | 17fc223395d51be582fc666bb6ea21bd1dff26dc (diff) |
Make the implicit-int handling error recovery stuff handle C++
nested name specifiers. Now we emit stuff like:
t.cpp:8:13: error: unknown type name 'X'
static foo::X P;
~~~~ ^
instead of:
t.cpp:8:16: error: invalid token after top level declarator
static foo::X P;
^
This is inspired by a really awful error message I got from
g++ when I misspelt diag::kind as diag::Kind.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69086 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Parse/Parser.h | 3 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 54 | ||||
-rw-r--r-- | test/SemaCXX/namespace.cpp | 11 | ||||
-rw-r--r-- | test/SemaCXX/nested-name-spec.cpp | 6 | ||||
-rw-r--r-- | test/SemaTemplate/instantiate-typedef.cpp | 4 | ||||
-rw-r--r-- | test/SemaTemplate/nested-name-spec-template.cpp | 5 | ||||
-rw-r--r-- | test/SemaTemplate/typename-specifier.cpp | 10 |
7 files changed, 59 insertions, 34 deletions
diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 0658359d35..dcf4c5affb 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -816,7 +816,8 @@ private: DeclGroupPtrTy ParseInitDeclaratorListAfterFirstDeclarator(Declarator &D); DeclPtrTy ParseFunctionStatementBody(DeclPtrTy Decl); - bool ParseImplicitInt(DeclSpec &DS, TemplateParameterLists *TemplateParams, + bool ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, + TemplateParameterLists *TemplateParams, AccessSpecifier AS); void ParseDeclarationSpecifiers(DeclSpec &DS, TemplateParameterLists *TemplateParams = 0, diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 47d21be60d..55355880b1 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -499,9 +499,11 @@ static bool isValidAfterIdentifierInDeclarator(const Token &T) { /// declspec is done being processed. If it recovers and thinks there may be /// other pieces of declspec after it, it returns true. /// -bool Parser::ParseImplicitInt(DeclSpec &DS, +bool Parser::ParseImplicitInt(DeclSpec &DS, CXXScopeSpec *SS, TemplateParameterLists *TemplateParams, AccessSpecifier AS) { + assert(Tok.is(tok::identifier) && "should have identifier"); + SourceLocation Loc = Tok.getLocation(); // If we see an identifier that is not a type name, we normally would // parse it as the identifer being declared. However, when a typename @@ -530,10 +532,12 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, // error anyway. Try to recover from various common problems. Check // to see if this was a reference to a tag name without a tag specified. // This is a common problem in C (saying 'foo' instead of 'struct foo'). - const char *TagName = 0; - tok::TokenKind TagKind = tok::unknown; + // + // C++ doesn't need this, and isTagName doesn't take SS. + if (SS == 0) { + const char *TagName = 0; + tok::TokenKind TagKind = tok::unknown; - if (Tok.is(tok::identifier)) { switch (Actions.isTagName(*Tok.getIdentifierInfo(), CurScope)) { default: break; case DeclSpec::TST_enum: TagName="enum" ;TagKind=tok::kw_enum ;break; @@ -541,25 +545,28 @@ bool Parser::ParseImplicitInt(DeclSpec &DS, case DeclSpec::TST_struct:TagName="struct";TagKind=tok::kw_struct;break; case DeclSpec::TST_class: TagName="class" ;TagKind=tok::kw_class ;break; } - } - if (TagName) { - Diag(Loc, diag::err_use_of_tag_name_without_tag) - << Tok.getIdentifierInfo() << TagName - << CodeModificationHint::CreateInsertion(Tok.getLocation(),TagName); - - // Parse this as a tag as if the missing tag were present. - if (TagKind == tok::kw_enum) - ParseEnumSpecifier(Loc, DS, AS); - else - ParseClassSpecifier(TagKind, Loc, DS, TemplateParams, AS); - return true; + if (TagName) { + Diag(Loc, diag::err_use_of_tag_name_without_tag) + << Tok.getIdentifierInfo() << TagName + << CodeModificationHint::CreateInsertion(Tok.getLocation(),TagName); + + // Parse this as a tag as if the missing tag were present. + if (TagKind == tok::kw_enum) + ParseEnumSpecifier(Loc, DS, AS); + else + ParseClassSpecifier(TagKind, Loc, DS, TemplateParams, AS); + return true; + } } // Since this is almost certainly an invalid type name, emit a // diagnostic that says it, eat the token, and mark the declspec as // invalid. - Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo(); + SourceRange R; + if (SS) R = SS->getRange(); + + Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo() << R; const char *PrevSpec; DS.SetTypeSpecType(DeclSpec::TST_error, Loc, PrevSpec); DS.SetRangeEnd(Tok.getLocation()); @@ -642,7 +649,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If the next token is the name of the class type that the C++ scope // denotes, followed by a '(', then this is a constructor declaration. // We're done with the decl-specifiers. - if (Actions.isCurrentClassName(*NextToken().getIdentifierInfo(), + if (Actions.isCurrentClassName(*Next.getIdentifierInfo(), CurScope, &SS) && GetLookAheadToken(2).is(tok::l_paren)) goto DoneWithDeclSpec; @@ -650,8 +657,15 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, TypeTy *TypeRep = Actions.getTypeName(*Next.getIdentifierInfo(), Next.getLocation(), CurScope, &SS); - if (TypeRep == 0) + // If the referenced identifier is not a type, then this declspec is + // erroneous: We already checked about that it has no type specifier, and + // C++ doesn't have implicit int. Diagnose it as a typo w.r.t. to the + // typename. + if (TypeRep == 0) { + ConsumeToken(); // Eat the scope spec so the identifier is current. + if (ParseImplicitInt(DS, &SS, TemplateParams, AS)) continue; goto DoneWithDeclSpec; + } ConsumeToken(); // The C++ scope. @@ -711,7 +725,7 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // If this is not a typedef name, don't parse it as part of the declspec, // it must be an implicit int or an error. if (TypeRep == 0) { - if (ParseImplicitInt(DS, TemplateParams, AS)) continue; + if (ParseImplicitInt(DS, 0, TemplateParams, AS)) continue; goto DoneWithDeclSpec; } diff --git a/test/SemaCXX/namespace.cpp b/test/SemaCXX/namespace.cpp index 24a0a4603d..592ca30790 100644 --- a/test/SemaCXX/namespace.cpp +++ b/test/SemaCXX/namespace.cpp @@ -56,3 +56,14 @@ namespace S1 { } namespace B {} // expected-error {{redefinition of 'B' as different kind of symbol}} + + +namespace foo { + enum x { + Y + }; +} + +static foo::x test1; // ok + +static foo::X test2; // typo: expected-error {{unknown type name 'X'}} diff --git a/test/SemaCXX/nested-name-spec.cpp b/test/SemaCXX/nested-name-spec.cpp index 29fa001e0f..4c3ecee090 100644 --- a/test/SemaCXX/nested-name-spec.cpp +++ b/test/SemaCXX/nested-name-spec.cpp @@ -13,8 +13,8 @@ namespace A { } A:: ; // expected-error {{expected unqualified-id}} -::A::ax::undef ex3; // expected-error {{expected a class or namespace}} expected-error {{invalid token after top level declarator}} -A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}} expected-error {{invalid token after top level declarator}} +::A::ax::undef ex3; // expected-error {{expected a class or namespace}} expected-error {{unknown type name 'undef'}} +A::undef1::undef2 ex4; // expected-error {{no member named 'undef1'}} expected-error {{unknown type name 'undef2'}} int A::C::Ag1() { return 0; } @@ -166,7 +166,7 @@ void N::f() { } // okay struct Y; // expected-note{{forward declaration of 'struct Y'}} Y::foo y; // expected-error{{incomplete type 'struct Y' named in nested name specifier}} \ - // FIXME: ugly: expected-error{{invalid token after top level declarator}} + // expected-error{{unknown type name 'foo'}} X::X() : a(5) { } // expected-error{{use of undeclared identifier 'X'}} \ // expected-error{{C++ requires a type specifier for all declarations}} \ diff --git a/test/SemaTemplate/instantiate-typedef.cpp b/test/SemaTemplate/instantiate-typedef.cpp index abdc37a062..c1355fca8d 100644 --- a/test/SemaTemplate/instantiate-typedef.cpp +++ b/test/SemaTemplate/instantiate-typedef.cpp @@ -11,5 +11,5 @@ add_pointer<float>::type test2(int * ptr) { return ptr; // expected-error{{incompatible type returning 'int *', expected 'add_pointer<float>::type' (aka 'float *')}} } -add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}} -test3(); // FIXME: expected-error{{invalid token after top level declarator}} +add_pointer<int&>::type // expected-note{{in instantiation of template class 'struct add_pointer<int &>' requested here}} expected-error {{unknown type name 'type'}} +test3(); diff --git a/test/SemaTemplate/nested-name-spec-template.cpp b/test/SemaTemplate/nested-name-spec-template.cpp index 7805040048..a5aa2dcb52 100644 --- a/test/SemaTemplate/nested-name-spec-template.cpp +++ b/test/SemaTemplate/nested-name-spec-template.cpp @@ -2,7 +2,7 @@ namespace N { namespace M { - template<typename T> struct Promote; // expected-note{{previous definition is here}} + template<typename T> struct Promote; template<> struct Promote<short> { typedef int type; @@ -32,8 +32,7 @@ N::M::template; // expected-error{{expected template name after 'template' keywo // expected-error{{expected unqualified-id}} N::M::template Promote; // expected-error{{expected '<' after 'template Promote' in nested name specifier}} \ -// expected-error{{C++ requires a type specifier for all declarations}} \ -// expected-error{{redefinition of 'Promote' as different kind of symbol}} +// expected-error{{C++ requires a type specifier for all declarations}} namespace N { template<typename T> struct A; diff --git a/test/SemaTemplate/typename-specifier.cpp b/test/SemaTemplate/typename-specifier.cpp index d15dbbc6e9..d3fca3eaca 100644 --- a/test/SemaTemplate/typename-specifier.cpp +++ b/test/SemaTemplate/typename-specifier.cpp @@ -42,12 +42,12 @@ namespace N { N::X<N::A>::type *ip4 = &i; N::X<N::B>::type *ip5 = &i; // expected-note{{in instantiation of template class 'struct N::X<struct N::B>' requested here}} \ -// FIXME: expected-error{{invalid token after top level declarator}} +// expected-error{{unknown type name 'type'}} N::X<N::C>::type *ip6 = &i; // expected-note{{in instantiation of template class 'struct N::X<struct N::C>' requested here}} \ -// FIXME: expected-error{{invalid token after top level declarator}} +// expected-error{{unknown type name 'type'}} N::X<int>::type fail1; // expected-note{{in instantiation of template class 'struct N::X<int>' requested here}} \ -// FIXME: expected-error{{invalid token after top level declarator}} +// expected-error{{unknown type name 'type'}} template<typename T> struct Y { @@ -69,6 +69,6 @@ struct C { ::Y<A>::type ip7 = &i; ::Y<B>::type ip8 = &i; // expected-note{{in instantiation of template class 'struct Y<struct B>' requested here}} \ -// FIXME: expected-error{{invalid token after top level declarator}} +// expected-error{{unknown type name 'type'}} ::Y<C>::type ip9 = &i; // expected-note{{in instantiation of template class 'struct Y<struct C>' requested here}} \ -// FIXME: expected-error{{invalid token after top level declarator}} +// expected-error{{unknown type name 'type'}} |