Skip to content

Commit

Permalink
[ASTImporter][AST] Fix structural equivalency crash on dependent Fiel…
Browse files Browse the repository at this point in the history
…dDecl

Differential Revision: https://reviews.llvm.org/D88665
  • Loading branch information
Gabor Marton committed Oct 5, 2020
1 parent 707c3d4 commit 007dd12
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 53 deletions.
45 changes: 3 additions & 42 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Expand Up @@ -1256,48 +1256,9 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
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;
}
Expand Down
12 changes: 1 addition & 11 deletions clang/test/ASTMerge/struct/test.c
Expand Up @@ -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
Expand All @@ -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
33 changes: 33 additions & 0 deletions clang/unittests/AST/StructuralEquivalenceTest.cpp
Expand Up @@ -976,6 +976,39 @@ TEST_F(StructuralEquivalenceTemplateTest, DifferentTemplateArgKind) {
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 T> 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 A, class B> class foo { int a : sizeof(A); };",
"template <class A, class B> class foo { int a : sizeof(B); };",
Lang_CXX03);
EXPECT_FALSE(testStructuralMatch(t));
}

TEST_F(StructuralEquivalenceTemplateTest, DependentBitFieldDeclDifferentVal2) {
auto t = makeNamedDecls(
"template <class A> class foo { int a : sizeof(A); };",
"template <class A> class foo { int a : sizeof(A) + 1; };", Lang_CXX03);
EXPECT_FALSE(testStructuralMatch(t));
}

TEST_F(StructuralEquivalenceTemplateTest, ExplicitBoolSame) {
auto Decls = makeNamedDecls(
"template <bool b> struct foo {explicit(b) foo(int);};",
Expand Down

0 comments on commit 007dd12

Please sign in to comment.