diff --git a/include/abg-comp-filter.h b/include/abg-comp-filter.h
index b8da315..8113003 100644
--- a/include/abg-comp-filter.h
+++ b/include/abg-comp-filter.h
@@ -89,6 +89,9 @@ has_anonymous_data_member_change(const diff *d);
 bool
 has_anonymous_data_member_change(const diff_sptr &d);
 
+bool
+has_data_member_replaced_by_anon_dm(const diff* diff);
+
 struct filter_base;
 /// Convenience typedef for a shared pointer to filter_base
 typedef shared_ptr<filter_base> filter_base_sptr;
diff --git a/include/abg-comparison.h b/include/abg-comparison.h
index cf95624..bb510a1 100644
--- a/include/abg-comparison.h
+++ b/include/abg-comparison.h
@@ -257,6 +257,15 @@ typedef unordered_map<string, var_decl*> string_var_ptr_map;
 /// the changed variable.
 typedef std::pair<var_decl*, var_decl*> changed_var_ptr;
 
+/// Convenience typedef for a pair of @ref var_decl_sptr representing
+/// a @ref var_decl change.  The first member of the pair represents
+/// the initial variable and the second member represents the changed
+/// variable.
+typedef std::pair<var_decl_sptr, var_decl_sptr> changed_var_sptr;
+
+/// Convenience typedef for a vector of @changed_var_sptr.gg381
+typedef vector<changed_var_sptr> changed_var_sptrs_type;
+
 /// Convenience typedef for a map whose key is a string and whose
 /// value is an @ref elf_symbol_sptr.
 typedef unordered_map<string, elf_symbol_sptr> string_elf_symbol_map;
@@ -375,61 +384,69 @@ enum diff_category
   /// alias change that is harmless.
   HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY = 1 << 6,
 
+  /// This means that a diff node in the sub-tree carries a harmless
+  /// union change.
   HARMLESS_UNION_CHANGE_CATEGORY = 1 << 7,
 
+  /// This means that a diff node in the sub-tree carries a harmless
+  /// data member change.  An example of harmless data member change
+  /// is an anonymous data member that replaces a given data member
+  /// without locally changing the layout.
+  HARMLESS_DATA_MEMBER_CHANGE_CATEGORY = 1 << 8,
+
   /// This means that a diff node was marked as suppressed by a
   /// user-provided suppression specification.
-  SUPPRESSED_CATEGORY = 1 << 8,
+  SUPPRESSED_CATEGORY = 1 << 9,
 
   /// This means that a diff node was warked as being for a private
   /// type.  That is, the diff node is meant to be suppressed by a
   /// suppression specification that was auto-generated to filter out
   /// changes to private types.
-  PRIVATE_TYPE_CATEGORY = 1 << 9,
+  PRIVATE_TYPE_CATEGORY = 1 << 10,
 
   /// This means the diff node (or at least one of its descendant
   /// nodes) carries a change that modifies the size of a type or an
   /// offset of a type member.  Removal or changes of enumerators in a
   /// enum fall in this category too.
-  SIZE_OR_OFFSET_CHANGE_CATEGORY = 1 << 10,
+  SIZE_OR_OFFSET_CHANGE_CATEGORY = 1 << 11,
 
   /// This means that a diff node in the sub-tree carries an
   /// incompatible change to a vtable.
-  VIRTUAL_MEMBER_CHANGE_CATEGORY = 1 << 11,
+  VIRTUAL_MEMBER_CHANGE_CATEGORY = 1 << 12,
 
   /// A diff node in this category is redundant.  That means it's
   /// present as a child of a other nodes in the diff tree.
-  REDUNDANT_CATEGORY = 1 << 12,
+  REDUNDANT_CATEGORY = 1 << 13,
 
   /// This means that a diff node in the sub-tree carries a class type
   /// that was declaration-only and that is now defined, or vice
   /// versa.
-  CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY = 1 << 13,
+  CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY = 1 << 14,
 
   /// A diff node in this category is a function parameter type which
   /// top cv-qualifiers change.
-  FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY = 1 << 14,
+  FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY = 1 << 15,
 
   /// A diff node in this category has a function parameter type with a
   /// cv-qualifiers change.
-  FN_PARM_TYPE_CV_CHANGE_CATEGORY = 1 << 15,
+  FN_PARM_TYPE_CV_CHANGE_CATEGORY = 1 << 16,
 
   /// A diff node in this category is a function return type with a
   /// cv-qualifier change.
-  FN_RETURN_TYPE_CV_CHANGE_CATEGORY = 1 << 16,
+  FN_RETURN_TYPE_CV_CHANGE_CATEGORY = 1 << 17,
 
   /// A diff node in this category is for a variable which type holds
   /// a cv-qualifier change.
-  VAR_TYPE_CV_CHANGE_CATEGORY = 1 << 17,
+  VAR_TYPE_CV_CHANGE_CATEGORY = 1 << 18,
 
   /// A diff node in this category carries a change from void pointer
   /// to non-void pointer.
-  VOID_PTR_TO_PTR_CHANGE_CATEGORY = 1 << 18,
+  VOID_PTR_TO_PTR_CHANGE_CATEGORY = 1 << 19,
 
   /// A diff node in this category carries a change in the size of the
   /// array type of a global variable, but the ELF size of the
   /// variable didn't change.
-  BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY = 1 << 19,
+  BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY = 1 << 20,
   /// A special enumerator that is the logical 'or' all the
   /// enumerators above.
   ///
@@ -444,6 +461,7 @@ enum diff_category
   | HARMLESS_ENUM_CHANGE_CATEGORY
   | HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY
   | HARMLESS_UNION_CHANGE_CATEGORY
+  | HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
   | SUPPRESSED_CATEGORY
   | PRIVATE_TYPE_CATEGORY
   | SIZE_OR_OFFSET_CHANGE_CATEGORY
@@ -1610,6 +1628,12 @@ public:
   size_t
   count_filtered_subtype_changed_data_members(bool local_only = false) const;
 
+  const string_decl_base_sptr_map&
+  data_members_replaced_by_adms() const;
+
+  const changed_var_sptrs_type&
+  ordered_data_members_replaced_by_adms() const;
+
   const edit_script&
   member_fn_tmpls_changes() const;
 
diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index 90a8114..f6e0c5b 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -223,6 +223,9 @@ class var_decl;
 /// Convenience typedef for a shared pointer on a @ref var_decl
 typedef shared_ptr<var_decl> var_decl_sptr;
 
+/// Convenience typedef for a weak pointer on a @ref var_decl
+typedef weak_ptr<var_decl> var_decl_wptr;
+
 typedef unordered_map<interned_string,
 		      var_decl*,
 		      hash_interned_string> istring_var_decl_ptr_map_type;
@@ -614,6 +617,9 @@ is_data_member(const decl_base *);
 var_decl*
 is_data_member(const decl_base *);
 
+const var_decl_sptr
+get_next_data_member(const class_or_union_sptr&, const var_decl_sptr&);
+
 bool
 is_anonymous_data_member(const decl_base&);
 
@@ -638,7 +644,14 @@ is_anonymous_data_member(const var_decl*);
 bool
 is_anonymous_data_member(const var_decl&);
 
-const class_or_union*
+const var_decl_sptr
+get_first_non_anonymous_data_member(const var_decl_sptr);
+
+var_decl_sptr
+find_data_member_from_anonymous_data_member(const var_decl_sptr&,
+					    const string&);
+
+class_or_union*
 anonymous_data_member_to_class_or_union(const var_decl*);
 
 class_or_union_sptr
@@ -678,6 +691,9 @@ uint64_t
 get_data_member_offset(const decl_base_sptr);
 
 uint64_t
+get_absolute_data_member_offset(const var_decl&);
+
+uint64_t
 get_var_size_in_bits(const var_decl_sptr&);
 
 void
diff --git a/include/abg-ir.h b/include/abg-ir.h
index 15b0b40..ebcc4b8 100644
--- a/include/abg-ir.h
+++ b/include/abg-ir.h
@@ -1601,8 +1601,8 @@ public:
   friend void
   set_member_function_is_virtual(function_decl&, bool);
 
+  friend class class_or_union;
   friend class class_decl;
-
   friend class scope_decl;
 };// end class decl_base
 
@@ -2637,61 +2637,45 @@ public:
 class dm_context_rel : public context_rel
 {
 protected:
-  bool is_laid_out_;
-  size_t offset_in_bits_;
+  struct priv;
+  typedef shared_ptr<priv> priv_sptr;
+
+  priv_sptr priv_;
 
 public:
-  dm_context_rel()
-    : context_rel(),
-      is_laid_out_(!is_static_),
-      offset_in_bits_(0)
-  {}
+  dm_context_rel();
 
   dm_context_rel(scope_decl* s,
 		 bool is_laid_out,
 		 size_t offset_in_bits,
 		 access_specifier a,
-		 bool is_static)
-    : context_rel(s, a, is_static),
-      is_laid_out_(is_laid_out),
-      offset_in_bits_(offset_in_bits)
-  {}
+		 bool is_static);
 
-  dm_context_rel(scope_decl* s)
-    : context_rel(s),
-      is_laid_out_(!is_static_),
-      offset_in_bits_(0)
-  {}
+  dm_context_rel(scope_decl* s);
 
   bool
-  get_is_laid_out() const
-  {return is_laid_out_;}
+  get_is_laid_out() const;
 
   void
