зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
17fc223395
Коммит
f4382f50b7
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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'}}
|
||||
|
|
|
@ -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}} \
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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'}}
|
||||
|
|
Загрузка…
Ссылка в новой задаче