[applied] ir: Recognize classes of same layout as being compatible

Message ID 87wmcb48jd.fsf@redhat.com
State New
Headers
Series [applied] ir: Recognize classes of same layout as being compatible |

Commit Message

Dodji Seketeli March 27, 2025, 12:33 a.m. UTC
  Hello,

The patch teaches libabigail to consider two classes having the same
layout as being compatible.

For instance, two classes whose only difference is the accessibility of
some data members are now considered compatible.

	* include/abg-fwd.h (classes_have_same_layout): Declare ...
	* src/abg-ir.cc (classes_have_same_layout): ... new function.
	(types_are_compatible): Use the new classes_have_same_layout.
	* tests/data/test-diff-filter/test5-report.txt: Adjust.
	* tests/data/test-diff-filter/test5-{2,3}-report.txt: Add new
	reference test output.
	* tests/data/test-diff-filter/test5-{2,3}-v{0,1}.{cc,o}: Add new
	source code and binary test input.
	* tests/test-diff-filter.cc (in_out_specs): Add the binary test
	inputs to the test harness.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
Applied to the mainline.
---
 include/abg-fwd.h                             |   4 +
 src/abg-ir.cc                                 | 121 +++++++++++++++++-
 tests/data/Makefile.am                        |  12 +-
 .../data/test-diff-filter/test5-2-report.txt  |  23 ++++
 tests/data/test-diff-filter/test5-2-v0.cc     |  18 +++
 tests/data/test-diff-filter/test5-2-v0.o      | Bin 0 -> 7232 bytes
 tests/data/test-diff-filter/test5-2-v1.cc     |  19 +++
 tests/data/test-diff-filter/test5-2-v1.o      | Bin 0 -> 7232 bytes
 .../data/test-diff-filter/test5-3-report.txt  |   3 +
 tests/data/test-diff-filter/test5-3-v0.cc     |  18 +++
 tests/data/test-diff-filter/test5-3-v0.o      | Bin 0 -> 7232 bytes
 tests/data/test-diff-filter/test5-3-v1.cc     |  19 +++
 tests/data/test-diff-filter/test5-3-v1.o      | Bin 0 -> 7280 bytes
 tests/data/test-diff-filter/test5-report.txt  |   9 +-
 tests/test-diff-filter.cc                     |  14 ++
 15 files changed, 250 insertions(+), 10 deletions(-)
 create mode 100644 tests/data/test-diff-filter/test5-2-report.txt
 create mode 100644 tests/data/test-diff-filter/test5-2-v0.cc
 create mode 100644 tests/data/test-diff-filter/test5-2-v0.o
 create mode 100644 tests/data/test-diff-filter/test5-2-v1.cc
 create mode 100644 tests/data/test-diff-filter/test5-2-v1.o
 create mode 100644 tests/data/test-diff-filter/test5-3-report.txt
 create mode 100644 tests/data/test-diff-filter/test5-3-v0.cc
 create mode 100644 tests/data/test-diff-filter/test5-3-v0.o
 create mode 100644 tests/data/test-diff-filter/test5-3-v1.cc
 create mode 100644 tests/data/test-diff-filter/test5-3-v1.o

new file mode 100644
index 00000000..53e02b91
new file mode 100644
index 00000000..31e12bb0
new file mode 100644
index 00000000..2a324dbc
index 3dccddda..9666a8fd 100644
  

Patch

diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index f65f3b20..c08b177a 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -1251,6 +1251,10 @@  get_type_declaration(type_base*);
 decl_base_sptr
 get_type_declaration(const type_base_sptr);
 
+bool
+classes_have_same_layout(const type_base_sptr& f,
+			 const type_base_sptr& s);
+
 bool
 types_are_compatible(const type_base_sptr,
 		     const type_base_sptr);
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index b86eb9a6..85593169 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -10222,7 +10222,96 @@  decl_base_sptr
 get_type_declaration(const type_base_sptr t)
 {return dynamic_pointer_cast<decl_base>(t);}
 
