suppression: Support offset_of_{first,last}_data_member_regexp offset selectors
authorDodji Seketeli <dodji@redhat.com>
Fri, 27 Jan 2023 16:00:42 +0000 (17:00 +0100)
committerDodji Seketeli <dodji@redhat.com>
Thu, 2 Mar 2023 17:18:37 +0000 (18:18 +0100)
This patch adds support for two data member offset selector
expressions for properties of the [suppress_type] directive:

offset_of_first_data_member_regexp() and offset_of_last_data_member_regexp().

These function-call expressions take a regular expression argument and
evaluate to the offset of the first (resp. last) data member matching
the regular expression argument.

An example of their use would be be:

    [suppress_type]
      type_kind = struct
      has_data_member_inserted_between =
{
  offset_of_first_data_member_regexp(^__special_padding_space),
  offset_of_last_data_member_regexp(^__special_padding_space)
}

This would be useful to suppress change reports involving a struct
which has "padding" data members added on-purpose like:

    struct S
    {
      int member0;
      char member1;
      unsigned __special_padding_space1;
      unsigned __special_padding_space2;
      unsigned __special_padding_space3;
    };

* doc/manuals/libabigail-concepts.rst: Document the new
properties.
* include/abg-fwd.h: Forward declare comparison::{diff_context,
diff_context_sptr, diff_context_wptr, diff, diff_wptr} and
regex::regex_t_sptr.
(find_first_data_member_matching_regexp)
(find_last_data_member_matching_regexp): Declare new functions.
* include/abg-suppression.h: Inject std::{string, shared_ptr,
vector} and comparison::{diff, diff_context_sptr} into the suppr
namespace.  Remove the "abg-comparison.h" header.
* src/abg-elf-helpers.cc: Include sstream.
* src/abg-ir.cc (find_first_data_member_matching_regexp)
(find_last_data_member_matching_regexp): Define new functions.
* src/abg-suppression.cc
(type_suppression::insertion_range::eval_boundary): Support
evaluating "offset_of_first_data_member_regexp" and
"offset_of_first_data_member_regexp".
* src/abg-ctf-reader.cc: Include sstream.
* tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-[1-4].txt:
New test reference outputs.
* tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v[0-4].c:
Source code of new test input.
* tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v[0-4].o:
New binary test input.
* tests/data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr:
New suppression specification.
* tests/data/Makefile.am: Add the new test input files to source
distribution.
* tests/test-diff-suppr.cc (in_out_specs): Add the new test input
to this test harness.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
24 files changed:
doc/manuals/libabigail-concepts.rst
include/abg-fwd.h
include/abg-suppression.h
src/abg-ctf-reader.cc
src/abg-elf-helpers.cc
src/abg-ir.cc
src/abg-suppression.cc
tests/data/Makefile.am
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.c [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.c [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.o [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.c [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.o [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.c [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.o [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.c [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.o [new file with mode: 0644]
tests/data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr [new file with mode: 0644]
tests/test-diff-suppr.cc

index dc5a4a5c640bf4b57431781a1ea3a2d7688a2d03..326a346eb1762acdaa13e9b2b709352bbc527ee6 100644 (file)
@@ -493,24 +493,48 @@ names start with the string "private_data_member".
           offset of the insertion point of the data member, starting
           from the beginning of the relevant structure or class.
 
-        - the keyword ``end`` which is a named constant which value
-          equals the offset of the end of the of the structure or
-          class.
-
-        - the function call expression
-          ``offset_of(data-member-name)`` where `data-member-name` is
-          the name of a given data member of the relevant structure
-          or class.  The value of this function call expression is an
-          integer that represents the offset of the data member
-          denoted by ``data-member-name``.
-
-        - the function call expression
-          ``offset_after(data-member-name)`` where `data-member-name`
-          is the name of a given data member of the relevant
-          structure or class.  The value of this function call
-          expression is an integer that represents the offset of the
-          point that comes right after the region occupied by the
-          data member denoted by ``data-member-name``.
+.. _suppr_data_member_offset_selector_expressions_label:
+
+        - data member offset selector expressions, such as:
+
+            - the keyword ``end`` which is a named constant which value
+              equals the offset of the end of the of the structure or
+              class.
+
+            - the function call expression
+              ``offset_of(data-member-name)`` where `data-member-name` is
+              the name of a given data member of the relevant structure
+              or class.  The value of this function call expression is an
+              integer that represents the offset of the data member
+              denoted by ``data-member-name``.
+
+            - the function call expression
+              ``offset_after(data-member-name)`` where `data-member-name`
+              is the name of a given data member of the relevant
+              structure or class.  The value of this function call
+              expression is an integer that represents the offset of the
+              point that comes right after the region occupied by the
+              data member denoted by ``data-member-name``.
+
+            - the function call expression
+              ``offset_of_first_data_member_regexp(data-member-name-regexp)``
+              where `data-member-name-regexp` is a regular expression
+              matching a data member.  The value of this function
+              call expression is an integer that represents the
+              offset of the first data member which name matches the
+              regular expression argument.  If no data member of a
+              given class type matches the regular expression, then
+              the class type won't match the current directive.
+
+            - the function call expression
+              ``offset_of_last_data_member_regexp(data-member-name-regexp)``
+              where `data-member-name-regexp` is a regular expression
+              matching a data member.  The value of this function
+              call expression is an integer that represents the
+              offset of the last data member which name matches the
+              regular expression argument.  If no data member of a
+              given class type matches the regular expression, then
+              the class type won't match the current directive.
 
   .. _suppr_has_data_member_inserted_between_label:
 
index 4051fab592a3fc04e3f46fcc7d8ab4afb5041a95..fc3f4374a53dd465ad3ab4e0bab1ecf4c2320882 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdint.h>
 #include <cstddef>
 #include <cstdlib>
+#include <regex.h>
 #include <list>
 #include <memory>
 #include <ostream>
@@ -62,6 +63,31 @@ typedef unordered_set<string> string_set_type;
 // Pull in relational operators.
 using namespace std::rel_ops;
 
+namespace comparison
+{
+class diff_context;
+
+/// Convenience typedef for a shared pointer of @ref diff_context.
+typedef shared_ptr<diff_context> diff_context_sptr;
+
+/// Convenience typedef for a weak pointer of @ref diff_context.
+typedef weak_ptr<diff_context> diff_context_wptr;
+
+class diff;
+
+/// Convenience typedef for a shared_ptr for the @ref diff class
+typedef shared_ptr<diff> diff_sptr;
+
+/// Convenience typedef for a weak_ptr for the @ref diff class
+typedef weak_ptr<diff> diff_wptr;
+}
+
+namespace regex
+{
+/// A convenience typedef for a shared pointer of regex_t.
+typedef std::shared_ptr<regex_t> regex_t_sptr;
+}// end namespace regex
+
 namespace ir
 {
 
@@ -1472,6 +1498,13 @@ build_internal_underlying_enum_type_name(const string &base_name,
                                         bool is_anonymous,
                                         uint64_t size);
 
+var_decl_sptr
+find_first_data_member_matching_regexp(const class_or_union& t,
+                                      const regex::regex_t_sptr& r);
+
+var_decl_sptr
+find_last_data_member_matching_regexp(const class_or_union& t,
+                                     const regex::regex_t_sptr& regex);
 } // end namespace ir
 
 using namespace abigail::ir;
index a51fdc5a4b7db6c0faffcbf3a7c73ea3c4be9cff..bfc37a40fed6b43a0f306c7116d98bc70e98077f 100644 (file)
@@ -11,7 +11,7 @@
 #include <unordered_set>
 
 #include "abg-ini.h"
-#include "abg-comparison.h"
+#include "abg-ir.h"
 
 namespace abigail
 {
@@ -29,9 +29,12 @@ class fe_iface;
 /// that are defined in this namespace.
 namespace suppr
 {
-
-using namespace abigail::comparison;
 using std::unordered_set;
+using std::string;
+using std::shared_ptr;
+using std::vector;
+using comparison::diff;
+using comparison::diff_context_sptr;
 
 /// Base type of the suppression specifications types.
 ///
index 7db8dbc62b5d1f8a6a4148efc335144792b1f1b4..9b34ee2e2b1463152d15ca4f40ee6ef2d12ea198 100644 (file)
@@ -14,6 +14,7 @@
 #include "config.h"
 
 #include <fcntl.h> /* For open(3) */
+#include <sstream>
 #include <iostream>
 #include <memory>
 #include <map>
index d61114bfffb37a9cc9fab2a07c57ab7372eb727d..8ffeefb371fb12ae3fe9d32ad3642ea5b5e753f7 100644 (file)
@@ -12,6 +12,7 @@
 #include <unistd.h>
 #include <limits.h>
 #include <elfutils/libdwfl.h>
+#include <sstream>
 #include "abg-elf-helpers.h"
 #include "abg-tools-utils.h"
 
index ef19eb4148fdcd9363ebc812dd45e6068295c10c..015aa2b329806160e4db70505e3ea74c60f060eb 100644 (file)
@@ -28,6 +28,7 @@ ABG_BEGIN_EXPORT_DECLARATIONS
 #include "abg-interned-str.h"
 #include "abg-ir.h"
 #include "abg-corpus.h"
+#include "abg-regex.h"
 
 ABG_END_EXPORT_DECLARATIONS
 // </headers defining libabigail's API>
@@ -26609,6 +26610,50 @@ build_internal_underlying_enum_type_name(const string &base_name,
   return o.str();
 }
 
+/// Find the first data member of a class or union which name matches
+/// a regular expression.
+///
+/// @param t the class or union to consider.
+///
+/// @param r the regular expression to consider.
+///
+/// @return the data member matched by @p r or nil if none was found.
+var_decl_sptr
+find_first_data_member_matching_regexp(const class_or_union& t,
+                                      const regex::regex_t_sptr& r)
+{
+  for (auto data_member : t.get_data_members())
+    {
+      if (regex::match(r, data_member->get_name()))
+       return data_member;
+    }
+
+  return var_decl_sptr();
+}
+
+/// Find the last data member of a class or union which name matches
+/// a regular expression.
+///
+/// @param t the class or union to consider.
+///
+/// @param r the regular expression to consider.
+///
+/// @return the data member matched by @p r or nil if none was found.
+var_decl_sptr
+find_last_data_member_matching_regexp(const class_or_union& t,
+                                     const regex::regex_t_sptr& regex)
+{
+  auto d = t.get_data_members().rbegin();
+  auto e = t.get_data_members().rend();
+  for (; d != e; ++d)
+    {
+      if (regex::match(regex, (*d)->get_name()))
+       return *d;
+    }
+
+  return var_decl_sptr();
+}
+
 bool
 ir_traversable_base::traverse(ir_node_visitor&)
 {return true;}
index 54d2d917d1c8240af3ad7bb70dc6309151109aad..a79deb3534bfe1e3775a39df3f6a899e8919df21 100644 (file)
@@ -24,6 +24,7 @@ ABG_BEGIN_EXPORT_DECLARATIONS
 #include "abg-suppression.h"
 #include "abg-tools-utils.h"
 #include "abg-fe-iface.h"
+#include "abg-comparison.h"
 
 ABG_END_EXPORT_DECLARATIONS
 // </headers defining libabigail's API>
@@ -36,6 +37,9 @@ namespace abigail
 namespace suppr
 {
 
+// Inject the abigail::comparison namespace in here.
+using namespace comparison;
+
 using std::dynamic_pointer_cast;
 using regex::regex_t_sptr;
 
@@ -1404,32 +1408,56 @@ type_suppression::insertion_range::eval_boundary(const boundary_sptr    boundary,
     {
       ini::function_call_expr_sptr fn_call = b->as_function_call_expr();
       if ((fn_call->get_name() == "offset_of"
-          || fn_call->get_name() == "offset_after")
+          || fn_call->get_name() == "offset_after"
+          || fn_call->get_name() == "offset_of_first_data_member_regexp"
+          || fn_call->get_name() == "offset_of_last_data_member_regexp")
          && fn_call->get_arguments().size() == 1)
        {
-         string member_name = fn_call->get_arguments()[0];
-         for (class_decl::data_members::const_iterator it =
-                context->get_data_members().begin();
-              it != context->get_data_members().end();
-              ++it)
+         if (fn_call->get_name() == "offset_of"
+             || fn_call->get_name() == "offset_after")
            {
-             if (!get_data_member_is_laid_out(**it))
-               continue;
-             if ((*it)->get_name() == member_name)
+             string member_name = fn_call->get_arguments()[0];
+             for (class_decl::data_members::const_iterator it =
+                    context->get_data_members().begin();
+                  it != context->get_data_members().end();
+                  ++it)
                {
-                 if (fn_call->get_name() == "offset_of")
-                   value = get_data_member_offset(*it);
-                 else if (fn_call->get_name() == "offset_after")
+                 if (!get_data_member_is_laid_out(**it))
+                   continue;
+                 if ((*it)->get_name() == member_name)
                    {
-                     if (!get_next_data_member_offset(context, *it, value))
+                     if (fn_call->get_name() == "offset_of")
+                       value = get_data_member_offset(*it);
+                     else if (fn_call->get_name() == "offset_after")
                        {
-                         value = get_data_member_offset(*it) +
-                           (*it)->get_type()->get_size_in_bits();
+                         if (!get_next_data_member_offset(context, *it, value))
+                           {
+                             value = get_data_member_offset(*it) +
+                               (*it)->get_type()->get_size_in_bits();
+                           }
                        }
+                     else
+                       // We should not reach this point.
+                       abort();
+                     return true;
                    }
-                 else
-                   // We should not reach this point.
-                   abort();
+               }
+           }
+         else if (fn_call->get_name() == "offset_of_first_data_member_regexp"
+                  || fn_call->get_name() == "offset_of_last_data_member_regexp")
+           {
+             string name_regexp = fn_call->get_arguments()[0];
+             auto r = regex::compile(name_regexp);
+             var_decl_sptr dm;
+
+             if (fn_call->get_name() == "offset_of_first_data_member_regexp")
+               dm = find_first_data_member_matching_regexp(*context, r);
+             else if (fn_call->get_name() == "offset_of_last_data_member_regexp")
+               dm = find_last_data_member_matching_regexp(*context, r);
+
+             if (dm)
+               {
+                 value = get_data_member_offset(dm);
                  return true;
                }
            }
index a37a364bd293c5bf5811d0f98fed85ffc87028c5..a343759ec58919f7673292a09db8a2d32f81c638 100644 (file)
@@ -1765,6 +1765,21 @@ 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-suppr/test-has-data-member-inserted-between-1-report-1.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt \
+test-diff-suppr/test-has-data-member-inserted-between-1-v0.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v0.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v1.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v1.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v2.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v2.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v3.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v3.o \
+test-diff-suppr/test-has-data-member-inserted-between-1-v4.c \
+test-diff-suppr/test-has-data-member-inserted-between-1-v4.o \
+test-diff-suppr/test-has-data-member-inserted-between-1.suppr \
 \
 test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1 \
 test-diff-dwarf-abixml/test0-pr19026-libvtkIOSQL-6.1.so.1.abi \
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt
new file mode 100644 (file)
index 0000000..fa4b750
--- /dev/null
@@ -0,0 +1,3 @@
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added variable
+
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt
new file mode 100644 (file)
index 0000000..605fb3c
--- /dev/null
@@ -0,0 +1,13 @@
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
+
+1 Changed variable:
+
+  [C] 'S s' was changed at test-has-data-member-inserted-between-1-v2.c:11:1:
+    type of variable changed:
+      type size hasn't changed
+      1 data member insertion:
+        'char data_member_incorrectly_inserted', at offset 32 (in bits) at test-has-data-member-inserted-between-1-v2.c:4:1
+      1 data member change:
+        'char member1' offset changed from 32 to 40 (in bits) (by +8 bits)
+
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt
new file mode 100644 (file)
index 0000000..e87aa12
--- /dev/null
@@ -0,0 +1,12 @@
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
+
+1 Changed variable:
+
+  [C] 'S s' was changed at test-has-data-member-inserted-between-1-v3.c:11:1:
+    size of symbol changed from 20 to 24
+    type of variable changed:
+      type size changed from 160 to 192 (in bits)
+      1 data member insertion:
+        'char data_member_incorrectly_inserted', at offset 160 (in bits) at test-has-data-member-inserted-between-1-v3.c:8:1
+
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt
new file mode 100644 (file)
index 0000000..dccae16
--- /dev/null
@@ -0,0 +1,11 @@
+Functions changes summary: 0 Removed, 0 Changed, 0 Added function
+Variables changes summary: 0 Removed, 1 Changed, 0 Added variable
+
+1 Changed variable:
+
+  [C] 'S s' was changed at test-has-data-member-inserted-between-1-v4.c:10:1:
+    type of variable changed:
+      type size hasn't changed
+      1 data member insertion:
+        'char data_member_incorrectly_inserted', at offset 40 (in bits) at test-has-data-member-inserted-between-1-v4.c:5:1
+
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.c b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.c
new file mode 100644 (file)
index 0000000..ea30911
--- /dev/null
@@ -0,0 +1,10 @@
+struct S
+{
+  int member0;
+  char member1;
+  unsigned __special_padding_space1;
+  unsigned __special_padding_space2;
+  unsigned __special_padding_space3;
+};
+
+struct S s;
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o
new file mode 100644 (file)
index 0000000..f091cba
Binary files /dev/null and b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o differ
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.c b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.c
new file mode 100644 (file)
index 0000000..dfb2370
--- /dev/null
@@ -0,0 +1,10 @@
+struct S
+{
+  int member0;
+  char member1;
+  int correctly_inserted_data_member;
+  unsigned __special_padding_space2;
+  unsigned __special_padding_space3;
+};
+
+struct S s;
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.o b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.o
new file mode 100644 (file)
index 0000000..657d471
Binary files /dev/null and b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.o differ
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.c b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.c
new file mode 100644 (file)
index 0000000..ee7efcb
--- /dev/null
@@ -0,0 +1,11 @@
+struct S
+{
+  int member0;
+  char data_member_incorrectly_inserted;
+  char member1;
+  unsigned __special_padding_space1;
+  unsigned __special_padding_space2;
+  unsigned __special_padding_space3;
+};
+
+struct S s;
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.o b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.o
new file mode 100644 (file)
index 0000000..4e02e07
Binary files /dev/null and b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.o differ
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.c b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.c
new file mode 100644 (file)
index 0000000..314803c
--- /dev/null
@@ -0,0 +1,11 @@
+struct S
+{
+  int member0;
+  char member1;
+  unsigned __special_padding_space1;
+  unsigned __special_padding_space2;
+  unsigned __special_padding_space3;
+  char data_member_incorrectly_inserted;
+};
+
+struct S s;
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.o b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.o
new file mode 100644 (file)
index 0000000..1d6d30f
Binary files /dev/null and b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.o differ
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.c b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.c
new file mode 100644 (file)
index 0000000..1326292
--- /dev/null
@@ -0,0 +1,10 @@
+struct S
+{
+  int member0;
+  char member1;
+  char data_member_incorrectly_inserted;
+  unsigned __special_padding_space1;
+  unsigned __special_padding_space2;
+  unsigned __special_padding_space3;
+};
+struct S s;
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.o b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.o
new file mode 100644 (file)
index 0000000..2ed4bcc
Binary files /dev/null and b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.o differ
diff --git a/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr b/tests/data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr
new file mode 100644 (file)
index 0000000..094d1d6
--- /dev/null
@@ -0,0 +1,7 @@
+[suppress_type]
+  type_kind = struct
+  has_data_member_inserted_between =
+    {
+      offset_of_first_data_member_regexp(^__special_padding_space),
+      offset_of_last_data_member_regexp(^__special_padding_space)
+    }
index a463b34158c078ca868eb379c4061422adfd6cba..11be9b9a49bfe41898b9a1325bedac713dff9abe 100644 (file)
@@ -2206,7 +2206,7 @@ InOutSpec in_out_specs[] =
     "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",
     "",
@@ -2216,6 +2216,46 @@ InOutSpec in_out_specs[] =
     "data/test-diff-suppr/test-has-data-member-output-1.txt",
     "output/test-diff-suppr/test-has-data-member-output-1.4.txt"
   },
+  {
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v1.o",
+    "",
+    "",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt",
+    "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-1.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v2.o",
+    "",
+    "",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt",
+    "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-2.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v3.o",
+    "",
+    "",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt",
+    "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-3.txt"
+  },
+  {
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v0.o",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-v4.o",
+    "",
+    "",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1.suppr",
+    "--drop-private-types --no-default-suppression",
+    "data/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt",
+    "output/test-diff-suppr/test-has-data-member-inserted-between-1-report-4.txt"
+  },
   // This should be the last entry
   {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}
 };