Skip to content

Commit 6d7d8e5

Browse files
authored
[Modules] Detect ODR mismatches for enums in non-C++ like in C++. (#90298)
There is no reason for C and Objective-C to differ from C++ in this matter. rdar://85531830
1 parent aae3835 commit 6d7d8e5

File tree

2 files changed

+77
-5
lines changed

2 files changed

+77
-5
lines changed

clang/lib/Serialization/ASTReaderDecl.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -805,9 +805,7 @@ void ASTDeclReader::VisitEnumDecl(EnumDecl *ED) {
805805

806806
// If this is a definition subject to the ODR, and we already have a
807807
// definition, merge this one into it.
808-
if (ED->isCompleteDefinition() &&
809-
Reader.getContext().getLangOpts().Modules &&
810-
Reader.getContext().getLangOpts().CPlusPlus) {
808+
if (ED->isCompleteDefinition() && Reader.getContext().getLangOpts().Modules) {
811809
EnumDecl *&OldDef = Reader.EnumDefinitions[ED->getCanonicalDecl()];
812810
if (!OldDef) {
813811
// This is the first time we've seen an imported definition. Look for a
@@ -3304,8 +3302,7 @@ DeclContext *ASTDeclReader::getPrimaryContextForMerging(ASTReader &Reader,
33043302
return RD->getDefinition();
33053303

33063304
if (auto *ED = dyn_cast<EnumDecl>(DC))
3307-
return ED->getASTContext().getLangOpts().CPlusPlus? ED->getDefinition()
3308-
: nullptr;
3305+
return ED->getDefinition();
33093306

33103307
if (auto *OID = dyn_cast<ObjCInterfaceDecl>(DC))
33113308
return OID->getDefinition();

clang/test/Modules/odr_hash-enum.c

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Clear and create directories
2+
// RUN: rm -rf %t
3+
// RUN: mkdir %t
4+
// RUN: mkdir %t/cache
5+
// RUN: mkdir %t/Inputs
6+
7+
// Build first header file
8+
// RUN: echo "#define FIRST" >> %t/Inputs/first.h
9+
// RUN: cat %s >> %t/Inputs/first.h
10+
11+
// Build second header file
12+
// RUN: echo "#define SECOND" >> %t/Inputs/second.h
13+
// RUN: cat %s >> %t/Inputs/second.h
14+
15+
// Test that each header can compile
16+
// RUN: %clang_cc1 -fsyntax-only -x c %t/Inputs/first.h
17+
// RUN: %clang_cc1 -fsyntax-only -x c %t/Inputs/second.h
18+
19+
// Build module map file
20+
// RUN: echo "module FirstModule {" >> %t/Inputs/module.modulemap
21+
// RUN: echo " header \"first.h\"" >> %t/Inputs/module.modulemap
22+
// RUN: echo "}" >> %t/Inputs/module.modulemap
23+
// RUN: echo "module SecondModule {" >> %t/Inputs/module.modulemap
24+
// RUN: echo " header \"second.h\"" >> %t/Inputs/module.modulemap
25+
// RUN: echo "}" >> %t/Inputs/module.modulemap
26+
27+
// Run test
28+
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/cache -x c -I%t/Inputs -verify %s
29+
30+
#if !defined(FIRST) && !defined(SECOND)
31+
#include "first.h"
32+
#include "second.h"
33+
#endif
34+
35+
#if defined(FIRST)
36+
enum DifferentEnumConstants { kDifferentEnumConstantsValueFirst };
37+
#elif defined(SECOND)
38+
enum DifferentEnumConstants { kDifferentEnumConstantsValueSecond };
39+
#else
40+
enum DifferentEnumConstants differentEnumConstants;
41+
// [email protected]:* {{'kDifferentEnumConstantsValueSecond' from module 'SecondModule' is not present in definition of 'enum DifferentEnumConstants' in module 'FirstModule'}}
42+
// [email protected]:* {{definition has no member 'kDifferentEnumConstantsValueSecond'}}
43+
#endif
44+
45+
#if defined(FIRST)
46+
enum DifferentEnumValues { kDifferentEnumValue = 0 };
47+
#elif defined(SECOND)
48+
enum DifferentEnumValues { kDifferentEnumValue = 1 };
49+
#else
50+
enum DifferentEnumValues differentEnumValue;
51+
// [email protected]:* {{'DifferentEnumValues' has different definitions in different modules; definition in module 'FirstModule' first difference is 1st element 'kDifferentEnumValue' has an initializer}}
52+
// [email protected]:* {{but in 'SecondModule' found 1st element 'kDifferentEnumValue' has different initializer}}
53+
#endif
54+
55+
#if defined(FIRST)
56+
enum {
57+
kAnonymousEnumValueFirst = 1,
58+
};
59+
#elif defined(SECOND)
60+
enum {
61+
kAnonymousEnumValueSecond = 2,
62+
};
63+
#else
64+
// Anonymous enums don't have to match, no errors expected.
65+
int anonymousEnumValue = kAnonymousEnumValueFirst + kAnonymousEnumValueSecond;
66+
#endif
67+
68+
// Keep macros contained to one file.
69+
#ifdef FIRST
70+
#undef FIRST
71+
#endif
72+
73+
#ifdef SECOND
74+
#undef SECOND
75+
#endif

0 commit comments

Comments
 (0)