aaron.ballman created this revision. aaron.ballman added reviewers: rsmith, dblaikie.
In C, enumerators are not hoisted into, say, a struct decl context when the enumeration is declared inside of a struct. Instead, the enumerators are hoisted into the translation unit decl context. This patch fixes `getRedeclContext()` to skip records as well as transparent contexts when the original context is an enumeration. This allows us to catch enumerator redeclarations as well as silent name hiding + miscompiles. This patch address PR15071. https://reviews.llvm.org/D52384 Files: lib/AST/DeclBase.cpp test/Sema/enum.c Index: test/Sema/enum.c =================================================================== --- test/Sema/enum.c +++ test/Sema/enum.c @@ -135,3 +135,26 @@ }; int makeStructNonEmpty; }; + +static int EnumRedecl; // expected-note 2 {{previous definition is here}} +struct S { + enum { + EnumRedecl = 4 // expected-error {{redefinition of 'EnumRedecl'}} + } e; +}; + +union U { + enum { + EnumRedecl = 5 // expected-error {{redefinition of 'EnumRedecl'}} + } e; +}; + +enum PR15071 { + PR15071_One // expected-note {{previous definition is here}} +}; + +struct EnumRedeclStruct { + enum { + PR15071_One // expected-error {{redefinition of enumerator 'PR15071_One'}} + } e; +}; Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -1700,8 +1700,16 @@ DeclContext *DeclContext::getRedeclContext() { DeclContext *Ctx = this; - // Skip through transparent contexts. - while (Ctx->isTransparentContext()) + + // In C, the redeclaration context for enumerators is the translation unit, + // so we skip through transparent contexts as well as struct/union contexts. + bool SkipRecords = getDeclKind() == Decl::Kind::Enum && + !getParentASTContext().getLangOpts().CPlusPlus; + + // Skip through contexts to get to the redeclaration context. Transparent + // contexts are always skipped. + while (SkipRecords ? Ctx->isTransparentContext() || Ctx->isRecord() + : Ctx->isTransparentContext()) Ctx = Ctx->getParent(); return Ctx; }
Index: test/Sema/enum.c =================================================================== --- test/Sema/enum.c +++ test/Sema/enum.c @@ -135,3 +135,26 @@ }; int makeStructNonEmpty; }; + +static int EnumRedecl; // expected-note 2 {{previous definition is here}} +struct S { + enum { + EnumRedecl = 4 // expected-error {{redefinition of 'EnumRedecl'}} + } e; +}; + +union U { + enum { + EnumRedecl = 5 // expected-error {{redefinition of 'EnumRedecl'}} + } e; +}; + +enum PR15071 { + PR15071_One // expected-note {{previous definition is here}} +}; + +struct EnumRedeclStruct { + enum { + PR15071_One // expected-error {{redefinition of enumerator 'PR15071_One'}} + } e; +}; Index: lib/AST/DeclBase.cpp =================================================================== --- lib/AST/DeclBase.cpp +++ lib/AST/DeclBase.cpp @@ -1700,8 +1700,16 @@ DeclContext *DeclContext::getRedeclContext() { DeclContext *Ctx = this; - // Skip through transparent contexts. - while (Ctx->isTransparentContext()) + + // In C, the redeclaration context for enumerators is the translation unit, + // so we skip through transparent contexts as well as struct/union contexts. + bool SkipRecords = getDeclKind() == Decl::Kind::Enum && + !getParentASTContext().getLangOpts().CPlusPlus; + + // Skip through contexts to get to the redeclaration context. Transparent + // contexts are always skipped. + while (SkipRecords ? Ctx->isTransparentContext() || Ctx->isRecord() + : Ctx->isTransparentContext()) Ctx = Ctx->getParent(); return Ctx; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits