[06/13] comparison, suppression: Support [allow_type] directive

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

Commit Message

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

This patch adds support for a new 'allow_type' suppression directive.
It suppresses all the changes that are NOT matched by the directive.
In other words, this directive determines the set of type changes that
are NOT suppressed.  Any other change is suppressed.  This thus called
a "negated suppression directive".

The way these negated suppression directives interact with the direct
suppression directives that already exist is the following.

The suppression evaluation pass visits every single diff node
(carrying a type change) of the diff graph.  Negated suppressions are
evaluated first, in order of occurrence.

There are thus, two alternatives:

    1/ At least one negated suppression matches the current diff node.
or
    2/ No negated suppression matches the current diff node.

In case of 1/ then direct suppression specifications are
considered. There are two alternatives:

    1.1/ At least one direct suppression matches the current diff node.
         The diff node is suppressed: categorized as being in the
         SUPPRESSED_CATEGORY category)
or
    1.2/ No direct suppression matches the current diff node.
         The diff node is not suppressed: categorized as being in the
         HAS_ALLOWED_CHANGE_CATEGORY category.

In case of 2/ then direct suppression specifications are
considered. There are two alternatives:

    2.1 At least one direct suppression matches the current diff node.
	The diff node is categorized as being in the
	SUPPRESSED_CATEGORY category, just like in 1.1.

    2.2 No direct suppression matches the current diff node.
	The diff node is not suppressed and not categorized.

As a result of the category propagation pass, a node which has a
parent node categorized as HAS_ALLOWED_CHANGE_CATEGORY is itself
categorized as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.  A node which
has a descendant categorized as HAS_ALLOWED_CHANGE_CATEGORY will
itself be categorized as HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.

Nodes that are categorized as HAS_ALLOWED_CHANGE_CATEGORY,
HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY and
HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY are not suppressed by the
reporting passes.  This is needed for the reporting passes to emit the
impact sub-tree up to the diff node which carry the change that was
actually categorized as HAS_ALLOWED_CHANGE_CATEGORY.

	* include/abg-comparison.h: Include abg-suppression.h
	(diff, diff_context, diff_sptr, diff_context_sptr): Remove these
	forward decls from here.
	(enum diff_category::{HAS_ALLOWED_CHANGE_CATEGORY,
	HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY,
	HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY}): Add new enumerators.
	(enum diff_category::EVERYTHING_CATEGORY): Update enumerator.
	(diff_context::{negated_suppressions, direct_suppressions}): Declare
	new member functions.
	(diff_context::suppressions): Add overload.
	(diff::{is_filtered_out_without_looking_at_allowed_changes,
	is_allowed_by_specific_negated_suppression,
	has_descendant_allowed_by_specific_negated_suppression,
	has_parent_allowed_by_specific_negated_suppression}): Declare new
	member functions.
	* include/abg-suppression.h (class negated_suppression_base, class
	negated_type_suppression): Declare new classes.
	(negated_suppression_sptr, negated_suppression_type): Define new
	typedefs.
	(is_negated_suppression): Declare new functions.
	* src/abg-suppression.cc
	(negated_suppression_base::{negated_suppression_base,
	~negated_suppression_base}): Define member functions.
	(negated_type_suppression::{negated_type_suppression,
	suppresses_diff, ~negated_type_suppression}): Likewise.
	(is_negated_suppression): Define functions.
	(read_type_suppression): Allow parsing the "allow_type" directive
	and instantiate a negated_type_suppression.
	* src/abg-comparison-priv.h
	(diff_context::priv::{negated_suppression_type_,
	direct_suppressions}): Define new data members.
	(diff::priv::is_filtered_out): A node categorized as
	HAS_DESCENDANT_ALLOWED_BY_SPECIFIC_NEGATED_SUPPRESSION,
	HAS_PARENT_ALLOWED_BY_SPECIFIC_NEGATED_SUPPRESSION and
	HAS_ALLOWED_CHANGE_CATEGORY is not filtered out.
	* src/abg-comparison.cc (diff_context::suppressions): Add a
	non-const overload.
	(diff_context::{negated,direct}_suppressions): Define new member
	function.
	(diff_context::add_suppression): Invalidate the cache data members
	diff_context::priv::{negated,direct}_suppressions_.
	(diff::is_filtered_out): A node categorized as
	HAS_DESCENDANT_ALLOWED_BY_SPECIFIC_NEGATED_SUPPRESSION,
	HAS_PARENT_ALLOWED_BY_SPECIFIC_NEGATED_SUPPRESSION and
	HAS_ALLOWED_CHANGE_CATEGORY is not filtered out.
	(diff::is_filtered_out_without_looking_at_allowed_changes): Define
	new member function.
	(diff::is_suppressed): If there is at least one negated
	suppression that match the diff node, then it's not suppressed,
	unless it's matched by a direct suppression.
	(diff::{is_allowed_by_specific_negated_suppression,
	has_descendant_allowed_by_specific_negated_suppression,
	has_parent_allowed_by_specific_negated_suppression}): Define new
	member functions.
	(operator<<(ostream& o, diff_category c)): Serialize
	HAS_{DESCENDANT_WITH,PARENT_WITH}_ALLOWED_CHANGE_CATEGORY
	enumerators.
	(category_propagation_visitor::visit_end): Do not propagate
	HAS_ALLOWED_CHANGE_CATEGORY,
	HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY and
	HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY categories.
	(suppression_categorization_visitor::visit_begin): Categorize a
	node that is not suppressed by a direct suppression and is
	suppressed by a negated one as
	HAS_ALLOWED_CHANGE_CATEGORY. Propagate it to descendant nodes as
	HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY ...
	(suppression_categorization_visitor::visit_end): ... and to parent
	node as HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
	* src/abg-default-reporter.cc (default::reporter): In the overload
	for typedef_diff, qualified_type_diff, reference_diff,
	fn_parm_diff, function_type_diff, array_diff, base_diff,
	function_decl_diff, report local changes only
	on node that are not filtered out wrt allowed changed.
	* tests/data/test-abidiff-exit/test-allow-type-array-suppr.txt:
	New test input.
	* tests/data/test-abidiff-exit/test-allow-type-array-v0--v1-report-{1,2}.txt:
	Likewise.
	* tests/data/test-abidiff-exit/test-allow-type-array-v0--v2-report-{1,2}.txt:
	Likewise.
	* tests/data/test-abidiff-exit/test-allow-type-array-v0--v3-report-{1,2}.txt:
	Likewise.
	* tests/data/test-abidiff-exit/test-allow-type-array-v{0,1,2,3}.c:
	Source code of new binary test inputs.
	* tests/data/test-abidiff-exit/test-allow-type-array-v{0,1,2,3}.o:
	New binary test inputs.
	* tests/data/test-abidiff-exit/test-allow-type-region-suppr.txt:
	New test input.
	* tests/data/test-abidiff-exit/test-allow-type-region-v0--v1-report-{1,2}.txt:
	* tests/data/test-abidiff-exit/test-allow-type-region-v0--v2-report-{1,2}.txt:
	Likewise.
	* tests/data/test-abidiff-exit/test-allow-type-region-v0--v3-report-{1,2}.txt:
	Likewise.
	* tests/data/test-abidiff-exit/test-allow-type-region-v0--v4-report-{1,2}.txt:
	Likewise.
	* tests/data/test-abidiff-exit/test-allow-type-region-v0--v5-report-{1,2}.txt:
	Likewise.
	* tests/data/test-abidiff-exit/test-allow-type-region-v{0,1,2,3,4,5}.c:
	Source code of new binary test input.
	* tests/data/test-abidiff-exit/test-allow-type-region-v{0,1,2,3,4,5}.o:
	New binary test inputs.
	* tests/data/test-abidiff-exit/test-allow-type-suppr{1,2}.txt: New
	test inputs.
	* tests/data/Makefile.am: Add the new testing files above to
	source distribution.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
---
 include/abg-comparison.h                      |  62 +++-
 include/abg-suppression.h                     |  69 +++-
 src/abg-comparison-priv.h                     |  17 +
 src/abg-comparison.cc                         | 289 +++++++++++++--
 src/abg-default-reporter.cc                   | 348 +++++++++---------
 src/abg-suppression.cc                        | 116 +++++-
 tests/data/Makefile.am                        |  40 ++
 .../test-allow-type-array-suppr.txt           |   7 +
 .../test-allow-type-array-v0--v1-report-1.txt |  23 ++
 .../test-allow-type-array-v0--v1-report-2.txt |   3 +
 .../test-allow-type-array-v0--v2-report-1.txt |  20 +
 .../test-allow-type-array-v0--v2-report-2.txt |  15 +
 .../test-allow-type-array-v0--v3-report-1.txt |  23 ++
 .../test-allow-type-array-v0--v3-report-2.txt |   3 +
 .../test-allow-type-array-v0.c                |  18 +
 .../test-allow-type-array-v0.o                | Bin 0 -> 3392 bytes
 .../test-allow-type-array-v1.c                |  20 +
 .../test-allow-type-array-v1.o                | Bin 0 -> 3448 bytes
 .../test-allow-type-array-v2.c                |  20 +
 .../test-allow-type-array-v2.o                | Bin 0 -> 3456 bytes
 .../test-allow-type-array-v3.c                |  20 +
 .../test-allow-type-array-v3.o                | Bin 0 -> 3456 bytes
 .../test-allow-type-region-suppr.txt          |  11 +
 ...test-allow-type-region-v0--v1-report-1.txt |  20 +
 ...test-allow-type-region-v0--v1-report-2.txt |   3 +
 ...test-allow-type-region-v0--v2-report-1.txt |  21 ++
 ...test-allow-type-region-v0--v2-report-2.txt |  16 +
 ...test-allow-type-region-v0--v3-report-1.txt |  23 ++
 ...test-allow-type-region-v0--v3-report-2.txt |  18 +
 ...test-allow-type-region-v0--v4-report-1.txt |  28 ++
 ...test-allow-type-region-v0--v4-report-2.txt |   3 +
 ...test-allow-type-region-v0--v5-report-1.txt |  30 ++
 ...test-allow-type-region-v0--v5-report-2.txt |  25 ++
 .../test-allow-type-region-v0.c               |  22 ++
 .../test-allow-type-region-v0.o               | Bin 0 -> 3576 bytes
 .../test-allow-type-region-v1.c               |  23 ++
 .../test-allow-type-region-v1.o               | Bin 0 -> 3632 bytes
 .../test-allow-type-region-v2.c               |  23 ++
 .../test-allow-type-region-v2.o               | Bin 0 -> 3632 bytes
 .../test-allow-type-region-v3.c               |  24 ++
 .../test-allow-type-region-v3.o               | Bin 0 -> 3688 bytes
 .../test-allow-type-region-v4.c               |  23 ++
 .../test-allow-type-region-v4.o               | Bin 0 -> 3640 bytes
 .../test-allow-type-region-v5.c               |  24 ++
 .../test-allow-type-region-v5.o               | Bin 0 -> 3696 bytes
 .../test-allow-type-suppr1.txt                |   7 +
 .../test-allow-type-suppr2.txt                |   7 +
 tests/test-abidiff-exit.cc                    | 187 ++++++++++
 48 files changed, 1442 insertions(+), 209 deletions(-)
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-suppr.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v0--v1-report-1.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v0--v1-report-2.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v0--v2-report-1.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v0--v2-report-2.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v0--v3-report-1.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v0--v3-report-2.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v0.c
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v0.o
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v1.c
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v1.o
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v2.c
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v2.o
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v3.c
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-array-v3.o
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-suppr.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0--v1-report-1.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0--v1-report-2.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0--v2-report-1.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0--v2-report-2.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0--v3-report-1.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0--v3-report-2.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0--v4-report-1.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0--v4-report-2.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0--v5-report-1.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0--v5-report-2.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0.c
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v0.o
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v1.c
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v1.o
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v2.c
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v2.o
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v3.c
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v3.o
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v4.c
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v4.o
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v5.c
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-region-v5.o
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-suppr1.txt
 create mode 100644 tests/data/test-abidiff-exit/test-allow-type-suppr2.txt

new file mode 100644
index 00000000..648f835a
new file mode 100644
index 00000000..2024aa8e
new file mode 100644
index 00000000..e8111f69
new file mode 100644
index 00000000..0706c4d6
new file mode 100644
index 00000000..09c1ec8d
new file mode 100644
index 00000000..e95b3115
new file mode 100644
index 00000000..a7a638cc
new file mode 100644
index 00000000..bcb26e95
new file mode 100644
index 00000000..a3a33698
new file mode 100644
index 00000000..18725f37
  

Patch

diff --git a/include/abg-comparison.h b/include/abg-comparison.h
index 440080a5..839478bf 100644
--- a/include/abg-comparison.h
+++ b/include/abg-comparison.h
@@ -17,6 +17,7 @@ 
 #include "abg-corpus.h"
 #include "abg-diff-utils.h"
 #include "abg-reporter.h"