-  set_is_laid_out(bool f)
-  {is_laid_out_ = f;}
+  set_is_laid_out(bool f);
 
   size_t
-  get_offset_in_bits() const
-  {return offset_in_bits_;}
+  get_offset_in_bits() const;
 
   void
-  set_offset_in_bits(size_t o)
-  {offset_in_bits_ = o;}
+  set_offset_in_bits(size_t o);
 
-  bool
-  operator==(const dm_context_rel& o) const
-  {
-    if (!context_rel::operator==(o))
-      return false;
+  const var_decl*
+  get_anonymous_data_member() const;
 
-    return (is_laid_out_ == o.is_laid_out_
-	    && offset_in_bits_ == o.offset_in_bits_);
-  }
+  void
+  set_anonymous_data_member(var_decl *);
 
   bool
-  operator!=(const dm_context_rel& o) const
-  {return !operator==(o);}
+  operator==(const dm_context_rel& o) const;
+
+  bool
+  operator!=(const dm_context_rel& o) const;
 
   virtual ~dm_context_rel();
 };// end class class_decl::dm_context_rel
@@ -2783,6 +2767,12 @@ public:
   friend uint64_t
   get_data_member_offset(const var_decl& m);
 
+  friend uint64_t
+  get_absolute_data_member_offset(const var_decl& m);
+
+  friend uint64_t
+  get_absolute_data_member_offset(const var_decl_sptr& m);
+
   friend void
   set_data_member_is_laid_out(var_decl_sptr m, bool l);
 
@@ -3731,6 +3721,9 @@ protected:
   virtual void
   remove_member_decl(decl_base_sptr);
 
+  void
+  maybe_fixup_members_of_anon_data_member(var_decl_sptr& anon_dm);
+
 public:
   /// Hasher.
   struct hash;
diff --git a/src/abg-comp-filter.cc b/src/abg-comp-filter.cc
index 75df901..67c2a18 100644
--- a/src/abg-comp-filter.cc
+++ b/src/abg-comp-filter.cc
@@ -533,6 +533,25 @@ non_static_data_member_added_or_removed(const diff* diff)
     (dynamic_cast<const class_diff*>(diff));
 }
 
+/// Test if a @ref class_or_union_diff has a data member replaced by
+/// an anonymous data member in a harmless way.  That means, the new
+/// anonymous data member somehow contains the replaced data member
+/// and it doesn't break the layout of the containing class.
+///
+/// @param diff the diff node to consider.
+///
+/// @return true iff the @ref class_or_union_diff has a data member
+/// harmlessly replaced by an anonymous data member.
+bool
+has_data_member_replaced_by_anon_dm(const diff* diff)
+{
+  const class_or_union_diff *c = is_class_or_union_diff(diff);
+
+  if (!c)
+    return false;
+  return !c->data_members_replaced_by_adms().empty();
+}
+
 /// Test if a class_diff node has static members added or removed.
 ///
 /// @param diff the diff node to consider.
@@ -1521,6 +1540,9 @@ categorize_harmless_diff_node(diff *d, bool pre)
 	  || static_data_member_type_size_changed(f, s))
 	category |= STATIC_DATA_MEMBER_CHANGE_CATEGORY;
 
+      if (has_data_member_replaced_by_anon_dm(d))
+	category |= HARMLESS_DATA_MEMBER_CHANGE_CATEGORY;
+
       if ((has_enumerator_insertion(d)
 	   && !has_harmful_enum_change(d))
 	  || has_harmless_enum_to_int_change(d))
diff --git a/src/abg-comparison-priv.h b/src/abg-comparison-priv.h
index 565f024..420e701 100644
--- a/src/abg-comparison-priv.h
+++ b/src/abg-comparison-priv.h
@@ -502,6 +502,13 @@ struct class_or_union_diff::priv
   // member bar at offset N.
   unsigned_var_diff_sptr_map changed_dm_;
   var_diff_sptrs_type sorted_changed_dm_;
+
+  // This is a data structure to represent data members that have been
+  // replaced by anonymous data members.  It's a map that associates
+  // the name of the data member to the anonymous data member that
+  // replaced it.
+  string_decl_base_sptr_map dms_replaced_by_adms_;
+  mutable changed_var_sptrs_type dms_replaced_by_adms_ordered_;
   string_member_function_sptr_map deleted_member_functions_;
   string_member_function_sptr_map inserted_member_functions_;
   string_function_decl_diff_sptr_map changed_member_functions_;
@@ -549,18 +556,18 @@ struct class_or_union_diff::priv
 /// offset.
 struct data_member_comp
 {
-  /// @param f the first data member to take into account.
+
+  /// Compare two data members.
   ///
-  /// @param s the second data member to take into account.
+  /// First look at their offset and then their name.
   ///
-  /// @return true iff f is before s.
+  /// @parm first_dm the first data member to consider.
+  ///
+  /// @param second_dm the second data member to consider.
   bool
-  operator()(const decl_base_sptr& f,
-	     const decl_base_sptr& s) const
+  compare_data_members(const var_decl_sptr& first_dm,
+		       const var_decl_sptr& second_dm) const
   {
-    var_decl_sptr first_dm = is_data_member(f);
-    var_decl_sptr second_dm = is_data_member(s);
-
     ABG_ASSERT(first_dm);
     ABG_ASSERT(second_dm);
 
@@ -578,6 +585,40 @@ struct data_member_comp
     // sort them lexicographically.
     return first_dm_name < second_dm_name;
   }
+
+  /// Compare two data members.
+  ///
+  /// First look at their offset and then their name.
+  ///
+  /// @parm first_dm the first data member to consider.
+  ///
+  /// @param second_dm the second data member to consider.
+  bool
+  operator()(const decl_base_sptr& f,
+	     const decl_base_sptr& s) const
+  {
+    var_decl_sptr first_dm = is_data_member(f);
+    var_decl_sptr second_dm = is_data_member(s);
+
+    return compare_data_members(first_dm, second_dm);
+  }
+
+  /// Compare two data members.
+  ///
+  /// First look at their offset and then their name.
+  ///
+  /// @parm first_dm the first data member to consider.
+  ///
+  /// @param second_dm the second data member to consider.
+  bool
+  operator()(const changed_var_sptr& f,
+	     const changed_var_sptr& s) const
+  {
+    var_decl_sptr first_dm = is_data_member(is_decl(f.first));
+    var_decl_sptr second_dm = is_data_member(is_decl(s.first));
+
+    return compare_data_members(first_dm, second_dm);
+  }
 };//end struct data_member_comp
 
 /// The type of the private data (pimpl sub-object) of the @ref
@@ -1347,6 +1388,9 @@ sort_data_members(const string_decl_base_sptr_map &data_members,
 		  vector<decl_base_sptr>& sorted);
 
 void
+sort_changed_data_members(changed_var_sptrs_type& input);
+
+void
 sort_string_function_ptr_map(const string_function_ptr_map& map,
 			     vector<function_decl*>& sorted);
 
diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
index e1689e5..7305a71 100644
--- a/src/abg-comparison.cc
+++ b/src/abg-comparison.cc
@@ -171,8 +171,18 @@ sort_data_members(const string_decl_base_sptr_map &data_members,
   std::sort(sorted.begin(), sorted.end(), comp);
 }
 
-/// Sort a an instance of @ref string_function_ptr_map map and stuff
-/// a resulting sorted vector of pointers to function_decl.
+/// Sort (in place) a vector of changed data members.
+///
+/// @param to_sort the vector to sort.
+void
+sort_changed_data_members(changed_var_sptrs_type& to_sort)
+{
+  data_member_comp comp;
+  std::sort(to_sort.begin(), to_sort.end(), comp);
+}
+
+/// Sort an instance of @ref string_function_ptr_map map and stuff a
+/// resulting sorted vector of pointers to function_decl.
 ///
 /// @param map the map to sort.
 ///
@@ -2946,6 +2956,7 @@ get_default_harmless_categories_bitmap()
 	  | abigail::comparison::HARMLESS_ENUM_CHANGE_CATEGORY
 	  | abigail::comparison::HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY
 	  | abigail::comparison::HARMLESS_UNION_CHANGE_CATEGORY
+	  | abigail::comparison::HARMLESS_DATA_MEMBER_CHANGE_CATEGORY
 	  | abigail::comparison::CLASS_DECL_ONLY_DEF_CHANGE_CATEGORY
 	  | abigail::comparison::FN_PARM_TYPE_TOP_CV_CHANGE_CATEGORY
 	  | abigail::comparison::FN_PARM_TYPE_CV_CHANGE_CATEGORY
@@ -3033,6 +3044,14 @@ operator<<(ostream& o, diff_category c)
       emitted_a_category |= true;
     }
 
