diff mbox series

[applied] suppression: Fix has_data_member_inserted_between = {offset_of(), offset_of()}

Message ID 875ys0s45x.fsf@redhat.com
State New
Headers show
Series [applied] suppression: Fix has_data_member_inserted_between = {offset_of(), offset_of()} | expand

Commit Message

Dodji Seketeli Dec. 7, 2021, 5:42 p.m. UTC
Hello,

This should fix bug https://sourceware.org/bugzilla/show_bug.cgi?id=28073

There is at least a case where the evaluation of the suppression
specification rule incarnated by the property
has_data_member_inserted_between doesn't work.  This is in the context
of the following suppression specification:

    [suppress_type]
     name = struct_foo
     has_data_member_inserted_between = {offset_of(dm1), offset_of(dm2)}

The evaluation of the rule incarnated by
has_data_member_inserted_between fails in the context of a type change
where the data member "dm1" is removed from the type struct_foo.  In
that case, the evaluation of the suppression should ALWAYS yield to
the suppression specification NOT suppressing the change.  But in some
cases the change is suppressed nonetheless.

This patch fixes that.

The idea of the patch is that if the class has a removed data member
or if its size shrinks then no type change on that class can be
suppressed.  This is because those two kinds of change are
incompatible ABI (or at least API) changes.  So they should be
reported.

The patch also fixes the evaluation of the boundaries of the insertion
range expressed as an "offset_after" expression.

	* doc/manuals/libabigail-concepts.rst: Update the documentation to
	reflect that has_data_member* properties will never suppress any
	type change if the change carries a data member suppression or a
	type size reduction.
	* include/abg-fwd.h (get_last_data_member)
	(get_next_data_member_offset): Declare new functions.
	* include/abg-suppression.h
	(insertion_range::boundary_value_is_end): Declare new static
	member function.
	(type_supression::insertion_range::eval_boundary): Make this
	static function take an uint64_t rather than ssize_t.
	(type_suppression::insertion_range::integer_boundary::{integer_boundary,
	as_integer, operator int}): Make these member functions and
	operator take or return uint64_t rather than int.
	* src/abg-ir.cc (get_last_data_member)
	(get_next_data_member_offset): Define new functions.
	* src/abg-suppression.cc
	(type_suppression::suppresses_diff): Rework logic to better handle
	"has_data_member_inserted_*" properties in the context of class
	diffs.  If the diff object carries data member removal or size
	reduction, the diff object is not suppressed by the current type
	suppression.  Also, the property "has_data_member_inserted_at =
	end", is now represented by an insertion range where the beginning
	and the end of the range are both the max possible value of
	insertion range boundaries; the code is made to recognize that.
	(type_suppression::insertion_range::eval_boundary): Make this
	static function take an uint64_t rather than ssize_t.  If the
	boundary is expressed as a "offset_after" expression, make sure
	the offset of the next data member is considered if it's present.
	(type_suppression::insertion_range::integer_boundary::{integer_boundary,
	as_integer, operator int}): Make these take or return uint64_t
	rather than int.
	(type_suppression::insertion_range::boundary_value_is_end): Define
	new member function.
	(type_suppression::insertion_range::integer_boundary::priv::value_):
	Turn the type of this into uint64_t, from int.
	(type_suppression::insertion_range::integer_boundary::priv::priv):
	The parameter of this is now uint64_t, from int.
	* tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.c:
	New test source code.
	* tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.o:
	New test binary.
	* tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.o.abi:
	New test input.
	* tests/data/test-diff-suppr/PR28073/PR28073-output-{1,2}.txt: New
	test reference output.
	* tests/data/test-diff-suppr/PR28073/PR28073.after.o: New test
	binary.
	* tests/data/test-diff-suppr/PR28073/PR28073.after.o.abi: New test
	input.
	* tests/data/test-diff-suppr/PR28073/PR28073.before.o: New test
	binary.
	* tests/data/test-diff-suppr/PR28073/PR28073.before.o.abi: New
	test input.
	* tests/data/test-diff-suppr/PR28073/PR28073.c: New test source
	code.
	* tests/data/test-diff-suppr/PR28073/bitfield.suppr: New test
	input.
	* tests/data/Makefile.am: Add the new test material to source
	distribution.
	* tests/test-diff-suppr.cc: Add the new test input to this test
	harness.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
Applied to master.
---
 doc/manuals/libabigail-concepts.rst           |  20 +-
 include/abg-fwd.h                             |   8 +
 include/abg-suppression.h                     |  11 +-
 src/abg-ir.cc                                 |  36 ++++
 src/abg-suppression.cc                        | 171 +++++++++++-------
 tests/data/Makefile.am                        |  11 ++
 .../PR28073/PR28073-bitfield-removed.c        |  14 ++
 .../PR28073/PR28073-bitfield-removed.o        | Bin 0 -> 3776 bytes
 .../PR28073/PR28073-bitfield-removed.o.abi    |  29 +++
 .../PR28073/PR28073-output-1.txt              |   3 +
 .../PR28073/PR28073-output-2.txt              |  14 ++
 .../test-diff-suppr/PR28073/PR28073.after.o   | Bin 0 -> 3848 bytes
 .../PR28073/PR28073.after.o.abi               |  35 ++++
 .../test-diff-suppr/PR28073/PR28073.before.o  | Bin 0 -> 3768 bytes
 .../PR28073/PR28073.before.o.abi              |  32 ++++
 tests/data/test-diff-suppr/PR28073/PR28073.c  |  24 +++
 .../test-diff-suppr/PR28073/bitfield.suppr    |   4 +
 tests/test-diff-suppr.cc                      |  20 ++
 18 files changed, 360 insertions(+), 72 deletions(-)
 create mode 100644 tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.c
 create mode 100644 tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.o
 create mode 100644 tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.o.abi
 create mode 100644 tests/data/test-diff-suppr/PR28073/PR28073-output-1.txt
 create mode 100644 tests/data/test-diff-suppr/PR28073/PR28073-output-2.txt
 create mode 100644 tests/data/test-diff-suppr/PR28073/PR28073.after.o
 create mode 100644 tests/data/test-diff-suppr/PR28073/PR28073.after.o.abi
 create mode 100644 tests/data/test-diff-suppr/PR28073/PR28073.before.o
 create mode 100644 tests/data/test-diff-suppr/PR28073/PR28073.before.o.abi
 create mode 100644 tests/data/test-diff-suppr/PR28073/PR28073.c
 create mode 100644 tests/data/test-diff-suppr/PR28073/bitfield.suppr
