From: Chris Lattner Date: Thu, 3 Jul 2008 03:30:58 +0000 (+0000) Subject: Fix PR2020 by recovering by defining an anonymous enum, instead of recovering X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=14943b90d99d6f695a4aee70c5d26086639261c5;p=clang Fix PR2020 by recovering by defining an anonymous enum, instead of recovering by filling in the body of a union with enum constants. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@53069 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 3b0e2e6f38..c0c3f09b8c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1688,35 +1688,38 @@ Sema::DeclTy *Sema::ActOnTag(Scope *S, unsigned TagType, TagKind TK, assert((isa(PrevDecl) || isa(PrevDecl)) && "unexpected Decl type"); if (TagDecl *PrevTagDecl = dyn_cast(PrevDecl)) { - // If this is a use of a previous tag, or if the tag is already declared in - // the same scope (so that the definition/declaration completes or + // If this is a use of a previous tag, or if the tag is already declared + // in the same scope (so that the definition/declaration completes or // rementions the tag), reuse the decl. if (TK == TK_Reference || IdResolver.isDeclInScope(PrevDecl, CurContext, S)) { - // Make sure that this wasn't declared as an enum and now used as a struct - // or something similar. + // Make sure that this wasn't declared as an enum and now used as a + // struct or something similar. if (PrevTagDecl->getTagKind() != Kind) { Diag(KWLoc, diag::err_use_with_wrong_tag, Name->getName()); Diag(PrevDecl->getLocation(), diag::err_previous_use); - } - - // 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. + // Recover by making this an anonymous redefinition. Name = 0; + PrevDecl = 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 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; + } 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 diff --git a/test/Sema/enum.c b/test/Sema/enum.c index 890b6a505b..2a20d3d7d5 100644 --- a/test/Sema/enum.c +++ b/test/Sema/enum.c @@ -28,3 +28,8 @@ int test2(int 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}} +