[02/13] suppr: Support has_data_member and has_data_member_regexp properties

Message ID 87ttz3q8wt.fsf_-_@redhat.com
State New
Headers
Series Support negative suppression specifications |

Commit Message

Dodji Seketeli March 2, 2023, 6:56 p.m. UTC
  Hello,

In the [supress_type] directive, this patch adds support for two new
properties:

* has_data_data_member = {foo, bar, blah}
  Suppresses change reports involving a type which has data members
  with names specified by the value of this property.

* has_data_member_regexp = some-regexp
  Suppresses change reports involving a type which has data members
  with names specified by the regular expression given as a value of
  this property.

	* include/abg-fwd.h (string_set_type): Define new typedef.
	* src/abg-suppression-priv.h
	* include/abg-suppression.h
	(type_suppression::{get,set}_potential_data_member_names[_regex_str]):
	Declare new data member.
	(type_suppression::priv::{potential_data_members_,
	potential_data_members_regex_str_,
	potential_data_members_regex_}): Define new data members.
	(type_suppression::priv::{get,set}_potential_data_member_names_regex):
	Define new member functions.
	* src/abg-suppression.cc
	(type_suppression::{get,set}_potential_data_member_names): Define new
	member functions.
	(type_suppression::{get,set}_potential_data_member_names_regex_str):
	Likewise.
	(type_suppression::suppresses_diff): Implement suppression using
	the new "has_data_member" and "has_data_member_regexp" properties.
	(read_type_suppression): Support parsing the new "has_data_member"
	and "has_data_member_regexp" properties of the type suppression
	directive.
	* tests/data/test-diff-suppr/has-data-member-[1-7].suppr: New
	suppression specifications for test purposes.
	* tests/data/test-diff-suppr/test-has-data-member-output-{1,2}.txt:
	New reference test outputs.
	* tests/data/test-diff-suppr/test-has-data-member-v{0,1}.cc:
	Source code of new input binary tests.
	* tests/data/test-diff-suppr/test-has-data-member-v{0,1}.o: New
	binary test inputs.
	* tests/data/Makefile.am: Add the test inputs below to source
	distribution.
	* tests/test-diff-suppr.cc (in_out_specs): Add the new test inputs
	above to this test harness.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 doc/manuals/libabigail-concepts.rst           |  48 +++++++
 include/abg-fwd.h                             |   4 +
 include/abg-suppression.h                     |  12 ++
 src/abg-suppression-priv.h                    |  37 +++++
 src/abg-suppression.cc                        | 126 ++++++++++++++++++
 tests/data/Makefile.am                        |  13 ++
 .../test-diff-suppr/has-data-member-1.suppr   |   3 +
 .../test-diff-suppr/has-data-member-2.suppr   |   3 +
 .../test-diff-suppr/has-data-member-3.suppr   |   3 +
 .../test-diff-suppr/has-data-member-4.suppr   |   3 +
 .../test-diff-suppr/has-data-member-5.suppr   |   3 +
 .../test-diff-suppr/has-data-member-6.suppr   |   3 +
 .../test-diff-suppr/has-data-member-7.suppr   |   3 +
 .../test-has-data-member-output-1.txt         |  19 +++
 .../test-has-data-member-output-2.txt         |  12 ++
 .../test-has-data-member-v0.cc                |  22 +++
 .../test-diff-suppr/test-has-data-member-v0.o | Bin 0 -> 3608 bytes
 .../test-has-data-member-v1.cc                |  24 ++++
 .../test-diff-suppr/test-has-data-member-v1.o | Bin 0 -> 3728 bytes
 tests/test-diff-suppr.cc                      |  80 +++++++++++
 20 files changed, 418 insertions(+)
 create mode 100644 tests/data/test-diff-suppr/has-data-member-1.suppr
 create mode 100644 tests/data/test-diff-suppr/has-data-member-2.suppr
 create mode 100644 tests/data/test-diff-suppr/has-data-member-3.suppr
 create mode 100644 tests/data/test-diff-suppr/has-data-member-4.suppr
 create mode 100644 tests/data/test-diff-suppr/has-data-member-5.suppr
 create mode 100644 tests/data/test-diff-suppr/has-data-member-6.suppr
 create mode 100644 tests/data/test-diff-suppr/has-data-member-7.suppr
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-output-1.txt
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-output-2.txt
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-v0.cc
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-v0.o
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-v1.cc
 create mode 100644 tests/data/test-diff-suppr/test-has-data-member-v1.o