+    if (c & HARMLESS_DATA_MEMBER_CHANGE_CATEGORY)
+    {
+      if (emitted_a_category)
+	o << "|";
+      o << "HARMLESS_DATA_MEMBER_CHANGE_CATEGORY";
+      emitted_a_category |= true;
+    }
+
   if (c & HARMLESS_SYMBOL_ALIAS_CHANGE_CATEORY)
     {
       if (emitted_a_category)
@@ -4688,21 +4707,179 @@ class_or_union_diff::ensure_lookup_tables_populated(void) const
 	    var_decl_sptr added_dm = is_var_decl(d);
 	    string name = added_dm->get_anon_dm_reliable_name();
 	    ABG_ASSERT(priv_->inserted_data_members_.find(name)
-		   == priv_->inserted_data_members_.end());
-	    string_decl_base_sptr_map::const_iterator j =
-	      priv_->deleted_data_members_.find(name);
-	    if (j != priv_->deleted_data_members_.end())
+		       == priv_->inserted_data_members_.end());
+
+	    bool ignore_added_anonymous_data_member = false;
+	    if (is_anonymous_data_member(added_dm))
 	      {
-		if (*j->second != *d)
+		//
+		// Handle insertion of anonymous data member to
+		// replace existing data members.
+		//
+		// For instance consider this:
+		//   struct S
+		//   {
+		//     int a;
+		//     int b;
+		//     int c;
+		//   };// end struct S
+		//
+		//   Where the data members 'a' and 'b' are replaced
+		//   by an anonymous data member without changing the
+		//   effective bit layout of the structure:
+		//
+		//   struct S
+		//   {
+		//     struct
+		//     {
+		//       union
+		//       {
+		//         int a;
+		//         char a_1;
+		//       };
+		//       union
+		//       {
+		//         int b;
+		//         char b_1;
+		//       };
+		//     };
+		//     int c;
+		//   }; // end struct S
+		//
+		var_decl_sptr replaced_dm, replacing_dm;
+		bool added_anon_dm_changes_dm = false;
+		// The vector of data members replaced by anonymous
+		// data members.
+		vector<var_decl_sptr> dms_replaced_by_anon_dm;
+
+		//
+		// Let's start collecting the set of data members
+		// which have been replaced by anonymous types in a
+		// harmless way.  These are going to be collected into
+		// dms_replaced_by_anon_dm and, ultimately, into
+		// priv_->dms_replaced_by_adms_
+		//
+		for (string_decl_base_sptr_map::const_iterator it =
+		       priv_->deleted_data_members_.begin();
+		     it != priv_->deleted_data_members_.end();
+		     ++it)
 		  {
-		    var_decl_sptr old_dm = is_var_decl(j->second);
-		    priv_->subtype_changed_dm_[name]=
-		      compute_diff(old_dm, added_dm, context());
+		    // We don't support this pattern for anonymous
+		    // data members themselves being replaced.  If
+		    // that occurs then we'll just report it verbatim.
+		    if (is_anonymous_data_member(it->second))
+		      continue;
+
+		    string deleted_dm_name = it->second->get_name();
+		    if ((replacing_dm =
+			 find_data_member_from_anonymous_data_member(added_dm,
+								     deleted_dm_name)))
+		      {
+			// So it looks like replacing_dm might have
+			// replaced the data member which name is
+			// 'deleted_dm_name'.  Let's look deeper to be
+			// sure.
+			//
+			// Note that replacing_dm is part (member) of
+			// an anonymous data member that might replace
+			// replaced_dm.
+
+			// So let's get that replaced data member.
+			replaced_dm = is_var_decl(it->second);
+			size_t replaced_dm_offset =
+			  get_data_member_offset(replaced_dm),
+			replacing_dm_offset =
+			  get_absolute_data_member_offset(replacing_dm);
+
+			if (replaced_dm_offset != replacing_dm_offset)
+			  {
+			    // So the replacing data member and the
+			    // replaced data member don't have the
+			    // same offset.  This is not the pattern we
+			    // are looking for.  Rather, it looks like
+			    // the anonymous data member has *changed*
+			    // the data member.
+			    added_anon_dm_changes_dm = true;
+			    break;
+			  }
+
+			if (replaced_dm->get_type()->get_size_in_bits()
+			    == replaced_dm->get_type()->get_size_in_bits())
+			  dms_replaced_by_anon_dm.push_back(replaced_dm);
+			else
+			  {
+			    added_anon_dm_changes_dm = true;
+			    break;
+			  }
+		      }
+		  }
+
+		// Now walk dms_replaced_by_anon_dm to fill up
+		// priv_->dms_replaced_by_adms_ with the set of data
+		// members replaced by anonymous data members.
+		if (!added_anon_dm_changes_dm
+		    && !dms_replaced_by_anon_dm.empty())
+		  {
+		    // See if the added data member isn't too big.
+		    type_base_sptr added_dm_type = added_dm->get_type();
+		    ABG_ASSERT(added_dm_type);
+		    var_decl_sptr new_next_dm =
+		      get_next_data_member(second_class_or_union(),
+					   added_dm);
+		    var_decl_sptr old_next_dm =
+		      first_class_or_union()->find_data_member(new_next_dm);
+
+		    if (!old_next_dm
+			|| (old_next_dm
+			    && (get_absolute_data_member_offset(old_next_dm)
+				== get_absolute_data_member_offset(new_next_dm))))
+		      {
+			// None of the data members that are replaced
+			// by the added union should be considered as
+			// having been deleted.
+			ignore_added_anonymous_data_member = true;
+			for (vector<var_decl_sptr>::const_iterator i =
+			       dms_replaced_by_anon_dm.begin();
+			     i != dms_replaced_by_anon_dm.end();
+			     ++i)
+			  {
+			    string n = (*i)->get_name();
+			    priv_->dms_replaced_by_adms_[n] =
+			      added_dm;
+			    priv_->deleted_data_members_.erase(n);
+			  }
+		      }
 		  }
-		priv_->deleted_data_members_.erase(j);
 	      }
-	    else
-	      priv_->inserted_data_members_[name] = d;
+
+	    if (!ignore_added_anonymous_data_member)
+	      {
+		// Detect changed data members.
+		//
+		// A changed data member (that we shall name D) is a data
+		// member that satisfies the conditions below:
+		//
+		// 1/ It must have been added.
+		//
+		// 2/ It must have been deleted as well.
+		//
+		// 3/ It there must be a non-empty difference between the
+		// deleted D and the added D.
+		string_decl_base_sptr_map::const_iterator j =
+		  priv_->deleted_data_members_.find(name);
+		if (j != priv_->deleted_data_members_.end())
+		  {
+		    if (*j->second != *d)
+		      {
+			var_decl_sptr old_dm = is_var_decl(j->second);
+			priv_->subtype_changed_dm_[name]=
+			  compute_diff(old_dm, added_dm, context());
+		      }
+		    priv_->deleted_data_members_.erase(j);
+		  }
+		else
+		  priv_->inserted_data_members_[name] = d;
+	      }
 	  }
       }
 
@@ -4987,6 +5164,47 @@ size_t
 class_or_union_diff::count_filtered_subtype_changed_data_members(bool local) const
 {return get_priv()->count_filtered_subtype_changed_dm(local);}
 
+/// Get the map of data members that got replaced by anonymous data
+/// members.
+///
+/// The key of a map entry is the name of the replaced data member and
+/// the value is the anonymous data member that replaces it.
+///
+/// @return the map of data members replaced by anonymous data
+/// members.
+const string_decl_base_sptr_map&
+class_or_union_diff::data_members_replaced_by_adms() const
+{return get_priv()->dms_replaced_by_adms_;}
+
+/// Get an ordered vector of of data members that got replaced by
+/// anonymous data members.
+///
+/// This returns a vector of pair of two data members: the one that
+/// was replaced, and the anonymous data member that replaced it.
+///
+/// @return the sorted vector data members replaced by anonymous data members.
+const changed_var_sptrs_type&
+class_or_union_diff::ordered_data_members_replaced_by_adms() const
+{
+  if (priv_->dms_replaced_by_adms_ordered_.empty())
+    {
+      for (string_decl_base_sptr_map::const_iterator it =
+	     priv_->dms_replaced_by_adms_.begin();
+	   it != priv_->dms_replaced_by_adms_.end();
+	   ++it)
+	{
+	  const var_decl_sptr dm =
+	    first_class_or_union()->find_data_member(it->first);
+	  ABG_ASSERT(dm);
+	  changed_var_sptr changed_dm(dm, is_data_member(it->second));
+	  priv_->dms_replaced_by_adms_ordered_.push_back(changed_dm);
+	}
+      sort_changed_data_members(priv_->dms_replaced_by_adms_ordered_);
+    }
+
+  return priv_->dms_replaced_by_adms_ordered_;
+}
+
 /// @return the edit script of the member function templates of the two
 /// @ref class_or_union.
 const edit_script&
@@ -11424,8 +11642,8 @@ void
 propagate_categories(corpus_diff_sptr diff_tree)
 {propagate_categories(diff_tree.get());}
 