+#include "abg-suppression.h"
 
 namespace abigail
 {
@@ -46,14 +47,6 @@  using diff_utils::insertion;
 using diff_utils::deletion;
 using diff_utils::edit_script;
 
-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;
-
 /// Hasher for @ref diff_sptr.
 struct diff_sptr_hasher
 {
@@ -261,14 +254,6 @@  typedef unordered_map<string, elf_symbol_sptr> string_elf_symbol_map;
 /// value is a @ref var_diff_sptr.
 typedef unordered_map<string, var_diff_sptr> string_var_diff_ptr_map;
 
-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_node_visitor;
 
 class diff_traversable_base;
@@ -438,6 +423,25 @@  enum diff_category
   /// variable didn't change.
   BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY = 1 << 21,
 
+  /// A diff node in this category carries a change that must be
+  /// reported, even if the diff node is also in the
+  /// SUPPRESSED_CATEGORY or PRIVATE_TYPE_CATEGORY categories.
+  /// Typically, this node matches a suppression specification like
+  /// the [allow_type] directive.
+  HAS_ALLOWED_CHANGE_CATEGORY = 1 << 22,
+
+  /// A diff node in this category has a descendant node that is in
+  /// the HAS_ALLOWED_CHANGE_CATEGORY category.  Nodes in this
+  /// category must be reported, even if they are also in the
+  /// SUPPRESSED_CATEGORY or PRIVATE_TYPE_CATEGORY categories.
+  HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY = 1 << 23,
+
+  /// A diff node in this category has a parent node that is in the
+  /// HAS_ALLOWED_CHANGE_CATEGORY category.  Nodes in this category
+  /// must be reported, even if they are also in the
+  /// SUPPRESSED_CATEGORY or PRIVATE_TYPE_CATEGORY categories.
+  HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY = 1 << 24,
+
   /// A special enumerator that is the logical 'or' all the
   /// enumerators above.
   ///
@@ -466,6 +470,9 @@  enum diff_category
   | VAR_TYPE_CV_CHANGE_CATEGORY
   | VOID_PTR_TO_PTR_CHANGE_CATEGORY
   | BENIGN_INFINITE_ARRAY_CHANGE_CATEGORY
+  | HAS_ALLOWED_CHANGE_CATEGORY
+  | HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
+  | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
 }; // enum diff_category
 
 diff_category
@@ -730,9 +737,18 @@  public:
   void
   maybe_apply_filters(corpus_diff_sptr diff);
 
-  suppr::suppressions_type&
+  const suppr::suppressions_type&
   suppressions() const;
 
+  suppr::suppressions_type&
+  suppressions();
+
+  const suppr::suppressions_type&
+  negated_suppressions() const;
+
+  const suppr::suppressions_type&
+  direct_suppressions() const;
+
   void
   add_suppression(const suppr::suppression_sptr suppr);
 
@@ -1037,6 +1053,9 @@  public:
   bool
   is_filtered_out_wrt_non_inherited_categories() const;
 
+  bool
+  is_filtered_out_without_looking_at_allowed_changes() const;
+
   bool
   is_suppressed() const;
 
@@ -1049,6 +1068,15 @@  public:
   bool
   has_local_changes_to_be_reported() const;
 
+  bool
+  is_allowed_by_specific_negated_suppression() const;
+
+  bool
+  has_descendant_allowed_by_specific_negated_suppression() const;
+
+  bool
+  has_parent_allowed_by_specific_negated_suppression() const;
+
   virtual const string&
   get_pretty_representation() const;
 
diff --git a/include/abg-suppression.h b/include/abg-suppression.h
index bfc37a40..05b0e8b4 100644
--- a/include/abg-suppression.h
+++ b/include/abg-suppression.h
@@ -36,11 +36,17 @@  using std::vector;
 using comparison::diff;
 using comparison::diff_context_sptr;
 
-/// Base type of the suppression specifications types.
+/// Base type of a direct suppression specifications types.
 ///
 /// This abstracts a suppression specification.  It's a way to specify
 /// how to drop reports about a particular diff node on the floor, if
 /// it matches the supppression specification.
+///
+/// Note that a direct suppression specification suppresses (for
+/// reporting purposes) the diff node that it matches.  A negated
+/// suppression specification, however, suppresses a diff node that it
+/// DOES NOT match.  A Negated suppression specification is abstracted
+/// by the class @ref negated_suppression_base.
 class suppression_base
 {
 public:
@@ -143,6 +149,36 @@  typedef shared_ptr<type_suppression> type_suppression_sptr;
 /// Convenience typedef for vector of @ref type_suppression_sptr.
 typedef vector<type_suppression_sptr> type_suppressions_type;
 
+/// The base class of suppression specifications that are defined by
+/// the negation of matching clauses.
+///
+/// A direct suppression specification suppresses (for reporting
+/// purposes) the diff node that it matches.  A negated suppression
+/// specification suppresses a diff node that it DOES NOT match.
+class negated_suppression_base
+{
+public:
+  negated_suppression_base();
+
+  virtual ~negated_suppression_base();
+}; // end class negated_suppression_base.
+
+/// A convenience typedef for a shared pointer to @ref
+/// negated_suppression_base.
+typedef shared_ptr<negated_suppression_base> negated_suppression_sptr;
+
+/// Convenience typedef for a vector of @ref negated_suppression_sptr
+typedef vector<negated_suppression_sptr> negated_suppressions_type;
+
+bool
+is_negated_suppression(const suppression_base&);
+
+const negated_suppression_base*
+is_negated_suppression(const suppression_base*);
+
+negated_suppression_sptr
+is_negated_suppression(const suppression_sptr&);
+
 /// Abstraction of a type suppression specification.
 ///
 /// Specifies under which condition reports about a type diff node
@@ -416,6 +452,37 @@  public:
   ~fn_call_expr_boundary();
 }; //end class type_suppression::insertion_range::fn_call_expr_boundary
 
+/// Abstraction of a negated type suppression specification.
+///
+/// A negated type suppression suppresses a type if the negation of
+/// the equivalent propositions for a @ref type_suppression are valid.
+class negated_type_suppression : virtual public type_suppression,
+				 virtual public negated_suppression_base
+{
+
+public:
+
+  negated_type_suppression(const string& label,
+			   const string& type_name_regexp,
+			   const string& type_name);
+
+  virtual bool
+  suppresses_diff(const diff* diff) const;
+
+  bool
+  suppresses_type(const type_base_sptr& type,
+		  const diff_context_sptr& ctxt) const;
+
+  bool
+  suppresses_type(const type_base_sptr& type) const;
+
+  bool
+  suppresses_type(const type_base_sptr& type,
+		  const scope_decl* type_scope) const;
+
+  virtual ~negated_type_suppression();
+};// end class negated_type_suppression
+
 class function_suppression;
 
 /// Convenience typedef for a shared pointer to function_suppression.
diff --git a/src/abg-comparison-priv.h b/src/abg-comparison-priv.h
index 46438e94..fb843665 100644
--- a/src/abg-comparison-priv.h
+++ b/src/abg-comparison-priv.h
@@ -174,7 +174,17 @@  struct diff_context::priv
   unordered_diff_sptr_set		live_diffs_;
   vector<diff_sptr>			canonical_diffs;
   vector<filtering::filter_base_sptr>	filters_;
+  // All the suppressions specifications are stored in this data
+  // member.
   suppressions_type			suppressions_;
+  // The negated suppressions specifications that are in
+  // suppressions_ are stored here.  Each time suppressions_ is
+  // modified, this data member should be cleared.
+  suppressions_type			negated_suppressions_;
+  // The non-negated suppressions specifications that are in
+  // suppressions_ are stored here.  Each time suppressions_ is
+  // modified, this data member should be cleared.
+  suppressions_type			direct_suppressions_;
   pointer_map				visited_diff_nodes_;
   corpus_diff_sptr			corpus_diff_;
   ostream*				default_output_stream_;
@@ -304,6 +314,13 @@  public:
     if (ctxt->get_allowed_category() == EVERYTHING_CATEGORY)
       return false;
 
+    // If this node is on the path of a node that *must* be reported,
+    // then do not filter it.
+    if (category & (HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
+		    | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
+		    | HAS_ALLOWED_CHANGE_CATEGORY))
+      return false;
+
   /// We don't want to display nodes suppressed by a user-provided
   /// suppression specification or by a "private type" suppression
   /// specification.
diff --git a/src/abg-comparison.cc b/src/abg-comparison.cc
index 969c32d8..609c5bf2 100644
--- a/src/abg-comparison.cc
+++ b/src/abg-comparison.cc
@@ -1399,10 +1399,72 @@  diff_context::maybe_apply_filters(corpus_diff_sptr diff)
 /// reports should be dropped on the floor.
 ///
 /// @return the set of suppressions.
-suppressions_type&
+const suppressions_type&
 diff_context::suppressions() const
 {return priv_->suppressions_;}
 
+/// Getter for the vector of suppressions that specify which diff node
+/// reports should be dropped on the floor.
+///
+/// @return the set of suppressions.
+suppr::suppressions_type&
+diff_context::suppressions()
+{
+  // Invalidate negated and direct suppressions caches that are built
+  // from priv_->suppressions_;
+  priv_->negated_suppressions_.clear();
+  priv_->direct_suppressions_.clear();
+  return priv_->suppressions_;
+}
+
+/// Getter of the negated suppression specifications that are
+/// comprised in the general vector of suppression specifications
+/// returned by diff_context::suppressions().
+///
+/// Note that the first invocation of this function scans the vector
+/// returned by diff_context::suppressions() and caches the negated
+/// suppressions from there.
+///
+/// Subsequent invocations of this function just return the cached
+/// negated suppressions.
+///
+/// @return the negated suppression specifications stored in this diff
+/// context.
+const suppr::suppressions_type&
+diff_context::negated_suppressions() const
+{
+  if (priv_->negated_suppressions_.empty())
+    for (auto s : suppressions())
+      if (is_negated_suppression(s))
+	priv_->negated_suppressions_.push_back(s);
+
+  return priv_->negated_suppressions_;
+}
+
+/// Getter of the direct suppression specification (those that are
+/// not negated) comprised in the general vector of suppression
+/// specifications returned by diff_context::suppression().
+///
+/// Note that the first invocation of this function scans the vector
+/// returned by diff_context::suppressions() and caches the direct
+/// suppressions from there.
+///
+/// Subsequent invocations of this function just return the cached
+/// direct suppressions.
+///
+/// @return the direct suppression specifications.
+const suppr::suppressions_type&
+diff_context::direct_suppressions() const
+{
+   if (priv_->direct_suppressions_.empty())
+    {
+      for (auto s : suppressions())
+	if (!is_negated_suppression(s))
+	  priv_->direct_suppressions_.push_back(s);
+    }
+   return priv_->direct_suppressions_;
+}
+
 /// Add a new suppression specification that specifies which diff node
 /// reports should be dropped on the floor.
 ///
@@ -1410,7 +1472,13 @@  diff_context::suppressions() const
 /// existing set of suppressions specifications of the diff context.
 void
 diff_context::add_suppression(const suppression_sptr suppr)
-{priv_->suppressions_.push_back(suppr);}
+{
+  priv_->suppressions_.push_back(suppr);
+  // Invalidate negated and direct suppressions caches that are built
+  // from priv_->suppressions_;
+  priv_->negated_suppressions_.clear();
+  priv_->direct_suppressions_.clear();
+}
 
 /// Add new suppression specifications that specify which diff node
 /// reports should be dropped on the floor.
@@ -2313,6 +2381,16 @@  diff::set_local_category(diff_category c)
 /// Test if this diff tree node is to be filtered out for reporting
 /// purposes.
 ///
+/// There is a difference between a diff node being filtered out and
+/// being suppressed.  Being suppressed means that there is a
+/// suppression specification that suppresses the diff node
+/// specifically.  Being filtered out mean the node is either
+/// suppressed, or it's filtered out because the suppression of a set
+/// of (children) nodes caused this node to be filtered out as well.
+/// For instance, if a function diff has all its children diff nodes
+/// suppressed and if the function diff node carries no local change,
+/// then the function diff node itself is going to be filtered out.
+///
 /// The function tests if the categories of the diff tree node are
 /// "forbidden" by the context or not.
 ///
@@ -2321,13 +2399,16 @@  bool
 diff::is_filtered_out() const
 {
   if (diff * canonical = get_canonical_diff())
-    if (canonical->get_category() & SUPPRESSED_CATEGORY
-	|| canonical->get_category() & PRIVATE_TYPE_CATEGORY)
+    if ((canonical->get_category() & SUPPRESSED_CATEGORY
+	 || canonical->get_category() & PRIVATE_TYPE_CATEGORY)
+	&& !canonical->is_allowed_by_specific_negated_suppression()
+	&& !canonical->has_descendant_allowed_by_specific_negated_suppression()
+	&& !canonical->has_parent_allowed_by_specific_negated_suppression())
       // The canonical type was suppressed either by a user-provided
       // suppression specification or by a "private-type" suppression
-      // specification..  This means all the class of equivalence of
-      // that canonical type was suppressed.  So this node should be
-      // suppressed too.
+      // specification..  This means all the classes of equivalence of
+      // that canonical type were suppressed.  So this node should be
+      // filtered out.
       return true;
   return priv_->is_filtered_out(get_category());
 }
@@ -2345,6 +2426,27 @@  bool
 diff::is_filtered_out_wrt_non_inherited_categories() const
 {return priv_->is_filtered_out(get_local_category());}
 
+/// Test if this diff tree node is to be filtered out for reporting
+/// purposes, but without considering the categories that can /force/
+/// the node to be unfiltered.
+///
+/// The function tests if the categories of the diff tree node are
+/// "forbidden" by the context or not.
+///
+/// @return true iff the current diff node should should NOT be
+/// reported, with respect to the categories that might filter it out
+/// only.
+bool
+diff::is_filtered_out_without_looking_at_allowed_changes() const
+{
+  diff_category c = get_category();
+  c &= ~(HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
+	 | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY
+	 | HAS_ALLOWED_CHANGE_CATEGORY);
+
+    return priv_->is_filtered_out(c);
+}
+
 /// Test if the current diff node has been suppressed by a
 /// user-provided suppression specification.
 ///
@@ -2364,6 +2466,13 @@  diff::is_suppressed() const
 /// Note that private type suppressions are auto-generated from the
 /// path to where public headers are, as given by the user.
 ///
+/// Here is the current algorithm:
+///
+///         First, suppress this diff node if it's not matched by any
+///         negated suppression specifications.  If it's not
+///         suppressed, then suppress it if it's matched by direct
+///         suppression specifications.
+///
 /// @param is_private_type out parameter if the current diff node was
 /// suppressed because it's a private type then this parameter is set
 /// to true.
@@ -2373,19 +2482,32 @@  diff::is_suppressed() const
 bool
 diff::is_suppressed(bool &is_private_type) const
 {
-  const suppressions_type& suppressions = context()->suppressions();
-  for (suppressions_type::const_iterator i = suppressions.begin();
-       i != suppressions.end();
-       ++i)
-    {
-      if ((*i)->suppresses_diff(this))
-	{
-	  if (is_private_type_suppr_spec(*i))
-	    is_private_type = true;
-	  return true;
-	}
-    }
-  return false;
+  // If there is at least one negated suppression, then suppress the
+  // current diff node by default ...
+  bool do_suppress = !context()->negated_suppressions().empty();
+
+  // ... unless there is at least one negated suppression that
+  // specifically asks to keep this diff node around (un-suppressed).
+  for (auto n : context()->negated_suppressions())
+    if (!n->suppresses_diff(this))
+      {
+	do_suppress = false;
+	break;
+      }
+
+  // Then walk the set of non-negated, AKA direct, suppressions.  If at
+  // least one suppression suppresses the current diff node then the
+  // diff node must be suppressed.
+  for (auto d : context()->direct_suppressions())
+    if (d->suppresses_diff(this))
+      {
+	do_suppress = true;
+	if (is_private_type_suppr_spec(d))
+	  is_private_type = true;
+	break;
+      }
+
+  return do_suppress;
 }
 
 /// Test if this diff tree node should be reported.
@@ -2412,6 +2534,51 @@  diff::has_local_changes_to_be_reported() const
   return false;
 }
 
+/// Test if this diff node is allowed (prevented from being
+/// suppressed) by at least one negated suppression specification.
+///
+/// @return true if this diff node is meant to be allowed by at least
+/// one negated suppression specification.
+bool
+diff::is_allowed_by_specific_negated_suppression() const
+{
+  const suppressions_type& suppressions = context()->suppressions();
+  for (suppressions_type::const_iterator i = suppressions.begin();
+       i != suppressions.end();
+       ++i)
+    {
+      if (is_negated_suppression(*i)
+	  && !(*i)->suppresses_diff(this))
+	return true;
+    }
+  return false;
+}
+
+/// Test if the current diff node has a descendant node which is
+/// specifically allowed by a negated suppression specification.
+///
+/// @return true iff the current diff node has a descendant node
+/// which is specifically allowed by a negated suppression
+/// specification.
+bool
+diff::has_descendant_allowed_by_specific_negated_suppression() const
+{
+  bool result = (get_category() & HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY);
+  return result;
+}
+
+/// Test if the current diff node has a parent node which is
+/// specifically allowed by a negated suppression specification.
+///
+/// @return true iff the current diff node has a parent node which is
+/// specifically allowed by a negated suppression specification.
+bool
+diff::has_parent_allowed_by_specific_negated_suppression() const
+{
+  bool result = (get_category() & HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
+  return result;
+}
+
 /// Get a pretty representation of the current @ref diff node.
 ///
 /// This is suitable for e.g. emitting debugging traces for the diff
@@ -3075,6 +3242,30 @@  operator<<(ostream& o, diff_category c)
       emitted_a_category |= true;
     }
 
+  if (c & HAS_ALLOWED_CHANGE_CATEGORY)
+    {
+      if (emitted_a_category)
+	o << "|";
+      o << "HAS_ALLOWED_CHANGE_CATEGORY";
+      emitted_a_category |= true;
+    }
+
+  if (c & HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY)
+    {
+      if (emitted_a_category)
+	o << "|";
+      o << "HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY";
+      emitted_a_category |= true;
+    }
+
+    if (c & HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY)
+    {
+      if (emitted_a_category)
+	o << "|";
+      o << "HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY";
+      emitted_a_category |= true;
+    }
+
   return o;
 }
 
@@ -11385,7 +11576,10 @@  struct category_propagation_visitor : public diff_node_visitor
 	// are propagated in a specific pass elsewhere.
 	c &= ~(REDUNDANT_CATEGORY
 	       | SUPPRESSED_CATEGORY
-	       | PRIVATE_TYPE_CATEGORY);
+	       | PRIVATE_TYPE_CATEGORY
+	       | HAS_ALLOWED_CHANGE_CATEGORY
+	       | HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY
+	       | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
 	// Also, if a (class) type has got a harmful name change, do not
 	// propagate harmless name changes coming from its sub-types
 	// (i.e, data members) to the class itself.
@@ -11481,6 +11675,40 @@  struct suppression_categorization_visitor : public diff_node_visitor
 	if (canonical_diff != d)
 	  canonical_diff->add_to_category(c);
       }