diff mbox series

Patch

diff --git a/doc/manuals/libabigail-concepts.rst b/doc/manuals/libabigail-concepts.rst
index b11c2c87..c30e87e8 100644
--- a/doc/manuals/libabigail-concepts.rst
+++ b/doc/manuals/libabigail-concepts.rst
@@ -433,7 +433,11 @@  The potential properties of this sections are listed below:
 
  Suppresses change reports involving a type which has at least one
  data member inserted at an offset specified by the property value
- ``offset-in-bit``.  The value ``offset-in-bit`` is either:
+ ``offset-in-bit``.  Please note that if a type has a change in which
+ at least one of its data members is removed or its size is reduced,
+ the type will *NOT* be suppressed by the evaluation of this property.
+
+ The value ``offset-in-bit`` is either:
 
 	 - an integer value, expressed in bits, which denotes the
 	   offset of the insertion point of the data member, starting
@@ -468,11 +472,14 @@  The potential properties of this sections are listed below:
    ``has_data_member_inserted_between`` ``=`` {<``range-begin``>, <``range-end``>}
 
  Suppresses change reports involving a type which has at least one
- data mber inserted at an offset that is comprised in the range
- between range-begin`` and ``range-end``.  Please note that each of
+ data member inserted at an offset that is comprised in the range
+ between ``range-begin`` and ``range-end``.  Please note that each of
  the values ``range-begin`` and ``range-end`` can be of the same form
  as the :ref:`has_data_member_inserted_at
- <suppr_has_data_member_inserted_at_label>` property above.
+ <suppr_has_data_member_inserted_at_label>` property above.  Please
+ also note that if a type has a change in which at least one of its
+ data members is removed or its size is reduced, the type will *NOT* be
+ suppressed by the evaluation of this property.
 
  Usage examples of this properties are: ::
 
@@ -508,7 +515,10 @@  The potential properties of this sections are listed below:
  long as the system can cope with.  The values of the boundaries of
  the ranges are of the same kind as for the
  :ref:`has_data_member_inserted_at
- <suppr_has_data_member_inserted_at_label>` property above.
+ <suppr_has_data_member_inserted_at_label>` property above.  Please
+ note that if a type has a change in which at least one of its data
+ members is removed or its size is reduced, the type will *NOT* be
+ suppressed by the evaluation of this property.
 
  Another usage example of this property is thus: ::
 
diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index 63895314..36a99c3b 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -639,6 +639,9 @@  is_data_member(const decl_base *);
 const var_decl_sptr
 get_next_data_member(const class_or_union_sptr&, const var_decl_sptr&);
 
+var_decl_sptr
+get_last_data_member(const class_or_union_sptr&);
+
 bool
 is_anonymous_data_member(const decl_base&);
 
@@ -721,6 +724,11 @@  get_data_member_offset(const decl_base_sptr);
 uint64_t
 get_absolute_data_member_offset(const var_decl&);
 
+bool
+get_next_data_member_offset(const class_or_union_sptr&,
+			    const var_decl_sptr&,
+			    uint64_t&);
+
 uint64_t
 get_var_size_in_bits(const var_decl_sptr&);
 
diff --git a/include/abg-suppression.h b/include/abg-suppression.h
index db0334e7..6c13e33d 100644
--- a/include/abg-suppression.h
+++ b/include/abg-suppression.h
@@ -328,7 +328,10 @@  public:
   static bool
   eval_boundary(boundary_sptr	boundary,
 		class_decl_sptr context,
-		ssize_t&	value);
+		uint64_t&	value);
+
+  static bool
+  boundary_value_is_end(uint64_t value);
 }; // end class insertion_range
 
 type_suppression::insertion_range::integer_boundary_sptr
@@ -360,9 +363,9 @@  class type_suppression::insertion_range::integer_boundary
   integer_boundary();
 
 public:
-  integer_boundary(int value);
-  int as_integer() const;
-  operator int() const;
+  integer_boundary(uint64_t value);
+  uint64_t as_integer() const;
+  operator uint64_t () const;
   ~integer_boundary();
 }; //end class type_suppression::insertion_range::integer_boundary
 
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 17a62153..2cc4cf8c 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -5739,6 +5739,13 @@  get_next_data_member(const class_or_union_sptr &klass,
   return var_decl_sptr();
 }
 
+/// Get the last data member of a class type.
+///
+/// @param klass the class type to consider.
+var_decl_sptr
+get_last_data_member(const class_or_union_sptr &klass)
+{return klass->get_non_static_data_members().back();}
+
 /// Test if a decl is an anonymous data member.
 ///
 /// @param d the decl to consider.
@@ -6003,6 +6010,35 @@  uint64_t
 get_data_member_offset(const decl_base_sptr d)
 {return get_data_member_offset(dynamic_pointer_cast<var_decl>(d));}
 
+/// Get the offset of the non-static data member that comes after a
+/// given one.
+///
+/// If there is no data member after after the one given to this
+/// function (maybe because the given one is the last data member of
+/// the class type) then the function return false.
+///
+/// @param klass the class to consider.
+///
+/// @param dm the data member before the one we want to retrieve.
+///
+/// @param offset out parameter.  This parameter is set by the
+/// function to the offset of the data member that comes right after
+/// the data member @p dm, iff the function returns true.
+///
+/// @return true iff the data member coming right after @p dm was
+/// found.
+bool
+get_next_data_member_offset(const class_or_union_sptr& klass,
+			    const var_decl_sptr& dm,
+			    uint64_t& offset)
+{
+  var_decl_sptr next_dm = get_next_data_member(klass, dm);
+  if (!next_dm)
+    return false;
+  offset = get_data_member_offset(next_dm);
+  return true;
+}
+
 /// Get the absolute offset of a data member.
 ///
 /// If the data member is part of an anonymous data member then this