new file mode 100644
index 00000000..afedcf91
index d9efa864..645afe53 100644
  

Patch

diff --git a/doc/manuals/libabigail-concepts.rst b/doc/manuals/libabigail-concepts.rst
index c30e87e8..2824b216 100644
--- a/doc/manuals/libabigail-concepts.rst
+++ b/doc/manuals/libabigail-concepts.rst
@@ -423,6 +423,54 @@  The potential properties of this sections are listed below:
  defined in header files whose path match the regular expression
  provided a value of the property.
 
+ .. _suppr_has_data_member_label:
+
+* ``has_data_member``
+
+  Usage:
+
+    ``has_data_member`` ``=`` <``list-of-data-member-names``>
+
+Suppresses change reports involving a type which contains data members
+whose names are provided in the list value of this property.
+
+A usage examples of this property would be: ::
+
+  has_data_member = {private_data_member0, private_data_member1}
+
+
+The property above would match any type which contains at least two
+data members whose names are ``private_data_member0`` and
+``private_data_member1``.
+
+Another usage examples of this property would be: ::
+
+  has_data_member = another_private_data_member
+
+The property above would match any type which contains
+a data member which name is ``another_private_data_member0``.
+
+ .. _suppr_has_data_member_regexp_label:
+
+* ``has_data_member_regexp``
+
+  Usage:
+
+    ``has_data_member_regexp`` ``=`` <``a-regular-expression``>
+
+Suppresses change reports involving a type which contains data members
+whose names match the regular expression provided as the value of this
+property.
+
+A usage examples of this property would be: ::
+
+  has_data_member_regexp = ^private_data_member
+
+The property above would match any type which contains data members
+whose names match the regular expression ``^private_data_member``.  In
+other words, it would match any type which contains data members whose
+names start with the string "private_data_member".
+
  .. _suppr_has_data_member_inserted_at_label:
 
 * ``has_data_member_inserted_at``
diff --git a/include/abg-fwd.h b/include/abg-fwd.h
index 96aeab54..155642f0 100644
--- a/include/abg-fwd.h
+++ b/include/abg-fwd.h
@@ -17,6 +17,7 @@ 
 #include <string>
 #include <typeinfo>
 #include <unordered_map>
+#include <unordered_set>
 #include <utility> // for std::rel_ops, at least.
 #include <vector>
 #include "abg-interned-str.h"
@@ -54,6 +55,9 @@  using std::weak_ptr;
 using std::unordered_map;
 using std::string;
 using std::vector;
+using std::unordered_set;
+
+typedef unordered_set<string> string_set_type;
 
 // Pull in relational operators.
 using namespace std::rel_ops;
diff --git a/include/abg-suppression.h b/include/abg-suppression.h
index 8e22e122..27f52110 100644
--- a/include/abg-suppression.h
+++ b/include/abg-suppression.h
@@ -243,6 +243,18 @@  public:
   void
   set_reach_kind(reach_kind k);
 
+  const string_set_type&
+  get_potential_data_member_names() const;
+
+  void
+  set_potential_data_member_names(const string_set_type&) const;
+
+  const string&
+  get_potential_data_member_names_regex_str() const;
+
+  void
+  set_potential_data_member_names_regex_str(const string&) const;
+
   void
   set_data_member_insertion_ranges(const insertion_ranges& r);
 
diff --git a/src/abg-suppression-priv.h b/src/abg-suppression-priv.h
index 4b74096d..5fc1ec52 100644
--- a/src/abg-suppression-priv.h
+++ b/src/abg-suppression-priv.h
@@ -570,6 +570,15 @@  class type_suppression::priv
   type_suppression::type_kind		type_kind_;
   bool					consider_reach_kind_;
   type_suppression::reach_kind		reach_kind_;
+  // The data members a class needs to have to match this suppression
+  // specification.  These might be selected by a regular expression.
+  string_set_type			potential_data_members_;
+  // The regular expression string that selects the potential data
+  // members of the class.
+  string				potential_data_members_regex_str_;
+  // The compiled regular expression that selects the potential data
+  // members of the class.
+  mutable regex::regex_t_sptr		potential_data_members_regex_;
   type_suppression::insertion_ranges	insertion_ranges_;
   unordered_set<string>			source_locations_to_keep_;
   string				source_location_to_keep_regex_str_;