+    else if (d->is_allowed_by_specific_negated_suppression())
+      {
+	// This diff node is specifically allowed by a
+	// negated_suppression, then mark it as being in the
+	// HAS_ALLOWED_CHANGE_CATEGORY.
+	diff_category c = HAS_ALLOWED_CHANGE_CATEGORY;
+	d->add_to_local_category(c);
+	diff *canonical_diff = d->get_canonical_diff();
+	canonical_diff->add_to_category(c);
+
+	// Note that some complementary code later down below does
+	// categorize the descendants and parents nodes of this node
+	// as HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY and
+	// HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY, repectively.
+      }
+
+    // If a parent node has been allowed by a negated suppression
+    // specification, then categorize the current node as
+    // HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY.
+    if (d->parent_node())
+      {
+	diff_category c = d->parent_node()->get_local_category();
+	if (c & (HAS_ALLOWED_CHANGE_CATEGORY
+		 | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY))
+	  d->add_to_category(HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
+	else
+	  {
+	    c = d->parent_node()->get_category();
+	    if (c & (HAS_ALLOWED_CHANGE_CATEGORY
+		     | HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY))
+	      d->add_to_category(HAS_PARENT_WITH_ALLOWED_CHANGE_CATEGORY);
+	  }
+      }
+
   }
 
   /// After visiting the children nodes of a given diff node,
@@ -11505,6 +11733,7 @@  struct suppression_categorization_visitor : public diff_node_visitor
     bool has_suppressed_child = false;
     bool has_non_private_child = false;
     bool has_private_child = false;
+    bool has_descendant_with_allowed_change = false;
 
     if (// A node to which we can propagate the "SUPPRESSED_CATEGORY"
 	// (or the PRIVATE_TYPE_CATEGORY for the same matter)
@@ -11670,6 +11899,24 @@  struct suppression_categorization_visitor : public diff_node_visitor
 		  }
 	  }
       }
+
+    // If any descendant node was selected by a negated suppression
+    // specification then categorize the current one as
+    // HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY.
+    for (auto child_node : d->children_nodes())
+      {
+	diff *canonical_diff = child_node->get_canonical_diff();
+	diff_category c = canonical_diff->get_category();
+	if (c & (HAS_ALLOWED_CHANGE_CATEGORY
+		 | HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY))
+	  has_descendant_with_allowed_change = true;
+      }
+    if (has_descendant_with_allowed_change)
+      {
+	diff_category c = HAS_DESCENDANT_WITH_ALLOWED_CHANGE_CATEGORY;
+	d->add_to_category(c);
+	d->get_canonical_diff()->add_to_category(c);
+      }
   }
 }; //end struct suppression_categorization_visitor
 
