diff options
author | Chris Lattner <sabre@nondot.org> | 2009-04-12 21:49:30 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2009-04-12 21:49:30 +0000 |
commit | 4c97d762d8c5a84f6554e5bfb31d28c90df64158 (patch) | |
tree | 2bcc513ad20cbd41013ac1ac397b09b65ce5039f /lib/Parse/ParseDecl.cpp | |
parent | 5186872629d6c9a48433bafe62dc06975bbbf7af (diff) |
Diagnose invalid uses of tagged types with a missing tag. For example, in:
struct xyz { int y; };
enum abc { ZZZ };
static xyz b;
abc c;
we used to produce:
t2.c:4:8: error: unknown type name 'xyz'
static xyz b;
^
t2.c:5:1: error: unknown type name 'abc'
abc c;
^
we now produce:
t2.c:4:8: error: use of tagged type 'xyz' without 'struct' tag
static xyz b;
^
struct
t2.c:5:1: error: use of tagged type 'abc' without 'enum' tag
abc c;
^
enum
GCC produces the normal:
t2.c:4: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘b’
t2.c:5: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘c’
rdar://6783347
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68914 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseDecl.cpp')
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 64 |
1 files changed, 44 insertions, 20 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 76bdd2f487..ae00ada311 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -654,19 +654,39 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, } // Otherwise, if we don't consume this token, we are going to emit an - // error anyway. Since this is almost certainly an invalid type name, - // emit a diagnostic that says it, eat the token, and pretend we saw an - // 'int'. + // 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' insteat of 'struct foo'). + const char *TagName = 0; + tok::TokenKind TagKind = tok::unknown; + + switch (Actions.isTagName(*Tok.getIdentifierInfo(), CurScope)) { + default: break; + case DeclSpec::TST_enum: TagName="enum" ;TagKind=tok::kw_enum ;break; + case DeclSpec::TST_union: TagName="union" ;TagKind=tok::kw_union ;break; + 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); + continue; + } + + // Since this is almost certainly an invalid type name, emit a + // diagnostic that says it, eat the token, and pretend we saw an 'int'. Diag(Loc, diag::err_unknown_typename) << Tok.getIdentifierInfo(); DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec); DS.SetRangeEnd(Tok.getLocation()); ConsumeToken(); - // TODO: in C, we could redo the lookup in the tag namespace to catch - // things like "foo x" where the user meant "struct foo x" etc, this - // would be much nicer for both error recovery, diagnostics, and we - // could even emit a fixit hint. - // TODO: Could inject an invalid typedef decl in an enclosing scope to // avoid rippling error messages on subsequent uses of the same type, // could be useful if #include was forgotten. @@ -780,8 +800,6 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, case tok::kw___thread: isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2; break; - - continue; // function-specifier case tok::kw_inline: @@ -851,13 +869,17 @@ void Parser::ParseDeclarationSpecifiers(DeclSpec &DS, // class-specifier: case tok::kw_class: case tok::kw_struct: - case tok::kw_union: - ParseClassSpecifier(DS, TemplateParams, AS); + case tok::kw_union: { + tok::TokenKind Kind = Tok.getKind(); + ConsumeToken(); + ParseClassSpecifier(Kind, Loc, DS, TemplateParams, AS); continue; + } // enum-specifier: case tok::kw_enum: - ParseEnumSpecifier(DS, AS); + ConsumeToken(); + ParseEnumSpecifier(Loc, DS, AS); continue; // cv-qualifier: @@ -1069,13 +1091,17 @@ bool Parser::ParseOptionalTypeSpecifier(DeclSpec &DS, int& isInvalid, // class-specifier: case tok::kw_class: case tok::kw_struct: - case tok::kw_union: - ParseClassSpecifier(DS, TemplateParams); + case tok::kw_union: { + tok::TokenKind Kind = Tok.getKind(); + ConsumeToken(); + ParseClassSpecifier(Kind, Loc, DS, TemplateParams); return true; + } // enum-specifier: case tok::kw_enum: - ParseEnumSpecifier(DS); + ConsumeToken(); + ParseEnumSpecifier(Loc, DS); return true; // cv-qualifier: @@ -1325,10 +1351,8 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, /// [C++] elaborated-type-specifier: /// [C++] 'enum' '::'[opt] nested-name-specifier[opt] identifier /// -void Parser::ParseEnumSpecifier(DeclSpec &DS, AccessSpecifier AS) { - assert(Tok.is(tok::kw_enum) && "Not an enum specifier"); - SourceLocation StartLoc = ConsumeToken(); - +void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, + AccessSpecifier AS) { // Parse the tag portion of this. AttributeList *Attr = 0; |