-/// Test if two types are equal modulo a typedef.
+/// Test if two classes have the same layout.
+///
+/// Test if all the types and offsets of the members are equal,
+/// regardless of their access modifiers.
+///
+/// @param f the first class to take into account.
+///
+/// @param s the second class to take into account.
+///
+/// @return true iff @p s and @p f are class types with the same
+/// layout.
+bool
+classes_have_same_layout(const type_base_sptr& f, const type_base_sptr& s)
+{
+  class_decl_sptr fc = is_class_type(peel_qualified_or_typedef_type(f)),
+    sc = is_class_type(peel_qualified_or_typedef_type(s));
+
+  if (!fc
+      || !sc
+      || (fc->get_qualified_name() != sc->get_qualified_name())
+      || (fc->get_size_in_bits() != sc->get_size_in_bits())
+      || (fc->get_data_members().size() != sc->get_data_members().size()))
+    return false;
+
+  if (*fc == *sc)
+    return true;
+
+  // Compare the types and offsets of data members one by one.
+  for (auto f_decl_it = fc->get_data_members().begin(),
+	 s_decl_it = sc->get_data_members().begin();
+       (f_decl_it != fc->get_data_members().end()
+	&& s_decl_it != sc->get_data_members().end());
+       ++f_decl_it, ++s_decl_it)
+    {
+      var_decl_sptr dm1 = *f_decl_it, dm2 = *s_decl_it;
+      type_base_sptr dm1_type = dm1->get_type(), dm2_type = dm2->get_type();
+
+      if (*dm1_type != *dm2_type
+	  || get_data_member_offset(dm1) != get_data_member_offset(dm2))
+	return false;
+    }
+
+  // Compare the layout of base types
+  for (auto f_bs_it = fc->get_base_specifiers().begin(),
+	 s_bs_it = sc->get_base_specifiers().end();
+       (f_bs_it != fc->get_base_specifiers().end()
+	&& s_bs_it != sc->get_base_specifiers().end());
+       ++f_bs_it, ++s_bs_it)
+    {
+      class_decl::base_spec_sptr f_bs = *f_bs_it, s_bs = *s_bs_it;
+      if ((f_bs->get_is_virtual() != s_bs->get_is_virtual())
+	  || (f_bs->get_offset_in_bits() != s_bs->get_offset_in_bits()))
+	return false;
+
+      class_decl_sptr fb = f_bs->get_base_class(), sb = s_bs->get_base_class();
+      if (!classes_have_same_layout(fb, sb))
+	return false;
+    }
+
+  if (fc->has_vtable() != sc->has_vtable())
+    return false;
+
+  // Compare virtual function types
+  if (fc->has_vtable())
+    {
+      if (fc->get_virtual_mem_fns().size() > sc->get_virtual_mem_fns().size())
+	// Some virtual member function got removed.  Bad.
+	return false;
+
+      for (auto it1 = fc->get_virtual_mem_fns().begin(),
+	     it2 = sc->get_virtual_mem_fns().begin();
+	   (it1 != fc->get_virtual_mem_fns().end()
+	    && it2 != sc->get_virtual_mem_fns().end());
+	   ++it1, ++it2)
+	{
+	  method_decl_sptr method1 = *it1;
+	  method_decl_sptr method2 = *it2;
+
+	  if ((get_member_function_vtable_offset(method1)
+	       != get_member_function_vtable_offset(method2))
+	      || types_are_compatible(method1->get_type(),
+				      method2->get_type()))
+	    return false;
+	}
+    }
+
+  return true;
+}
+
+/// Test if two types are equal modulo a typedef or CV qualifiers.
 ///
 /// Type A and B are compatible if
 ///
@@ -10230,6 +10319,7 @@  get_type_declaration(const type_base_sptr t)
 ///	- or A and B are integral types with harmless name change
 ///	- or if one type is a typedef of the other one.
 ///	- or if one type is the CV qualified version of the other
+///	- or if A and B are classes with the same layout.
 ///	- or if A and B are pointers, references or arrays of
 ///	  compatible types
 ///
@@ -10287,6 +10377,35 @@  types_are_compatible(const type_base_sptr type1, const type_base_sptr type2)
       return true;
     }
 