diff --git a/src/abg-suppression.cc b/src/abg-suppression.cc
index d3343a81..48c73cf8 100644
--- a/src/abg-suppression.cc
+++ b/src/abg-suppression.cc
@@ -14,6 +14,7 @@ 
 
 #include "abg-internal.h"
 #include <memory>
+#include <limits>
 
 // <headers defining libabigail's API go under here>
 ABG_BEGIN_EXPORT_DECLARATIONS
@@ -773,67 +774,93 @@  type_suppression::suppresses_diff(const diff* diff) const
       d = is_type_diff(get_typedef_diff_underlying_type_diff(d));
     }
 
+  // Now let's consider class diffs in the context of a suppr spec
+  // that contains properties like "has_data_member_inserted_*".
+
   const class_diff* klass_diff = dynamic_cast<const class_diff*>(d);
-  if (// We are looking at a class diff ...
-      klass_diff
-      // ... that has inserted data members ...
-      && !get_data_member_insertion_ranges().empty()
-      // ... that has no deleted data members ...
-      && klass_diff->deleted_data_members().empty()
-      // ... and in which the class size hasn't shrunk (because, e.g,
-      // the base classes have changed).
-      && (klass_diff->first_class_decl()->get_size_in_bits()
-	  <= klass_diff->second_class_decl()->get_size_in_bits()))
+  if (klass_diff)
     {
-      const class_decl_sptr& first_type_decl = klass_diff->first_class_decl();
-      const class_decl_sptr& second_type_decl = klass_diff->second_class_decl();
-      size_t first_type_size = first_type_decl->get_size_in_bits();
-      size_t second_type_size = second_type_decl->get_size_in_bits();
-
-      for (string_decl_base_sptr_map::const_iterator m =
-	     klass_diff->inserted_data_members().begin();
-	   m != klass_diff->inserted_data_members().end();
-	   ++m)
+      // We are looking at a class diff ...
+      if (!get_data_member_insertion_ranges().empty())
 	{
-	  decl_base_sptr member = m->second;
-	  size_t dm_offset = get_data_member_offset(member);
-	  bool matched = false;
-
-	  for (insertion_ranges::const_iterator i =
-		 get_data_member_insertion_ranges().begin();
-	       i != get_data_member_insertion_ranges().end();
-	       ++i)
+	  // ... and the suppr spec contains a
+	  // "has_data_member_inserted_*" clause ...
+	  if (klass_diff->deleted_data_members().empty()
+	      && (klass_diff->first_class_decl()->get_size_in_bits()
+		  <= klass_diff->second_class_decl()->get_size_in_bits()))
 	    {
-	      type_suppression::insertion_range_sptr range = *i;
-	      ssize_t range_begin_val = 0,range_end_val = 0;
-	      if (!type_suppression::insertion_range::eval_boundary
-		  (range->begin(), first_type_decl, range_begin_val))
-		break;
-	      if (!type_suppression::insertion_range::eval_boundary
-		  (range->end(), first_type_decl, range_end_val))
-		break;
-
-	      unsigned range_begin =
-		(range_begin_val < 0) ? first_type_size : range_begin_val;
-
-	      unsigned range_end =
-		(range_end_val < 0) ? second_type_size : range_end_val;
-
-	      if (range_begin > range_end)
-		continue;
-
-	      if (range_begin_val < 0 || range_end_val < 0)
+	      // That "has_data_member_inserted_*" clause doesn't hold
+	      // if the class has deleted data members or shrunk.
+
+	      const class_decl_sptr& first_type_decl =
+		klass_diff->first_class_decl();
+	      const class_decl_sptr& second_type_decl =
+		klass_diff->second_class_decl();
+
+	      for (string_decl_base_sptr_map::const_iterator m =
+		     klass_diff->inserted_data_members().begin();
+		   m != klass_diff->inserted_data_members().end();
+		   ++m)
 		{
-		  if (dm_offset < range_begin)
-		    continue;
+		  decl_base_sptr member = m->second;
+		  size_t dm_offset = get_data_member_offset(member);
+		  bool matched = false;
+
+		  for (insertion_ranges::const_iterator i =
+			 get_data_member_insertion_ranges().begin();
+		       i != get_data_member_insertion_ranges().end();
+		       ++i)
+		    {
+		      type_suppression::insertion_range_sptr range = *i;
+		      uint64_t range_begin_val = 0, range_end_val = 0;
+		      if (!type_suppression::insertion_range::eval_boundary
+			  (range->begin(), first_type_decl, range_begin_val))
+			break;
+		      if (!type_suppression::insertion_range::eval_boundary
+			  (range->end(), first_type_decl, range_end_val))
+			break;
+
+		      uint64_t range_begin = range_begin_val;
+		      uint64_t range_end = range_end_val;
+
+		      if (insertion_range::boundary_value_is_end(range_begin)
+			  && insertion_range::boundary_value_is_end(range_end))
+			{
+			  // This idiom represents the predicate
+			  // "has_data_member_inserted_at = end"
+			  if (dm_offset >
+			      get_data_member_offset(get_last_data_member
+						     (first_type_decl)))
+			    {
+			      // So the data member was added after
+			      // last data member of the klass.  That
+			      // matches the suppr spec
+			      // "has_data_member_inserted_at = end".
+			      matched = true;
+			      continue;
+			    }
+			}
+
+			if (range_begin > range_end)
+			  // Wrong suppr spec.  Ignore it.
+			  continue;
+
+		      if (dm_offset < range_begin || dm_offset > range_end)
+			// The offset of the added data member doesn't
+			// match the insertion range specified.  So
+			// the diff object won't be suppressed.
+			continue;
+
+		      // If we reached this point, then all the
+		      // insertion range constraints have been
+		      // satisfied.  So
+		      matched = true;
+		    }
+		  if (!matched)
+		    return false;
 		}
-	      else
-		if (dm_offset < range_begin || dm_offset > range_end)
-		  continue;
-
-	      matched = true;
 	    }
-	  if (!matched)
+	  else
 	    return false;
 	}
     }
