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-corpus.h"
#include "abg-diff-utils.h"
#include "abg-reporter.h"
+#include "abg-suppression.h"
namespace abigail
{
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
{
/// 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;
/// 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.
///
| 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
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);
bool
is_filtered_out_wrt_non_inherited_categories() const;
+ bool
+ is_filtered_out_without_looking_at_allowed_changes() const;
+
bool
is_suppressed() const;
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;
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:
/// 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
~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.
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_;
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.
/// 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.
///
/// 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.
/// 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.
///
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());
}
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.
///
/// 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.
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.
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
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;
}
// 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.
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,
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)
}
}
}
+
+ // 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
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())
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);
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())
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();
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
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.
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.
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())
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.
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())
{
&& 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.
// </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.
///
{
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[] = {
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)
{
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 \
--- /dev/null
+[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}
--- /dev/null
+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
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
--- /dev/null
+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
+
--- /dev/null
+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)
+
--- /dev/null
+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
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
--- /dev/null
+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;
+}
--- /dev/null
+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;
+}
--- /dev/null
+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;
+}
--- /dev/null
+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;
+}
--- /dev/null
+[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)
+ }
--- /dev/null
+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
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
--- /dev/null
+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
+
--- /dev/null
+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)
+
--- /dev/null
+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
+
--- /dev/null
+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)
+
--- /dev/null
+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
+
--- /dev/null
+Functions changes summary: 0 Removed, 0 Changed (1 filtered out), 0 Added function
+Variables changes summary: 0 Removed, 0 Changed, 0 Added variable
+
--- /dev/null
+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
+
--- /dev/null
+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
+
--- /dev/null
+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;
+}
--- /dev/null
+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;
+}
--- /dev/null
+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;
+}
--- /dev/null
+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;
+}
--- /dev/null
+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;
+}
--- /dev/null
+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;
+}
--- /dev/null
+[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}
--- /dev/null
+[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}
"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",