+  if (function_type_sptr fn_type1 = is_function_type(t1))
+    if (function_type_sptr fn_type2 = is_function_type(t2))
+      {
+	// Compare return types
+	if (!types_are_compatible(fn_type1->get_return_type(),
+				  fn_type2->get_return_type()))
+	  return false;
+
+	// Compare parameter types, omitting the implicit parameter to
+	// avoid infinite recursion when we are being called from
+	// classes_have_same_layout on classes with virtual member
+	// functions.
+	if (fn_type1->get_parameters().size()
+	    != fn_type2->get_parameters().size())
+	  return false;
+
+	for (auto p1 = fn_type1->get_first_non_implicit_parm(),
+	     p2 = fn_type2->get_first_non_implicit_parm();
+	     (p1 != fn_type1->get_parameters().end()
+	      && p2 != fn_type2->get_parameters().end());
+	     ++p1, ++p2)
+	  if (!types_are_compatible((*p1)->get_type(),
+				    (*p2)->get_type()))
+	    return false;
+      }
+
+  if (classes_have_same_layout(t1, t2))
+    return true;
+
   return false;
 }
 
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 9f05f169..ebc5f0bc 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -1019,7 +1019,17 @@  test-diff-filter/test5-v0.cc		\
 test-diff-filter/test5-v1.cc		\
 test-diff-filter/test5-v0.o		\
 test-diff-filter/test5-v1.o		\
-test-diff-filter/test5-report.txt		\
+test-diff-filter/test5-report.txt	\
+test-diff-filter/test5-2-report.txt     \
+test-diff-filter/test5-2-v0.cc          \
+test-diff-filter/test5-2-v0.o           \
+test-diff-filter/test5-2-v1.cc          \
+test-diff-filter/test5-2-v1.o           \
+test-diff-filter/test5-3-report.txt     \
+test-diff-filter/test5-3-v0.cc          \
+test-diff-filter/test5-3-v0.o           \
+test-diff-filter/test5-3-v1.cc          \
+test-diff-filter/test5-3-v1.o           \
 test-diff-filter/test6-v0.cc		\
 test-diff-filter/test6-v1.cc		\
 test-diff-filter/test6-v0.o		\