@@ -677,6 +686,34 @@  public:
   set_source_location_to_keep_regex(regex::regex_t_sptr r)
   {source_location_to_keep_regex_ = r;}
 
+  /// Getter for the "potential_data_member_names_regex" object.
+  ///
+  /// This regex object matches the names of the data members that are
+  /// needed for this suppression specification to select the type.
+  ///
+  /// @return the "potential_data_member_names_regex" object.
+  const regex::regex_t_sptr
+  get_potential_data_member_names_regex() const
+  {
+    if (!potential_data_members_regex_
+	&& !potential_data_members_regex_str_.empty())
+      {
+	potential_data_members_regex_ =
+	  regex::compile(potential_data_members_regex_str_);
+      }
+    return potential_data_members_regex_;
+  }
+
+  /// Setter for the "potential_data_member_names_regex" object.
+  ///
+  /// This regex object matches the names of the data members that are
+  /// needed for this suppression specification to select the type.
+  ///
+  /// @param r the new "potential_data_member_names_regex" object.
+  void
+  set_potential_data_member_names_regex(regex::regex_t_sptr &r)
+  {potential_data_members_regex_ = r;}
+
   friend class type_suppression;
 }; // class type_suppression::priv
 
diff --git a/src/abg-suppression.cc b/src/abg-suppression.cc
index 059c3909..5fcdef97 100644
--- a/src/abg-suppression.cc
+++ b/src/abg-suppression.cc
@@ -569,6 +569,38 @@  void
 type_suppression::set_reach_kind(reach_kind k)
 {priv_->reach_kind_ = k;}
 
+/// Getter of the "potential_data_member_names" property.
+///
+/// @return the set of potential data member names of this
+/// suppression.
+const unordered_set<string>&
+type_suppression::get_potential_data_member_names() const
+{return priv_->potential_data_members_;}
+
+/// Setter of the "potential_data_member_names" property.
+///
+/// @param s the new set of potential data member names of this
+/// suppression.
+void
+type_suppression::set_potential_data_member_names
+(const string_set_type& s) const
+{priv_->potential_data_members_ = s;}
+
+/// Getter of the "potential_data_member_names_regex" string.
+///
+/// @return the "potential_data_member_names_regex" string.
+const string&
+type_suppression::get_potential_data_member_names_regex_str() const
+{return priv_->potential_data_members_regex_str_;}
+
+/// Setter of the "potential_data_member_names_regex" string.
+///
+/// @param d the new "potential_data_member_names_regex" string.
+void
+type_suppression::set_potential_data_member_names_regex_str
+(const string& d) const
+{priv_->potential_data_members_regex_str_ = d;}
+
 /// Setter for the vector of data member insertion ranges that
 /// specifies where a data member is inserted as far as this
 /// suppression specification is concerned.
@@ -778,6 +810,43 @@  type_suppression::suppresses_diff(const diff* diff) const
   // Now let's consider class diffs in the context of a suppr spec
   // that contains properties like "has_data_member_inserted_*".
 
+  const class_or_union_diff* cou_diff = is_class_or_union_diff(d);
+  if (cou_diff)
+    {
+      class_or_union_sptr f = cou_diff->first_class_or_union();
+      // We are looking at the a class or union diff ...
+      if (!get_potential_data_member_names().empty())
+	{
+	  // ... and the suppr spec has a:
+	  //
+	  //    "has_data_member = {foo, bar}" property
+	  //
+	  for (string var_name : get_potential_data_member_names())
+	    if (!f->find_data_member(var_name))
+	      return false;
+	}
+
+      if (!get_potential_data_member_names_regex_str().empty())
+	{
+	  if (const regex_t_sptr& data_member_name_regex =
+	      priv_->get_potential_data_member_names_regex())
+	    {
+	      bool data_member_matched = false;
+	      for (var_decl_sptr dm : f->get_data_members())
+		{
+		  if (regex::match(data_member_name_regex, dm->get_name()))
+		    {
+		      data_member_matched = true;
+		      break;
+		    }
+		}
+	      if (!data_member_matched)
+		return false;
+	    }
+	}
+    }
+
+  // Evaluate has_data_member_inserted_*" clauses.
   const class_diff* klass_diff = dynamic_cast<const class_diff*>(d);
   if (klass_diff)
     {
@@ -1720,6 +1789,56 @@  read_type_suppression(const ini::config::section& section)
 	read_suppression_reach_kind(reach_kind_prop->get_value()->as_string());
     }
 
