diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 64 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 22 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 23 |
4 files changed, 80 insertions, 31 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 76bdd2f4877..ae00ada3110 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/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; diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 91c05669b2d..d4310e0cbf4 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -390,19 +390,19 @@ Parser::TypeResult Parser::ParseClassName(SourceLocation &EndLocation, /// struct-or-union: /// 'struct' /// 'union' -void Parser::ParseClassSpecifier(DeclSpec &DS, +void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, + SourceLocation StartLoc, DeclSpec &DS, TemplateParameterLists *TemplateParams, AccessSpecifier AS) { - assert((Tok.is(tok::kw_class) || - Tok.is(tok::kw_struct) || - Tok.is(tok::kw_union)) && - "Not a class specifier"); - DeclSpec::TST TagType = - Tok.is(tok::kw_class) ? DeclSpec::TST_class : - Tok.is(tok::kw_struct) ? DeclSpec::TST_struct : - DeclSpec::TST_union; - - SourceLocation StartLoc = ConsumeToken(); + DeclSpec::TST TagType; + if (TagTokKind == tok::kw_struct) + TagType = DeclSpec::TST_struct; + else if (TagTokKind == tok::kw_class) + TagType = DeclSpec::TST_class; + else { + assert(TagTokKind == tok::kw_union && "Not a class specifier"); + TagType = DeclSpec::TST_union; + } AttributeList *Attr = 0; // If attributes exist after tag, parse them. diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index e8eb960a3f1..f48e75afb35 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -332,6 +332,8 @@ public: virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc, Scope *S, const CXXScopeSpec *SS); + virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S); + virtual DeclPtrTy ActOnDeclarator(Scope *S, Declarator &D) { return ActOnDeclarator(S, D, false); } diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 603b8b31a26..8ce624b7888 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -139,6 +139,29 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, return 0; } +/// isTagName() - This method is called *for error recovery purposes only* +/// to determine if the specified name is a valid tag name ("struct foo"). If +/// so, this returns the TST for the tag corresponding to it (TST_enum, +/// TST_union, TST_struct, TST_class). This is used to diagnose cases in C +/// where the user forgot to specify the tag. +DeclSpec::TST Sema::isTagName(IdentifierInfo &II, Scope *S) { + // Do a tag name lookup in this scope. + LookupResult R = LookupName(S, &II, LookupTagName, false, false); + if (R.getKind() == LookupResult::Found) + if (const TagDecl *TD = dyn_cast<TagDecl>(R.getAsDecl())) { + switch (TD->getTagKind()) { + case TagDecl::TK_struct: return DeclSpec::TST_struct; + case TagDecl::TK_union: return DeclSpec::TST_union; + case TagDecl::TK_class: return DeclSpec::TST_class; + case TagDecl::TK_enum: return DeclSpec::TST_enum; + } + } + + return DeclSpec::TST_unspecified; +} + + + DeclContext *Sema::getContainingDC(DeclContext *DC) { if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(DC)) { // A C++ out-of-line method will return to the file declaration context. |

