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
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
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
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
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
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
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
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
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
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
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",