+  // Support has_data_member = {}
+  string_set_type potential_data_member_names;
+  if (ini::property_sptr propertee = section.find_property("has_data_member"))
+    {
+      // This is either has_data_member = {foo, blah} or
+      // has_data_member = foo.
+      ini::tuple_property_value_sptr tv;
+      ini::string_property_value_sptr sv;
+      if (ini::tuple_property_sptr prop = is_tuple_property(propertee))
+	// Value is of the form {foo,blah}
+	tv = prop->get_value();
+      else if (ini::simple_property_sptr prop = is_simple_property(propertee))
+	// Value is of the form foo.
+	sv = prop->get_value();
+
+      // Ensure that the property value has the form {"foo", "blah", ...};
+      // Meaning it's a tuple of one element which is a list or a string.
+      if (tv
+	  && tv->get_value_items().size() == 1
+	  && (is_list_property_value(tv->get_value_items().front())
+	      || is_string_property_value(tv->get_value_items().front())))
+	{
+	  ini::list_property_value_sptr val =
+	    is_list_property_value(tv->get_value_items().front());
+	  if (!val)
+	    {
+	      // We have just one potential data member name,as a
+	      // string_property_value.
+	      string name =
+		is_string_property_value(tv->get_value_items().front())
+		->as_string();
+	      potential_data_member_names.insert(name);
+	    }
+	  else
+	    for (const string& name : val->get_content())
+	      potential_data_member_names.insert(name);
+	}
+      else if (sv)
+	{
+	  string name = sv->as_string();
+	  potential_data_member_names.insert(name);
+	}
+    }
+
+  // Support has_data_member_regexp = str
+  string potential_data_member_names_regexp_str;
+  if (ini::simple_property_sptr prop =
+      is_simple_property(section.find_property("has_data_member_regexp")))
+      potential_data_member_names_regexp_str = prop->get_value()->as_string();
+
   // Support has_data_member_inserted_at
   vector<type_suppression::insertion_range_sptr> insert_ranges;
   bool consider_data_member_insertion = false;
@@ -1919,6 +2038,13 @@  read_type_suppression(const ini::config::section& section)
       result->set_reach_kind(reach_kind);
     }
 
+  if (!potential_data_member_names.empty())
+    result->set_potential_data_member_names(potential_data_member_names);
+
+  if (!potential_data_member_names_regexp_str.empty())
+    result->set_potential_data_member_names_regex_str
+      (potential_data_member_names_regexp_str);
+
   if (consider_data_member_insertion)
     result->set_data_member_insertion_ranges(insert_ranges);
 
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 1a0a3fa4..57abf7a9 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -1740,6 +1740,19 @@  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-suppr/has-data-member-1.suppr \
+test-diff-suppr/has-data-member-2.suppr \
+test-diff-suppr/has-data-member-3.suppr \
+test-diff-suppr/has-data-member-4.suppr \
+test-diff-suppr/has-data-member-5.suppr \
+test-diff-suppr/has-data-member-6.suppr \
+test-diff-suppr/has-data-member-7.suppr \
+test-diff-suppr/test-has-data-member-output-1.txt \
+test-diff-suppr/test-has-data-member-output-2.txt \
+test-diff-suppr/test-has-data-member-v0.cc \
+test-diff-suppr/test-has-data-member-v0.o \
+test-diff-suppr/test-has-data-member-v1.cc \
+test-diff-suppr/test-has-data-member-v1.o \
 \
 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/has-data-member-1.suppr b/tests/data/test-diff-suppr/has-data-member-1.suppr