@@ -1311,7 +1338,7 @@  type_suppression::insertion_range::create_fn_call_expr_boundary(const string& s)
 bool
 type_suppression::insertion_range::eval_boundary(boundary_sptr	 boundary,
 						 class_decl_sptr context,
-						 ssize_t&	 value)
+						 uint64_t&	 value)
 {
   if (integer_boundary_sptr b = is_integer_boundary(boundary))
     {
@@ -1338,8 +1365,13 @@  type_suppression::insertion_range::eval_boundary(boundary_sptr	 boundary,
 		  if (fn_call->get_name() == "offset_of")
 		    value = get_data_member_offset(*it);
 		  else if (fn_call->get_name() == "offset_after")
-		    value = get_data_member_offset(*it) +
-		      (*it)->get_type()->get_size_in_bits();
+		    {
+		      if (!get_next_data_member_offset(context, *it, value))
+			{
+			  value = get_data_member_offset(*it) +
+			    (*it)->get_type()->get_size_in_bits();
+			}
+		    }
 		  else
 		    // We should not reach this point.
 		    abort();
@@ -1351,6 +1383,19 @@  type_suppression::insertion_range::eval_boundary(boundary_sptr	 boundary,
   return false;
 }
 
+/// Test if a given value supposed to be inside an insertion range
+/// represents the end of the range.
+///
+/// @param value the value to test for.
+///
+/// @return true iff @p value represents the end of the insertion
+/// range.
+bool
+type_suppression::insertion_range::boundary_value_is_end(uint64_t value)
+{
+  return value == std::numeric_limits<uint64_t>::max();
+}
+
 /// Tests if a given instance of @ref
 /// type_suppression::insertion_range::boundary is actually an integer boundary.
 ///
@@ -1398,13 +1443,13 @@  type_suppression::insertion_range::boundary::~boundary()
 /// type_suppression::insertion_range::integer_boundary.
 struct type_suppression::insertion_range::integer_boundary::priv
 {
-  int value_;
+  uint64_t value_;
 
   priv()
     : value_()
   {}
 
-  priv(int value)
+  priv(uint64_t value)
     : value_(value)
   {}
 }; // end type_suppression::insertion_range::integer_boundary::priv
@@ -1413,22 +1458,22 @@  struct type_suppression::insertion_range::integer_boundary::priv
 /// type_suppression::insertion_range::integer_boundary.
 ///
 /// @param value the integer value of the newly created integer boundary.
-type_suppression::insertion_range::integer_boundary::integer_boundary(int value)
+type_suppression::insertion_range::integer_boundary::integer_boundary(uint64_t value)
   : priv_(new priv(value))
 {}
 
-/// Return the integer value of the current inace of @ref
+/// Return the integer value of the current instance of @ref
 /// type_suppression::insertion_range::integer_boundary.
 ///
 /// @return the integer value of the current boundary.
-int
+uint64_t
 type_suppression::insertion_range::integer_boundary::as_integer() const
 {return priv_->value_;}
 
 /// Converts the current boundary into an integer value.
 ///
 /// @return the integer value of the current boundary.
-type_suppression::insertion_range::integer_boundary::operator int() const
+type_suppression::insertion_range::integer_boundary::operator uint64_t() const
 {return as_integer();}
 
 /// Destructor of @ref type_suppression::insertion_range::integer_boundary.
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index b83f05be..7edb1e24 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -1550,6 +1550,17 @@  test-diff-suppr/PR27267/v1.c \
 test-diff-suppr/PR27267/libtestpr27267-v0.so \
 test-diff-suppr/PR27267/libtestpr27267-v1.so \
 test-diff-suppr/PR27267/report-1.txt \
+test-diff-suppr/PR28073/PR28073-bitfield-removed.c \
+test-diff-suppr/PR28073/PR28073-bitfield-removed.o \
+test-diff-suppr/PR28073/PR28073-bitfield-removed.o.abi \
+test-diff-suppr/PR28073/PR28073-output-1.txt \
+test-diff-suppr/PR28073/PR28073-output-2.txt \
+test-diff-suppr/PR28073/PR28073.after.o \
+test-diff-suppr/PR28073/PR28073.after.o.abi \
+test-diff-suppr/PR28073/PR28073.before.o \
+test-diff-suppr/PR28073/PR28073.before.o.abi \
+test-diff-suppr/PR28073/PR28073.c \
+test-diff-suppr/PR28073/bitfield.suppr \
 \
 test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1 \
 test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1.abi \
diff --git a/tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.c b/tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.c
new file mode 100644
index 00000000..e88aec9e
--- /dev/null
+++ b/tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.c
@@ -0,0 +1,14 @@ 
+/*
+ * Compile this with:
+ * gcc -g -c PR28073-bitfield-removed.c
+ */
+#include <inttypes.h>
+
+struct bigstruct {
+  char name[128];
+  uint8_t other;
+};
+
+void access_bigstruct(struct bigstruct *st __attribute__((unused)))
+{
+}
diff --git a/tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.o b/tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.o
new file mode 100644
index 0000000000000000000000000000000000000000..bdfe7d35e40fbc3883ffbf2ffa6a27255ba8f2a3
GIT binary patch
literal 3776
zcmbtX&2Jk;6rb_Nv6D^QBra`2KygrMn+mVv0BIVO)+i!PM2SjJkw74KZBOh4dmZhr
zt0bsuD@3J=13_>^q7pqI_ya(K15yR*0VIwb=n;X$0db4O0p6Q^V{fKz_<GXLyx(u$
z$9(Nu`^q!tmSUVUC7hjR9i&*suJ(2Gf>aCa0d|mGSibSo@{P;8JFnjU73etQNgVCL
z=3#82VnzTD4S6hqB<~5kWZ3auBxABUde}mPSR7HjC+@fbB$0?m?2OU$^I#wyukl3k
zQve3KB&8baedZQ0S6RY??h71Tgyss9i{k^*83?8(%0Ku8P`?iu2c}Ssy<1~u@-4LC
zN0@1zHjNaphnSI?H=i<3nJZ~XJBV<Shj<Qx^$hbzQ)$zf7@rvCBZ;BIuo7~I?dnZ)
zBW0Rl01g2XoUf!&NlvnrbPfXaS^UhH%5iKAgA_)$$Izxf&Wxl=9vg+pAApJBJlJD6
zW1K6Khaxp>)biQ{DKA1F2irO5Ip=?*2C>8I01qe=VKBfk&=1H%20$XO4Ucoy*ETZ-
z_?s~UTwAX1R9#WY;OW(yZZ)%qaqWg+#bOIa=ZXO<IaNRKTIGN#rfprW*&dUPjDq2s
zK}~qfuQk13Z&XStt<SDr$SmehX7YJ!#>!`Arf2f`>HMk8@imy#vK`Psc6KV0Z3Hb>
zEL4RnJf{rM_R6(|&AHj^>=T)6mD%O8@cm+El3{9`O0L#yh+L&vdCkdHogi0tN;cTp
zPCd8oYzjZO;RV7E{M`AqnYrnck2C7CB_~*SM7@&rM5B30RIKv9kCkirUe0mL^;SjX
zAfUfr^nDTsTN}c+YRnHRu%;{?feVnGU0j^c9EXjZ`UktHE(P9^3_SS0f-77{{#Eqe
zaKiHPfXzX8Q26#5<C{Z#d?1nBfx(A>!v{rP-=|YU*JF!=y-Q#a(p_7O+rxhUv)dqC
z%x*N4is%eGCPr9YIs|D(SU<Y(-Cs0=4cudkYa5Bor|r4VLEUo^A%@zEe$b<<7^IBI
zW0|`~cqGDO?adQDr11pVgQVcjwO@14PY{psWo;&`;;Fm^;<3b_D83Xzc7}Sz6J$#o
zuh#RN#<vKsY5Wnw7d8GaVOQf{Agto4`K%JZt=X&fT-SK~cA>l%cJ1{}5dKi(Um^UZ
z#(zurHud`ct4|lsQ-1cyZs<Ptj}VXcc<$#2AJzEFgr_zB9l}p){3nFxHU4YD(euT;
z-x0q;y}qst@p#vw_l;TpRwJ-W&<9@F*OV5B&45`IJFuBm@_lA`qHbFiQEF9-j=SE3
zF{#_7k|!?h8MZy!t%|)ab;lLT1yU##>7vBtW}_jX`de-@5EfLqtRL9r*9lkMmbKwE
zH-r~#Q7%y{u6y{&`~NZyA#l&s`KyQpQrdNdFxp0C5&&}1JA>oTV$(%*|6^c-HRr$j
zV|~zLVp^5|Hv|#UZSf}#*11B&2G#GW2<?&s);Y9O^$~t2Nm+nakBI~GM1CZ#I*o37
z9)@%dt?v@4-WwG`x5agKoBthrIY5*@&L1g#{uSW#m_V^XdRbmZ5E0$B2xHyy?^6Dc
z$rtnEuVg*{25=Zt%@b59Rm%UfBB)pSRsRO?-TYVSLjCwR{%_yM{{$`yBo}t=R^?Uw
z`!J&Pwh<^Vk$;p!UAMgj9B$Q~+64F_`Rn_l_76;?V4cU9y8jOOtM5u^-PwPIKLZ6#
z3yPrrCM8n$9M5kE9+hA5-Ew1yJCy$i1R(f#0)2IVyc7Dn4-~se?_U-{MD+a|hOut`
OpHrf5BEG2V{(k{M7*tCD

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.o.abi b/tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.o.abi
new file mode 100644
index 00000000..3d3756c8
--- /dev/null
+++ b/tests/data/test-diff-suppr/PR28073/PR28073-bitfield-removed.o.abi
@@ -0,0 +1,29 @@ 
+<abi-corpus version='2.1' path='PR28073-bitfield-removed.o' architecture='elf-amd-x86_64'>
+  <elf-function-symbols>
+    <elf-symbol name='access_bigstruct' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-function-symbols>
+  <abi-instr address-size='64' path='PR28073-bitfield-removed.c' comp-dir-path='/home/dodji/git/libabigail/fixes/prtests/PR28073' language='LANG_C11'>
+    <type-decl name='char' size-in-bits='8' id='type-id-1'/>
+    <array-type-def dimensions='1' type-id='type-id-1' size-in-bits='1024' id='type-id-2'>
+      <subrange length='128' type-id='type-id-3' id='type-id-4'/>
+    </array-type-def>
+    <type-decl name='unsigned char' size-in-bits='8' id='type-id-5'/>
+    <type-decl name='unsigned long int' size-in-bits='64' id='type-id-3'/>
+    <class-decl name='bigstruct' size-in-bits='1032' is-struct='yes' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073-bitfield-removed.c' line='7' column='1' id='type-id-6'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='name' type-id='type-id-2' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073-bitfield-removed.c' line='8' column='1'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='1024'>
+        <var-decl name='other' type-id='type-id-7' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073-bitfield-removed.c' line='9' column='1'/>
+      </data-member>
+    </class-decl>
+    <typedef-decl name='uint8_t' type-id='type-id-8' filepath='/usr/include/bits/stdint-uintn.h' line='24' column='1' id='type-id-7'/>
+    <typedef-decl name='__uint8_t' type-id='type-id-5' filepath='/usr/include/bits/types.h' line='38' column='1' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-6' size-in-bits='64' id='type-id-9'/>
+    <function-decl name='access_bigstruct' mangled-name='access_bigstruct' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073-bitfield-removed.c' line='12' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='access_bigstruct'>
+      <parameter type-id='type-id-9' name='st' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073-bitfield-removed.c' line='12' column='1'/>
+      <return type-id='type-id-10'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-10'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-diff-suppr/PR28073/PR28073-output-1.txt b/tests/data/test-diff-suppr/PR28073/PR28073-output-1.txt
new file mode 100644
index 00000000..9666a8fd
--- /dev/null
+++ b/tests/data/test-diff-suppr/PR28073/PR28073-output-1.txt
@@ -0,0 +1,3 @@ 
+Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
diff --git a/tests/data/test-diff-suppr/PR28073/PR28073-output-2.txt b/tests/data/test-diff-suppr/PR28073/PR28073-output-2.txt
new file mode 100644
index 00000000..8731043c
--- /dev/null
+++ b/tests/data/test-diff-suppr/PR28073/PR28073-output-2.txt
@@ -0,0 +1,14 @@ 
+Functions changes summary: 0 Removed, 1 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C] 'function void access_bigstruct(bigstruct*)' at PR28073-bitfield-removed.c:12:1 has some indirect sub-type changes:
+    parameter 1 of type 'bigstruct*' has sub-type changes:
+      in pointed to type 'struct bigstruct' at PR28073-bitfield-removed.c:7:1:
+        type size changed from 1040 to 1032 (in bits)
+        1 data member deletion:
+          'uint8_t bitfield0', at offset 1024 (in bits) at plop.c:5:1
+        1 data member change:
+          'uint8_t other' offset changed from 1032 to 1024 (in bits) (by -8 bits)
+
diff --git a/tests/data/test-diff-suppr/PR28073/PR28073.after.o b/tests/data/test-diff-suppr/PR28073/PR28073.after.o
new file mode 100644
index 0000000000000000000000000000000000000000..948323d75eeb8a8e82a5f8b914c050484bb47897
GIT binary patch
literal 3848
zcmbtXO>7%Q6n^8i6DN*SCoXM5L2(eY2_ow_K$@m%YKYn<{Ha7#LWs&;+Z%hSvyOJx
zC<%f9g(_7q1$shATsVN>zzK@P0SSRB?jSB45k1mdr5@nD**ErPY6L1z+IjDN^ZsV$
z?X10h;+c~%AwZFU1?XrB1-RbVk&99+!acAT&MaN}ed*Hcx0WuSxV7i2D{tb|g`Z+O
zQn+&V`vk^HfJl-@f`<EPh|*X@5uu@o^%5xJAxnl#^bi=6!@>O~8N_7Bo_NA>156?{
z5wSByvd^QP^nY9QC4WH0paA_+ggD8m)F!dGRMK%$L|j^B<jh-;^bq?QpT0#LwxJ(K
z5LsCdiE0VrqZlqX<zp?`NfKl4)nOp{t~7rT6D_2SK}7d~F*u((nmUqN&SF7nQpZK8
z&!w=GT}XOdoX3?VhQvdI*_1JMU~EVX_h$A3^l(hv-QKJ)22-gps=%m8A(pcw^o_%E
zHjh#JO>ulwB|bDtL5d?=qhymxfRR)c#YO-I_F%PC96W-L+;fm;NK28V)~s~JUq&H;
zwsXjZ5Vr@@#Hge2L18QmhI$O;J#y1gVIn&a*ff1@Gb1Y!L+>O+av^45fU*;;I(DO4
zfR^h!HP^1@=<pj&x0c(5xYn8trBVxL=Sl&Tothtbtx5n2X<Jw7mIrc>Q7Bw9sM{X+
z^`;l>j>;*e^{MC1<Q5BubA^IAV-|8V(=&y_bm2&DVg-v@vI3r%nw`u|tpzRDK320`
z+jA<YT3)4oY-4VAYWA_*R1K_3#rFMDr%1KTX)c0_I=wP8H+}d~vjX{gbIs0Io7GpG
ze9Z~+4X13OujMrItIme)=hwZ!_5(l9E_dP3^1Zy{RvN9UoyTJQNcK)0!RET{n|1Jm
zDi%0JJL{qfrxq9Ia}&5flmB6J!lS1~$l*ipFgjw-iSMG#Ay}6kf;M~cArf0FAT~1M
zz(8;E3QpdK7(GO?N1qtXT#PNIdtO3=5bios+&J9)tJ@^@T{jr7l4yk;69d{;LkC33
zfXF2pnK1xg&n{%Zz#S-A4oB)~zlWVuxucmVh*~?{UD2x3G>JqwRehNhq~VZBT;89o
z@6&L37b12q<Fr%lcNgV{87DhBTSWyHRNkjpr+b4);f+v*<IELKoaki8+V*%YN_tkq
zw^?7&aQcoAos(lH?@iWS4L{3zOT%AeeM`fiWc{Lst95>$;ghU?tl@vK{)L9K3g2k>
zD(k;!xYB=PTt6@B0V3L8`4N;FK!&+){{Z7;PknNf^@AF&&T(49-(dZ54c}pXUc=vK
zJ=zbH_d~{)nd^1t7^mKh_9vMB=2~Etkq2JL>q-jjjR4H56<A=FeIHEEZdhj3F1KnW
z$6amWoRqC{*|T5WHEns8TeEk&G#uAfE|@}z1ec^<X|Ao=c+s0~Gq6p(1*iPLs+?!N
z=C;grueok}!6xUj>!nqXzH|Sd4qyn{Gj;wdVv&V01u!SuD2<~+ShQzozC=S8()|yi
z4c$?9>reNI9+T3l{C(P_rpn(rbT1akDMB~+(wg9=p?i_+)O|X_w#Sg`F=?vK;5D{W
zOt(Fa6FNq=InJxzn}70u8YjBdpW#B4Kh;m~i(Y>fv2OWKbN+KUA0^$E_PJaBA}9Kk
zohd(k1@-*vh*3;cCyJ83<ovf4z+B~5{58b8`G3w0_1VAp(|50%{|mGzq<qNQqspuJ
zRh&_B+X#gV>>tHQ)@?sQjLwCZOD2+b*k9ilwSUU)TNEg!?thK_)%Ql(>;7Nk1eq3<
z0rMMdsQR4FFN2TrS9rJF6yi_L|0^j-^q+!!b${v!{oO|huJik+e$x>~r0?GlV%_}J
NPp%)OS7*@u{|4a1N=E<y

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-suppr/PR28073/PR28073.after.o.abi b/tests/data/test-diff-suppr/PR28073/PR28073.after.o.abi
new file mode 100644
index 00000000..d594bf67
--- /dev/null
+++ b/tests/data/test-diff-suppr/PR28073/PR28073.after.o.abi
@@ -0,0 +1,35 @@ 
+<abi-corpus version='2.1' path='PR28073.after.o' architecture='elf-amd-x86_64'>
+  <elf-function-symbols>
+    <elf-symbol name='access_bigstruct' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-function-symbols>
+  <abi-instr address-size='64' path='PR28073.c' comp-dir-path='/home/dodji/git/libabigail/fixes/prtests/PR28073' language='LANG_C11'>
+    <type-decl name='char' size-in-bits='8' id='type-id-1'/>
+    <array-type-def dimensions='1' type-id='type-id-1' size-in-bits='1024' id='type-id-2'>
+      <subrange length='128' type-id='type-id-3' id='type-id-4'/>
+    </array-type-def>
+    <type-decl name='unsigned char' size-in-bits='8' id='type-id-5'/>
+    <type-decl name='unsigned long int' size-in-bits='64' id='type-id-3'/>
+    <class-decl name='bigstruct' size-in-bits='1040' is-struct='yes' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073.c' line='9' column='1' id='type-id-6'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='name' type-id='type-id-2' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073.c' line='10' column='1'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='1024'>
+        <var-decl name='bitfield0' type-id='type-id-7' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073.c' line='11' column='1'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='1025'>
+        <var-decl name='bitfield1' type-id='type-id-7' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073.c' line='13' column='1'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='1032'>
+        <var-decl name='other' type-id='type-id-7' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073.c' line='16' column='1'/>
+      </data-member>
+    </class-decl>
+    <typedef-decl name='uint8_t' type-id='type-id-8' filepath='/usr/include/bits/stdint-uintn.h' line='24' column='1' id='type-id-7'/>
+    <typedef-decl name='__uint8_t' type-id='type-id-5' filepath='/usr/include/bits/types.h' line='38' column='1' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-6' size-in-bits='64' id='type-id-9'/>
+    <function-decl name='access_bigstruct' mangled-name='access_bigstruct' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073.c' line='19' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='access_bigstruct'>
+      <parameter type-id='type-id-9' name='st' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/PR28073.c' line='19' column='1'/>
+      <return type-id='type-id-10'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-10'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-diff-suppr/PR28073/PR28073.before.o b/tests/data/test-diff-suppr/PR28073/PR28073.before.o
new file mode 100644
index 0000000000000000000000000000000000000000..84d14ee6ab64609f28b89011a8dda0d92ae9de42
GIT binary patch
literal 3768
zcmbtXO>7%Q6rS<giIa_8CoXN$fa0LiHVE&=0n#)mtx-f83#dX+IUtZ(+Z%hSy|#AO
z$O%HFm53B^Nd*TENO0i5sp<(3;!p{R190NRg(KohPau#e@6En(HiIirdD8B@@0<5G
zKl_|qedf8f80Sn1XXn`gk}PArkpsOb)FOL;9c7o-_kLdAd+Yc8SHJ!P=mg_QoQ>n_
zA$&zej{qJT^4KtvJRT0oaNt8o#>DH?aRUuv2}Fr_!f^vgA`p+*X_MI(z(6=&=UVbh
z02;c)h04Of34I$V&f;QfRG@1t=>hpIJR_^{y2?i3&3H=0LRHqyKl}}m4+W&=P>tPa
zu(9MjXv0r3T|cjDX<&~rExoKirJvJFS*Rj~aF&O734+DP`6KD9uFXu(jPr@%%yC#4
zxx?-aWx1Bt^)LX30K*~x#Y^c|VC_lHOIe&7nPsJ{2{A_veql<cJw1hSi<3K3Xrm{X
zmX!6xCK($$0<~gk>@i#fme0ho2@PLz#eIU5mtahQ?GlWf^FPxm9Pq-x1IkPo3~&te
zBjOqWAQ2afCpa7Fn`tS&8`HqG>-tXJwQD&%-)7sb=MFKh)v{T++=bbta=<E1-4DEO
zHDHqITUQ&F$HYrS!Eo)MVSCJPw7uYPR7xqVFJ8KwTP>W;6$-|JQOGUKFBA&%g>$(x
zn^4rc70^U}aW0o{1zp!(soSpYIaPp`S8c5HmKO7iPvr7-W>u@U@0SmXtT@4zV>fH_
zR0I~)X|_8?m6?rp%QkE6+Ut&4cLKBNR4j0`oTj<u^labkc!BK)zPYivurz=6@%wP-
z`kv{y)n>P5n^1`_Q&R=OcE|RO2J?d&)Ro5#bpf)AtE<boGq5dl|6xz$5#x#H;KA<`
zT;X!@+tFLV35%-$Hb>z>;X9j*_cDBXY&f|OlMe!i4~n>qPp31xvDMVj8W@E1z&FN?
zvpaVOO~N%BL_?d1R(N2dh27+UAWdVDW*C{(?(x}ZY%F3Gs<?)UNIm@zjt=D?SBN6W
zwPTBlR-K}G<gssEBRmn|MGGW+OyT9+3F2|5`X4Fik4Ef8?<HJ_@R+wq7#jqNtfvw}
zc7aC86J%=&FW2+D!gmR8D*Q>puPOX5gk6Pyk+6&>>$ybyj$$v@v#ap<+l2C7IP}*$
zL--?w|B3KTg@1+ccMAVK;U8#J&jt4!1?v~TX#z2pp;5Jen0U0uGneZ+rSJ~nd4+$I
z@RJIEo$#{4?-7okJLbJXe2GT2&K&VE81d<g;cvGBtHKQE|KZq>T447AX4I^}Vn)UH
znc>+@%c$9vZoTZdTWy#Vx>c!o_8W($Ezff6_F<Q%<J!^%Qb-l)vcT1Lt7StcH{5n$
z8_@0YeqdFv5U#sjqvN$Zwij$uF1u0Q^6-c3|I0Llz&(@aFC!L7>Gu=DXd9JT0LVq}
z49-7`uK}X^p9UN3MfdBEeM60jX=VPu5JW_^#XnrI{}m%PsNSOHl%Y$5{SWPA-<(7v
zkQI2;n8=ri{0u=vRND=hQ#mxhOQig6WC+z3*Ey*E+xT&SNPny!DYgC@aB57Tm`Uq?
z89_u;+cL}z%Kt0n|CD?&KmOXO`8&X2Oj#$WLiQ;C9ZAqA^UD$Y$RPh6x=<hgi~qa#
z@IQfz0x`p(|CV{>_&&@?y>A3ciTtA+>Z<K0z~NTWa?wP{2KlS|BKJ?)eFX}}RQ=y3
zf7zF%z3TrtOrU8|8qoLw8OnQ(=a+#;`b&OLZVd4S<^K@@2>z3RzN$ao3H93titW?)
YH-#V~>i&(x+#vs3l<1p?FRH5l-+ZY+KmY&$

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-suppr/PR28073/PR28073.before.o.abi b/tests/data/test-diff-suppr/PR28073/PR28073.before.o.abi
new file mode 100644
index 00000000..81c4ac2b
--- /dev/null
+++ b/tests/data/test-diff-suppr/PR28073/PR28073.before.o.abi
@@ -0,0 +1,32 @@ 
+<abi-corpus version='2.1' path='PR28073.before.o' architecture='elf-amd-x86_64'>
+  <elf-function-symbols>
+    <elf-symbol name='access_bigstruct' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+  </elf-function-symbols>
+  <abi-instr address-size='64' path='plop.c' comp-dir-path='/home/dodji/git/libabigail/fixes/prtests/PR28073' language='LANG_C11'>
+    <type-decl name='char' size-in-bits='8' id='type-id-1'/>
+    <array-type-def dimensions='1' type-id='type-id-1' size-in-bits='1024' id='type-id-2'>
+      <subrange length='128' type-id='type-id-3' id='type-id-4'/>
+    </array-type-def>
+    <type-decl name='unsigned char' size-in-bits='8' id='type-id-5'/>
+    <type-decl name='unsigned long int' size-in-bits='64' id='type-id-3'/>
+    <class-decl name='bigstruct' size-in-bits='1040' is-struct='yes' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/plop.c' line='3' column='1' id='type-id-6'>
+      <data-member access='public' layout-offset-in-bits='0'>
+        <var-decl name='name' type-id='type-id-2' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/plop.c' line='4' column='1'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='1024'>
+        <var-decl name='bitfield0' type-id='type-id-7' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/plop.c' line='5' column='1'/>
+      </data-member>
+      <data-member access='public' layout-offset-in-bits='1032'>
+        <var-decl name='other' type-id='type-id-7' visibility='default' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/plop.c' line='10' column='1'/>
+      </data-member>
+    </class-decl>
+    <typedef-decl name='uint8_t' type-id='type-id-8' filepath='/usr/include/bits/stdint-uintn.h' line='24' column='1' id='type-id-7'/>
+    <typedef-decl name='__uint8_t' type-id='type-id-5' filepath='/usr/include/bits/types.h' line='38' column='1' id='type-id-8'/>
+    <pointer-type-def type-id='type-id-6' size-in-bits='64' id='type-id-9'/>
+    <function-decl name='access_bigstruct' mangled-name='access_bigstruct' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/plop.c' line='13' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='access_bigstruct'>
+      <parameter type-id='type-id-9' name='st' filepath='/home/dodji/git/libabigail/fixes/prtests/PR28073/plop.c' line='13' column='1'/>
+      <return type-id='type-id-10'/>
+    </function-decl>
+    <type-decl name='void' id='type-id-10'/>
+  </abi-instr>
+</abi-corpus>
diff --git a/tests/data/test-diff-suppr/PR28073/PR28073.c b/tests/data/test-diff-suppr/PR28073/PR28073.c
new file mode 100644
index 00000000..2b84d59c
--- /dev/null
+++ b/tests/data/test-diff-suppr/PR28073/PR28073.c
@@ -0,0 +1,24 @@ 
+/*
+ * Compile this twice:
+ * gcc -g -c -DBEFORE -o PR28073.before.o PR28073.c
+ * gcc -g -c -o PR28073.after.o PR28073.c
+ */
+
+#include <inttypes.h>
+
+struct bigstruct {
+  char name[128];
+  uint8_t bitfield0:1
+  #ifndef BEFORE
+  ,bitfield1:1
+    #endif
+    ;
+  uint8_t other;
+};
+
+void access_bigstruct(struct bigstruct *st)
+{
+  #ifndef BEFORE
+  st->bitfield1 = 1;
+  #endif
+}
diff --git a/tests/data/test-diff-suppr/PR28073/bitfield.suppr b/tests/data/test-diff-suppr/PR28073/bitfield.suppr
new file mode 100644
index 00000000..4acd81b0
--- /dev/null
+++ b/tests/data/test-diff-suppr/PR28073/bitfield.suppr
@@ -0,0 +1,4 @@ 
+[suppress_type]
+  name = bigstruct
+  type_kind = struct
+  has_data_member_inserted_between = {offset_of(bitfield0), offset_of(other)}
diff --git a/tests/test-diff-suppr.cc b/tests/test-diff-suppr.cc
index 5b4d08d3..0f797fa6 100644
--- a/tests/test-diff-suppr.cc
+++ b/tests/test-diff-suppr.cc
@@ -2036,6 +2036,26 @@  InOutSpec in_out_specs[] =
     "data/test-diff-suppr/PR27267/report-1.txt",
     "output/test-diff-suppr/PR27267/report-1.txt"
   },
+  {
+    "data/test-diff-suppr/PR28073/PR28073.before.o.abi",
+    "data/test-diff-suppr/PR28073/PR28073.after.o.abi",
+    "",
+    "",
+    "data/test-diff-suppr/PR28073/bitfield.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/PR28073/PR28073-output-1.txt",
+    "output/test-diff-suppr/PR28073/PR28073-output-1.txt"
+  },
+  {
+    "data/test-diff-suppr/PR28073/PR28073.before.o.abi",
+    "data/test-diff-suppr/PR28073/PR28073-bitfield-removed.o.abi",
+    "",
+    "",
+    "data/test-diff-suppr/PR28073/bitfield.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/PR28073/PR28073-output-2.txt",
+    "output/test-diff-suppr/PR28073/PR28073-output-2.txt"
+  },
   // This should be the last entry
   {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
 };