diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -1256,48 +1256,9 @@ return false; } - if (Field1->isBitField() != Field2->isBitField()) { - if (Context.Complain) { - Context.Diag2( - Owner2->getLocation(), - Context.getApplicableDiagnostic(diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(Owner2); - if (Field1->isBitField()) { - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() - << Field1->getBitWidthValue(Context.FromCtx); - Context.Diag2(Field2->getLocation(), diag::note_odr_not_bit_field) - << Field2->getDeclName(); - } else { - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() - << Field2->getBitWidthValue(Context.ToCtx); - Context.Diag1(Field1->getLocation(), diag::note_odr_not_bit_field) - << Field1->getDeclName(); - } - } - return false; - } - - if (Field1->isBitField()) { - // Make sure that the bit-fields are the same length. - unsigned Bits1 = Field1->getBitWidthValue(Context.FromCtx); - unsigned Bits2 = Field2->getBitWidthValue(Context.ToCtx); - - if (Bits1 != Bits2) { - if (Context.Complain) { - Context.Diag2(Owner2->getLocation(), - Context.getApplicableDiagnostic( - diag::err_odr_tag_type_inconsistent)) - << Context.ToCtx.getTypeDeclType(Owner2); - Context.Diag2(Field2->getLocation(), diag::note_odr_bit_field) - << Field2->getDeclName() << Field2->getType() << Bits2; - Context.Diag1(Field1->getLocation(), diag::note_odr_bit_field) - << Field1->getDeclName() << Field1->getType() << Bits1; - } - return false; - } - } + if (Field1->isBitField()) + return IsStructurallyEquivalent(Context, Field1->getBitWidth(), + Field2->getBitWidth()); return true; } diff --git a/clang/test/ASTMerge/struct/test.c b/clang/test/ASTMerge/struct/test.c --- a/clang/test/ASTMerge/struct/test.c +++ b/clang/test/ASTMerge/struct/test.c @@ -21,16 +21,6 @@ // CHECK: struct1.c:27:8: note: no corresponding field here // CHECK: struct2.c:24:31: warning: external variable 'x4' declared with incompatible types in different translation units ('struct S4' vs. 'struct S4') // CHECK: struct1.c:27:22: note: declared here with type 'struct S4' -// CHECK: struct1.c:33:8: warning: type 'struct S6' has incompatible definitions in different translation units -// CHECK: struct1.c:33:33: note: bit-field 'j' with type 'unsigned int' and length 8 here -// CHECK: struct2.c:30:33: note: field 'j' is not a bit-field -// CHECK: struct2.c:30:38: warning: external variable 'x6' declared with incompatible types in different translation units ('struct S6' vs. 'struct S6') -// CHECK: struct1.c:33:42: note: declared here with type 'struct S6' -// CHECK: struct1.c:36:8: warning: type 'struct S7' has incompatible definitions in different translation units -// CHECK: struct1.c:36:33: note: bit-field 'j' with type 'unsigned int' and length 8 here -// CHECK: struct2.c:33:33: note: bit-field 'j' with type 'unsigned int' and length 16 here -// CHECK: struct2.c:33:43: warning: external variable 'x7' declared with incompatible types in different translation units ('struct S7' vs. 'struct S7') -// CHECK: struct1.c:36:42: note: declared here with type 'struct S7' // CHECK: struct1.c:56:10: warning: type 'struct DeeperError' has incompatible definitions in different translation units // CHECK: struct1.c:56:35: note: field 'f' has type 'int' here // CHECK: struct2.c:53:37: note: field 'f' has type 'float' here @@ -52,4 +42,4 @@ // CHECK: struct2.c:129:9: note: field 'S' has type 'struct (anonymous struct at [[PATH_TO_INPUTS]]struct2.c:127:7)' here // CHECK: struct2.c:138:3: warning: external variable 'x16' declared with incompatible types in different translation units ('struct DeepUnnamedError' vs. 'struct DeepUnnamedError') // CHECK: struct1.c:141:3: note: declared here with type 'struct DeepUnnamedError' -// CHECK: 20 warnings generated +// CHECK: 17 warnings generated diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp --- a/clang/unittests/AST/StructuralEquivalenceTest.cpp +++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp @@ -976,6 +976,39 @@ EXPECT_FALSE(testStructuralMatch(t)); } +TEST_F(StructuralEquivalenceTemplateTest, BitFieldDecl) { + const char *Code = "class foo { int a : 2; };"; + auto t = makeNamedDecls(Code, Code, Lang_CXX03); + EXPECT_TRUE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceTemplateTest, BitFieldDeclDifferentWidth) { + auto t = makeNamedDecls("class foo { int a : 2; };", + "class foo { int a : 4; };", Lang_CXX03); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceTemplateTest, DependentBitFieldDecl) { + const char *Code = "template class foo { int a : sizeof(T); };"; + auto t = makeNamedDecls(Code, Code, Lang_CXX03); + EXPECT_TRUE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceTemplateTest, DependentBitFieldDeclDifferentVal) { + auto t = makeNamedDecls( + "template class foo { int a : sizeof(A); };", + "template class foo { int a : sizeof(B); };", + Lang_CXX03); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceTemplateTest, DependentBitFieldDeclDifferentVal2) { + auto t = makeNamedDecls( + "template class foo { int a : sizeof(A); };", + "template class foo { int a : sizeof(A) + 1; };", Lang_CXX03); + EXPECT_FALSE(testStructuralMatch(t)); +} + TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolSame) { auto Decls = makeNamedDecls( "template struct foo {explicit(b) foo(int);};",