new file mode 100644
index 00000000..37c0d1e9
--- /dev/null
+++ b/tests/data/test-diff-suppr/has-data-member-1.suppr
@@ -0,0 +1,3 @@ 
+[suppress_type]
+  type_kind = struct
+  has_data_member = {private_data_member0, private_data_member1}
diff --git a/tests/data/test-diff-suppr/has-data-member-2.suppr b/tests/data/test-diff-suppr/has-data-member-2.suppr
new file mode 100644
index 00000000..909fd01d
--- /dev/null
+++ b/tests/data/test-diff-suppr/has-data-member-2.suppr
@@ -0,0 +1,3 @@ 
+[suppress_type]
+  type_kind = struct
+  has_data_member = {private_data_member0}
diff --git a/tests/data/test-diff-suppr/has-data-member-3.suppr b/tests/data/test-diff-suppr/has-data-member-3.suppr
new file mode 100644
index 00000000..43823d79
--- /dev/null
+++ b/tests/data/test-diff-suppr/has-data-member-3.suppr
@@ -0,0 +1,3 @@ 
+[suppress_type]
+  type_kind = struct
+  has_data_member = private_data_member1
diff --git a/tests/data/test-diff-suppr/has-data-member-4.suppr b/tests/data/test-diff-suppr/has-data-member-4.suppr
new file mode 100644
index 00000000..779a39f0
--- /dev/null
+++ b/tests/data/test-diff-suppr/has-data-member-4.suppr
@@ -0,0 +1,3 @@ 
+[suppress_type]
+  type_kind = struct
+  has_data_member = {private_data_member3, private_data_member4}
diff --git a/tests/data/test-diff-suppr/has-data-member-5.suppr b/tests/data/test-diff-suppr/has-data-member-5.suppr
new file mode 100644
index 00000000..6ab80758
--- /dev/null
+++ b/tests/data/test-diff-suppr/has-data-member-5.suppr
@@ -0,0 +1,3 @@ 
+[suppress_type]
+  type_kind = struct
+  has_data_member = private_data_member5
diff --git a/tests/data/test-diff-suppr/has-data-member-6.suppr b/tests/data/test-diff-suppr/has-data-member-6.suppr
new file mode 100644
index 00000000..7bd34159
--- /dev/null
+++ b/tests/data/test-diff-suppr/has-data-member-6.suppr
@@ -0,0 +1,3 @@ 
+[suppress_type]
+  type_kind = struct
+  has_data_member_regexp = ^private_data_member
diff --git a/tests/data/test-diff-suppr/has-data-member-7.suppr b/tests/data/test-diff-suppr/has-data-member-7.suppr
new file mode 100644
index 00000000..03c9d99b
--- /dev/null
+++ b/tests/data/test-diff-suppr/has-data-member-7.suppr
@@ -0,0 +1,3 @@ 
+[suppress_type]
+  type_kind = struct
+  has_data_member_regexp = ^private_data_memberWRONG
diff --git a/tests/data/test-diff-suppr/test-has-data-member-output-1.txt b/tests/data/test-diff-suppr/test-has-data-member-output-1.txt
new file mode 100644
index 00000000..2212998a
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-output-1.txt
@@ -0,0 +1,19 @@ 
+Functions changes summary: 0 Removed, 2 Changed, 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+2 functions with some indirect sub-type change:
+
+  [C] 'function int bar(S1*)' at test-has-data-member-v0.cc:19:1 has some indirect sub-type changes:
+    parameter 1 of type 'S1*' has sub-type changes:
+      in pointed to type 'struct S1' at test-has-data-member-v1.cc:8:1:
+        type size changed from 32 to 64 (in bits)
+        1 data member insertion:
+          'char non_suppressed_added_member', at offset 32 (in bits) at test-has-data-member-v1.cc:11:1
+
+  [C] 'function void foo(S0&)' at test-has-data-member-v0.cc:14:1 has some indirect sub-type changes:
+    parameter 1 of type 'S0&' has sub-type changes:
+      in referenced type 'struct S0' at test-has-data-member-v1.cc:1:1:
+        type size changed from 64 to 96 (in bits)
+        1 data member insertion:
+          'int suppressed_added_member', at offset 64 (in bits) at test-has-data-member-v1.cc:5:1
+
diff --git a/tests/data/test-diff-suppr/test-has-data-member-output-2.txt b/tests/data/test-diff-suppr/test-has-data-member-output-2.txt
new file mode 100644
index 00000000..ab0110c9
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-output-2.txt
@@ -0,0 +1,12 @@ 
+Functions changes summary: 0 Removed, 1 Changed (1 filtered out), 0 Added functions
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
+1 function with some indirect sub-type change:
+
+  [C] 'function int bar(S1*)' at test-has-data-member-v0.cc:19:1 has some indirect sub-type changes:
+    parameter 1 of type 'S1*' has sub-type changes:
+      in pointed to type 'struct S1' at test-has-data-member-v1.cc:8:1:
+        type size changed from 32 to 64 (in bits)
+        1 data member insertion:
+          'char non_suppressed_added_member', at offset 32 (in bits) at test-has-data-member-v1.cc:11:1
+
diff --git a/tests/data/test-diff-suppr/test-has-data-member-v0.cc b/tests/data/test-diff-suppr/test-has-data-member-v0.cc
new file mode 100644
index 00000000..554002c3
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-v0.cc
@@ -0,0 +1,22 @@ 
+struct S0
+{
+  int private_data_member0;
+  char private_data_member1;
+};
+
+struct S1
+{
+  int m0;
+};
+
+
+void
+foo(S0&)
+{
+}
+
+int
+bar(S1* s)
+{
+  return s->m0;
+}
diff --git a/tests/data/test-diff-suppr/test-has-data-member-v0.o b/tests/data/test-diff-suppr/test-has-data-member-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..dfbebe4c76a0100982e6b62657392d081a5d40e6
GIT binary patch
literal 3608
zcmcIm&2Jk;6o2EjV>_ETPF+Dlkm6Jz`oXS0T1uLdVicuKR0M6JN)f1X*Y?CViS1~;
zF`<YLsZgoPB}j1Nz<~>#khpN*R{j7ajz}DkxFT_@!~x#ho#$-EZiGNQX=i@#_daIk
z&4>NL@~c-PLI8_^D{!bW3ow;D#3dh=;3Q<=*2;t5Rvx_f=-~E4hAaEakM`mA!(Y%X
z1|mV;1~qfkgk>hAi1j=q#7$%(#2Rse0gfg%5Jn*yjWydI#KZ`h#Cidu@gAa)Rvtt$
z2!MFSaY1DKHTWsW7bP8ZAU^*ZQKE}JNkWlN8jwts5shwkIv`R<R&VyBenw<cLjhw6
zn+!ONkuc4LIdR#%G?x$=w2p(33J7yGGmr7cq<A)!F^$=o*-3FCo_-RS@(h^f71O}d
z#1u^7GB7l;U}7p28MnpD(@eEfs~L(fP2HWQffBKhcVr46Ie|%6(K328EF5IUU^PR|
zV`=3K&(o4<G2m~MkEjXnO`k;YI({+qJ&U~%;?LALbyPI`5X}1Zi-_6CM35FO7$G3p
zSB;doSBj0_i-~$9f-&Vc&f})tDB_0hxXqs9$#Tu{oN`OHD$>mlBMWftwOiSxbLR>#
zW(x)Tyj{o^^TlGJP%LCmugO|=#qpHEx^O0IwY=T7T&&BsbemOF9k<$8+?&5>UA$oR
zidm};I0@YUwIUwFY6FjuC%c~2aJm*v#R{fk_40PL3b{t7C3Ce-?X706-t=<Y&5BcL
z)}7{d&TV)Wo>A$xo$Xw$E4QR4iM6)S!*XR;x;>er+}#`{_Mug4Zf;uL-JKoxf6aZ&
zl8!OKwWXzn>}jm`nSW4ff48wYserh<24XKQX2#-)13Vf}BTpZRf4N>srSC_U#z(HA
z19D`0iHs=zm1X<&z#dozTRL@7_~WlZ3q3ymnH(?~>fq}JBY3WK8rkRoM}z_XgEU|>
zAU?na{-MV-<Y5FA2{8dQU~GUR!T@|VhKK<ZLs;@3AK<CpCqnh%2k$w>v(C@warYv0
zg+f<47?K~CQB=d#;u#T7Re2$B$2kQ;Jbf%rD8M{FQ%@<LcDn!2AU+%N=Q$8{Da6yb
zyv}8f&no>*jXzNO`x>uQxUT@uhx31@`G2hR?=^p=_G?A!jWLNm?+52+(<ueGK5r|X
zo_P}He+pD6sGj-Xm3~?Edj729sm9?tmo%Q&3wHONmgiKk_uQawF!JP{2R1!}U{|_b
zuwA+B*fm+%t(Tka%?{dp>{KeQ>>V*XuG6l|qaoYPw&V~Tf+5jmU$1srEs1|1>~_bK
zHa=)p*K?{{DzR*oH(jSC)k6MbN9U4i7e4EhvP2CEpW8qSd>K<ehabiJf1HR=!sn26
z?#VYSbbsl*|J!&v7kW<0&*T3}N=S5HI&bt^mO?%R8>%4lDqs>h^5eUS|4n>Z#8%Hq
zhDAmG;Cmf5y6+7%=^S|rb!hX4p+3@muOmBb{$Hpko#Sc#MCtRdA*bg=3JPlcby7m2
z`_doMVdMX(#=oOtX?%LW^znC)qntcXguZ;F#{Y~7)${n=zl;2^_-S>ZlI-}H`2EMk
zpQ1&f<btl>aysrmMGND;6M~y6KFkr;eZNwiT5jKcL&b0OnE-J8nEnz0xt5qveO@_o
zU8(-`Ys>L`erZ1X*p%WMHU5Wc!t^^wzv6m4?Wuluk%GLsKSfePqOYIkH7x#)8tB_l
IEI~c~Z@Q&JasU7T

literal 0
HcmV?d00001

diff --git a/tests/data/test-diff-suppr/test-has-data-member-v1.cc b/tests/data/test-diff-suppr/test-has-data-member-v1.cc
--- /dev/null
+++ b/tests/data/test-diff-suppr/test-has-data-member-v1.cc
@@ -0,0 +1,24 @@ 
+struct S0
+{
+  int private_data_member0;
+  char private_data_member1;
+  int suppressed_added_member;
+};
+
+struct S1
+{
+  int m0;
+  char non_suppressed_added_member;
+};
+
+
+void
+foo(S0&)
+{
+}
+
+int
+bar(S1* s)
+{
+  return s->m0;
+}
diff --git a/tests/data/test-diff-suppr/test-has-data-member-v1.o b/tests/data/test-diff-suppr/test-has-data-member-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..b5bfe1205553f779fd2855010b6ae4e631a198e3
GIT binary patch
literal 3728
zcmcIm-D_h-6hD*Ow70$eNH?ptR%j}U`{7NR?7HrD?HVcFZCTN^r65X)H_0@KZIW_x
zTkDD_E(l9ODu_>2eDGm?6MXX3^~E<qAN&V=6-1Dt4|>kMbJFP~EuwfJGr#jYA2W02
z<K~_D=dZ_v02Tq);80^0V6XoW=R=r>(~yLfg}Xm5+<p6CZ}mRIh28msU0A*UJG#X|
z*yL?dGewOq6PglRo`ylOicC1X)kiSGJ$4ykPsqnZ-iDr@c&!mYT=bG#Y&i?I{Q;uh
z`ZS0EE!c^Ip|9xqARY*lgsCYGB@uNX_P;@7x6r4bQ0&7h^xNx*2G*KQ5Q#8SIfJ8s
z*#8ZYLk$HC+G#R~A+UyLro>g}inEx!jLxy7ux!VPxG7sCu_UA7@!_OnO-@XXic@`w
zhj59Hf#Y0rEG$`E!C_nyX0vCU!(@GF@$5KLjp4;4#plOvk5gJZu6f7C0QyHT=^|PN
zj)v($P8=4K<UE*A&hR8Hi53Il28M_leb3q?f*0`@N8fYU3nBg-9-@wlhCc+8Vf|ua
zGBy&WMGHm<=x?i5Lfpy6hwj8hB^JY&!YdbW({AN(b2t6kwin1k*$ccvUDk`zpYBFx
zq0wv<T3ef&zHGH*x!{${*hUd>9Dn15mDJq%^Vz3U*=+hkI-AN(=W^L>E}J^DB+ID<
zFHi>e;@Om254IX|wjvwSua!{s{8Dvx=kg`@(nWVWmvSqB6UQ^Nl*1!ks^YN=WGis1
zUdyHFyU}Fa?QFVKf=snpmzi?2{CX`@sRfyhTG1=kDqd|P<5vS0&$#p(-bSX}lIt>%
z#JcO~;o|zFzb!MAyOp8DA#}^NwKX?f=>MAgge9F|f*W&lGpRFJ@3a4))O0{jQ-dOI
zFM-%eh>5{Idk>G&BgoN@B)p8z4JY1@%?<TlM+fA{_6!+O!Yj`9n~^=TbhdO#d*Ii<
zIxX~wg=e_KWT}f{8m#EqGihXdIyfRM2p_W!n+1IxT;#7k%9@AOex5WEp#_6S38h(p
zuS^%QV5AF6d4@W8s`n|aKKwvFp?KE$xjpGlXxB%30-_=LF&aQsuNKdUc&bV*a>qGE
zLOlIg9#nvNe%2mVJneM*VM2UP^XEAbbw%T8TwdqA!Kak|lEJfHG5Bwl{+_`<rSy*t
zUa9b@0z7}7&-aG^*Gm7<@K<WPwp5=uli2hAaeg*EssPvX4W-j(goODYA{DZ#XZ{zZ
zUsb)CKc#ru6MbLu2G8q-bnDG};1#hC{HU)o3gk`zX?ijtU2L@=?aK`>U6#eIN}<+R
zYoaa0Ua{!Q?IUK-_Zk&>G-RXJkQ{<TFeJJV>ZNAAF7eMwy3q_|8XrHm6?mm}l~`5_
zYra>PY9arzqjOBP)9(hQ%u|EH=RDFPU&ho=;g90OKWs!Od6j|Dldmpx-|2q*+ju$`
zW=_h_<Nra5CZ;c)H+o(3nh(J*RY9sMU=%s><GYOieL|VV*33zU6-DyB44u39-s-}U
z@3=a&)1+u(j&&1l-R3{0Cd%<NfBGtz^DiT3=0pk>)%eS#Xkz*n(AI7I1vSuXDwf8l
z_s$%D6FJJs^F$cRz8e2KCRESkbN?3d-QuM>Q2p$9O#JRK@eNuON+#;sEvMuDBeXDX
zJ0bW)#p@hl)AtL-spYoaKU489x0wiV{h0n70lDUxQ2jmS$aSUq)7P2f`TWv+%&{rO
tfg1l^HDUTL(pTS%r#&_AE>f_g?oW;sP0aPvyt>8zqz3v*izR5r{|)=SU!?#5

literal 0
HcmV?d00001

diff --git a/tests/test-diff-suppr.cc b/tests/test-diff-suppr.cc
--- a/tests/test-diff-suppr.cc
+++ b/tests/test-diff-suppr.cc
@@ -2056,6 +2056,86 @@  InOutSpec in_out_specs[] =
     "data/test-diff-suppr/PR28073/PR28073-output-2.txt",
     "output/test-diff-suppr/PR28073/PR28073-output-2.txt"
   },
+  {
+    "data/test-diff-suppr/test-has-data-member-v0.o",
+    "data/test-diff-suppr/test-has-data-member-v1.o",
+    "",
+    "",
+    "",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-output-1.txt",
+    "output/test-diff-suppr/test-has-data-member-output-1.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-v0.o",
+    "data/test-diff-suppr/test-has-data-member-v1.o",
+    "",
+    "",
+    "data/test-diff-suppr/has-data-member-1.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-output-2.txt",
+    "output/test-diff-suppr/test-has-data-member-output-2.1.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-v0.o",
+    "data/test-diff-suppr/test-has-data-member-v1.o",
+    "",
+    "",
+    "data/test-diff-suppr/has-data-member-2.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-output-2.txt",
+    "output/test-diff-suppr/test-has-data-member-output-2.2.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-v0.o",
+    "data/test-diff-suppr/test-has-data-member-v1.o",
+    "",
+    "",
+    "data/test-diff-suppr/has-data-member-3.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-output-2.txt",
+    "output/test-diff-suppr/test-has-data-member-output-2.3.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-v0.o",
+    "data/test-diff-suppr/test-has-data-member-v1.o",
+    "",
+    "",
+    "data/test-diff-suppr/has-data-member-4.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-output-1.txt",
+    "output/test-diff-suppr/test-has-data-member-output-1.2.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-v0.o",
+    "data/test-diff-suppr/test-has-data-member-v1.o",
+    "",
+    "",
+    "data/test-diff-suppr/has-data-member-5.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-output-1.txt",
+    "output/test-diff-suppr/test-has-data-member-output-1.3.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-v0.o",
+    "data/test-diff-suppr/test-has-data-member-v1.o",
+    "",
+    "",
+    "data/test-diff-suppr/has-data-member-6.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-output-2.txt",
+    "output/test-diff-suppr/test-has-data-member-output-2.4.txt"
+  },
+    {
+    "data/test-diff-suppr/test-has-data-member-v0.o",
+    "data/test-diff-suppr/test-has-data-member-v1.o",
+    "",
+    "",
+    "data/test-diff-suppr/has-data-member-7.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-output-1.txt",
+    "output/test-diff-suppr/test-has-data-member-output-1.4.txt"
+  },
   // This should be the last entry
   {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
 };