Fix PR2020 by recovering by defining an anonymous enum, instead of recovering

by filling in the body of a union with enum constants.

llvm-svn: 53069
This commit is contained in:
Chris Lattner 2008-07-03 03:30:58 +00:00
parent b261292917
commit 9ff58d7caf
2 changed files with 29 additions and 21 deletions

View File

@ -1688,35 +1688,38 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK,
assert((isa<TagDecl>(PrevDecl) || isa<NamespaceDecl>(PrevDecl)) && assert((isa<TagDecl>(PrevDecl) || isa<NamespaceDecl>(PrevDecl)) &&
"unexpected Decl type"); "unexpected Decl type");
if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) { if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
// If this is a use of a previous tag, or if the tag is already declared in // If this is a use of a previous tag, or if the tag is already declared
// the same scope (so that the definition/declaration completes or // in the same scope (so that the definition/declaration completes or
// rementions the tag), reuse the decl. // rementions the tag), reuse the decl.
if (TK == TK_Reference || if (TK == TK_Reference ||
IdResolver.isDeclInScope(PrevDecl, CurContext, S)) { IdResolver.isDeclInScope(PrevDecl, CurContext, S)) {
// Make sure that this wasn't declared as an enum and now used as a struct // Make sure that this wasn't declared as an enum and now used as a
// or something similar. // struct or something similar.
if (PrevTagDecl->getTagKind() != Kind) { if (PrevTagDecl->getTagKind() != Kind) {
Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName()); Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName());
Diag(PrevDecl->getLocation(), diag::err_previous_use); Diag(PrevDecl->getLocation(), diag::err_previous_use);
} // Recover by making this an anonymous redefinition.
// If this is a use or a forward declaration, we're good.
if (TK != TK_Definition)
return PrevDecl;
// Diagnose attempts to redefine a tag.
if (PrevTagDecl->isDefinition()) {
Diag(NameLoc, diag::err_redefinition, Name->getName());
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
// If this is a redefinition, recover by making this struct be
// anonymous, which will make any later references get the previous
// definition.
Name = 0; Name = 0;
PrevDecl = 0;
} else { } else {
// Okay, this is definition of a previously declared or referenced tag. // If this is a use or a forward declaration, we're good.
// Move the location of the decl to be the definition site. if (TK != TK_Definition)
PrevDecl->setLocation(NameLoc); return PrevDecl;
return PrevDecl;
// Diagnose attempts to redefine a tag.
if (PrevTagDecl->isDefinition()) {
Diag(NameLoc, diag::err_redefinition, Name->getName());
Diag(PrevDecl->getLocation(), diag::err_previous_definition);
// If this is a redefinition, recover by making this struct be
// anonymous, which will make any later references get the previous
// definition.
Name = 0;
} else {
// Okay, this is definition of a previously declared or referenced
// tag. Move the location of the decl to be the definition site.
PrevDecl->setLocation(NameLoc);
return PrevDecl;
}
} }
} }
// If we get here, this is a definition of a new struct type in a nested // If we get here, this is a definition of a new struct type in a nested

View File

@ -28,3 +28,8 @@ int test2(int i)
{ {
ve + i; ve + i;
} }
// PR2020
union u0; // expected-error {{previous use is here}}
enum u0 { U0A }; // expected-error {{error: use of 'u0' with tag type that does not match previous declaration}}