diff --git a/src/abg-default-reporter.cc b/src/abg-default-reporter.cc
index 0c7d3e1d..243ddbfb 100644
--- a/src/abg-default-reporter.cc
+++ b/src/abg-default-reporter.cc
@@ -272,7 +272,8 @@  default_reporter::report(const typedef_diff& d,
 
   typedef_decl_sptr f = d.first_typedef_decl(), s = d.second_typedef_decl();
 
-  report_non_type_typedef_changes(d, out, indent);
+  if (!d.is_filtered_out_without_looking_at_allowed_changes())
+    report_non_type_typedef_changes(d, out, indent);
 
   diff_sptr dif = d.underlying_type_diff();
   if (dif && dif->has_changes())
@@ -364,11 +365,12 @@  default_reporter::report(const qualified_type_diff& d, ostream& out,
   RETURN_IF_BEING_REPORTED_OR_WAS_REPORTED_EARLIER(d.first_qualified_type(),
 						   d.second_qualified_type());
 
-  if (report_local_qualified_type_changes(d, out, indent))
-    // The local change was emitted and it's a name change.  If the
-    // type name changed, the it means the type changed altogether.
-    // It makes a little sense to detail the changes in extenso here.
-    return;
+  if (!d.is_filtered_out_without_looking_at_allowed_changes())
+    if (report_local_qualified_type_changes(d, out, indent))
+      // The local change was emitted and it's a name change.  If the
+      // type name changed, the it means the type changed altogether.
+      // It makes a little sense to detail the changes in extenso here.
+      return;
 
   diff_sptr dif = d.leaf_underlying_type_diff();
   ABG_ASSERT(dif);
@@ -474,8 +476,9 @@  default_reporter::report(const reference_diff& d, ostream& out,
   enum change_kind k = ir::NO_CHANGE_KIND;
   equals(*d.first_reference(), *d.second_reference(), &k);
 
-  if ((k & ALL_LOCAL_CHANGES_MASK) && !(k & SUBTYPE_CHANGE_KIND))
-    report_local_reference_type_changes(d, out, indent);
+  if (!d.is_filtered_out_without_looking_at_allowed_changes())
+    if ((k & ALL_LOCAL_CHANGES_MASK) && !(k & SUBTYPE_CHANGE_KIND))
+      report_local_reference_type_changes(d, out, indent);
 
   if (k & SUBTYPE_CHANGE_KIND)
     if (diff_sptr dif = d.underlying_type_diff())
@@ -503,6 +506,9 @@  void
 default_reporter::report(const fn_parm_diff& d, ostream& out,
 			 const string& indent) const
 {
+  if (!d.to_be_reported())
+    return;
+
   function_decl::parameter_sptr f = d.first_parameter(),
     s = d.second_parameter();
 
@@ -514,26 +520,23 @@  default_reporter::report(const fn_parm_diff& d, ostream& out,
     type_has_sub_type_changes(d.first_parameter()->get_type(),
 			      d.second_parameter()->get_type());
 
-  if (d.to_be_reported())
-    {
-      diff_sptr type_diff = d.type_diff();
-      ABG_ASSERT(type_diff->has_changes());
+  diff_sptr type_diff = d.type_diff();
+  ABG_ASSERT(type_diff->has_changes());
 
-      out << indent;
-      if (f->get_is_artificial())
-	out << "implicit ";
-      out << "parameter " << f->get_index();
-      report_loc_info(f, *d.context(), out);
-      out << " of type '"
-	  << f->get_type_pretty_representation();
-
-      if (has_sub_type_change)
-	out << "' has sub-type changes:\n";
-      else
-	out << "' changed:\n";
+  out << indent;
+  if (f->get_is_artificial())
+    out << "implicit ";
+  out << "parameter " << f->get_index();
+  report_loc_info(f, *d.context(), out);
+  out << " of type '"
+      << f->get_type_pretty_representation();
 
-      type_diff->report(out, indent + "  ");
-    }
+  if (has_sub_type_change)
+    out << "' has sub-type changes:\n";
+  else
+    out << "' changed:\n";
+
+  type_diff->report(out, indent + "  ");
 }
 
 /// For a @ref function_type_diff node, report the local changes
@@ -645,8 +648,8 @@  default_reporter::report(const function_type_diff& d, ostream& out,
 	dif->report(out, indent);
     }
 
-  report_local_function_type_changes(d, out, indent);
-
+  if (!d.is_filtered_out_without_looking_at_allowed_changes())
+    report_local_function_type_changes(d, out, indent);
 }
 
 /// Report a @ref array_diff in a serialized form.
@@ -678,10 +681,11 @@  default_reporter::report(const array_diff& d, ostream& out,
       dif->report(out, indent + "  ");
     }
 
-  report_name_size_and_alignment_changes(d.first_array(),
-					 d.second_array(),
-					 d.context(),
-					 out, indent);
+  if (!d.is_filtered_out_without_looking_at_allowed_changes())
+    report_name_size_and_alignment_changes(d.first_array(),
+					   d.second_array(),
+					   d.context(),
+					   out, indent);
 }
 
 /// Generates a report for an intance of @ref base_diff.
@@ -702,30 +706,32 @@  default_reporter::report(const base_diff& d, ostream& out,
   string repr = f->get_base_class()->get_pretty_representation();
   bool emitted = false;
 
-  if (f->get_is_static() != s->get_is_static())
+  if (!d.is_filtered_out_without_looking_at_allowed_changes())
     {
-      if (f->get_is_static())
-	out << indent << "is no more static";
-      else
-	out << indent << "now becomes static";
-      emitted = true;
-    }
+      if (f->get_is_static() != s->get_is_static())
+	{
+	  if (f->get_is_static())
+	    out << indent << "is no more static";
+	  else
+	    out << indent << "now becomes static";
+	  emitted = true;
+	}
 
-  if ((d.context()->get_allowed_category() & ACCESS_CHANGE_CATEGORY)
-      && (f->get_access_specifier() != s->get_access_specifier()))
-    {
-      if (emitted)
-	out << ", ";
+      if ((d.context()->get_allowed_category() & ACCESS_CHANGE_CATEGORY)
+	  && (f->get_access_specifier() != s->get_access_specifier()))
+	{
+	  if (emitted)
+	    out << ", ";
 
-      out << "has access changed from '"
-	  << f->get_access_specifier()
-	  << "' to '"
-	  << s->get_access_specifier()
-	  << "'";
+	  out << "has access changed from '"
+	      << f->get_access_specifier()
+	      << "' to '"
+	      << s->get_access_specifier()
+	      << "'";
 
-      emitted = true;
+	  emitted = true;
+	}
     }
-
   if (class_diff_sptr dif = d.get_underlying_class_diff())
     {
       if (dif->to_be_reported())
@@ -1493,135 +1499,138 @@  default_reporter::report(const function_decl_diff& d, ostream& out,
     linkage_names2 =
       s2->get_aliases_id_string(sc->get_fun_symbol_map());
 
-  /// If the set of linkage names of the function have changed, report
-  /// it.
-  if (linkage_names1 != linkage_names2)
+  if (!d.is_filtered_out_without_looking_at_allowed_changes())
     {
-      if (linkage_names1.empty())
+      /// If the set of linkage names of the function have changed, report
+      /// it.
+      if (linkage_names1 != linkage_names2)
 	{
-	  out << indent << ff->get_pretty_representation()
-	      << " didn't have any linkage name, and it now has: '"
-	      << linkage_names2 << "'\n";
+	  if (linkage_names1.empty())
+	    {
+	      out << indent << ff->get_pretty_representation()
+		  << " didn't have any linkage name, and it now has: '"
+		  << linkage_names2 << "'\n";
+	    }
+	  else if (linkage_names2.empty())
+	    {
+	      out << indent << ff->get_pretty_representation()
+		  << " did have linkage names '" << linkage_names1
+		  << "'\n"
+		  << indent << "but it doesn't have any linkage name anymore\n";
+	    }
+	  else
+	    out << indent << "linkage names of "
+		<< ff->get_pretty_representation()
+		<< "\n" << indent << "changed from '"
+		<< linkage_names1 << "' to '" << linkage_names2 << "'\n";
 	}
-      else if (linkage_names2.empty())
+
+      if (qn1 != qn2
+	  && d.type_diff()
+	  && d.type_diff()->to_be_reported())
 	{
-	  out << indent << ff->get_pretty_representation()
-	      << " did have linkage names '" << linkage_names1
-	      << "'\n"
-	      << indent << "but it doesn't have any linkage name anymore\n";
+	  // So the function has sub-type changes that are to be
+	  // reported.  Let's see if the function name changed too; if it
+	  // did, then we'd report that change right before reporting the
+	  // sub-type changes.
+	  string frep1 = d.first_function_decl()->get_pretty_representation(),
+	    frep2 = d.second_function_decl()->get_pretty_representation();
+	  out << indent << "'" << frep1 << " {" << linkage_names1<< "}"
+	      << "' now becomes '"
+	      << frep2 << " {" << linkage_names2 << "}" << "'\n";
 	}
-      else
-	out << indent << "linkage names of "
-	    << ff->get_pretty_representation()
-	    << "\n" << indent << "changed from '"
-	    << linkage_names1 << "' to '" << linkage_names2 << "'\n";
-    }
 
-  if (qn1 != qn2
-      && d.type_diff()
-      && d.type_diff()->to_be_reported())
-    {
-      // So the function has sub-type changes that are to be
-      // reported.  Let's see if the function name changed too; if it
-      // did, then we'd report that change right before reporting the
-      // sub-type changes.
-      string frep1 = d.first_function_decl()->get_pretty_representation(),
-	frep2 = d.second_function_decl()->get_pretty_representation();
-      out << indent << "'" << frep1 << " {" << linkage_names1<< "}"
-	  << "' now becomes '"
-	  << frep2 << " {" << linkage_names2 << "}" << "'\n";
-    }
-
-  maybe_report_diff_for_symbol(ff->get_symbol(),
-			       sf->get_symbol(),
-			       d.context(), out, indent);
-
-  // Now report about inline-ness changes
-  if (ff->is_declared_inline() != sf->is_declared_inline())
-    {
-      out << indent;
-      if (ff->is_declared_inline())
-	out << sf->get_pretty_representation()
-	    << " is not declared inline anymore\n";
-      else
-	out << sf->get_pretty_representation()
-	    << " is now declared inline\n";
-    }
+      maybe_report_diff_for_symbol(ff->get_symbol(),
+				   sf->get_symbol(),
+				   d.context(), out, indent);
 
-  // Report about vtable offset changes.
-  if (is_member_function(ff) && is_member_function(sf))
-    {
-      bool ff_is_virtual = get_member_function_is_virtual(ff),
-	sf_is_virtual = get_member_function_is_virtual(sf);
-      if (ff_is_virtual != sf_is_virtual)
+      // Now report about inline-ness changes
+      if (ff->is_declared_inline() != sf->is_declared_inline())
 	{
 	  out << indent;
-	  if (ff_is_virtual)
-	    out << ff->get_pretty_representation()
-		<< " is no more declared virtual\n";
+	  if (ff->is_declared_inline())
+	    out << sf->get_pretty_representation()
+		<< " is not declared inline anymore\n";
 	  else
-	    out << ff->get_pretty_representation()
-		<< " is now declared virtual\n";
+	    out << sf->get_pretty_representation()
+		<< " is now declared inline\n";
 	}
 
-      size_t ff_vtable_offset = get_member_function_vtable_offset(ff),
-	sf_vtable_offset = get_member_function_vtable_offset(sf);
-      if (ff_is_virtual && sf_is_virtual
-	  && (ff_vtable_offset != sf_vtable_offset))
+      // Report about vtable offset changes.
+      if (is_member_function(ff) && is_member_function(sf))
 	{
-	  out << indent
-	      << "the vtable offset of "  << ff->get_pretty_representation()
-	      << " changed from " << ff_vtable_offset
-	      << " to " << sf_vtable_offset << "\n";
-	}
+	  bool ff_is_virtual = get_member_function_is_virtual(ff),
+	    sf_is_virtual = get_member_function_is_virtual(sf);
+	  if (ff_is_virtual != sf_is_virtual)
+	    {
+	      out << indent;
+	      if (ff_is_virtual)
+		out << ff->get_pretty_representation()
+		    << " is no more declared virtual\n";
+	      else
+		out << ff->get_pretty_representation()
+		    << " is now declared virtual\n";
+	    }
 
-      // the parent types (classe or union) of the two member
-      // functions.
-      class_or_union_sptr f =
-	is_class_or_union_type(is_method_type(ff->get_type())->get_class_type());
-      class_or_union_sptr s =
-	is_class_or_union_type(is_method_type(sf->get_type())->get_class_type());
+	  size_t ff_vtable_offset = get_member_function_vtable_offset(ff),
+	    sf_vtable_offset = get_member_function_vtable_offset(sf);
+	  if (ff_is_virtual && sf_is_virtual
+	      && (ff_vtable_offset != sf_vtable_offset))
+	    {
+	      out << indent
+		  << "the vtable offset of "  << ff->get_pretty_representation()
+		  << " changed from " << ff_vtable_offset
+		  << " to " << sf_vtable_offset << "\n";
+	    }
 
-      class_decl_sptr fc = is_class_type(f);
-      class_decl_sptr sc = is_class_type(s);
+	  // the parent types (classe or union) of the two member
+	  // functions.
+	  class_or_union_sptr f =
+	    is_class_or_union_type(is_method_type(ff->get_type())->get_class_type());
+	  class_or_union_sptr s =
+	    is_class_or_union_type(is_method_type(sf->get_type())->get_class_type());
 
-      // Detect if the virtual member function changes above
-      // introduced a vtable change or not.
-      bool vtable_added = false, vtable_removed = false;
-      if (!f->get_is_declaration_only() && !s->get_is_declaration_only())
-	{
-	  if (fc && sc)
+	  class_decl_sptr fc = is_class_type(f);
+	  class_decl_sptr sc = is_class_type(s);
+
+	  // Detect if the virtual member function changes above
+	  // introduced a vtable change or not.
+	  bool vtable_added = false, vtable_removed = false;
+	  if (!f->get_is_declaration_only() && !s->get_is_declaration_only())
 	    {
-	      vtable_added = !fc->has_vtable() && sc->has_vtable();
-	      vtable_removed = fc->has_vtable() && !sc->has_vtable();
+	      if (fc && sc)
+		{
+		  vtable_added = !fc->has_vtable() && sc->has_vtable();
+		  vtable_removed = fc->has_vtable() && !sc->has_vtable();
+		}
+	    }
+	  bool vtable_changed = ((ff_is_virtual != sf_is_virtual)
+				 || (ff_vtable_offset != sf_vtable_offset));
+	  bool incompatible_change = (ff_vtable_offset != sf_vtable_offset);
+
+	  if (vtable_added)
+	    out << indent
+		<< "  note that a vtable was added to "
+		<< fc->get_pretty_representation()
+		<< "\n";
+	  else if (vtable_removed)
+	    out << indent
+		<< "  note that the vtable was removed from "
+		<< fc->get_pretty_representation()
+		<< "\n";
+	  else if (vtable_changed)
+	    {
+	      out << indent;
+	      if (incompatible_change)
+		out << "  note that this is an ABI incompatible "
+		  "change to the vtable of ";
+	      else
+		out << "  note that this induces a change to the vtable of ";
+	      out << fc->get_pretty_representation()
+		  << "\n";
 	    }
-	}
-      bool vtable_changed = ((ff_is_virtual != sf_is_virtual)
-			     || (ff_vtable_offset != sf_vtable_offset));
-      bool incompatible_change = (ff_vtable_offset != sf_vtable_offset);
 
-      if (vtable_added)
-	out << indent
-	    << "  note that a vtable was added to "
-	    << fc->get_pretty_representation()
-	    << "\n";
-      else if (vtable_removed)
-	out << indent
-	    << "  note that the vtable was removed from "
-	    << fc->get_pretty_representation()
-	    << "\n";
-      else if (vtable_changed)
-	{
-	  out << indent;
-	  if (incompatible_change)
-	    out << "  note that this is an ABI incompatible "
-	      "change to the vtable of ";
-	  else
-	    out << "  note that this induces a change to the vtable of ";
-	  out << fc->get_pretty_representation()
-	      << "\n";
 	}
-
     }
 
   // Report about function type differences.
@@ -1648,17 +1657,20 @@  default_reporter::report(const var_diff& d, ostream& out,
   decl_base_sptr first = d.first_var(), second = d.second_var();
   string n = first->get_pretty_representation();
 
-  report_name_size_and_alignment_changes(first, second,
-					 d.context(),
-					 out, indent);
+  if (!d.is_filtered_out_without_looking_at_allowed_changes())
+    {
+      report_name_size_and_alignment_changes(first, second,
+					     d.context(),
+					     out, indent);
 
-  maybe_report_diff_for_symbol(d.first_var()->get_symbol(),
-			       d.second_var()->get_symbol(),
-			       d.context(), out, indent);
+      maybe_report_diff_for_symbol(d.first_var()->get_symbol(),
+				   d.second_var()->get_symbol(),
+				   d.context(), out, indent);
 
-  maybe_report_diff_for_member(first, second, d.context(), out, indent);
+      maybe_report_diff_for_member(first, second, d.context(), out, indent);
 
-  maybe_report_diff_for_variable(first, second, d.context(), out, indent);
+      maybe_report_diff_for_variable(first, second, d.context(), out, indent);
+    }
 
   if (diff_sptr dif = d.type_diff())
     {
diff --git a/src/abg-suppression.cc b/src/abg-suppression.cc
index a79deb35..aaf175ca 100644
--- a/src/abg-suppression.cc
+++ b/src/abg-suppression.cc
@@ -274,6 +274,67 @@  suppression_base::has_soname_related_property() const
 	    && get_soname_not_regex_str().empty()));
 }
 
+/// Constructor of the @ref negated_suppression_base.
+negated_suppression_base::negated_suppression_base()
+{
+}
+
+/// Destructor of the @ref negated_suppression_base.
+negated_suppression_base::~negated_suppression_base()
+{
+}
+
+/// Test if a suppression specification is a negated suppression.
+///
+/// @param s the suppression to consider.
+///
+/// @return true iff @p s is an instance of @ref
+/// negated_suppression_base.
+bool
+is_negated_suppression(const suppression_base& s)
+{
+  bool result = true;
+  try
+    {
+      dynamic_cast<const negated_suppression_base&>(s);
+    }
+  catch (...)
+    {
+      result = false;
+    }
+  return result;
+}
+
+/// Test if a suppression specification is a negated suppression.
+///
+/// @param s the suppression to consider.
+///
+/// @return true a pointer to the @ref negated_suppression_base which
+/// @p s, or nil if it's not a negated suppression.
+/// negated_suppression_base.
+const negated_suppression_base*
+is_negated_suppression(const suppression_base* s)
+{
+  const negated_suppression_base* result = nullptr;
+  result = dynamic_cast<const negated_suppression_base*>(s);
+  return result;
+}
+
+/// Test if a suppression specification is a negated suppression.
+///
+/// @param s the suppression to consider.
+///
+/// @return true a pointer to the @ref negated_suppression_base which
+/// @p s, or nil if it's not a negated suppression.
+/// negated_suppression_base.
+negated_suppression_sptr
+is_negated_suppression(const suppression_sptr& s)
+{
+  negated_suppression_sptr result;
+  result = dynamic_pointer_cast<negated_suppression_base>(s);
+  return result;
+}
+
 /// Check if the SONAMEs of the two binaries being compared match the
 /// content of the properties "soname_regexp" and "soname_not_regexp"
 /// of the current suppression specification.
@@ -1619,6 +1680,52 @@  is_type_suppression(suppression_sptr suppr)
 
 // </type_suppression stuff>
 
+// <negated_type_suppression stuff>
+
+/// Constructor for @ref negated_type_suppression.
+///
+/// @param label the label of the suppression.  This is just a free
+/// form comment explaining what the suppression is about.
+///
+/// @param type_name_regexp the regular expression describing the
+/// types about which diff reports should be suppressed.  If it's an
+/// empty string, the parameter is ignored.
+///
+/// @param type_name the name of the type about which diff reports
+/// should be suppressed.  If it's an empty string, the parameter is
+/// ignored.
+///
+/// Note that parameter @p type_name_regexp and @p type_name_regexp
+/// should not necessarily be populated.  It usually is either one or
+/// the other that the user wants.
+negated_type_suppression::negated_type_suppression(const string& label,
+						   const string& type_name_regexp,
+						   const string& type_name)
+  : type_suppression(label, type_name_regexp, type_name),
+    negated_suppression_base()
+{
+}
+
+/// Evaluate this suppression specification on a given diff node and
+/// say if the diff node should be suppressed or not.
+///
+/// @param diff the diff node to evaluate this suppression
+/// specification against.
+///
+/// @return true if @p diff should be suppressed.
+bool
+negated_type_suppression::suppresses_diff(const diff* diff) const
+{
+  return !type_suppression::suppresses_diff(diff);
+}
+
+/// Destructor of the @ref negated_type_suppression type.
+negated_type_suppression::~negated_type_suppression()
+{
+}
+
+// </negated_type_suppression stuff>
+
 /// Parse the value of the "type_kind" property in the "suppress_type"
 /// section.
 ///
@@ -1681,7 +1788,8 @@  read_type_suppression(const ini::config::section& section)
 {
   type_suppression_sptr result;
 
-  if (section.get_name() != "suppress_type")
+  if (section.get_name() != "suppress_type"
+      && section.get_name() != "allow_type")
     return result;
 
   static const char *const sufficient_props[] = {
@@ -2046,7 +2154,11 @@  read_type_suppression(const ini::config::section& section)
 	changed_enumerator_names.push_back(p->get_value()->as_string());
     }
 
-  result.reset(new type_suppression(label_str, name_regex_str, name_str));
+  if (section.get_name() == "suppress_type")
+    result.reset(new type_suppression(label_str, name_regex_str, name_str));
+  else if (section.get_name() == "allow_type")
+    result.reset(new negated_type_suppression(label_str, name_regex_str,
+					      name_str));
 
   if (consider_type_kind)
     {
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index a343759e..aafa41de 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -258,6 +258,46 @@  test-abidiff-exit/PR30048-test-2-v0.cc \
 test-abidiff-exit/PR30048-test-2-v0.o \
 test-abidiff-exit/PR30048-test-2-v1.cc \
 test-abidiff-exit/PR30048-test-2-v1.o \
+test-abidiff-exit/test-allow-type-array-suppr.txt \
+test-abidiff-exit/test-allow-type-array-v0--v1-report-1.txt \
+test-abidiff-exit/test-allow-type-array-v0--v1-report-2.txt \
+test-abidiff-exit/test-allow-type-array-v0--v2-report-1.txt \
+test-abidiff-exit/test-allow-type-array-v0--v2-report-2.txt \
+test-abidiff-exit/test-allow-type-array-v0--v3-report-1.txt \
+test-abidiff-exit/test-allow-type-array-v0--v3-report-2.txt \
+test-abidiff-exit/test-allow-type-array-v0.c \
+test-abidiff-exit/test-allow-type-array-v0.o \
+test-abidiff-exit/test-allow-type-array-v1.c \
+test-abidiff-exit/test-allow-type-array-v1.o \
+test-abidiff-exit/test-allow-type-array-v2.c \
+test-abidiff-exit/test-allow-type-array-v2.o \
+test-abidiff-exit/test-allow-type-array-v3.c \
+test-abidiff-exit/test-allow-type-array-v3.o \
+test-abidiff-exit/test-allow-type-region-suppr.txt \
+test-abidiff-exit/test-allow-type-region-v0--v1-report-1.txt \
+test-abidiff-exit/test-allow-type-region-v0--v1-report-2.txt \
+test-abidiff-exit/test-allow-type-region-v0--v2-report-1.txt \
+test-abidiff-exit/test-allow-type-region-v0--v2-report-2.txt \
+test-abidiff-exit/test-allow-type-region-v0--v3-report-1.txt \
+test-abidiff-exit/test-allow-type-region-v0--v3-report-2.txt \
+test-abidiff-exit/test-allow-type-region-v0--v4-report-1.txt \
+test-abidiff-exit/test-allow-type-region-v0--v4-report-2.txt \
+test-abidiff-exit/test-allow-type-region-v0--v5-report-1.txt \
+test-abidiff-exit/test-allow-type-region-v0--v5-report-2.txt \
+test-abidiff-exit/test-allow-type-region-v0.c \
+test-abidiff-exit/test-allow-type-region-v0.o \
+test-abidiff-exit/test-allow-type-region-v1.c \
+test-abidiff-exit/test-allow-type-region-v1.o \
+test-abidiff-exit/test-allow-type-region-v2.c \
+test-abidiff-exit/test-allow-type-region-v2.o \
+test-abidiff-exit/test-allow-type-region-v3.c \
+test-abidiff-exit/test-allow-type-region-v3.o \
+test-abidiff-exit/test-allow-type-region-v4.c \
+test-abidiff-exit/test-allow-type-region-v4.o \
+test-abidiff-exit/test-allow-type-region-v5.c \
+test-abidiff-exit/test-allow-type-region-v5.o \
+test-abidiff-exit/test-allow-type-suppr2.txt \
+test-abidiff-exit/test-allow-type-suppr1.txt \
 \
 test-diff-dwarf/test0-v0.cc		\
 test-diff-dwarf/test0-v0.o			\
diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-suppr.txt b/tests/data/test-abidiff-exit/test-allow-type-array-suppr.txt
new file mode 100644
index 00000000..043cfb39
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-array-suppr.txt
@@ -0,0 +1,7 @@ 
+[allow_type]
+ type_kind = struct
+ has_data_member_regexp = rh_kabi_reserved
+
+[suppress_type]
+ type_kind = struct
+ has_data_member_inserted_between = {offset_of(rh_kabi_reserved1), end}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v0--v1-report-1.txt b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v1-report-1.txt
new file mode 100644
index 00000000..36987f27
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v1-report-1.txt
@@ -0,0 +1,23 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-array-v0.c:15:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-array-v1.c:1:1:
+        type size hasn't changed
+        1 data member insertion:
+          'int inserted', at offset 64 (in bits) at test-allow-type-array-v1.c:5:1
+        1 data member change:
+          type of 'char rh_kabi_reserved1[50]' changed:
+            type name changed from 'char[50]' to 'char[46]'
+            array type size changed from 400 to 368
+            array type subrange 1 changed length from 50 to 46
+          and offset changed from 64 to 96 (in bits) (by +32 bits)
+    parameter 2 of type 'C1*' has sub-type changes:
+      in pointed to type 'struct C1' at test-allow-type-array-v1.c:9:1:
+        type size changed from 64 to 96 (in bits)
+        1 data member insertion:
+          'int m2', at offset 64 (in bits) at test-allow-type-array-v1.c:13:1
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v0--v1-report-2.txt b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v1-report-2.txt
new file mode 100644
index 00000000..9666a8fd
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v1-report-2.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-abidiff-exit/test-allow-type-array-v0--v2-report-1.txt b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v2-report-1.txt
new file mode 100644
index 00000000..5d2fb16c
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v2-report-1.txt
@@ -0,0 +1,20 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-array-v0.c:15:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-array-v2.c:1:1:
+        type size changed from 480 to 512 (in bits)
+        1 data member insertion:
+          'int wrongly_inserted', at offset 32 (in bits) at test-allow-type-array-v2.c:4:1
+        2 data member changes:
+          'int m1' offset changed from 32 to 64 (in bits) (by +32 bits)
+          'char rh_kabi_reserved1[50]' offset changed from 64 to 96 (in bits) (by +32 bits)
+    parameter 2 of type 'C1*' has sub-type changes:
+      in pointed to type 'struct C1' at test-allow-type-array-v2.c:9:1:
+        type size changed from 64 to 96 (in bits)
+        1 data member insertion:
+          'int m2', at offset 64 (in bits) at test-allow-type-array-v2.c:13:1
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v0--v2-report-2.txt b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v2-report-2.txt
new file mode 100644
index 00000000..cade60df
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v2-report-2.txt
@@ -0,0 +1,15 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-array-v0.c:15:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-array-v2.c:1:1:
+        type size changed from 480 to 512 (in bits)
+        1 data member insertion:
+          'int wrongly_inserted', at offset 32 (in bits) at test-allow-type-array-v2.c:4:1
+        2 data member changes:
+          'int m1' offset changed from 32 to 64 (in bits) (by +32 bits)
+          'char rh_kabi_reserved1[50]' offset changed from 64 to 96 (in bits) (by +32 bits)
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v0--v3-report-1.txt b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v3-report-1.txt
new file mode 100644
index 00000000..b0e1d85c
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v3-report-1.txt
@@ -0,0 +1,23 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-array-v0.c:15:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-array-v3.c:1:1:
+        type size hasn't changed
+        1 data member insertion:
+          'int correctly_inserted', at offset 64 (in bits) at test-allow-type-array-v3.c:5:1
+        1 data member change:
+          type of 'char rh_kabi_reserved1[50]' changed:
+            type name changed from 'char[50]' to 'char[46]'
+            array type size changed from 400 to 368
+            array type subrange 1 changed length from 50 to 46
+          and offset changed from 64 to 96 (in bits) (by +32 bits)
+    parameter 2 of type 'C1*' has sub-type changes:
+      in pointed to type 'struct C1' at test-allow-type-array-v3.c:9:1:
+        type size changed from 64 to 96 (in bits)
+        1 data member insertion:
+          'int m2', at offset 64 (in bits) at test-allow-type-array-v3.c:13:1
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v0--v3-report-2.txt b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v3-report-2.txt
new file mode 100644
index 00000000..9666a8fd
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-array-v0--v3-report-2.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-abidiff-exit/test-allow-type-array-v0.c b/tests/data/test-abidiff-exit/test-allow-type-array-v0.c
new file mode 100644
index 00000000..174de3a0
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-array-v0.c
@@ -0,0 +1,18 @@ 
+struct C0
+{
+  int m0;
+  int m1;
+  char rh_kabi_reserved1[50];
+};
+
+struct C1
+{
+  int m0;
+  char m1;
+};
+
+int
+foo(struct C0 *c0, struct C1 *c1)
+{
+  return c0->m0 + c1->m0;
+}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v0.o b/tests/data/test-abidiff-exit/test-allow-type-array-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..83dc3783c1bdbaec61f46a705554269a55bba07d
GIT binary patch
literal 3392
zcmc&$&2Jl35TEDuCYx*$J24*(0cDLqZ6kK=4OIy#DM6t$5vZV|s+WSZwx8`K{)pC_
zPgEf;h$t73IC4T<kPsJ+9Qg-&<Aj6|NSsjMRH+A;S<g$hn{9>Qz(~6@^PBn2ynSEx
z2Up&BEh7Xd5pWq!JcR-*8!<aFm*Ej8z>U>|Usn%q-(5Y}I$Axva`!Ng@1sKyci#E_
z7tGT^M9d-LJQWdRuP0-6W~B@-iCc(>P8qaeve0xP8=2YR$k&Y;Y6Fa{?sr2N*+;LB
z&nUfI(2OWe6H&j+iVKGE1xBdk=t)V_AYK;CMz04V7j;D-5;Z3A`H$#lYh}ojk@>Wh
zt+_D!b7ZfB?x3N6h%XT1*mtogE}1WyYlQ_9lM6yKOml!04N(Blo&nRmY-$r&Q|J6*
zjtH4ESSSZ((OAR0p-J)VM8VW%XJ#kG)NuZBfMKjZv1p!@H@Ftg?1&I+1*$(<gtbBm
zdz+4Uc^bzP<)58iD^Qu`GyBt&1<&D=p+Vyu#zlQ~93%T}e00p6LoI~3H!)6%b_hOb
z%to6fBW5$XL0OC-L%_(ftL20~_MQG{L!WHuqLj%X@9MQ1){6Ur<+{%Ej%&@A=jUB_
z-nGtMmvw8^3prq4IB(gVaH}hqnzAbczlN?C)LKis3m5H+7wqkM%Wguu*KJx`-M-)K
zBAxa{(5h^BRlgF*z6`cy-Gy4q3!v2Mb!4gDtH0-$ntoVn`&G<pdVaeUv_c!1GU$5k
zQoS!XWGD%>sgBKcN}=qB{Zicvy~wmNR`(kXTkiTHP|)_;?cR<Z?rloj3j%M?-Yz?}
z|F7{w#spVaRu-*uxD@CA!8%0i3V7xRBKEI?*v*TXv0>vA+yk_K)E<iTD--#TGArXl
zH!*=ZX^OT_7XJ7vEvBX3M0k{V2PZiiM$$yX4r!u6bW5BHX%Jl^Dfq}Ki~tSr*rkXD
zV<{-*<0X(H8st(?${#<4(;QF5=10x_!!{vZc4{p~kstqh)q(K%S59$f!s&UJ{l^kG
zyYK`Xw64cD0NQhmQw=o+g5Heb)OVfz?F4>}{o4sVVE-G|$-e3vsjtpCr1ESh^Pgs%
z^6A-QpYBZ(h5s;c@h4{>3jdS+ORSUiEyihX;`0Mef3FjIRn%cH&@E+!ayJBrE*)^H
z{XRH>Y<o^!R=1iJzuV|xEV8|7HIUo)g}uP*Hs$@4w%?VCf-RIua3%6<y-r8sCF*p0
zp>*(mu=}A`+u*{oRcQoXNAidKM>T_dnj^JNs@yUg$NQRn%8g4A9m0|)|5iLHW+(Y)
zF-H6G-|}hwlQpTG>i-)#F-hjqzM|V{IhI4_5pUKb#wSrzo;o}DpCOVZd?#yC;8g~{
zj<QZ($=tUvl*B0eh{5s+HL{YquOpf^{-1b36`#gWw`y|yb;Oc25dw=3$4zo#lFY4O
zEUkZ@ukdx|Qh&N%lKnRkqnc`*XhyQb{dW|=TJ=}@eZ<rFzcYVaB|d<E_yGPr-jF5c
zDW%FO{TcIBT<JNQloU}s75WMd!g#m}hBEUPj*)?(=1;+2qLDWLn>_z&pVIu(ubbj4
xJgqm?ZgKw>514+3=vOnzr!`HUU4-BcpC5~ym?XcS#+AnZn8*KZj7w&c|2JnMH)a3;

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v1.c b/tests/data/test-abidiff-exit/test-allow-type-array-v1.c
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-array-v1.c
@@ -0,0 +1,20 @@ 
+struct C0
+{
+  int m0;
+  int m1;
+  int inserted;
+  char rh_kabi_reserved1[46];
+};
+
+struct C1
+{
+  int m0;
+  char m1;
+  int m2;
+};
+
+int
+foo(struct C0 *c0, struct C1 *c1)
+{
+  return c0->m0 + c1->m0;
+}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v1.o b/tests/data/test-abidiff-exit/test-allow-type-array-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..9be83bf41befede1b2da405aa7036bca3a37edcf
GIT binary patch
literal 3448
zcmcImOK&4Z5U%!kl1U~HJLZuPP#gr>hZs8(R=Z)BEJ4w-37}=QXtfd#C1bm753$Fq
z@gyXRcpX3+1tE|)a^wI9PF#?<Ai)pd#xLL=;1YoZRE?{hNoR-<h>~Wi>g#%ScTL%E
zUwQtSj1Ztmz-2hp6bi6y9m-3wxCHk=0dB7B{<O0D=E2JD=Kjjwm4m$;zW4V){P5~`
zzoDH8BK904pNC?{#OuL?oLQcOCq)Ah(VhcikR%jc$i`yUAl-~*E0zbW0Fe=}vZfzI
zF!Ua3Z{agcF9)(#oHHv1P=(C03nN2cqeRi|!{{Rx`DI0W9!7h?!LD~YAo6i7<V&O~
z6`%f!npvHL90{3^n`YI8nS)qfhk+6b10UcE#3&fn#aVI5e!^ZYEZAsV5Qb&jJ#5wz
z1pot$#*P?e9|7CGY#U>k#pDRHc?yx4#L(kl&swYKIhYrZjumWUW_l(sCI)l&16b^e
z2R<akYJn0A&%$b<jLGeicxnm@vZ<a^Q>z8?TAI8wMON?_J{hVS68DUn+IGB@c)f_S
ziMD5v3n6|V8zn}KgAWQbaSvt0OlG_nHug0I4E0qbFU*l|%zNu*zHW+gCWC%guiY#z
zyBCVCTY9|Y7U$>Y=UsQ+EuOw1YsD2W;sxj2nWEE<HUqiXkbw;SDym*sZ7yyvoOjNj
zbGGJ-P6Jw<pi$fmx_%=-cj^&8=*lpXH3*w)8(zg<3nc<uvgSgy>4gx<Zsd5aR_Apm
z+PN(qFATjMXUi>Bq1^1WWx3X=z2=u2epGJx6%5eu{8l+^Mh-@oVc@mOwXWQdktEci
z6b`2-Q|xZJ=0#pCI=EKz>vczN`_ca#{e*3uumo3^moFAi<DH!O2Nx1wFyKt+k+^dM
z#CA?hj|^HLVKY!8sb-4#(_^{!Gs~j`x6pun(irto7JmLSZOurXRQOSGE9*W6uB4HH
z8Pdprcyt_FG9aETDfrMai~s}h`%57MhgTXIfFFMf88DuLQvA_lIGyoC;(XNEpVZ<s
z_S9VrqknSuDg)ukT~2Uj!s$_T9}5bfX8i%?bg%tUfbv<!$zIh!&<hEi@~*S~vWEMt
zzpLTbSih^`Z?OJ7bG;t5cdEx^8)7+@b^C`ISNq*zodzqB!hh_k;4)YEFRWi;uE#Gj
zPG^=pHz;*?+L2d59)&&LR8l0jBPh|tfl{U0g;FS6Ua2N4n~gO;sCRHJmc2?Plv_uZ
zz0eC9@~BJ852SLz6iOs`E!L}@c3a|<Ed`xOmT+!3-N>tMaA4V7tA}1&@<#q6qkf_@
zQun07EwRw=ch<=^NwcUBrcZ=dl12$x_dkVe)TjT}pYC6eN$FJnKS)WCZcBYdQ)?+<
zLt>5(#A1g$Vq~YjDf|x+(;~k0n6&T`gI~s0hcDgsIxguLSr2k^&K<hOl5YDPqG|O{
z@@Q55R6jv_{WZk&m<YiI&VP%P1nIVGxR#cGh4ZhoFXgAXqvyYk7{yd|q8QVMoc|rx
z6;t^Yr}>lSKgJC;sth@RQWf9(8~<tA6jHgz`fuf@_$Roc<h~IK&$53KBU!iof-&B1
z-~2lJFZ7X~pw3UhpP@jeOA28AIiJ7kQ#yb8)l>cor+W0<6yh%DZ*sx(`$WH{x<B2i
e{_P?J`#kK6q$Eh+Kh>4y|1H=5Rl=7<-TyDlemc<r

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v2.c b/tests/data/test-abidiff-exit/test-allow-type-array-v2.c
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-array-v2.c
@@ -0,0 +1,20 @@ 
+struct C0
+{
+  int m0;
+  int wrongly_inserted;
+  int m1;
+  char rh_kabi_reserved1[50];
+};
+
+struct C1
+{
+  int m0;
+  char m1;
+  int m2;
+};
+
+int
+foo(struct C0 *c0, struct C1 *c1)
+{
+  return c0->m0 + c1->m0;
+}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v2.o b/tests/data/test-abidiff-exit/test-allow-type-array-v2.o
new file mode 100644
index 0000000000000000000000000000000000000000..88f3d0bfb043d22f936663784792614fb2aeb844
GIT binary patch
literal 3456
zcmc&$&2Jl35TEDu#+z)M*fErZfU@R8{Sdp(nyL-0QjAP#B2ZNYRYiQcYx~(=Vz0}3
zlO{!c34s~~p(1hYkqZYTBrZrC;lPm_e*yObmk1<aX8oSC*=#EW2S)OHGru>#nRy=`
z``z;|JeOh&q%b%K`<6rj-qZH=N~l)gJ}AKDm7SkgcHZ7w+1a?WvU`4SH;3b$U0^@H
z_TBI3rveL^8R9$~5+lPy5j|C1gbHgT!g`CKWJm*rhIFW>S<ePFRJ9Nu(>z?91TC$)
zUI61CqV*1bCTOrBt%W($Yz$3ERc)9Y{{}URt`DPA#7T{K7`zPGVQ|n}{XVdKSPOAU
zWTou(Z)mBFMaYqo`n01qY*^R}^{X&up)&R{4#2XYXlIJ-tp1d~T3FK2xxf@n*N0e9
zV+GtFI!zsLN<Rj=eoj}WFpDZ86!R1!HH)FAK`&~n$js!~<5LA)S(snQvzbip0RT-<
z@xaF!TP;w6i6X2PN|;=?*wb@ZkWTd+om(vst1^3Ij=bOr{G_OAh}<(;a@*ljWOxyE
z6@5?O%ozJ)DoYbR9Q>fN5Wb-lTS!e0!-iay!T88j@=TrlR=vNa=36Q&rBcYdaPhKH
zwND$iZ9Qq(MtQMZw(YWQ99!c}W5o%?f_d_|VfKOzk1w~m$9=bfrsFp{%UesQ%u^@L
z&9Y&(q1*S`#)da=+aA*Cja>H;>TcIuZ@~S4H^J}J)}6Xr^Em>WylF$D<M>eO^n1M2
z>^I+VOKmqOb=^98wH>!x@;iZvp}6lk-BNSF*LlDRH7SlM;*<hD2nMC56F8x2;#$*f
zwM@R{20)9Z)9v=Jo5A)qZaTj2Y-7z<<Nr&1kDA~@wR*-lhIe!PA6!g$(SW^SDD1`>
zu&o@MpUh~t@KMl%l8-8!pP9;il&WUOuAqb9Bu(_5((ub)Noz`C$D-yjdTa-1%CM~*
zz{pTALy{;Ewva<h3WOad0Utkv5ugBm4--VeCYB@$U=v6X1*Q{Fil04%(;3f1&PSg8
zy&fU8KY14u$dB$`W*|Je%NdcGaQeJ1>?1K;nDC%b=w73@bRyy}Yar;^2u^vg3j389
z{-&_skKq@EeKUrCAnfnO9Ir?2o%W;(ADVJPkNZC&aCr{f!lnjGBJrPwCjL$hMdH5-
z`>dGb@eP5~nMKbHtig6KaOyY*{&4O{E#O-LSk#Qbst*QW`Mm2`O<vz<V<&9&aV^xH
zdfn%n2bLY*@!I?#rR#cJQZR*739f~9qu=Xs?6#KI54eSW!yE)oV_gL1om$IxdR%Pe
zKTh+=r!$iGB*RsNGJ5aACf}$O(I71RM-f?gHKIq=IR7Xv(mVaPe7gU5Ov)$o|4Bwf
z;=c5*sB2XsKBUfy1JMK_j~MyM?-c%*2xS?^cuZP&S%6=LUi(Ab_Yy9}G4jrc$GNyq
z4Yj!M^N1$ZZ-~|^`BXna@%o#H#bY7_r$zoNWJDzHTf?=a{Fg-jtAb1Usqe(|Uqg&y
z$~sXE<r9(rrUb++^UL`y#FO|(#DmI8$Gh-%@4|nSHic3ePNPwVlk;b|BK46IDr<rt
z#Ym6)ejzZi-I4oCg1<CEhKf8t34e|XxmF|~=C8#0%XdoWPrrJSFLA0To|{7468Sr#
oVETQcU(-0B?lk`0MF{ppvp2|yNPPcPR}%jRQUBKwE~#<;-*v`5{r~^~

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v3.c b/tests/data/test-abidiff-exit/test-allow-type-array-v3.c
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-array-v3.c
@@ -0,0 +1,20 @@ 
+struct C0
+{
+  int m0;
+  int m1;
+  int correctly_inserted;
+  char rh_kabi_reserved1[46];
+};
+
+struct C1
+{
+  int m0;
+  char m1;
+  int m2;
+};
+
+int
+foo(struct C0 *c0, struct C1 *c1)
+{
+  return c0->m0 + c1->m0;
+}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-array-v3.o b/tests/data/test-abidiff-exit/test-allow-type-array-v3.o
new file mode 100644
index 0000000000000000000000000000000000000000..5fb6bf50c1869701bc5779720ae8eb61bf80a262
GIT binary patch
literal 3456
zcmc&$&2Jk;6o2FO#+z)M*l~e`fMO%6eu!PiZq<gC6eFuN5vWv!s)#RVZI3^QKdSX6
zBt?83K!hMvB#u3D;edq11&JdZICA4J;9lSofdsrao^dvlZH3^#NIUc1Z{F{{w=-{_
z{m#W_pN=sGYB0C}`<g-l-nI7Sk`PO91Tt`KW#{LWowxQ@b~f&;>|Wg4P2qfJ7ub)l
ze)l`tnZN`yL7ayLF*H3Cl4IpXc!D(%VckVA5+tEmfVdFj2I;1dEg_FtJwztKikt0T
z0ORkY_BK8fG&vBrM9erFLlt7>0!)s7gA#eS_q|VA#EY|T5t2jaU^n`GU}=#HacQVb
z+3nv@Gi!^GA|du^%d8b(VNb|wFy^8#_AyStl3-Zpa_qeQxV@TLve7uh49m8MSk7V@
z00WJt4j9EB1>3%08&ep?lpb<vauJ(F*VAC<tW{(t((LF|#x@q_7t(Adk$M2Yl2knK
zamH3N6ks9;tC>6ow_Wz+942H_KF8)(GsG&*-kc*VcnqHyWeuTwMoqo8*a}V0qimw>
zNn9CYe@rE5p~Arjg#}SVF}4t!9=a7=lfn2%HPXzS{MNj$VWt}<%g18KyL9<lwp=)y
zEfm~SZXsJ-EEWreVj+9{Dz9f(yg+U^r%z;^Zm`kg%T3<ne!GUM=hs@xTT5r0GpC)+
zV%BLwr{8O4H+qA1vxju55x-Sg_p0rR&j;M!<n;p7`o7O=L1(+t?jaWNI@DU85BXNV
z%k%Yq{q=Uf*$(oZb`^<DuieS}t-wKN-0yjve0{*zdB6#E$h9L~=L0?n2Kl-dctUh=
zuikDn9KO{KfHobk)9JtA1lu>b<N3a~?QEWMYyV&1d*lR{%H?y}<9ItK{=wCVt3D!T
ztc9Cbfo-MO{A9wqg+)OHrHV?dPfevhh?SFL*U><7q86&BIQ;Tg)SeO9vGC)PC9QJ|
z+=&_nMu-{)h!%2a%K*_~BJlA;7y$<0cNj4YY+_Nv0Biyg!+_}sl>8?T;dI6`q4QB^
zf3Fgx_NVS*0{P*$R}lygzvYaKOgKHSN&S8emnu9c1-jQ!OF;Rg#L0)sfuQF?IK}m)
z{<4OzN&P(yzby3+HJqA1jqitxIH_<x>fI?HQ`*pylCqxvBN8WjdbXub4VH$&e;TS#
zkgLLfmHK(P>i)A5ryRq1f;-sm23{4{z#pzHB?Wvd0GC=3xYfY`T%UJ5x6Z2@P3(G&
zKJE$Gt5$u!d0^Y~y<U?aq;%Rnt|%Bni3C@KUh8+e9J{UC>j&J$uHg&<ueL57^H!zd
zdtEMH<UcO+$fq+>_oUpFq%f*?sgrGZ<WM0@?+CAijY6`{KZbi$r~j5u_pke;a4P<v
zq=bfUOLawEs}!;!aaJCPB?)Q7$WDDz_+LVdWt?@NwDFPzzZ6#clWuzjw{(oG6S6oL
z_o+hCZJ$9jD*vo(t%^_i6Qt)~M@;vL5S*3quagoQx@`sbqT*kX@z*4m;#1$z<KIAx
ze5yQA6yp;a|04y+RmE59n}|p8XJtVpmEm3ZyLaIqrI*5yA1<R=xl`+BxTEBe5ehFz
zei$QJxBWt5@^we%FG~K>2pJ0M{1p5-3S?SRfLy<l=dbFN&Yynu6kp+#j~<&`+>-HI
pGGY3CqF+;;Pj{++y9mLaZ1!1FLPLLl$}5WhgUtWy5SK)q|2NDSKh*#L

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-suppr.txt b/tests/data/test-abidiff-exit/test-allow-type-region-suppr.txt
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-suppr.txt
@@ -0,0 +1,11 @@ 
+[allow_type]
+ type_kind = struct
+ has_data_member_regexp = rh_kabi_reserved
+
+[suppress_type]
+ type_kind = struct
+ has_data_member_inserted_between =
+  {
+   offset_of_first_data_member_regexp(rh_kabi_reserved),
+   offset_of_last_data_member_regexp(rh_kabi_reserved)
+  }
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v0--v1-report-1.txt b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v1-report-1.txt
new file mode 100644
index 00000000..7249e6c8
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v1-report-1.txt
@@ -0,0 +1,20 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-region-v0.c:19:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-region-v1.c:1:1:
+        type size hasn't changed
+        1 data member change:
+          type of 'unsigned int rh_kabi_reserved1' changed:
+            type name changed from 'unsigned int' to 'int'
+            type size hasn't changed
+          and name of 'C0::rh_kabi_reserved1' changed to 'C0::correctly_inserted' at test-allow-type-region-v1.c:5:1
+    parameter 2 of type 'C1*' has sub-type changes:
+      in pointed to type 'struct C1' at test-allow-type-region-v1.c:12:1:
+        type size hasn't changed
+        1 data member insertion:
+          'char wrongly_inserted', at offset 40 (in bits) at test-allow-type-region-v1.c:16:1
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v0--v1-report-2.txt b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v1-report-2.txt
new file mode 100644
index 00000000..9666a8fd
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v1-report-2.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-abidiff-exit/test-allow-type-region-v0--v2-report-1.txt b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v2-report-1.txt
new file mode 100644
index 00000000..0db5dda4
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v2-report-1.txt
@@ -0,0 +1,21 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-region-v0.c:19:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-region-v2.c:1:1:
+        type size hasn't changed
+        1 data member deletion:
+          'unsigned int rh_kabi_reserved1', at offset 64 (in bits) at test-allow-type-region-v0.c:5:1
+        1 data member insertion:
+          'int incorrectly_inserted', at offset 32 (in bits) at test-allow-type-region-v2.c:4:1
+        1 data member change:
+          'int m1' offset changed from 32 to 64 (in bits) (by +32 bits)
+    parameter 2 of type 'C1*' has sub-type changes:
+      in pointed to type 'struct C1' at test-allow-type-region-v2.c:12:1:
+        type size hasn't changed
+        1 data member insertion:
+          'char wrongly_inserted', at offset 40 (in bits) at test-allow-type-region-v2.c:16:1
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v0--v2-report-2.txt b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v2-report-2.txt
new file mode 100644
index 00000000..e807fcec
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v2-report-2.txt
@@ -0,0 +1,16 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-region-v0.c:19:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-region-v2.c:1:1:
+        type size hasn't changed
+        1 data member deletion:
+          'unsigned int rh_kabi_reserved1', at offset 64 (in bits) at test-allow-type-region-v0.c:5:1
+        1 data member insertion:
+          'int incorrectly_inserted', at offset 32 (in bits) at test-allow-type-region-v2.c:4:1
+        1 data member change:
+          'int m1' offset changed from 32 to 64 (in bits) (by +32 bits)
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v0--v3-report-1.txt b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v3-report-1.txt
new file mode 100644
index 00000000..c5dbee67
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v3-report-1.txt
@@ -0,0 +1,23 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-region-v0.c:19:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-region-v3.c:1:1:
+        type size changed from 224 to 256 (in bits)
+        1 data member insertion:
+          'int incorrectly_inserted', at offset 64 (in bits) at test-allow-type-region-v3.c:5:1
+        5 data member changes:
+          'unsigned int rh_kabi_reserved1' offset changed from 64 to 96 (in bits) (by +32 bits)
+          'unsigned int rh_kabi_reserved2' offset changed from 96 to 128 (in bits) (by +32 bits)
+          'unsigned int rh_kabi_reserved3' offset changed from 128 to 160 (in bits) (by +32 bits)
+          'unsigned int rh_kabi_reserved4' offset changed from 160 to 192 (in bits) (by +32 bits)
+          'unsigned int rh_kabi_reserved5' offset changed from 192 to 224 (in bits) (by +32 bits)
+    parameter 2 of type 'C1*' has sub-type changes:
+      in pointed to type 'struct C1' at test-allow-type-region-v3.c:13:1:
+        type size hasn't changed
+        1 data member insertion:
+          'char wrongly_inserted', at offset 40 (in bits) at test-allow-type-region-v3.c:17:1
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v0--v3-report-2.txt b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v3-report-2.txt
new file mode 100644
index 00000000..e4f836e9
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v3-report-2.txt
@@ -0,0 +1,18 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-region-v0.c:19:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-region-v3.c:1:1:
+        type size changed from 224 to 256 (in bits)
+        1 data member insertion:
+          'int incorrectly_inserted', at offset 64 (in bits) at test-allow-type-region-v3.c:5:1
+        5 data member changes:
+          'unsigned int rh_kabi_reserved1' offset changed from 64 to 96 (in bits) (by +32 bits)
+          'unsigned int rh_kabi_reserved2' offset changed from 96 to 128 (in bits) (by +32 bits)
+          'unsigned int rh_kabi_reserved3' offset changed from 128 to 160 (in bits) (by +32 bits)
+          'unsigned int rh_kabi_reserved4' offset changed from 160 to 192 (in bits) (by +32 bits)
+          'unsigned int rh_kabi_reserved5' offset changed from 192 to 224 (in bits) (by +32 bits)
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v0--v4-report-1.txt b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v4-report-1.txt
new file mode 100644
index 00000000..8a435001
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v4-report-1.txt
@@ -0,0 +1,28 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-region-v0.c:19:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-region-v4.c:1:1:
+        type size hasn't changed
+        3 data member changes:
+          type of 'unsigned int rh_kabi_reserved1' changed:
+            type name changed from 'unsigned int' to 'int'
+            type size hasn't changed
+          and name of 'C0::rh_kabi_reserved1' changed to 'C0::correctly_inserted1' at test-allow-type-region-v4.c:5:1
+          type of 'unsigned int rh_kabi_reserved3' changed:
+            type name changed from 'unsigned int' to 'int'
+            type size hasn't changed
+          and name of 'C0::rh_kabi_reserved3' changed to 'C0::correctly_inserted2' at test-allow-type-region-v4.c:7:1
+          type of 'unsigned int rh_kabi_reserved4' changed:
+            type name changed from 'unsigned int' to 'int'
+            type size hasn't changed
+          and name of 'C0::rh_kabi_reserved4' changed to 'C0::correctly_inserted3' at test-allow-type-region-v4.c:8:1
+    parameter 2 of type 'C1*' has sub-type changes:
+      in pointed to type 'struct C1' at test-allow-type-region-v4.c:12:1:
+        type size hasn't changed
+        1 data member insertion:
+          'char wrongly_inserted', at offset 40 (in bits) at test-allow-type-region-v4.c:16:1
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v0--v4-report-2.txt b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v4-report-2.txt
new file mode 100644
index 00000000..9666a8fd
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v4-report-2.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-abidiff-exit/test-allow-type-region-v0--v5-report-1.txt b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v5-report-1.txt
new file mode 100644
index 00000000..ffc32324
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v5-report-1.txt
@@ -0,0 +1,30 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-region-v0.c:19:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-region-v5.c:1:1:
+        type size changed from 224 to 256 (in bits)
+        1 data member insertion:
+          'int incorrectly_inserted', at offset 224 (in bits) at test-allow-type-region-v5.c:10:1
+        3 data member changes:
+          type of 'unsigned int rh_kabi_reserved1' changed:
+            type name changed from 'unsigned int' to 'int'
+            type size hasn't changed
+          and name of 'C0::rh_kabi_reserved1' changed to 'C0::correctly_inserted1' at test-allow-type-region-v5.c:5:1
+          type of 'unsigned int rh_kabi_reserved3' changed:
+            type name changed from 'unsigned int' to 'int'
+            type size hasn't changed
+          and name of 'C0::rh_kabi_reserved3' changed to 'C0::correctly_inserted2' at test-allow-type-region-v5.c:7:1
+          type of 'unsigned int rh_kabi_reserved4' changed:
+            type name changed from 'unsigned int' to 'int'
+            type size hasn't changed
+          and name of 'C0::rh_kabi_reserved4' changed to 'C0::correctly_inserted3' at test-allow-type-region-v5.c:8:1
+    parameter 2 of type 'C1*' has sub-type changes:
+      in pointed to type 'struct C1' at test-allow-type-region-v5.c:13:1:
+        type size hasn't changed
+        1 data member insertion:
+          'char wrongly_inserted', at offset 40 (in bits) at test-allow-type-region-v5.c:17:1
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v0--v5-report-2.txt b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v5-report-2.txt
new file mode 100644
index 00000000..c467ab22
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v0--v5-report-2.txt
@@ -0,0 +1,25 @@ 
+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 int foo(C0*, C1*)' at test-allow-type-region-v0.c:19:1 has some indirect sub-type changes:
+    parameter 1 of type 'C0*' has sub-type changes:
+      in pointed to type 'struct C0' at test-allow-type-region-v5.c:1:1:
+        type size changed from 224 to 256 (in bits)
+        1 data member insertion:
+          'int incorrectly_inserted', at offset 224 (in bits) at test-allow-type-region-v5.c:10:1
+        3 data member changes:
+          type of 'unsigned int rh_kabi_reserved1' changed:
+            type name changed from 'unsigned int' to 'int'
+            type size hasn't changed
+          and name of 'C0::rh_kabi_reserved1' changed to 'C0::correctly_inserted1' at test-allow-type-region-v5.c:5:1
+          type of 'unsigned int rh_kabi_reserved3' changed:
+            type name changed from 'unsigned int' to 'int'
+            type size hasn't changed
+          and name of 'C0::rh_kabi_reserved3' changed to 'C0::correctly_inserted2' at test-allow-type-region-v5.c:7:1
+          type of 'unsigned int rh_kabi_reserved4' changed:
+            type name changed from 'unsigned int' to 'int'
+            type size hasn't changed
+          and name of 'C0::rh_kabi_reserved4' changed to 'C0::correctly_inserted3' at test-allow-type-region-v5.c:8:1
+
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v0.c b/tests/data/test-abidiff-exit/test-allow-type-region-v0.c
new file mode 100644
index 00000000..d053a313
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v0.c
@@ -0,0 +1,22 @@ 
+struct C0
+{
+  int m0;
+  int m1;
+  unsigned rh_kabi_reserved1;
+  unsigned rh_kabi_reserved2;
+  unsigned rh_kabi_reserved3;
+  unsigned rh_kabi_reserved4;
+  unsigned rh_kabi_reserved5;
+};
+
+struct C1
+{
+  int m0;
+  char m1;
+};
+
+int
+foo(struct C0 *c0, struct C1 *c1)
+{
+  return c0->m0 + c1->m0;
+}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v0.o b/tests/data/test-abidiff-exit/test-allow-type-region-v0.o
new file mode 100644
index 0000000000000000000000000000000000000000..4a036677aa27e0c2cc8b16106ed3421cf6820086
GIT binary patch
literal 3576
zcmc&$&2Jl35TEDu#tzPh6BkHGQEUWiTCsMVhLSc)F^WnP6+u;0RpO)R+J3f|_#;|x
zLK=h$mr7BD)JhyU^adBs2&pPZE<JMOAK+djBqBh-%=5ft^So537e?~VZ+>s)&AgAD
z^{oqUz7Z1wv<Ns4hn8jm_LGOWq+kh-K?bg_?Ebv6`^o;w?&hPFy$kz$X?#A~1M%Yr
zKm3J$HV74&pqS@XVCZo?gstUSI4*7@6Kl<al^}$$2yq4Dsw(?)B$Emb5FAo4K`^ag
zlHf4~2MJC<GH!eA0OD~~g0)<P<j{9GLRm%*vy3K*j6+-upoYO(rvoCR>LHs%S1a!Q
zhL&BKg*1WK-G*H$!t|dC-++NUf`Kpa0b&@ek#jk*m^zyqTFoq^&>N{_k4p6zD<iCA
zD#dO|k-;)vgjDK$${N8mHv8u?XE7i)fpd>SDwkYEzr>h$X(W@frl+RI#CRh8EN%{m
z;;s+o#cPw8EQRS)Cni@j<Wrj1nWPl(GX7#zB!rF@Exk%L6neaa*hb$|sD%)Jj0}^a
zoyH%6X|?GwF&!K2O{-#U0fPr7uGAj--hR4fkJW5Zh{Z5&v)%RTZCTCIAzggyYIeE!
zYPML+pUxMvbF*`E#o}BsJ97mcR@{IGocWVkrxk3r<x*X?rSDbHbp1+WX?x*}b7tPz
zn#($M@EdFEZrNM&Wmo!JvRdq8=K7e^eaw6x^9ocNt`CJqrzH#3PW3~tQ1^mD(<@`P
zy6ZIyej{*jJ<@Nx%|f*+*JU7yb*LVP>nQ}X8*~d*H*ghnaIEUpYL49Y0-!<1Z8kd}
zIl;{hi9vO*({{FI^OgTG^W&<5i_6RBvNL#wC;!6%s@s9DDr>QG1;ln*ObsQHckm|B
zEz~zr>DNcnw`0r01J}@jW1<vY!Z`f$chr~_+1UUreh<tT3rC{F!VFPjfodInLl&sk
z6TuJmaYR^veIi0E7>Z!YANxdvSTGvFlK*fYPpx@8v_E?9AA1j}N3!TMc?#|DF6d0e
z(`vOn&T+)k?>gJh7(AQs90NMvgMNbe6!SEPu7RkxLp<eukL`C2zQwjQ_*-mm82nwf
zKQ{QU*uG=%Y{Gqmr;iQE!=6$*A6}Q<Lt2;3KBUr&&3$-*dGe><4%^h_Ni_dc&x9gt
z&Hu{wB5QO0Eb~-jxK7A-Z?*!rj5_dpx}i}Zw*$yie}jCv+l9O@n{K`;%bWEzuU+fl
zn8I$k?8~hq!>;eP>+)zw(`!o|f+;j4dQI7tPOByHE0S+_0-47?<a7hKvd$CB##+sH
zTl%1RJx{8pFp&00pOc=a#NgolVViuzl0$<yv%|a}b_!uL{sfNEeSgw;I)8IcN~iP3
zj6uUx{~o9dmMADBE4(3>IbaOO$WOnU`1eK05<bm2Y2Z4O_mtP+!}Pt3LncSwzcV>|
z7^;xzdkNX7`oH8>t>dYFqRjfM$eD8@1*iDsxJE`uOy4yei^~6y^WWfD%1`~v%)fyg
z&8h1|sN^%w|3DM0b$+d>e?`SF@`dXCn?9UG$7#LyFY%XXQ7DC;I(X_ht?BQv#s^La
zb~rxF5jK6lVeUvTLhe(JU!b6n=>5~w*9ge9qzTqD?5OW4?LU1*b-d=O9y2#hai8-y
oxM2Fu(bw6Gr!zI*U8Eq(?@x}5keKVIx}xGsoaoz7EI~8=A2fhgBme*a

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v1.c b/tests/data/test-abidiff-exit/test-allow-type-region-v1.c
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v1.c
@@ -0,0 +1,23 @@ 
+struct C0
+{
+  int m0;
+  int m1;
+  int correctly_inserted;
+  unsigned rh_kabi_reserved2;
+  unsigned rh_kabi_reserved3;
+  unsigned rh_kabi_reserved4;
+  unsigned rh_kabi_reserved5;
+};
+
+struct C1
+{
+  int m0;
+  char m1;
+  char wrongly_inserted;
+};
+
+int
+foo(struct C0 *c0, struct C1 *c1)
+{
+  return c0->m0 + c1->m0;
+}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v1.o b/tests/data/test-abidiff-exit/test-allow-type-region-v1.o
new file mode 100644
index 0000000000000000000000000000000000000000..668224e36f697e124c0928a75922eac538893d5a
GIT binary patch
literal 3632
zcmc&$&2Jl35TEsC6Q@obCpM6fB0C7w53zPO4JD*XF|tY%fdCa%JwQp;_Ordj_Ezgn
zngl^_NKq~=f&-!lgt%~q6C9C1NE~`Be*pI)aj3)rW}fFco0nCE;J`@x<~P5YdGo&Z
z?cTcd+A9ge03`-oghNZQ0P~}VxGZ5Aa*&0qtNXvL?tk!bb${!@>cORl2N`T19Ds4}
z`VSM>kp)JQ!bhliikhgLj2LER9!?qu$Rs-RV2%(%=)jPKLvmD>#7T*V$3Di0F^NYc
z&Pbe;I4AL_#M6)*vb=5xLql>LX2pTz*pFN)eOPKDNo2oNMq&%CVdP-6;rn3Z<N(Pg
zQNuUx(ul0uJY)zY?zF6$1Nm`@H(<DkvBRHHhA|FidU?*cka{t-mR(9=Ffz#_jF~me
zWGdC?=8{GhNAwJ&QWsNZ8mm|wKbNB}64TiA1f=GYYZx~&X*`?Grp)|oe$tp4$vgp&
z<W$^+(W3Fv3>HgK^;0uzS&Au7@6AvNcn+TgjS=LANkomB<bYuC7HSJ)&!RRA<InUs
zDOz=W5abC$!pJ8k`rVQVmI0#!)65yx*!R|B4QsMt8Kp!5^Mcm;rd##a1JM(~wx~Z3
zTiu@5?23AUcJT7+R|^&Ag@WT0&lR1*!u-O5<19FZ(^oKH)eYHUFP<sbop7rwR+^$K
z0<VUq8`N4WJ4@&7^NaTOLcwmr&A{(A+q>&t7mJ0W4tn*4W6Zf@%p%nMAP}`M+EK0L
z22g7G9Z{<L_4m9|(+f*&uZmM^x?Z~!v_c!_BZ98mF4cQtQ-p$8n<j7b<V&IGg}qYU
z4P6Os^wqsa!xlSU2;{WgcH6&chr2ffCN(|3Yi~Qn+W%PjQKN#(mCADAH16S<f3Sh_
zyyRqy2WsyM7&{qbc5Ebh8&4LUN_8@&emR}_C{Y<7zJ>vu6Q}4<4#Dq##re$Gn-9R`
z_d?Gx(Gw>oR)`Z5<V|wSW%h5!7(R08M!Y8Ay%8fOjK#1te!Mqg#Ds|$mg2{c@pN@h
zMb<~H{Uc8yU70LuPfnm6T?JK%c$#gV<EK~?PtUt-Kd$j?!jlYWe+Tyq;<L<CA8HIl
zy%FK5?ze2et??hS-PHKoZ1*(&OSW%mJe%;T#;bXLr|})Of7bY)*#4EZK3}!AG+&Ej
zNM#u7@lP{P@$~GmO<w~N#ozCn;ILNwA8cP>t@mGGp7tcVFHr35c0#v`It=={rBEn#
zLMYO$2gPcy2gN|N-C|u-x0-lUH+=L->{hFR*goQR1Gn20M^oBfSEv*$p&-%g(ysZP
zj=*nAvFnGTh_{p73*Fi#cPv`#jlk^)p2&YxvzSk7r1nX5S7tDHuh^#8sLY{3oPP7X
z6Ag-BJ^vK?=sozi`LzFfpHxoO&uUK1lz$m?JC-RaA}wB!7AH)ikK)uji@!NiR<PCk
zB!|!B=Q8TB(PQ64m(Ef22|k?jhp7_jv9BT<H~xF_#}faOIiJQ)ls^7Ca(bVXvds0b
zkr5F+b{&0j^;Mw_&ZYWvuj%z~AV+<waUzs*hwJ~M2-d2;((fZ5mw%lPRR0(JuoIQ1
zH2u}b<#%XOD5bs{v?@>OPtc?AAPB)-&X010_1LeO<LM5<zu^3(0n-O+{S^Hb0tziF
zg7pRms&h)~PhVG+uXq}dUYokO&-K;$r|$xNwe@`3Q~ljV3d;Qc%#jfhef~7AxcnV1
L^i3p}pq~FXvNv33

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v2.c b/tests/data/test-abidiff-exit/test-allow-type-region-v2.c
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v2.c
@@ -0,0 +1,23 @@ 
+struct C0
+{
+  int m0;
+  int incorrectly_inserted;
+  int m1;
+  unsigned rh_kabi_reserved2;
+  unsigned rh_kabi_reserved3;
+  unsigned rh_kabi_reserved4;
+  unsigned rh_kabi_reserved5;
+};
+
+struct C1
+{
+  int m0;
+  char m1;
+  char wrongly_inserted;
+};
+
+int
+foo(struct C0 *c0, struct C1 *c1)
+{
+  return c0->m0 + c1->m0;
+}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v2.o b/tests/data/test-abidiff-exit/test-allow-type-region-v2.o
new file mode 100644
index 0000000000000000000000000000000000000000..924ae596926394cd7f0f020d9486c5eecfca4294
GIT binary patch
literal 3632
zcmcIm&2Jl35TEsW6Q_0(Ck~L1qBscD53zQfh7wYx7@5*UAcTsl9soIO``KP%?^f$g
zngl^_NKr17j{^cB4shVy0}>pOkhq{8%OAkKNE|A0fSKoc&gNwmArK>Z=QqDMU+-g|
z_x6=nUrrbXC^6tN99oJ6SQt6PWeLkL1v$9Bw*TAO{(BGC_O~9a9b9>Mkj3YN12FEr
z{o^<$vcO1@`!GG8phr|rM+~#F0H=)uWD?y4Foy~CTS-csOms_NNtluy4rM+<kBr2_
z5@#h&NjxR-h{V&7N?NWLLNY1)Fe@cUWq#sPWBpQ;emq5FQif(Fw$K_v4n~^355|;i
zkZcmwzVQWhWYrfSOCWKlZPiOKH!AT43>DCK=rf8iM!_6gnKv$_pHHvnmec5rOzH?@
z<_t5HPWQR_l##=Zo`Q7xa@rijDi-_CPf?1*G^QSh^n7X^{e~xur^j+>b8dES!k8S+
zJ_eBDP~3%)g7Lx(7E4q0Gc)Ts@+nX6%}@z=27d|a5#)wRL=QE|0m0x6)E4@lM{O9!
zpJSt>XzB2WV2&UpjJd>kKP{PH889+1%_+mm{9rxOv?iLCQA{K-E@)Rbotj$>L{9|U
zqVX(jc|Et~iAJ7w@ak*V^Oe$b`BJHHp-{>%E-WsVN{glZ*=y*q=7c<8FP+QV-Ehkj
zt1aP)z^$X{1oign&hkb3;*!0+n73PSEAYKmXSeElSS%C`aJ{-81fm{BNxh{-(3z!U
z%mt{ood8173vH*<@o(AT?oD9_qUHJ?Rxi|{*!H`k*zg<gxW$$m7CUYYC*E@0PBCbQ
zHqKTAp3^BddSX+Af>@iD29wC8DN^!YvEhV{gf@;f+-B1jJ8t+tXFq9PCyl|?N@XQ~
z7I*R7KiEP%FH`c=;DOq^2F6a-n9U5QKE#tnr&66vsb3t+evqh)4&6Wpj)_xrD3kE}
zUvXn*?9B&Y@_V7jm^czACRT_O6XZ>DY{=~2jxl`X(v6IofcHj>n2?EKseimTV#I{;
z7?%7;kMVSMPe#^9t^J87oUTk3wI`?0j;?~LL_E!Qj{PTD6Hh-Sk1|la>f>?dX@3Xz
z3*z$;f7Js~FGYB&`##%mYW&A+w>17cwtE`?4coUho=x~v<JCOB*Z3~mKWn_Qe`Q{u
zuUcDLAB%lRWf|-KPcpC8bB}HMHy}~`{k{n$){6gw?Mtln{CVbSPonz*h2CyAbZV%>
zps(8sg<>a!0^Ms+sP%eK2t>yzG(>Hyg*SE6$1#bWS}hRUM~0oi@mk_&NXPYr3c(Tz
z5?z&c-S2h<{<jo7KNJPLo9tfb)HgY?Xjhwo(-l0C|EOj$p4Le1lS)@+pw6@6$u}zV
zXb`90Ja0vvB3O?<gJbj_{M&fie?2FaQ}uJ&pk~Ui47wf56cmv*FG!mMCUA`W)H{ox
zIZ{^fspq5tpUKaq*Wp9=eI18%j=WFt;aoTjl}Pt}1=+a%@5v8K{7&Y0>YpgR{|0h;
zP6}D!`Zvgki0)g(vAFuG&<4j+eY)55`ZtlIoT^WRQtoj5UlhSw)mQpm<m2M2e4zTD
z;D<?6oYM4F9~bY_q)>`|HF&Bxr9Z(Dg$GUuzU25QM_Bj$mN}m8!2K(ZUmh@hpw>^(
zUn3ybvLaY-u%kMswEpz(s^S$-{phtR#eJ@?&OiMx(7(1GPkXAryGTKq-=BFhBBIZq
R`ihI+;X-#Ku>|$_zX1}OT?haG

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v3.c b/tests/data/test-abidiff-exit/test-allow-type-region-v3.c
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v3.c
@@ -0,0 +1,24 @@ 
+struct C0
+{
+  int m0;
+  int m1;
+  int incorrectly_inserted;
+  unsigned rh_kabi_reserved1;
+  unsigned rh_kabi_reserved2;
+  unsigned rh_kabi_reserved3;
+  unsigned rh_kabi_reserved4;
+  unsigned rh_kabi_reserved5;
+};
+
+struct C1
+{
+  int m0;
+  char m1;
+  char wrongly_inserted;
+};
+
+int
+foo(struct C0 *c0, struct C1 *c1)
+{
+  return c0->m0 + c1->m0;
+}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v3.o b/tests/data/test-abidiff-exit/test-allow-type-region-v3.o
new file mode 100644
index 0000000000000000000000000000000000000000..b30403eba8fe5a73be8dda242406da5fac9b2ed8
GIT binary patch
literal 3688
zcmc&$O=u)l5U!q{PC7gJnPieRF)NvfvOm}}nIx`pm#mRtcM}wqm1Ph9Bt0{4X4=g3
zEIplUl4V^_;u3@v1O<OU(1SO@g9kkbg5XUALGa>b?<;r+c+jdh^(LK{CWsz<(67Gw
zs_NDI>*~IJ@!3lW!vNI`xB&Z_Vgc%X`*=yhB^ZSaTwT6%Z~4xxz2!R__m_7s?(L?r
zzrPE{kFR_;i33?+*yP?z-9ywx+lh!`7H1%9yoXGpIRj=dA%q1;N|=<hvLv=8?&<#+
zJ^Cf?l{hW2E%B(teG-pLd`#jKU?(ll4<VV9b25tsum^tPv_t!8(>9Tvw8IixsP!NR
zebrVAj4?S`(y6JX7#~t*t2_f~0*QC(R=EIE6B4gMPY!*1KBEX@0L;O2)5iJKlc|-=
zLJFOcu@5k2#xU(vs>4m&Mh0i}2&7UMQsy9LvDklljD|>z<IqEpnzmQauXosZbTE@L
zrzWR{jgj8;0{}LM;)(R-jHf0rS&FisoLI?_&(iqL1f_t-@JY}dK^~q&)Tu>w2?j5s
zw9xkqO2aVz92_7)yN(ZnDT0tNrV>M)VMztcfWEG3ju}?}*Vb6o8m?MKK9Rt<puW29
zmb}$Kv_-HfDv!g4-}Y+0sATB`FF$uRTP!@0EfjKdxk7e!W_Gqvm@Q;aT|tLsH)Mk|
ze>&?l!wp|7)`TwtuZ*f2l<SLI3um3P^UmgM)~Ugbpyk&Z+pC_B$wE;9J$nH>zuXD}
zQ4WuCn>`dbe~6iba@`FeUvD)<zS63^=H+W%m~VI`TyD+v8u_3eI=Ds=_--R#X^V9c
z3Su4F5QjG;ABuL^&R5*fmC!+3#j92wvE_w8M#pV5S~r|<`?|oOn%DB3&AD9pf6RQ;
ztl)C7crJSi&-L^_I8=FuMrDteZ08CXTWMpmzt_Htw~cP9x~)<^J(zwoQ5@*Gh7KGP
zC+MOk;rGAdY-Vg_1Tgts(PK=s#5EH$#5EISbva}*JJmCWj}+yI)dZ|1G0lYj7?$Rb
zwIrsQFcia*|G*)hO8ZD;f7IR|c?+qGa#Lq=4E5+Ps7%DuYNyzLgeCFxyvq7<jb{}e
zWI*TJtvQI#Fi&HsIS}=Hgr~fBS$|36UuV6h@v_1r*VgzSSii0DU$MTc@vOop8n4#>
zy~a0L|5@XIW&IvYeIL}G(>_@2Ln6&s_kWmq@~3Bqb^3BpQ~WO-6$&gB{|D>mS?c3w
znWwXgo)_fW+s)7|p$vnLtSc0Xtq^il4Ix)*w;>mZhMTL1(nbxddbNc%iQQ5u5Ss_g
zZs7VgaWJIe`9g(Y3I&N?m3q0=Yzq7i<@{DCa#*#TcIcMZd0<grtp;vW@IwBhn8bM6
zBXv${xFrVN_l<S(jkal2h|??5%TcEY*5gm2joy!c8&Bu2k4foN{>~o)F`cIS(!HXp
zxzsUt`?q*Q-r#^?w2+^Am+_ZKwngmqG0AX~$q%I0ey97sfF_+I@8f(qXZAxS(tV#n
zHg5hlPgKRz{OP|`pMM28eN3d_66e20N~Gz&t7wbMzrcysIF|BLz0>nwM~=o+^F%1y
zN1XpR)|F8CmAr|DxcFOqp*p|rDtdpdDxT_MT>RU#C~WzT==Lg3$#>DBaMuaJHyj`3
z2<yI|GsnyAx_`^@3tgrI)cz^@Qv~F?qzIPpv!lAFwEy(gRq=|a`RKW6h&|3<=Lyqy
mfxhN?Je{fj?ji+i{QgXn5^4JSX<l*hUvQ!?Be4Ya_`d<0OK8jh

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v4.c b/tests/data/test-abidiff-exit/test-allow-type-region-v4.c
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v4.c
@@ -0,0 +1,23 @@ 
+struct C0
+{
+  int m0;
+  int m1;
+  int correctly_inserted1;
+  unsigned rh_kabi_reserved2;
+  int correctly_inserted2;
+  int correctly_inserted3;
+  unsigned rh_kabi_reserved5;
+};
+
+struct C1
+{
+  int m0;
+  char m1;
+  char wrongly_inserted;
+};
+
+int
+foo(struct C0 *c0, struct C1 *c1)
+{
+  return c0->m0 + c1->m0;
+}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v4.o b/tests/data/test-abidiff-exit/test-allow-type-region-v4.o
new file mode 100644
index 0000000000000000000000000000000000000000..8c77f1ab621c96d80c1e49893ffe116c04ebc514
GIT binary patch
literal 3640
zcmc&$O>7%g5T57tCYw4xPHZ3{MRpLVKVt3J4JD*%35rS+fdCa%J@AvR?Pq(5f1>p!
zO@g4DkfK~#1P25cq#oeR1;G&s35f&T%8d*6B5|n10cM`(Ih)s2h2X$Q`{tW(X5PHN
zeY-a<zVt#u2+$(n0vuYJ1y~$8#LEgULl!b{Wp)3z)%|zxt?qB#T|KyX?;wrs-2)Im
zz4_e)c4UKaD14Zj$Eb<Q@rYrq%)@bUfJ~x257satge6ESm{g;(6?POJ8vPI>Mim}b
zd|F{g;jF?VDrOp-r0sV?NG8=dtd$Ztqu+C>aTTvhO*lmMOQjXI(HcSyM(W)zh^!hQ
z*(7@S;xihNU7d$CfyAw*T`fUwOyO%VRKVDwPbfo-fi=D~C(fmwO|4}XQy7elbA+)n
z!g5lnJ~!ux436jtNTn{MtZ}SjbNpPEx=2i8*AtMMbJj3!cv3t$o=I7`+1#X<8csg~
z;BYGL!bm|pH-p7eRQ<%vT83hlr}t*41U!XLg2o7H!xW-MPjWyocn!6Uv8PcBA^sd6
zBSou@4}u&)NQhiwqTel<U<()-m{wNUqu<&O)$Pf;EsBW*<^|354X@&_2eK!FZCQI7
zwmLn((UG-0?ck-CujE%s&*V#`!kI!TU!E_QOQmutfATU0ta>3k+=Wwlw;gVE<oSl|
z$iT0n=>^s1`JKhH?%4%*yPS6$a6RaD8m--Rzk|g>Sp&0r8LHhNkkv2}REpu^;?6*|
z=><@1cH6R8>(<`(iw!?4w)_gtui^QvV$cj-oRkbYUaMH^$qgAwVqIDRmsg+|%3jzj
z*1XVD&_!R(uh(6<<A*>_*K4)9*WGY;Q({uX?{?hng+ldzto)!+!KIazrTj_U$W#Ad
z7uBJ`Cd)wVT?Vm}7PF(n&P_aFbUO73Rr>ky^aqKRv7xINpp#=X9nK{D{#T3(tk@e6
zkRP1fBWV_T;>5xVabkhGQSNhD{aZ4Ik6gYHuLXF2#E1o>F)WQA?~fR<U?PU4__6zV
zy27U->!a8Hfd`SUP8Pi<$Iy<hg04h7%{IsJQ>=-n=PkA$Hh4DSQ3kZX(cL;7iPvKw
z>Xisjb#Jo$y1~E4cEjLrv)wcJui3s~@NB}z2CwJ&jls9s{=wjXWcwG^=6v<q(wf;E
zLn_VKjDMVYz0P}V(^r8+^LP3tlvr#254O*-Hv7*rPkR#G7bx_0+o4xM9R_{f)F_lY
zAr$E1gF>a(gF+x%UZEx{TMfLi>s|CI>{Tj(+&<#=0<Y7MM^jpUN9q(Tp&`-h%C2_X
zZHeEQLZ=(b0$xyVFZ8M#+_7w~*8{IDc_RN&&0;>Sk=`fW-7<s0d&M@zMr95S;>?@p
zjc8B=oB1cuNAJPE&8Pi0`=oNZe#USbruy5U+i{taBC^Q~(&U6m^iiCCXYqGO$$4ze
zKFQH#@>3Oc*qE`eqRZqc`WPS1`NLF&%-9!^jT`?R^@9nZ^J)A<nd7e^XZDE{EOGs-
zWJJV_T}NMBeTNHO<6Npw_nKLM6FKTrj}xJiTU`HVO|aJWwSEWrxcmwqsQ$0`VJA9I
zYx=v7%MWN$D8;@Sv^r1gkI<v>APB+doFC-~o3URq$I~5zf5G{S1Evr3`f2($0t#K$
z1nVXT>T^o#PhVG^uX!4eS)01}mFw&CPu~UlYMc4Ar{=qh6s+?5Ge<^5%=y!};_~0;
MLSIF437YwT1884f`v3p{

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v5.c b/tests/data/test-abidiff-exit/test-allow-type-region-v5.c
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-region-v5.c
@@ -0,0 +1,24 @@ 
+struct C0
+{
+  int m0;
+  int m1;
+  int correctly_inserted1;
+  unsigned rh_kabi_reserved2;
+  int correctly_inserted2;
+  int correctly_inserted3;
+  unsigned rh_kabi_reserved5;
+  int incorrectly_inserted;
+};
+
+struct C1
+{
+  int m0;
+  char m1;
+  char wrongly_inserted;
+};
+
+int
+foo(struct C0 *c0, struct C1 *c1)
+{
+  return c0->m0 + c1->m0;
+}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-region-v5.o b/tests/data/test-abidiff-exit/test-allow-type-region-v5.o
new file mode 100644
index 0000000000000000000000000000000000000000..a1da2d31dfa842f08f93a6e54b71b3ee9dbb50cf
GIT binary patch
literal 3696
zcmc&$O>7%g5T57F#!j6dCuvGUisB$pf5h5x`a@{dVidJa1Oil4^}tWMwx8`K_BvW`
z(liwm2??pnB?u%A{0OA>z?n-WZXh8J91s!`R}SS|Bo380z|7lu&gNxRAviG7zWL^R
zGjHDC&hE|gFI-3o0a^r{gB?q=0ILH#xU66q_QN<_Uc7a0@zz@p7H_THU)(zXU@M31
z{VfnbzW(hL4rGJKkb9b%$Eb<Rp_pMU%tBs#giNYE3s#yC!V>f;*r#S?E1XfdfABN(
z7*sf|_?*HSh4(8wpnMK0yif6mAk$}ieh7ViYEITd2{J=JaoQ2(qtfOwL`G>x6}Hjp
zM-B$+oeqczHCeJr^isqpl-aJ%LXJS{{ia<l!StlUSE0XvzWsM7LJWa5e0oNl$v%@^
z8lTUiGcuW7j5RK-Og0;FGZ`_CGkOBD*>hQI7_->yKQlo?qz>ZHBaofRETLa|R6IF6
zp0%c@rboqCI`;@bhC}g01`6WYNlccd?1v|p#>uCAaC4GUz*G37XpW!`Pa$gbB6|db
zS5VvNdknP@;?LnBQnc&%AebfyDKVWIiH0Q;Yyks3)0z<W;Mev<-5#ymqL@lyT+m!z
zaVy?(AiFYHm$j3y=6Ah@FKc-^!HX|m&M%an&X-Ds<AqXwZgy_2RGKU0k6c2BMK|OQ
z=fu&x(+<~sdA1>a8F*DR-Jse$yD@*tId#HWpUXQ9xE6H$M(g^r=VP)^*1*g@2h~mx
z$Z8mKDkX49e#gP{_eMjt=>|}2cG|L7>(t)#iVZI;w!8{1y5V}QV$cj7T&WCvw^gil
z<%$d?u?}sE!`o5}WjE{=Yi{T&=wM&XtJfX5;e|k*j@xQ=t~ufLRf$0juj4!GCkxg8
zG4sP_1s4|<PUnx{=^p(DN2_iUU@eM7Y+eGfkrPvc>C86XI=Zp?)++tnaPGa-!chMe
zbl{jIMHjXYe*Y_}&q}P202aS9W{ibBNn&A!B(XqMnLS-rR7Df`SaFW^T7WerK`a<d
zU}^qXQxe32kp!0fhxYJP;>Tk9qxb%y_mIjdi$0TmXvcR!XCj_fJI(%Mtcj=R4Ym&$
zJe%++13KSc?LmBuc^X5{fvA^aJmuYH`&EN~o9%|d-)6gO@ORn1Y4B{qmcjqP_7?`P
z*Z-Ztx7q&L;D2TN9&2+S^q$i`*z7|p$Jq3LoO$x6XOnIEf{<wbm&k+?Yt8?`_8HdZ
z_<82(tm5Ydh3@rs=vGjNL8O}+g>oZ=0@Xt(RJvU#1hVB8YO=D{!0KM_V4uQnr4q>X
zUEOZr`VF}|q~-ZihhPc~iC$KAwbO1({2mqjPACglx14V1R#$jn*<7v%Zd>v~{-c`0
zc-kX<PI|a9gWmhbHu=V71`XoOiu79CDTdAX!`Mgf$G?rI^Ebz&bUJ_Zr$9_3rZ3$q
zs+#4fyVq{>hP=Z8qu4`!`d!9fBPD0CHOHim8%%zzymlJX_hsxdIr2WhmveR}R3X#%
zd1RC3pW}(@c$z=`pPKWpA!m+>6kOo^SICHo>AQ@5N%_m1=qkrjeyVq7{#E2?Og&G8
zN<QWMziEQC&ad?i<dfpx<qH-4!tV^C<Fux_m=ym3EefR=sa~t&wEhr#H10Ve_=e--
z9AVS<OXhgFJ@@Z9e!j;<K<}TXZzCYrvL;x6&W`$?(*Dy|SI29f=40koLvXQf@`UNT
lKwon+p3c;KcPYNf@6QYwF)`Oq^Gb@p%Za{<#S%2*{|4n9YbO8z

literal 0
HcmV?d00001

diff --git a/tests/data/test-abidiff-exit/test-allow-type-suppr1.txt b/tests/data/test-abidiff-exit/test-allow-type-suppr1.txt
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-suppr1.txt
@@ -0,0 +1,7 @@ 
+[allow_type]
+ kind = struct
+ has_data_member_inserted_between = {offsetof(rh_kabi_reserved1), end}
+
+[allow_type]
+ kind = union
+ has_data_member_inserted_between = {offsetof(rh_kabi_reserved1), end}
diff --git a/tests/data/test-abidiff-exit/test-allow-type-suppr2.txt b/tests/data/test-abidiff-exit/test-allow-type-suppr2.txt
new file mode 100644
index 00000000..043cfb39
--- /dev/null
+++ b/tests/data/test-abidiff-exit/test-allow-type-suppr2.txt
@@ -0,0 +1,7 @@ 
+[allow_type]
+ type_kind = struct
+ has_data_member_regexp = rh_kabi_reserved
+
+[suppress_type]
+ type_kind = struct
+ has_data_member_inserted_between = {offset_of(rh_kabi_reserved1), end}
diff --git a/tests/test-abidiff-exit.cc b/tests/test-abidiff-exit.cc
index 2424675f..f7ded109 100644
--- a/tests/test-abidiff-exit.cc
+++ b/tests/test-abidiff-exit.cc
@@ -493,6 +493,193 @@  InOutSpec in_out_specs[] =
     "data/test-abidiff-exit/PR30048-test-2-report-1.txt",
     "output/test-abidiff-exit/PR30048-test-2-report-1.txt"
   },
+  {
+    "data/test-abidiff-exit/test-allow-type-array-v0.o",
+    "data/test-abidiff-exit/test-allow-type-array-v1.o",
+    "",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-array-v0--v1-report-1.txt",
+    "output/test-abidiff-exit/test-allow-type-array-v0--v1-report-1.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-array-v0.o",
+    "data/test-abidiff-exit/test-allow-type-array-v1.o",
+    "data/test-abidiff-exit/test-allow-type-array-suppr.txt",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_OK,
+    "data/test-abidiff-exit/test-allow-type-array-v0--v1-report-2.txt",
+    "output/test-abidiff-exit/test-allow-type-array-v0--v1-report-2.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-array-v0.o",
+    "data/test-abidiff-exit/test-allow-type-array-v2.o",
+    "",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-array-v0--v2-report-1.txt",
+    "output/test-abidiff-exit/test-allow-type-array-v0--v2-report-1.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-array-v0.o",
+    "data/test-abidiff-exit/test-allow-type-array-v2.o",
+    "data/test-abidiff-exit/test-allow-type-array-suppr.txt",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-array-v0--v2-report-2.txt",
+    "output/test-abidiff-exit/test-allow-type-array-v0--v2-report-2.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-array-v0.o",
+    "data/test-abidiff-exit/test-allow-type-array-v3.o",
+    "",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-array-v0--v3-report-1.txt",
+    "output/test-abidiff-exit/test-allow-type-array-v0--v3-report-1.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-array-v0.o",
+    "data/test-abidiff-exit/test-allow-type-array-v3.o",
+    "data/test-abidiff-exit/test-allow-type-array-suppr.txt",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_OK,
+    "data/test-abidiff-exit/test-allow-type-array-v0--v3-report-2.txt",
+    "output/test-abidiff-exit/test-allow-type-array-v0--v3-report-2.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-region-v0.o",
+    "data/test-abidiff-exit/test-allow-type-region-v1.o",
+    "",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-region-v0--v1-report-1.txt",
+    "output/test-abidiff-exit/test-allow-type-region-v0--v1-report-1.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-region-v0.o",
+    "data/test-abidiff-exit/test-allow-type-region-v1.o",
+    "data/test-abidiff-exit/test-allow-type-region-suppr.txt",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_OK,
+    "data/test-abidiff-exit/test-allow-type-region-v0--v1-report-2.txt",
+    "output/test-abidiff-exit/test-allow-type-region-v0--v1-report-2.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-region-v0.o",
+    "data/test-abidiff-exit/test-allow-type-region-v2.o",
+    "",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-region-v0--v2-report-1.txt",
+    "output/test-abidiff-exit/test-allow-type-region-v0--v2-report-1.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-region-v0.o",
+    "data/test-abidiff-exit/test-allow-type-region-v2.o",
+    "",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-region-v0--v2-report-1.txt",
+    "output/test-abidiff-exit/test-allow-type-region-v0--v2-report-1.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-region-v0.o",
+    "data/test-abidiff-exit/test-allow-type-region-v2.o",
+    "data/test-abidiff-exit/test-allow-type-region-suppr.txt",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-region-v0--v2-report-2.txt",
+    "output/test-abidiff-exit/test-allow-type-region-v0--v2-report-2.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-region-v0.o",
+    "data/test-abidiff-exit/test-allow-type-region-v3.o",
+    "",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-region-v0--v3-report-1.txt",
+    "output/test-abidiff-exit/test-allow-type-region-v0--v3-report-1.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-region-v0.o",
+    "data/test-abidiff-exit/test-allow-type-region-v3.o",
+    "data/test-abidiff-exit/test-allow-type-region-suppr.txt",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-region-v0--v3-report-2.txt",
+    "output/test-abidiff-exit/test-allow-type-region-v0--v3-report-2.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-region-v0.o",
+    "data/test-abidiff-exit/test-allow-type-region-v4.o",
+    "",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-region-v0--v4-report-1.txt",
+    "output/test-abidiff-exit/test-allow-type-region-v0--v4-report-1.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-region-v0.o",
+    "data/test-abidiff-exit/test-allow-type-region-v4.o",
+    "data/test-abidiff-exit/test-allow-type-region-suppr.txt",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_OK,
+    "data/test-abidiff-exit/test-allow-type-region-v0--v4-report-2.txt",
+    "output/test-abidiff-exit/test-allow-type-region-v0--v4-report-2.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-region-v0.o",
+    "data/test-abidiff-exit/test-allow-type-region-v5.o",
+    "",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-region-v0--v5-report-1.txt",
+    "output/test-abidiff-exit/test-allow-type-region-v0--v5-report-1.txt"
+  },
+  {
+    "data/test-abidiff-exit/test-allow-type-region-v0.o",
+    "data/test-abidiff-exit/test-allow-type-region-v5.o",
+    "data/test-abidiff-exit/test-allow-type-region-suppr.txt",
+    "",
+    "",
+    "--no-default-suppression",
+    abigail::tools_utils::ABIDIFF_ABI_CHANGE,
+    "data/test-abidiff-exit/test-allow-type-region-v0--v5-report-2.txt",
+    "output/test-abidiff-exit/test-allow-type-region-v0--v5-report-2.txt"
+  },
 #ifdef WITH_BTF
   {
     "data/test-abidiff-exit/btf/test0-v0.o",