diff --git a/tests/data/test-diff-filter/test5-2-report.txt b/tests/data/test-diff-filter/test5-2-report.txt
new file mode 100644
index 00000000..e2f5f0ba
--- /dev/null
+++ b/tests/data/test-diff-filter/test5-2-report.txt
@@ -0,0 +1,23 @@ 
+Functions changes summary: 0 Removed, 2 Changed (2 filtered out), 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+2 functions with some indirect sub-type change:
+
+  [C] 'method C0::C0()' has some indirect sub-type changes:
+    implicit parameter 0 of type 'C0*' has sub-type changes:
+      in pointed to type 'class C0':
+        type size hasn't changed
+        1 member function changes (1 filtered):
+          'method virtual unsigned int C0::vfn2(char)' has some sub-type changes:
+            return type changed:
+              type name changed from 'unsigned int' to 'int'
+              type size hasn't changed
+            implicit parameter 0 of type 'C0*' has sub-type changes:
+              pointed to type 'class C0' changed, as being reported
+        no data member change (1 filtered);
+
+  [C] 'method virtual unsigned int C0::vfn2(char)' has some indirect sub-type changes:
+    return type changed:
+      type name changed from 'unsigned int' to 'int'
+      type size hasn't changed
+
diff --git a/tests/data/test-diff-filter/test5-2-v0.cc b/tests/data/test-diff-filter/test5-2-v0.cc
new file mode 100644
index 00000000..cdf5814e
--- /dev/null
+++ b/tests/data/test-diff-filter/test5-2-v0.cc
@@ -0,0 +1,18 @@ 
+// g++ -g -Wall -c test5-2-v0.cc
+
+class C0
+{
+  int m0;
+
+public:
+  C0()
+    :m0(0)
+  {}
+
+  virtual int vfn1() {return 0;}
+  virtual unsigned vfn2(char) {return 0;}
+};
+
+C0
+foo()
+{return C0();}
diff --git a/tests/data/test-diff-filter/test5-2-v0.o b/tests/data/test-diff-filter/test5-2-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..42f38cdb6276377f59e07c9c37772e2bb35fcb1b
GIT binary patch
literal 7232
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
F|1Svz5BvZC

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-filter/test5-2-v1.cc b/tests/data/test-diff-filter/test5-2-v1.cc
--- /dev/null
+++ b/tests/data/test-diff-filter/test5-2-v1.cc
@@ -0,0 +1,19 @@ 
+// g++ -g -Wall -c test5-2-v1.cc
+
+struct C0
+{
+  int m0;
+
+  C0()
+    :m0(0)
+  {}
+
+  virtual int vfn1() {return 0;}
+  virtual int vfn2(char) {return 0;}
+};
+
+typedef C0 c0_type;
+
+c0_type
+foo()
+{return C0();}
diff --git a/tests/data/test-diff-filter/test5-2-v1.o b/tests/data/test-diff-filter/test5-2-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..1d38fdfec12229c8587ec07ef60fcea76e7fc724
GIT binary patch
literal 7232
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

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-filter/test5-3-report.txt b/tests/data/test-diff-filter/test5-3-report.txt
--- /dev/null
+++ b/tests/data/test-diff-filter/test5-3-report.txt
@@ -0,0 +1,3 @@ 
+Functions changes summary: 0 Removed, 0 Changed (4 filtered out), 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
diff --git a/tests/data/test-diff-filter/test5-3-v0.cc b/tests/data/test-diff-filter/test5-3-v0.cc
new file mode 100644
index 00000000..2c15c4e5
--- /dev/null
+++ b/tests/data/test-diff-filter/test5-3-v0.cc
@@ -0,0 +1,18 @@ 
+// g++ -g -Wall -c test5-3-v0.cc
+
+class C0
+{
+  int m0;
+
+public:
+  C0()
+    :m0(0)
+  {}
+
+  virtual int vfn1() {return 0;}
+  virtual unsigned vfn2(char) {return 0;}
+};
+
+C0
+foo()
+{return C0();}
diff --git a/tests/data/test-diff-filter/test5-3-v0.o b/tests/data/test-diff-filter/test5-3-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..acabc3befe030df90319a2ee1b94262ff0b25c8a
GIT binary patch
literal 7232
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
F{$E%h5C8xG

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-filter/test5-3-v1.cc b/tests/data/test-diff-filter/test5-3-v1.cc
--- /dev/null
+++ b/tests/data/test-diff-filter/test5-3-v1.cc
@@ -0,0 +1,19 @@ 
+// g++ -g -Wall -c test5-3-v1.cch
+
+struct C0
+{
+  int m0;
+
+  C0()
+    :m0(0)
+  {}
+
+  virtual int vfn1() {return 0;}
+  virtual unsigned vfn2(char) {return 0;}
+};
+
+typedef C0 c0_type;
+
+c0_type
+foo()
+{return C0();}
diff --git a/tests/data/test-diff-filter/test5-3-v1.o b/tests/data/test-diff-filter/test5-3-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..8fa45b495da79479f61d51ce32dd9c089afddf86
GIT binary patch
literal 7280
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
V84meuLYZOyH>Cd4j)No8zW||>7h(Va

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-filter/test5-report.txt b/tests/data/test-diff-filter/test5-report.txt
--- a/tests/data/test-diff-filter/test5-report.txt
+++ b/tests/data/test-diff-filter/test5-report.txt
@@ -1,10 +1,3 @@ 
-Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function
 Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
 
-1 function with some indirect sub-type change:
-
-  [C] 'function void foo(C0)' has some indirect sub-type changes:
-    parameter 1 of type 'class C0' has sub-type changes:
-      entity changed from 'class C0' to 'typedef c0_type'
-      type size hasn't changed
-
diff --git a/tests/test-diff-filter.cc b/tests/test-diff-filter.cc
index 94abc906..0bf2eb81 100644
--- a/tests/test-diff-filter.cc
+++ b/tests/test-diff-filter.cc
@@ -93,6 +93,20 @@  InOutSpec in_out_specs[] =
     "data/test-diff-filter/test5-report.txt",
     "output/test-diff-filter/test5-report.txt",
   },
+  {
+    "data/test-diff-filter/test5-2-v0.o",
+    "data/test-diff-filter/test5-2-v1.o",
+    "--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
+    "data/test-diff-filter/test5-2-report.txt",
+    "output/test-diff-filter/test5-2-report.txt",
+  },
+  {
+    "data/test-diff-filter/test5-3-v0.o",
+    "data/test-diff-filter/test5-3-v1.o",
+    "--no-default-suppression --no-linkage-name --no-show-locs --no-redundant",
+    "data/test-diff-filter/test5-3-report.txt",
+    "output/test-diff-filter/test5-3-report.txt",
+  },
   {
     "data/test-diff-filter/test6-v0.o",
     "data/test-diff-filter/test6-v1.o",