-/// A tree node visitor that knows how to categorizes a given in the
-/// SUPPRESSED_CATEGORY category and how to propagate that
+/// A tree node visitor that knows how to categorizes a given diff
+/// node in the SUPPRESSED_CATEGORY category and how to propagate that
 /// categorization.
 struct suppression_categorization_visitor : public diff_node_visitor
 {
@@ -11501,6 +11719,12 @@ struct suppression_categorization_visitor : public diff_node_visitor
 	// Note that all pointer/reference diff node changes are
 	// potentially considered local, i.e, local changes of the
 	// pointed-to-type are considered local to the pointer itself.
+	//
+	// Similarly, changes local to the type of function parameters,
+	// variables (and data members) and classe (that are not of
+	// LOCAL_NON_TYPE_CHANGE_KIND kind) and that have been
+	// suppressed can propagate their SUPPRESSED_CATEGORY-ness to
+	// those kinds of diff node.
 	!(d->get_category() & SUPPRESSED_CATEGORY)
 	&& (!d->has_local_changes()
 	    || is_pointer_diff(d)
@@ -11512,6 +11736,10 @@ struct suppression_categorization_visitor : public diff_node_visitor
 	    || (is_fn_parm_diff(d)
 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
 	    || (is_function_type_diff(d)
+		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
+	    || (is_var_diff(d)
+		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))
+	    ||  (is_class_diff(d)
 		&& (!(d->has_local_changes() & LOCAL_NON_TYPE_CHANGE_KIND)))))
       {
 	// Note that we handle private diff nodes differently from
@@ -11544,8 +11772,8 @@ struct suppression_categorization_visitor : public diff_node_visitor
 		  has_private_child = true;
 		else if (child->get_class_of_equiv_category()
 			 & SUPPRESSED_CATEGORY)
-		  // Propagation of the SUPPRESSED_CATEGORY is going
-		  // to be handled later below.
+		  // Propagation of the SUPPRESSED_CATEGORY has been
+		  // handled above already.
 		  ;
 		else
 		  has_non_private_child = true;
diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc
index b59e8d6..80cb663 100644
--- a/src/abg-default-reporter.cc
+++ b/src/abg-default-reporter.cc
@@ -1016,6 +1016,10 @@ default_reporter::report(const class_or_union_diff& d,
 	    if ((*it)->to_be_reported())
 	      represent(*it, ctxt, out, indent + "  ");
 	}
+
+      // Report about data members replaced by an anonymous union data
+      // member.
+      maybe_report_data_members_replaced_by_anon_dm(d, out, indent);
     }
 
   // member types
diff --git a/src/abg-ir.cc b/src/abg-ir.cc
index 85c27e3..aefbd08 100644
--- a/src/abg-ir.cc
+++ b/src/abg-ir.cc
@@ -2537,8 +2537,98 @@ elf_symbol::version::operator=(const elf_symbol::version& o)
 
 // </elf_symbol stuff>
 
+// <class dm_context_rel stuff>
+struct dm_context_rel::priv
+{
+  bool is_laid_out_;
+  size_t offset_in_bits_;
+  var_decl* anonymous_data_member_;
+
+  priv(bool is_static = false)
+    : is_laid_out_(!is_static),
+      offset_in_bits_(0),
+      anonymous_data_member_()
+  {}
+
+  priv(bool is_laid_out, size_t offset_in_bits)
+    : is_laid_out_(is_laid_out),
+      offset_in_bits_(offset_in_bits),
+      anonymous_data_member_()
+  {}
+}; //end struct dm_context_rel::priv
+
+dm_context_rel::dm_context_rel()
+  : context_rel(),
+    priv_(new priv)
+{}
+
+dm_context_rel::dm_context_rel(scope_decl* s,
+			       bool is_laid_out,
+			       size_t offset_in_bits,
+			       access_specifier a,
+			       bool is_static)
+  : context_rel(s, a, is_static),
+    priv_(new priv(is_laid_out, offset_in_bits))
+{}
+
+dm_context_rel::dm_context_rel(scope_decl* s)
+  : context_rel(s),
+    priv_(new priv())
+{}
+
+bool
+dm_context_rel::get_is_laid_out() const
+{return priv_->is_laid_out_;}
+
+void
+dm_context_rel::set_is_laid_out(bool f)
+{priv_->is_laid_out_ = f;}
+
+size_t
+dm_context_rel::get_offset_in_bits() const
+{return priv_->offset_in_bits_;}
+
+void
+dm_context_rel::set_offset_in_bits(size_t o)
+{priv_->offset_in_bits_ = o;}
+
+bool
+dm_context_rel::operator==(const dm_context_rel& o) const
+{
+  if (!context_rel::operator==(o))
+    return false;
+
+  return (priv_->is_laid_out_ == o.priv_->is_laid_out_
+	    && priv_->offset_in_bits_ == o.priv_->offset_in_bits_);
+}
+
+bool
+dm_context_rel::operator!=(const dm_context_rel& o) const
+{return !operator==(o);}
+
+/// Return a non-nil value if this data member context relationship
+/// has an anonymous data member.  That means, if the data member this
+/// relation belongs to is part of an anonymous data member.
+///
+/// @return the containing anonymous data member of this data member
+/// relationship.  Nil if there is none.
+const var_decl*
+dm_context_rel::get_anonymous_data_member() const
+{return priv_->anonymous_data_member_;}
+
+/// Set the containing anonymous data member of this data member
+/// context relationship. That means that the data member this
+/// relation belongs to is part of an anonymous data member.
+///
+/// @param anon_dm the containing anonymous data member of this data
+/// member relationship.  Nil if there is none.
+void
+dm_context_rel::set_anonymous_data_member(var_decl* anon_dm)
+{priv_->anonymous_data_member_ = anon_dm;}
+
 dm_context_rel::~dm_context_rel()
 {}
+// </class dm_context_rel stuff>
 
 // <environment stuff>
 
@@ -4423,6 +4513,71 @@ is_data_member(const decl_base *d)
   return 0;
 }
 
+/// Get the first non-anonymous data member of a given anonymous data
+/// member.
+///
+/// E.g:
+///
+///   struct S
+///   {
+///     union // <-- for this anonymous data member, the function
+///           // returns a.
+///     {
+///       int a;
+///       charb;
+///     };
+///   };
+///
+/// @return anon_dm the anonymous data member to consider.
+///
+/// @return the first non-anonymous data member of @p anon_dm.  If no
+/// data member was found then this function returns @p anon_dm.
+const var_decl_sptr
+get_first_non_anonymous_data_member(const var_decl_sptr anon_dm)
+{
+  if (!anon_dm || !is_anonymous_data_member(anon_dm))
+    return anon_dm;
+
+  class_or_union_sptr klass = anonymous_data_member_to_class_or_union(anon_dm);
+ var_decl_sptr first = *klass->get_non_static_data_members().begin();
+
+ if (is_anonymous_data_member(first))
+   return get_first_non_anonymous_data_member(first);
+
+ return first;
+}
+
+/// In the context of a given class or union, this function returns
+/// the data member that is located after a given data member.
+///
+/// @param klass the class or union to consider.
+///
+/// @param the data member to consider.
+///
+/// @return the data member that is located right after @p
+/// data_member.
+const var_decl_sptr
+get_next_data_member(const class_or_union_sptr &klass,
+		     const var_decl_sptr &data_member)
+{
+  if (!klass ||!data_member)
+    return var_decl_sptr();
+
+  for (class_or_union::data_members::const_iterator it =
+	 klass->get_non_static_data_members().begin();
+       it != klass->get_non_static_data_members().end();
+       ++it)
+    if (**it == *data_member)
+      {
+	++it;
+	if (it != klass->get_non_static_data_members().end())
+	  return get_first_non_anonymous_data_member(*it);
+	break;
+      }
+
+  return var_decl_sptr();
+}
+
 /// Test if a decl is an anonymous data member.
 ///
 /// @param d the decl to consider.
@@ -4544,7 +4699,7 @@ is_anonymous_data_member(const var_decl& d)
 ///
 /// @return the @ref class_or_union type of the anonymous data member
 /// @p d.
-const class_or_union*
+class_or_union*
 anonymous_data_member_to_class_or_union(const var_decl* d)
 {
   if ((d = is_anonymous_data_member(d)))
@@ -4657,6 +4812,53 @@ uint64_t
 get_data_member_offset(const decl_base_sptr d)
 {return get_data_member_offset(dynamic_pointer_cast<var_decl>(d));}
 
+/// Get the absolute offset of a data member.
+///
+/// If the data member is part of an anonymous data member then this
+/// returns the absolute offset -- relative to the beginning of the
+/// containing class of the anonymous data member.
+///
+/// @param m the data member to consider.
+///
+/// @return the aboslute offset of the data member @p m.
+uint64_t
+get_absolute_data_member_offset(const var_decl& m)
+{
+  ABG_ASSERT(is_data_member(m));
+  const dm_context_rel* ctxt_rel =
+    dynamic_cast<const dm_context_rel*>(m.get_context_rel());
+  ABG_ASSERT(ctxt_rel);
+
+  const var_decl *containing_anonymous_data_member =
+    ctxt_rel->get_anonymous_data_member();
+
+  uint64_t containing_anonymous_data_member_offset = 0;
+  if (containing_anonymous_data_member)
+    containing_anonymous_data_member_offset =
+      get_absolute_data_member_offset(*containing_anonymous_data_member);
+
+  return (ctxt_rel->get_offset_in_bits()
+	  +
+	  containing_anonymous_data_member_offset);
+}
+
+/// Get the absolute offset of a data member.
+///
+/// If the data member is part of an anonymous data member then this
+/// returns the absolute offset -- relative to the beginning of the
+/// containing class of the anonymous data member.
+///
+/// @param m the data member to consider.
+///
+/// @return the aboslute offset of the data member @p m.
+uint64_t
+get_absolute_data_member_offset(const var_decl_sptr& m)
+{
+  if (!m)
+    return 0;
+  return get_absolute_data_member_offset(*m);
+}
+
 /// Get the size of a given variable.
 ///
 /// @param v the variable to consider.
@@ -5621,7 +5823,7 @@ canonical_type_hash::operator()(const type_base_sptr& l) const
 ///
 /// @param l the canonical type to hash.
 ///
-/// @return the the pointer value of the canonical type of @p l.
+/// @return the pointer value of the canonical type of @p l.
 size_t
 canonical_type_hash::operator()(const type_base *l) const
 {return reinterpret_cast<size_t>(l);}
@@ -7405,6 +7607,29 @@ is_at_class_scope(const decl_base& decl)
   return 0;
 }
 
