[cfe-commits] r68914 - in /cfe/trunk: include/clang/Basic/DiagnosticParseKinds.td include/clang/Parse/Action.h include/clang/Parse/Parser.h lib/Parse/ParseDecl.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/Sema.h lib/Sema/SemaDecl.cpp test/Parser/declarators.c
Chris Lattner
sabre at nondot.org
Sun Apr 12 14:49:32 PDT 2009
Author: lattner
Date: Sun Apr 12 16:49:30 2009
New Revision: 68914
URL: http://llvm.org/viewvc/llvm-project?rev=68914&view=rev
Log:
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
Modified:
cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
cfe/trunk/include/clang/Parse/Action.h
cfe/trunk/include/clang/Parse/Parser.h
cfe/trunk/lib/Parse/ParseDecl.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/test/Parser/declarators.c
Modified: cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td?rev=68914&r1=68913&r2=68914&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticParseKinds.td Sun Apr 12 16:49:30 2009
@@ -145,6 +145,8 @@
"cannot combine with previous '%0' declaration specifier">;
def err_unknown_typename : Error<
"unknown type name %0">;
+def err_use_of_tag_name_without_tag : Error<
+ "use of tagged type %0 without '%1' tag">;
/// Objective-C parser diagnostics
Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=68914&r1=68913&r2=68914&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Sun Apr 12 16:49:30 2009
@@ -139,6 +139,15 @@
virtual TypeTy *getTypeName(IdentifierInfo &II, SourceLocation NameLoc,
Scope *S, const CXXScopeSpec *SS = 0) = 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.
+ virtual DeclSpec::TST isTagName(IdentifierInfo &II, Scope *S) {
+ return DeclSpec::TST_unspecified;
+ }
+
/// isCurrentClassName - Return true if the specified name is the
/// name of the innermost C++ class type currently being defined.
virtual bool isCurrentClassName(const IdentifierInfo &II, Scope *S,
Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=68914&r1=68913&r2=68914&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Sun Apr 12 16:49:30 2009
@@ -825,7 +825,8 @@
void ParseObjCTypeQualifierList(ObjCDeclSpec &DS);
- void ParseEnumSpecifier(DeclSpec &DS, AccessSpecifier AS = AS_none);
+ void ParseEnumSpecifier(SourceLocation TagLoc, DeclSpec &DS,
+ AccessSpecifier AS = AS_none);
void ParseEnumBody(SourceLocation StartLoc, DeclPtrTy TagDecl);
void ParseStructUnionBody(SourceLocation StartLoc, unsigned TagType,
DeclPtrTy TagDecl);
@@ -1012,7 +1013,8 @@
// C++ 9: classes [class] and C structs/unions.
TypeResult ParseClassName(SourceLocation &EndLocation,
const CXXScopeSpec *SS = 0);
- void ParseClassSpecifier(DeclSpec &DS,
+ void ParseClassSpecifier(tok::TokenKind TagTokKind, SourceLocation TagLoc,
+ DeclSpec &DS,
TemplateParameterLists *TemplateParams = 0,
AccessSpecifier AS = AS_none);
void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType,
Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=68914&r1=68913&r2=68914&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Sun Apr 12 16:49:30 2009
@@ -654,19 +654,39 @@
}
// 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 @@
case tok::kw___thread:
isInvalid = DS.SetStorageClassSpecThread(Loc, PrevSpec)*2;
break;
-
- continue;
// function-specifier
case tok::kw_inline:
@@ -851,13 +869,17 @@
// 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 @@
// 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 @@
/// [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;
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=68914&r1=68913&r2=68914&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Sun Apr 12 16:49:30 2009
@@ -390,19 +390,19 @@
/// 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.
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=68914&r1=68913&r2=68914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Sun Apr 12 16:49:30 2009
@@ -332,6 +332,8 @@
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);
}
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=68914&r1=68913&r2=68914&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Sun Apr 12 16:49:30 2009
@@ -139,6 +139,29 @@
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.
Modified: cfe/trunk/test/Parser/declarators.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/declarators.c?rev=68914&r1=68913&r2=68914&view=diff
==============================================================================
--- cfe/trunk/test/Parser/declarators.c (original)
+++ cfe/trunk/test/Parser/declarators.c Sun Apr 12 16:49:30 2009
@@ -40,16 +40,26 @@
// PR3963 & rdar://6759604 - test error recovery for mistyped "typenames".
-struct xyz { int y; };
-
+foo_t *d; // expected-error {{unknown type name 'foo_t'}}
foo_t a = 4; // expected-error {{unknown type name 'foo_t'}}
-xyz b; // expected-error {{unknown type name 'xyz'}}
+int test6() { return a; } // a should be declared.
+
+// Use of tagged type without tag. rdar://6783347
+struct xyz { int y; };
+enum myenum { ASDFAS };
+xyz b; // expected-error {{use of tagged type 'xyz' without 'struct' tag}}
+myenum c; // expected-error {{use of tagged type 'myenum' without 'enum' tag}}
+
+float *test7() {
+ // We should recover 'b' by parsing it with a valid type of "struct xyz", which
+ // allows us to diagnose other bad things done with y, such as this.
+ return &b.y; // expected-warning {{incompatible pointer types returning 'int *', expected 'float *'}}
+}
-foo_t *d; // expected-error {{unknown type name 'foo_t'}}
+// Verify that implicit int still works.
static f; // expected-warning {{type specifier missing, defaults to 'int'}}
static g = 4; // expected-warning {{type specifier missing, defaults to 'int'}}
static h // expected-warning {{type specifier missing, defaults to 'int'}}
__asm__("foo"); // expected-warning {{extension used}}
-int bar() { return a; }
More information about the cfe-commits
mailing list