+/// Find a data member inside an anonymous data member.
+///
+/// An anonymous data member has a type which is a class or union.
+/// This function looks for a data member inside the type of that
+/// anonymous data member.
+///
+/// @param anon_dm the anonymous data member to consider.
+///
+/// @param name the name of the data member to look for.
+var_decl_sptr
+find_data_member_from_anonymous_data_member(const var_decl_sptr& anon_dm,
+					    const string& name)
+{
+  const class_or_union* containing_class_or_union =
+    anonymous_data_member_to_class_or_union(anon_dm.get());
+
+  if (!containing_class_or_union)
+    return var_decl_sptr();
+
+  var_decl_sptr result = containing_class_or_union->find_data_member(name);
+  return result;
+}
+
 /// Tests whether a given decl is at template scope.
 ///
 /// Note that only template parameters , types that are compositions,
@@ -18119,6 +18344,39 @@ class_or_union::remove_member_decl(decl_base_sptr decl)
   remove_member_type(t);
 }
 
+/// Fixup the members of the type of an anonymous data member.
+///
+/// Walk all data members of (the type of) a given anonymous data
+/// member and set a particular property of the relationship between
+/// each data member and its containing type.
+///
+/// That property records the fact that the data member belongs to the
+/// anonymous data member we consider.
+///
+/// In the future, if there are other properties of this relationship
+/// to set in this manner, they ought to be added here.
+///
+/// @param anon_dm the anonymous data member to consider.
+void
+class_or_union::maybe_fixup_members_of_anon_data_member(var_decl_sptr& anon_dm)
+{
+  class_or_union * anon_dm_type =
+    anonymous_data_member_to_class_or_union(anon_dm.get());
+  if (!anon_dm_type)
+    return;
+
+  for (class_or_union::data_members::const_iterator it =
+	 anon_dm_type->get_non_static_data_members().begin();
+       it != anon_dm_type->get_non_static_data_members().end();
+       ++it)
+    {
+      dm_context_rel *rel =
+	dynamic_cast<dm_context_rel*>((*it)->get_context_rel());
+      ABG_ASSERT(rel);
+      rel->set_anonymous_data_member(anon_dm.get());
+    }
+}
+
 /// Insert a member type.
 ///
 /// @param t the type to insert in the @ref class_or_union type.
@@ -18479,7 +18737,6 @@ class_or_union::add_data_member(var_decl_sptr v, access_specifier access,
   set_member_access_specifier(v, access);
   set_member_is_static(v, is_static);
 
-
   if (!is_static)
     {
       // If this is a non-static variable, add it to the set of
@@ -18497,6 +18754,13 @@ class_or_union::add_data_member(var_decl_sptr v, access_specifier access,
       if (!is_already_in)
 	priv_->non_static_data_members_.push_back(v);
     }
+
+  // If v is an anonymous data member, then fixup its data members.
+  // For now, the only thing the fixup does is to make the data
+  // members of the anonymous data member be aware of their containing
+  // anonymous data member.  That is helpful to compute the absolute
+  // bit offset of each of the members of the anonymous data member.
+  maybe_fixup_members_of_anon_data_member(v);
 }
 
 /// Get the data members of this @ref class_or_union.
diff --git a/src/abg-leaf-reporter.cc b/src/abg-leaf-reporter.cc
index afe5692..f9d905a 100644
--- a/src/abg-leaf-reporter.cc
+++ b/src/abg-leaf-reporter.cc
@@ -631,6 +631,10 @@ leaf_reporter::report(const class_or_union_diff& d,
 	    if (diff_to_be_reported((*it).get()))
 	      represent(*it, ctxt, out, indent + "  ", /*local_only=*/true);
 	}
+
+      // Report about data members replaced by an anonymous union data
+      // member.
+      maybe_report_data_members_replaced_by_anon_dm(d, out, indent);
     }
 }
 
diff --git a/src/abg-reporter-priv.cc b/src/abg-reporter-priv.cc
index df7df88..9f2c5a4 100644
--- a/src/abg-reporter-priv.cc
+++ b/src/abg-reporter-priv.cc
@@ -1415,5 +1415,88 @@ bool
 reporter_base::diff_to_be_reported(const diff *d) const
 {return d && d->to_be_reported();}
 
-} // namespace comparison
+/// Report about data members replaced by an anonymous data member
+/// without changing the overall bit-layout of the class or union in
+/// an ABI-meaningful way.
+///
+/// @param d the diff to consider.
+///
+/// @param out the output stream to emit the change report to.
+///
+/// @param indent the indentation string to use.
+void
+maybe_report_data_members_replaced_by_anon_dm(const class_or_union_diff &d,
+					      ostream			&out,
+					      const string		indent)
+{
+  const diff_context_sptr& ctxt = d.context();
+
+  if ((ctxt->get_allowed_category() & HARMLESS_DATA_MEMBER_CHANGE_CATEGORY)
+      && !d.data_members_replaced_by_adms().empty())
+    {
+      // Let's detect all the data members that are replaced by
+      // members of the same anonymous data member and report them
+      // in one go.
+      changed_var_sptrs_type::const_iterator i, j;
+      i = d.ordered_data_members_replaced_by_adms().begin();
+      // This contains the data members replaced by the same
+      // anonymous data member.
+      vector<var_decl_sptr> dms_replaced_by_same_anon_dm;
+      // This contains the anonymous data member that replaced the
+      // data members in the variable above.
+      var_decl_sptr anonymous_data_member;
+
+      while (i != d.ordered_data_members_replaced_by_adms().end())
+	{
+	  anonymous_data_member = i->second;
+	  // Let's look forward to see if the subsequent data
+	  // members were replaced by members of
+	  // anonymous_data_member.
+	  for (j = i;
+	       j != d.ordered_data_members_replaced_by_adms().end();
+	       ++j)
+	    {
+	      if (*i->second == *j->second)
+		dms_replaced_by_same_anon_dm.push_back(j->first);
+	      else
+		break;
+	    }
+
+	  bool several_data_members_replaced =
+	    dms_replaced_by_same_anon_dm.size() > 1;
+
+	  out << indent << "data member";
+	  if (several_data_members_replaced)
+	    out << "s";
+
+	  bool first_data_member = true;
+	  for (vector<var_decl_sptr>::const_iterator it =
+		 dms_replaced_by_same_anon_dm.begin();
+	       it != dms_replaced_by_same_anon_dm.end();
+	       ++it)
+	    {
+	      string name = (*it)->get_qualified_name();
+	      if (!first_data_member)
+		out << ",";
+	      out << " '" << name << "'";
+	      first_data_member = false;
+	    }
+
+	  if (several_data_members_replaced)
+	    out << " were ";
+	  else
+	    out << " was ";
+
+	  out << "replaced by anonymous data member:\n"
+	      << indent + "  "
+	      << "'"
+	      << i->second->get_pretty_representation()
+	      << "'\n";
+
+	  i = j;
+	}
+    }
+}
+
+} // Namespace comparison
 } // end namespace abigail
diff --git a/src/abg-reporter-priv.h b/src/abg-reporter-priv.h
index b221fdc..84cb238 100644
--- a/src/abg-reporter-priv.h
+++ b/src/abg-reporter-priv.h
@@ -250,6 +250,12 @@ maybe_report_interfaces_impacted_by_diff(const diff_sptr	&d,
 					 ostream		&out,
 					 const string		&indent);
 
+void
+maybe_report_data_members_replaced_by_anon_dm(const class_or_union_diff &d,
+					      ostream			&out,
+					      const string		indent);
+
+
 } // end namespace comparison
 } // end namespace abigail
 
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 7e91f52..f5b551b 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -778,6 +778,54 @@ test-diff-filter/PR24787-libtwo.so \
 test-diff-filter/PR24787-one.c \
 test-diff-filter/PR24787-two.c \
 test-diff-filter/PR24787-report-0.txt \
+test-diff-filter/test-PR25661-1-report-1.txt \
+test-diff-filter/test-PR25661-1-report-2.txt \
+test-diff-filter/test-PR25661-1-report-3.txt \
+test-diff-filter/test-PR25661-1-report-4.txt \
+test-diff-filter/test-PR25661-1-v0.o \
+test-diff-filter/test-PR25661-1-v1.o \
+test-diff-filter/test-PR25661-1-v0.c \
+test-diff-filter/test-PR25661-1-v1.c \
+test-diff-filter/test-PR25661-2-report-1.txt \
+test-diff-filter/test-PR25661-2-report-2.txt \
+test-diff-filter/test-PR25661-2-report-3.txt \
+test-diff-filter/test-PR25661-2-report-4.txt \
+test-diff-filter/test-PR25661-2-v0.o \
+test-diff-filter/test-PR25661-2-v1.o \
+test-diff-filter/test-PR25661-2-v0.c \
+test-diff-filter/test-PR25661-2-v1.c \
+test-diff-filter/test-PR25661-3-report-1.txt \
+test-diff-filter/test-PR25661-3-report-2.txt \
+test-diff-filter/test-PR25661-3-report-3.txt \
+test-diff-filter/test-PR25661-3-report-4.txt \
+test-diff-filter/test-PR25661-3-v0.o \
+test-diff-filter/test-PR25661-3-v1.o \
+test-diff-filter/test-PR25661-3-v0.c \
+test-diff-filter/test-PR25661-3-v1.c \
+test-diff-filter/test-PR25661-4-report-1.txt \
+test-diff-filter/test-PR25661-4-report-2.txt \
+test-diff-filter/test-PR25661-4-report-3.txt \
+test-diff-filter/test-PR25661-4-report-4.txt \
+test-diff-filter/test-PR25661-4-v0.o \
+test-diff-filter/test-PR25661-4-v1.o \
+test-diff-filter/test-PR25661-4-v0.c \
+test-diff-filter/test-PR25661-4-v1.c \
+test-diff-filter/test-PR25661-5-v0.o \
+test-diff-filter/test-PR25661-5-v1.o \
+test-diff-filter/test-PR25661-5-v0.c \
+test-diff-filter/test-PR25661-5-v1.c \
+test-diff-filter/test-PR25661-5-report-1.txt \
+test-diff-filter/test-PR25661-5-report-2.txt \
+test-diff-filter/test-PR25661-5-report-3.txt \
+test-diff-filter/test-PR25661-5-report-4.txt \
+test-diff-filter/test-PR25661-6-v0.c \
+test-diff-filter/test-PR25661-6-v1.c \
+test-diff-filter/test-PR25661-6-v0.o \
+test-diff-filter/test-PR25661-6-v1.o \
+test-diff-filter/test-PR25661-6-report-1.txt \
+test-diff-filter/test-PR25661-6-report-2.txt \
+test-diff-filter/test-PR25661-6-report-3.txt \
+test-diff-filter/test-PR25661-6-report-4.txt \
 \
 test-diff-suppr/test0-type-suppr-v0.cc	\
 test-diff-suppr/test0-type-suppr-v1.cc	\
diff --git a/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt b/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt
index 4ffd8b3..ada9d3a 100644
--- a/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt
+++ b/tests/data/test-diff-dwarf/test45-anon-dm-change-report-0.txt
@@ -18,6 +18,6 @@ Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
     parameter 1 of type 'S0&' has sub-type changes:
       in referenced type 'struct S0':
         type size hasn't changed
-        1 data member change:
-          data member int S0::m0 at offset 0 (in bits) became anonymous data member 'union {int m0; char m01;}'
+        data member 'S0::m0' was replaced by anonymous data member:
+          'union {int m0; char m01;}'
 
diff --git a/tests/data/test-diff-filter/test-PR25661-1-report-1.txt b/tests/data/test-diff-filter/test-PR25661-1-report-1.txt
new file mode 100644
index 0000000..9666a8f
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-1-report-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-filter/test-PR25661-1-report-2.txt b/tests/data/test-diff-filter/test-PR25661-1-report-2.txt
new file mode 100644
index 0000000..3d9f663
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-1-report-2.txt
@@ -0,0 +1,12 @@
+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 foo(S*)' at test-PR25661-1-v1.c:18:1 has some indirect sub-type changes:
+    parameter 1 of type 'S*' has sub-type changes:
+      in pointed to type 'struct S' at test-PR25661-1-v1.c:1:1:
+        type size hasn't changed
+        data members 'S::a', 'S::b', 'S::c' were replaced by anonymous data member:
+          'union {int tag[3]; struct {int a; int b; int c;};}'
+
diff --git a/tests/data/test-diff-filter/test-PR25661-1-report-3.txt b/tests/data/test-diff-filter/test-PR25661-1-report-3.txt
new file mode 100644
index 0000000..0927b7a
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-1-report-3.txt
@@ -0,0 +1,5 @@
+Leaf changes summary: 0 artifact changed (1 filtered out)
+Changed leaf types summary: 0 (1 filtered out) leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
diff --git a/tests/data/test-diff-filter/test-PR25661-1-report-4.txt b/tests/data/test-diff-filter/test-PR25661-1-report-4.txt
new file mode 100644
index 0000000..577aff8
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-1-report-4.txt
@@ -0,0 +1,9 @@
+Leaf changes summary: 1 artifact changed
+Changed leaf types summary: 1 leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
+'struct S at test-PR25661-1-v0.c:1:1' changed:
+  type size hasn't changed
+  data members 'S::a', 'S::b', 'S::c' were replaced by anonymous data member:
+    'union {int tag[3]; struct {int a; int b; int c;};}'
diff --git a/tests/data/test-diff-filter/test-PR25661-1-v0.c b/tests/data/test-diff-filter/test-PR25661-1-v0.c
new file mode 100644
index 0000000..9c672ba
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-1-v0.c
@@ -0,0 +1,12 @@
+struct S
+{
+  int a;
+  int b;
+  int c;
+  int d;
+};
+
+void
+foo(struct S* s __attribute__((unused)))
+{
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-1-v0.o b/tests/data/test-diff-filter/test-PR25661-1-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..202c0673d80383920ecd2333224afbc6e6072ed4
GIT binary patch
diff --git a/tests/data/test-diff-filter/test-PR25661-1-v1.c b/tests/data/test-diff-filter/test-PR25661-1-v1.c
new file mode 100644
index 0000000..24346b9
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-1-v1.c
@@ -0,0 +1,20 @@
+struct S
+{
+  union
+  {
+    int tag[3];
+    struct
+    {
+      int a;
+      int b;
+      int c;
+    };
+  };
+
+  int d;
+};
+
+void
+foo(struct S* s __attribute__((unused)))
+{
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-1-v1.o b/tests/data/test-diff-filter/test-PR25661-1-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..28bb43d96bbde31452b190960d280810b594dc22
GIT binary patch
diff --git a/tests/data/test-diff-filter/test-PR25661-2-report-1.txt b/tests/data/test-diff-filter/test-PR25661-2-report-1.txt
new file mode 100644
index 0000000..9666a8f
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-2-report-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-filter/test-PR25661-2-report-2.txt b/tests/data/test-diff-filter/test-PR25661-2-report-2.txt
new file mode 100644
index 0000000..31ce245
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-2-report-2.txt
@@ -0,0 +1,12 @@
+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 foo(S*)' at test-PR25661-2-v1.c:20:1 has some indirect sub-type changes:
+    parameter 1 of type 'S*' has sub-type changes:
+      in pointed to type 'struct S' at test-PR25661-2-v1.c:1:1:
+        type size hasn't changed
+        data members 'S::b', 'S::c' were replaced by anonymous data member:
+          'struct {int b; struct {union {char added_char; int c;};};}'
+
diff --git a/tests/data/test-diff-filter/test-PR25661-2-report-3.txt b/tests/data/test-diff-filter/test-PR25661-2-report-3.txt
new file mode 100644
index 0000000..0927b7a
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-2-report-3.txt
@@ -0,0 +1,5 @@
+Leaf changes summary: 0 artifact changed (1 filtered out)
+Changed leaf types summary: 0 (1 filtered out) leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
diff --git a/tests/data/test-diff-filter/test-PR25661-2-report-4.txt b/tests/data/test-diff-filter/test-PR25661-2-report-4.txt
new file mode 100644
index 0000000..9540c0a
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-2-report-4.txt
@@ -0,0 +1,9 @@
+Leaf changes summary: 1 artifact changed
+Changed leaf types summary: 1 leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
+'struct S at test-PR25661-2-v0.c:1:1' changed:
+  type size hasn't changed
+  data members 'S::b', 'S::c' were replaced by anonymous data member:
+    'struct {int b; struct {union {char added_char; int c;};};}'
diff --git a/tests/data/test-diff-filter/test-PR25661-2-v0.c b/tests/data/test-diff-filter/test-PR25661-2-v0.c
new file mode 100644
index 0000000..9c672ba
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-2-v0.c
@@ -0,0 +1,12 @@
+struct S
+{
+  int a;
+  int b;
+  int c;
+  int d;
+};
+
+void
+foo(struct S* s __attribute__((unused)))
+{
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-2-v0.o b/tests/data/test-diff-filter/test-PR25661-2-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..8f3768c5fb6b5649bbdc6c2dbe2031fab98516ae
GIT binary patch
diff --git a/tests/data/test-diff-filter/test-PR25661-2-v1.c b/tests/data/test-diff-filter/test-PR25661-2-v1.c
new file mode 100644
index 0000000..f8eee3d
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-2-v1.c
@@ -0,0 +1,22 @@
+struct S
+{
+  int a;
+  struct
+  {
+    int b;
+    struct
+    {
+      union
+      {
+	char added_char;
+	int c;
+      };
+    };
+  };
+  int d;
+};
+
+void
+foo(struct S* s __attribute__((unused)))
+{
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-2-v1.o b/tests/data/test-diff-filter/test-PR25661-2-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..0dbbc1faa6700ce64d9638d7c485e17d268650e3
GIT binary patch
diff --git a/tests/data/test-diff-filter/test-PR25661-3-report-1.txt b/tests/data/test-diff-filter/test-PR25661-3-report-1.txt
new file mode 100644
index 0000000..9666a8f
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-3-report-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-filter/test-PR25661-3-report-2.txt b/tests/data/test-diff-filter/test-PR25661-3-report-2.txt
new file mode 100644
index 0000000..f275382
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-3-report-2.txt
@@ -0,0 +1,12 @@
+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 foo(S*)' at test-PR25661-3-v1.c:21:1 has some indirect sub-type changes:
+    parameter 1 of type 'S*' has sub-type changes:
+      in pointed to type 'struct S' at test-PR25661-3-v1.c:1:1:
+        type size hasn't changed
+        data member 'S::a' was replaced by anonymous data member:
+          'union {struct {struct {int a;};}; int new_union_member;}'
+
diff --git a/tests/data/test-diff-filter/test-PR25661-3-report-3.txt b/tests/data/test-diff-filter/test-PR25661-3-report-3.txt
new file mode 100644
index 0000000..0927b7a
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-3-report-3.txt
@@ -0,0 +1,5 @@
+Leaf changes summary: 0 artifact changed (1 filtered out)
+Changed leaf types summary: 0 (1 filtered out) leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
diff --git a/tests/data/test-diff-filter/test-PR25661-3-report-4.txt b/tests/data/test-diff-filter/test-PR25661-3-report-4.txt
new file mode 100644
index 0000000..bad754e
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-3-report-4.txt
@@ -0,0 +1,9 @@
+Leaf changes summary: 1 artifact changed
+Changed leaf types summary: 1 leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
+'struct S at test-PR25661-3-v0.c:1:1' changed:
+  type size hasn't changed
+  data member 'S::a' was replaced by anonymous data member:
+    'union {struct {struct {int a;};}; int new_union_member;}'
diff --git a/tests/data/test-diff-filter/test-PR25661-3-v0.c b/tests/data/test-diff-filter/test-PR25661-3-v0.c
new file mode 100644
index 0000000..bd7a6df
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-3-v0.c
@@ -0,0 +1,12 @@
+ struct S
+{
+  int a;
+  int b;
+  int c;
+  int d;
+};
+
+void
+foo(struct S* s __attribute__((unused)))
+{
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-3-v0.o b/tests/data/test-diff-filter/test-PR25661-3-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..269bfca7a6337d91fc8268a9518eb6483c0908da
GIT binary patch
diff --git a/tests/data/test-diff-filter/test-PR25661-3-v1.c b/tests/data/test-diff-filter/test-PR25661-3-v1.c
new file mode 100644
index 0000000..476af8f
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-3-v1.c
@@ -0,0 +1,23 @@
+struct S
+{
+  union
+  {
+    struct
+    {
+      struct
+      {
+	int a;
+      };
+    };
+    int new_union_member;
+  };
+
+  int b;
+  int c;
+  int d;
+};
+
+void
+foo(struct S* s __attribute__((unused)))
+{
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-3-v1.o b/tests/data/test-diff-filter/test-PR25661-3-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..604b7afec751ee544a9f3ef2ea77fea9c7ce23d9
GIT binary patch
diff --git a/tests/data/test-diff-filter/test-PR25661-4-report-1.txt b/tests/data/test-diff-filter/test-PR25661-4-report-1.txt
new file mode 100644
index 0000000..9666a8f
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-4-report-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-filter/test-PR25661-4-report-2.txt b/tests/data/test-diff-filter/test-PR25661-4-report-2.txt
new file mode 100644
index 0000000..19f2582
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-4-report-2.txt
@@ -0,0 +1,12 @@
+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 func(S*)' at test-PR25661-4-v1.c:18:1 has some indirect sub-type changes:
+    parameter 1 of type 'S*' has sub-type changes:
+      in pointed to type 'struct S' at test-PR25661-4-v1.c:3:1:
+        type size hasn't changed
+        data members 'S::a', 'S::marker', 'S::b' were replaced by anonymous data member:
+          'union {uint64_t marker[]; struct {uint64_t a; uint64_t b;};}'
+
diff --git a/tests/data/test-diff-filter/test-PR25661-4-report-3.txt b/tests/data/test-diff-filter/test-PR25661-4-report-3.txt
new file mode 100644
index 0000000..0927b7a
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-4-report-3.txt
@@ -0,0 +1,5 @@
+Leaf changes summary: 0 artifact changed (1 filtered out)
+Changed leaf types summary: 0 (1 filtered out) leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
diff --git a/tests/data/test-diff-filter/test-PR25661-4-report-4.txt b/tests/data/test-diff-filter/test-PR25661-4-report-4.txt
new file mode 100644
index 0000000..578dcd5
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-4-report-4.txt
@@ -0,0 +1,9 @@
+Leaf changes summary: 1 artifact changed
+Changed leaf types summary: 1 leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
+'struct S at test-PR25661-4-v0.c:3:1' changed:
+  type size hasn't changed
+  data members 'S::a', 'S::marker', 'S::b' were replaced by anonymous data member:
+    'union {uint64_t marker[]; struct {uint64_t a; uint64_t b;};}'
diff --git a/tests/data/test-diff-filter/test-PR25661-4-v0.c b/tests/data/test-diff-filter/test-PR25661-4-v0.c
new file mode 100644
index 0000000..b82973a
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-4-v0.c
@@ -0,0 +1,15 @@
+#include <inttypes.h>
+
+struct S
+{
+  uint64_t marker[0];
+  uint64_t a;
+  uint64_t b;
+  uint64_t c;
+};
+
+void
+func(struct S *s)
+{
+  s->a = 1;
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-4-v0.o b/tests/data/test-diff-filter/test-PR25661-4-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..9362ec606da80b2cea9aba063c529d2bfdd62c4a
GIT binary patch
diff --git a/tests/data/test-diff-filter/test-PR25661-4-v1.c b/tests/data/test-diff-filter/test-PR25661-4-v1.c
new file mode 100644
index 0000000..b3a2774
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-4-v1.c
@@ -0,0 +1,21 @@
+#include <inttypes.h>
+
+struct S
+{
+  union
+  {
+    uint64_t marker[0];
+    struct
+    {
+      uint64_t a;
+      uint64_t b;
+    };
+  };
+  uint64_t c;
+};
+
+void
+func(struct S *s)
+{
+  s->a = 1;
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-4-v1.o b/tests/data/test-diff-filter/test-PR25661-4-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..df219fc03e618fa9278605cb21f2227ac2200a94
GIT binary patch
diff --git a/tests/data/test-diff-filter/test-PR25661-5-report-1.txt b/tests/data/test-diff-filter/test-PR25661-5-report-1.txt
new file mode 100644
index 0000000..9666a8f
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-5-report-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-filter/test-PR25661-5-report-2.txt b/tests/data/test-diff-filter/test-PR25661-5-report-2.txt
new file mode 100644
index 0000000..e0c2d44
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-5-report-2.txt
@@ -0,0 +1,12 @@
+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 func(S*)' at test-PR25661-5-v1.c:22:1 has some indirect sub-type changes:
+    parameter 1 of type 'S*' has sub-type changes:
+      in pointed to type 'struct S' at test-PR25661-5-v1.c:3:1:
+        type size hasn't changed
+        data members 'S::a', 'S::b' were replaced by anonymous data member:
+          'struct {union {int a; char a_1;}; union {int b; char b_1;};}'
+
diff --git a/tests/data/test-diff-filter/test-PR25661-5-report-3.txt b/tests/data/test-diff-filter/test-PR25661-5-report-3.txt
new file mode 100644
index 0000000..0927b7a
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-5-report-3.txt
@@ -0,0 +1,5 @@
+Leaf changes summary: 0 artifact changed (1 filtered out)
+Changed leaf types summary: 0 (1 filtered out) leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
diff --git a/tests/data/test-diff-filter/test-PR25661-5-report-4.txt b/tests/data/test-diff-filter/test-PR25661-5-report-4.txt
new file mode 100644
index 0000000..85b6e74
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-5-report-4.txt
@@ -0,0 +1,9 @@
+Leaf changes summary: 1 artifact changed
+Changed leaf types summary: 1 leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
+'struct S at test-PR25661-5-v0.c:3:1' changed:
+  type size hasn't changed
+  data members 'S::a', 'S::b' were replaced by anonymous data member:
+    'struct {union {int a; char a_1;}; union {int b; char b_1;};}'
diff --git a/tests/data/test-diff-filter/test-PR25661-5-v0.c b/tests/data/test-diff-filter/test-PR25661-5-v0.c
new file mode 100644
index 0000000..db814df
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-5-v0.c
@@ -0,0 +1,14 @@
+#include <inttypes.h>
+
+struct S
+{
+  int a;
+  int b;
+  int c;
+};// end struct S
+
+void
+func(struct S *s)
+{
+  s->a = 1;
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-5-v0.o b/tests/data/test-diff-filter/test-PR25661-5-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..332f35dac2ec19817f452a49b06504bb12c8c01a
GIT binary patch
diff --git a/tests/data/test-diff-filter/test-PR25661-5-v1.c b/tests/data/test-diff-filter/test-PR25661-5-v1.c
new file mode 100644
index 0000000..7f0eb6e
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-5-v1.c
@@ -0,0 +1,25 @@
+#include <inttypes.h>
+
+struct S
+{
+  struct
+  {
+    union
+    {
+      int a;
+      char a_1;
+    };
+    union
+    {
+      int b;
+      char b_1;
+    };
+  };
+  int c;
+}; // end struct S
+
+void
+func(struct S *s)
+{
+  s->a = 1;
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-5-v1.o b/tests/data/test-diff-filter/test-PR25661-5-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..1d32777cc2733aa0c62652eaad9039ca4f0d2e0e
GIT binary patch
diff --git a/tests/data/test-diff-filter/test-PR25661-6-report-1.txt b/tests/data/test-diff-filter/test-PR25661-6-report-1.txt
new file mode 100644
index 0000000..9666a8f
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-6-report-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-filter/test-PR25661-6-report-2.txt b/tests/data/test-diff-filter/test-PR25661-6-report-2.txt
new file mode 100644
index 0000000..0927b7a
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-6-report-2.txt
@@ -0,0 +1,5 @@
+Leaf changes summary: 0 artifact changed (1 filtered out)
+Changed leaf types summary: 0 (1 filtered out) leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
diff --git a/tests/data/test-diff-filter/test-PR25661-6-report-3.txt b/tests/data/test-diff-filter/test-PR25661-6-report-3.txt
new file mode 100644
index 0000000..e0044f6
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-6-report-3.txt
@@ -0,0 +1,12 @@
+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 foo(S*)' at test-v1.c:11:1 has some indirect sub-type changes:
+    parameter 1 of type 'S*' has sub-type changes:
+      in pointed to type 'struct S' at test-v1.c:1:1:
+        type size hasn't changed
+        data member 'S::a' was replaced by anonymous data member:
+          'union {int a; char added;}'
+
diff --git a/tests/data/test-diff-filter/test-PR25661-6-report-4.txt b/tests/data/test-diff-filter/test-PR25661-6-report-4.txt
new file mode 100644
index 0000000..a3f4c72
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-6-report-4.txt
@@ -0,0 +1,9 @@
+Leaf changes summary: 1 artifact changed
+Changed leaf types summary: 1 leaf type changed
+Removed/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added function
+Removed/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable
+
+'struct S at test-v0.c:1:1' changed:
+  type size hasn't changed
+  data member 'S::a' was replaced by anonymous data member:
+    'union {int a; char added;}'
diff --git a/tests/data/test-diff-filter/test-PR25661-6-v0.c b/tests/data/test-diff-filter/test-PR25661-6-v0.c
new file mode 100644
index 0000000..4c93e56
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-6-v0.c
@@ -0,0 +1,10 @@
+struct S
+{
+  int a;
+};
+
+void
+foo(struct S *s)
+{
+  s->a = 1;
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-6-v0.o b/tests/data/test-diff-filter/test-PR25661-6-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..ec1797da0d1daa3c1deb9d0be5af339154db6e6b
GIT binary patch
diff --git a/tests/data/test-diff-filter/test-PR25661-6-v1.c b/tests/data/test-diff-filter/test-PR25661-6-v1.c
new file mode 100644
index 0000000..9e31021
--- /dev/null
+++ b/tests/data/test-diff-filter/test-PR25661-6-v1.c
@@ -0,0 +1,14 @@
+struct S
+{
+  union
+  {
+    int  a;
+    char added;
+  };
+};
+
+void
+foo(struct S *s)
+{
+  s->a = 1;
+}
diff --git a/tests/data/test-diff-filter/test-PR25661-6-v1.o b/tests/data/test-diff-filter/test-PR25661-6-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..21a6a89e89dddeda3b3fea16180c78fce773952f
GIT binary patch
diff --git a/tests/test-diff-filter.cc b/tests/test-diff-filter.cc
index 215485b..3ddbdbc 100644
--- a/tests/test-diff-filter.cc
+++ b/tests/test-diff-filter.cc
@@ -570,6 +570,174 @@ InOutSpec in_out_specs[] =
     "data/test-diff-filter/PR24787-report-0.txt",
     "output/test-diff-filter/PR24787-report-0.txt",
   },
+  {
+   "data/test-diff-filter/test-PR25661-1-v0.o",
+   "data/test-diff-filter/test-PR25661-1-v1.o",
+   "--no-default-suppression",
+   "data/test-diff-filter/test-PR25661-1-report-1.txt",
+   "output/test-diff-filter/test-PR25661-1-report-1.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-1-v0.o",
+   "data/test-diff-filter/test-PR25661-1-v1.o",
+   "--no-default-suppression --harmless",
+   "data/test-diff-filter/test-PR25661-1-report-2.txt",
+   "output/test-diff-filter/test-PR25661-1-report-2.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-1-v0.o",
+   "data/test-diff-filter/test-PR25661-1-v1.o",
+   "--no-default-suppression --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-1-report-3.txt",
+   "output/test-diff-filter/test-PR25661-1-report-3.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-1-v0.o",
+   "data/test-diff-filter/test-PR25661-1-v1.o",
+   "--no-default-suppression --harmless --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-1-report-4.txt",
+   "output/test-diff-filter/test-PR25661-1-report-4.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-2-v0.o",
+   "data/test-diff-filter/test-PR25661-2-v1.o",
+   "--no-default-suppression",
+   "data/test-diff-filter/test-PR25661-2-report-1.txt",
+   "output/test-diff-filter/test-PR25661-2-report-1.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-2-v0.o",
+   "data/test-diff-filter/test-PR25661-2-v1.o",
+   "--no-default-suppression --harmless",
+   "data/test-diff-filter/test-PR25661-2-report-2.txt",
+   "output/test-diff-filter/test-PR25661-2-report-2.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-2-v0.o",
+   "data/test-diff-filter/test-PR25661-2-v1.o",
+   "--no-default-suppression --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-2-report-3.txt",
+   "output/test-diff-filter/test-PR25661-2-report-3.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-2-v0.o",
+   "data/test-diff-filter/test-PR25661-2-v1.o",
+   "--no-default-suppression --harmless --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-2-report-4.txt",
+   "output/test-diff-filter/test-PR25661-2-report-4.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-3-v0.o",
+   "data/test-diff-filter/test-PR25661-3-v1.o",
+   "--no-default-suppression",
+   "data/test-diff-filter/test-PR25661-3-report-1.txt",
+   "output/test-diff-filter/test-PR25661-3-report-1.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-3-v0.o",
+   "data/test-diff-filter/test-PR25661-3-v1.o",
+   "--no-default-suppression --harmless",
+   "data/test-diff-filter/test-PR25661-3-report-2.txt",
+   "output/test-diff-filter/test-PR25661-3-report-2.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-3-v0.o",
+   "data/test-diff-filter/test-PR25661-3-v1.o",
+   "--no-default-suppression --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-3-report-3.txt",
+   "output/test-diff-filter/test-PR25661-3-report-3.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-3-v0.o",
+   "data/test-diff-filter/test-PR25661-3-v1.o",
+   "--no-default-suppression --harmless --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-3-report-4.txt",
+   "output/test-diff-filter/test-PR25661-3-report-4.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-4-v0.o",
+   "data/test-diff-filter/test-PR25661-4-v1.o",
+   "--no-default-suppression",
+   "data/test-diff-filter/test-PR25661-4-report-1.txt",
+   "output/test-diff-filter/test-PR25661-4-report-1.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-4-v0.o",
+   "data/test-diff-filter/test-PR25661-4-v1.o",
+   "--no-default-suppression --harmless",
+   "data/test-diff-filter/test-PR25661-4-report-2.txt",
+   "output/test-diff-filter/test-PR25661-4-report-2.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-4-v0.o",
+   "data/test-diff-filter/test-PR25661-4-v1.o",
+   "--no-default-suppression --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-4-report-3.txt",
+   "output/test-diff-filter/test-PR25661-4-report-3.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-4-v0.o",
+   "data/test-diff-filter/test-PR25661-4-v1.o",
+   "--no-default-suppression --harmless --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-4-report-4.txt",
+   "output/test-diff-filter/test-PR25661-4-report-4.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-5-v0.o",
+   "data/test-diff-filter/test-PR25661-5-v1.o",
+   "--no-default-suppression",
+   "data/test-diff-filter/test-PR25661-5-report-1.txt",
+   "output/test-diff-filter/test-PR25661-5-report-1.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-5-v0.o",
+   "data/test-diff-filter/test-PR25661-5-v1.o",
+   "--no-default-suppression --harmless",
+   "data/test-diff-filter/test-PR25661-5-report-2.txt",
+   "output/test-diff-filter/test-PR25661-5-report-2.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-5-v0.o",
+   "data/test-diff-filter/test-PR25661-5-v1.o",
+   "--no-default-suppression --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-5-report-3.txt",
+   "output/test-diff-filter/test-PR25661-5-report-3.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-5-v0.o",
+   "data/test-diff-filter/test-PR25661-5-v1.o",
+   "--no-default-suppression --harmless --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-5-report-4.txt",
+   "output/test-diff-filter/test-PR25661-5-report-4.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-6-v0.o",
+   "data/test-diff-filter/test-PR25661-6-v1.o",
+   "--no-default-suppression",
+   "data/test-diff-filter/test-PR25661-6-report-1.txt",
+   "output/test-diff-filter/test-PR25661-6-report-1.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-6-v0.o",
+   "data/test-diff-filter/test-PR25661-6-v1.o",
+   "--no-default-suppression --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-6-report-2.txt",
+   "output/test-diff-filter/test-PR25661-6-report-2.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-6-v0.o",
+   "data/test-diff-filter/test-PR25661-6-v1.o",
+   "--no-default-suppression --harmless",
+   "data/test-diff-filter/test-PR25661-6-report-3.txt",
+   "output/test-diff-filter/test-PR25661-6-report-3.txt",
+  },
+  {
+   "data/test-diff-filter/test-PR25661-6-v0.o",
+   "data/test-diff-filter/test-PR25661-6-v1.o",
+   "--no-default-suppression --harmless --leaf-changes-only",
+   "data/test-diff-filter/test-PR25661-6-report-4.txt",
+   "output/test-diff-filter/test-PR25661-6-report-4.txt",
+  },
   // This should be the last entry
   {NULL, NULL, NULL, NULL, NULL}
 };
